Linux内核源码编译-built-in.o 文件编译生成过程

一. Linux内核源码make过程

之前的文章分析了 Linux内核源码的 make过程。顶层 Makefile会编译 目标 _all ,经过上一篇文章的分析,目标_all 最终依赖于 vmlinux。
之前理清了 make 的过程,重点就是将各个子目录下的 built-in.o 、 .a 等文件链接 在一起,最终生成 vmlinux 这个 ELF 格式的可执行文件。链接脚本为 arch/arm/kernel/vmlinux.lds , 链接过程是由 shell 脚本 scripts/link-vmlinux.s 来完成的。

接下来的问题就是这些子目录下的 built-in.o 、 .a 等文件又是如何编译出来的呢?

二.built-in.o文件编译生成过程

1. vmlinux的依赖项vmlinux-deps

vmliux 依赖 vmlinux-deps,而 vmlinux-deps 如下:
vmlinux-deps= (KBUILD_LDS) (KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
KBUILD_LDS 是链接脚本,这个不需要分析,剩下的 依赖项 KBUILD_VMLINUX_INIT 和 KBUILD_VMLINUX_MAIN 就 是各个子目录下的 built-in.o 、 .a 等文件。
最终 vmlinux-deps 的值如下:

复制代码
vmlinux-deps = arch/arm/kernel/vmlinux.lds    arch/arm/kernel/head.o \
               init/built-in.o                usr/built-in.o \
               arch/arm/vfp/built-in.o        arch/arm/vdso/built-in.o \
               arch/arm/kernel/built-in.o     arch/arm/mm/built-in.o \
               arch/arm/common/built-in.o     arch/arm/probes/built-in.o \
               arch/arm/net/built-in.o        arch/arm/crypto/built-in.o \
               arch/arm/firmware/built-in.o   arch/arm/mach-imx/built-in.o \
               kernel/built-in.o              mm/built-in.o \
               fs/built-in.o                  ipc/built-in.o \
               security/built-in.o            crypto/built-in.o\
               block/built-in.o               arch/arm/lib/lib.a\
               lib/lib.a                      arch/arm/lib/built-in.o\
               lib/built-in.o                 drivers/built-in.o \
               sound/built-in.o               firmware/built-in.o \
               net/built-in.o

除了 arch/arm/kernel/vmlinux.lds 以外,其他都是要编译链接生成的。在顶层 Makefile 中有
如下代码:

复制代码
937 $(sort $(vmlinux-deps)): $(vmlinux-dirs) ;

sort 是排序函数,用于对 vmlinux-deps 的字符串列表进行排序,并且去掉重复的单词。可
以看出 vmlinux-deps 依赖 vmlinux-dirs。
vmlinux-dirs 也定义在顶层 Makefile 中,定义如下:

复制代码
889 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
890 $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
891 $(net-y) $(net-m) $(libs-y) $(libs-m)))

vmlinux-dirs 看名字就知道和目录有关,此变量保存着生成 vmlinux 所需源码文件的目录,
值如下:

复制代码
vmlinux-dirs = init             usr               arch/arm/vfp \
               arch/arm/vdso    arch/arm/kernel   arch/arm/mm \
               arch/arm/common  arch/arm/probes   arch/arm/net \
               arch/arm/crypto  arch/arm/firmware arch/arm/mach-imx\
               kernel           mm                fs \
               ipc              security          crypto \
               block            drivers           sound \
               firmware         net               arch/arm/lib \
               lib

在顶层 Makefile 中有如下代码:

复制代码
946 $(vmlinux-dirs): prepare scripts
947 $(Q)$(MAKE) $(build)=$@

目标 vmlinux-dirs 依赖 prepare 和 scripts,这两个依赖不去浪费时间了。

重点看一下第 947 行的命令。build 前面已经说了,值为"-f ./scripts/Makefile.build obj",

因此,第 947 行的命令展开就是:

复制代码
@ make -f ./scripts/Makefile.build obj=$@

$@ 表示目标文件,也就是 vmlinux-dirs 的值,将 vmlinux-dirs 中的这些目录全部带入到命 令中,结果如下(这里只列出了 vmlinux-dirs的一部分):

