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文件。

相关推荐
2035去旅行8 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
陈希1239 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡9 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
且从容.13 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道13 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.16 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落18 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨18 小时前
WSL2的安装与使用
linux·wsl
微小的鱼18 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng18 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器