vmlinux.o 生成
vmlinux.oMakefile 对应内核版本:2.6.35.13vmlinux.o 是生成 vmlinux 的依赖之一,在链接出 vmlinux 之前会先链接出 vmlinux.o 。vmlinux.o 定义在顶层 Makefile 中:vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE $(call if
·
vmlinux.o
Makefile 对应内核版本:2.6.35.13vmlinux.o 是生成 vmlinux 的依赖之一,在链接出 vmlinux 之前会先链接出 vmlinux.o 。
vmlinux.o 定义在顶层 Makefile 中:
vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE $(call if_changed_rule,vmlinux-modpost)
上面 $(modpost-init) 定义在顶层 Makefile 中:
modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
它只是从 $(vmlinux-init) 中去掉 init/built-in.o 文件。比如在默认的配置下,$(vmlinux-init) 指代的生成文件为:
arch/x86/kernel/head_32.o arch/x86/kernel/head32.o arch/x86/kernel/head.o arch/x86/kernel/init_task.o init/built-in.o
则 $(modpost-init) 就是:
arch/x86/kernel/head_32.o arch/x86/kernel/head32.o arch/x86/kernel/head.o arch/x86/kernel/init_task.o
在 vmlinux.o 底下的 if_changed_rule 函数和 if_changed 函数类似,它会使构建系统调用 rule_vmlinux-modpost --- 该变量也定义在顶层 Makefile 中:
define rule_vmlinux-modpost : +$(call cmd,vmlinux-modpost) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@ $(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd endef
一开始就使用 $(call cmd,vmlinux-modpost) 即为 cmd_vmlinux-modpost ,它也定义在顶层 Makefile 中:
cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@ \ $(vmlinux-init) --start-group $(vmlinux-main) --end-group \ $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
上面 $(LD) 即为 ld 链接命令。
$(LDFLAGS) 指代 -m elf_i386 (编译内核在 x86 平台,如果是交叉编译,则 -m 选项后会有相应更改)。
ld 的 --start-group 和 --end-group 之间放置目标文件列表,ld 会对列表中列出的目标文件进行重复的搜索,目的是查看各个文件之间再也没有未决的互相引用,当然这么做是相当耗时的,除非是非做不可。自然的,对于内核而言,这非做不可。
接着 $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^) 是从所有的依赖中去掉伪目标 FORCE,$(vmlinux-init) 和 $(vmlinux-main) 这几个依赖后看看还有什么别的依赖。默认配置情况下没有,所以这里为空。
在链接出 vmlinux.o 目标后,接着使用 scripts/Makefile.modpost 这个文件来处理 vmlinux.o 目标。跟到 scripts/Makefile.modpost 中看到:
vmlinux.o: FORCE $(call cmd,kernel-mod)
所以执行的是 cmd_kernel-mod 中的语句,这些语句也在 scripts/Makefile.modpost 中:
quiet_cmd_kernel-mod = MODPOST $@ cmd_kernel-mod = $(modpost) $@
其中 $(modpost) 的定义为:
# Step 2), invoke modpost # Includes step 3,4 modpost = scripts/mod/modpost \ $(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \ $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ $(if $(cross_build),-c)
由上可见,这里实际使用的是 scripts/mod/ 目录下的 modpost 用来解析 vmlinux.o 对象文件,它检查目标中的 sections 是否 mis match,然后还将基本内核导出的所有符号都记录到文件 Module.symvers 中去。详情可以看 Makefile.modpost 中的注释以及参考 scripts/mod/modpost.c 中的代码。
在上面的诸多判断中,在默认的内核配置下,CONFIG_MODVERSION,CONFIG_MODULE_SRCVERSION,KBUILD_EXTMOD,KBUILD_EXTRA_SYMBOLS,CONFIG_DEBUG_SECTION_MISMATCH 以及 KBUILD_MODPOST_WARN 这些变量都为空,所以最后综合起来得到的命令为:
scripts/mod/modpost -o /home/beyes/Downloads/linux-2.6.35.13/Module.symvers -S vmlinux.o
上面调用 modpost 处理完后,再返回到主 Makefile 中,使用 $(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd 将编译 vmlinux.o 的命令写入到.vmlinux.o.cmd 文件中保存起来,以便下次再编译内核时可以进行新旧命令的比较。
更多推荐
已为社区贡献2条内容
所有评论(0)