编译过内核的话,一般都会看到在根目录下有个文件vmlinux,这个就是通常所说的内核了。但是用了这么久,倒是从来没看过是怎么编译出来的。那今天我们就来探索一下。
那些七大姑八大姨们一切的一切都是make读取makefile编译链接的,就好像孙悟空逃不出如来佛祖的手掌,vmlinux的出世也是在makefile的安排之下。那就现在看看makefile
# SHELL used by kbuild CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) # Final link of vmlinux cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) quiet_cmd_link-vmlinux = LINK $@ vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE +$(call if_changed,link-vmlinux)看完这一段差点一口老血吐出来,我真是没有想到他们尽然可以这么玩。。。
注:对if_changed函数的分析可以看我的这篇文章
这个cmd_link-vmlinux就是把第一个依赖作为脚本传给了系统使用的shell,由系统shell执行。好吧,我也是醉了,道行就这么又深了一点点。
回到正题,我们先看看vmlinux相关的都是谁。
vmlinux一共依赖两个 一个是vmlinux_prereq,另一个是vmlinux-deps。那分头分析。
vmlinux_prereq # Include targets which we want to execute sequentially if the rest of the # kernel build went well. If CONFIG_TRIM_UNUSED_KSYMS is set, this might be # evaluated more than once. PHONY += vmlinux_prereq vmlinux_prereq: $(vmlinux-deps) FORCE ifdef CONFIG_HEADERS_CHECK $(Q)$(MAKE) -f $(srctree)/Makefile headers_check endif ifdef CONFIG_BUILD_DOCSRC $(Q)$(MAKE) $(build)=Documentation endif ifdef CONFIG_GDB_SCRIPTS $(Q)ln -fsn `cd $(srctree) && /bin/pwd`/scripts/gdb/vmlinux-gdb.py endif ifdef CONFIG_TRIM_UNUSED_KSYMS $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \ "$(MAKE) KBUILD_MODULES=1 -f $(srctree)/Makefile vmlinux_prereq" endif这个看觉和最后的vmlinux关系不大, 咱暂时就不看了。
vmlinux-deps vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)vmlinux依赖这几个变量,我们一个个来看~
KBUILD_LDS, 链接文件 export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds这个好说,就是链接文件~
KBUILD_VMLINUX_INIT export KBUILD_VMLINUX_INIT := $(head-y) $(init-y) head-y这个head-y定义根据架构不同而不同,比如在x86架构下,该定义为:
head-y := arch/x86/kernel/head_$(BITS).o head-y += arch/x86/kernel/head$(BITS).o head-y += arch/x86/kernel/head.o恩,就一个架构,都有三个文件,好多~
在搜索的时候又发现这么一句在文档中:
$(head-y) lists objects to be linked first in vmlinux.这个提醒了我一下,在链接的时候,文件出现的顺序是有影响的。
init-y init-y := init/ init-y := $(patsubst %/, %/built-in.o, $(init-y))这个init-y原来就是init/built-in.o一个文件。
KBUILD_VMLINUX_MAIN export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) $(virt-y)这个包含的内容比较多了啊。
#core-y core-y := usr/ core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ core-y := $(patsubst %/, %/built-in.o, $(core-y)) #libs-y libs-y := lib/ libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) libs-y := $(libs-y1) $(libs-y2) #drivers-y drivers-y := drivers/ sound/ firmware/ drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) #net-y net-y := net/ net-y := $(patsubst %/, %/built-in.o, $(net-y)) #virt-y virt-y := virt/ virt-y := $(patsubst %/, %/built-in.o, $(virt-y))这下,内核根目录下所有的子目录就都包含了~
除了lib目录下有两个文件,built-in.o 和 lib.a,其余下都只有一个文件built-in.o。
谁是你们的粘合剂房子是由转头垒起来的,同样的转头不同的垒法造出来的房子会不一样。我们看完了构造vmlinux的原料,现在来看看他们是如何构造vmlinux的吧。