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

相关推荐
Dovis(誓平步青云)14 分钟前
《内核视角下的 Linux 锁与普通生产消费模型:同步原语设计与性能优化思路》
linux·运维·性能优化
xu_yule25 分钟前
Linux_13(多线程)页表详解+轻量级进程+pthread_create
linux·运维·服务器
江湖有缘2 小时前
Linux系统之htop命令基本使用
linux·运维·服务器
CodeByV2 小时前
【Linux】基础 IO 深度解析:文件、描述符与缓冲区
linux
xu_yule8 小时前
Linux_12(进程信号)内核态和用户态+处理信号+不可重入函数+volatile
linux·运维·服务器
虾..9 小时前
Linux 环境变量&&进程优先级
linux·运维·服务器
i***t9199 小时前
Linux下MySQL的简单使用
linux·mysql·adb
偶像你挑的噻9 小时前
11-Linux驱动开发-I2C子系统–mpu6050简单数据透传驱动
linux·驱动开发·stm32·嵌入式硬件
稚辉君.MCA_P8_Java9 小时前
DeepSeek 插入排序
linux·后端·算法·架构·排序算法
郝学胜-神的一滴11 小时前
Linux命名管道:创建与原理详解
linux·运维·服务器·开发语言·c++·程序人生·个人开发