2. 以一条命令举例

这些命令运行过程其实都是一样的,我们就以以下的一条命令举例说明,讲解一下详细的运行过程:

复制代码
"@ make -f ./scripts/Makefile.build obj=init"

这里又要用到 Makefile.build 这个脚本了,此脚本默 认目标为__build,

我们再来看一下,__build 目标对应的规则如 下:

复制代码
94 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target)
$(extra-y)) \
95 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
96 $(subdir-ym) $(always)
97 @:

当 只 编 译 Linux 内 核 镜 像 文 件 , 也 就 是 使 用 " make zImage " 编 译 的 时 候 , KBUILD_BUILTIN=1 , KBUILD_MODULES 为空。" make "命令是会编译所有的东西,包括 Linux 内核镜像文件和一些模块文件。 __build 目标简化为:

复制代码
__build: $(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
 @:

重点来看一下 builtin-target 这个依赖, builtin-target 同样定义在文件 scripts/Makefile.build
中,定义如下:

复制代码
86 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(libtarget)),)
87 builtin-target := $(obj)/built-in.o
88 endif

第 87 行就是 builtin-target 变量的值,为" $(obj)/built-in.o ",这就是这些 built-in.o 的来源了。
要生成 built-in.o ,要求 obj-y 、 obj-m 、 obj- 、 subdir-m 和 lib-target 这些变量不能全部为空。
最后 一个问题: built-in.o 是怎么生成的?在文件 scripts/Makefile.build 中有如下代码:

复制代码
328 ifdef builtin-target
329 quiet_cmd_link_o_target = LD $@
330 # If the list of objects to link is empty, just create an empty 
built-in.o
331 cmd_link_o_target = $(if $(strip $(obj-y)),\
332 $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
333 $(cmd_secanalysis),\
334 rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
335
336 $(builtin-target): $(obj-y) FORCE
337 $(call if_changed,link_o_target)
338
339 targets += $(builtin-target)
340 endif # builtin-target

第 336 行的目标就是 builtin-target ,依赖为 obj-y,目标builtin-target对用的命令为:

复制代码
$(call if_changed,link_o_target)

也就是调用函数 if_changed,参数为 link_o_target,其返回值就是具体的命令。前面讲过了 if_changed,它会调用 cmd_(1)所对应的命令((1)就是函数的第 1 个参数)。

在这里就是调用 cmd_link_o_target 所对应的命令,也就是第 331~334 行的命令。cmd_link_o_target 就是使用 LD 将某个目录下的所有 .o 文件链接在一起,最终形成 built-in.o。
vmlinux-deps 对应的其它命令的工作过程,与上述 "@ make -f ./scripts/Makefile.build obj=init" 命令类似。最终生成 不同目录下的 built-in.o文件。

相关推荐
☆凡尘清心☆20 分钟前
CentOS Stream 9 源码编译搭建 Zabbix7.0.29 完整部署方案(部署成功)
linux·运维·centos
予昊32 分钟前
Linux 资源控制实战分析:用 LXC 亲手造一个 “迷你虚拟机“
linux·运维·服务器
allforgood39 分钟前
管理网络安全
linux
灵晔君1 小时前
【Linux】进程控制(一)——进程创建、进程终止与进程等待
linux·c语言·算法
wsad05321 小时前
CentOS 10 上使用 Docker Compose 部署 Discuz X5.0 论坛完整教程
linux·docker·centos·discuz
张宇Joaquin1 小时前
openEuler编译和更换内核的方法
java·linux·服务器
小此方1 小时前
Re:Linux系统篇(五十六)线程篇 · 九:基于阻塞队列的生产者消费者模型与条件变量
linux·运维·服务器
迷途之人不知返1 小时前
自动化工程的构建
linux·自动化
Escalating_xu1 小时前
【Linux】库制作与链接原理:从静态库、动态库到 ELF、重定位、GOT 与 PLT
linux·运维·服务器
三言老师11 小时前
秘诀-如何远程SSN访问家里的八台电脑(frp 实操方案)
linux·运维·ssh