1. 文章说明
内核版本号为:4.11.4,针对x86平台,前提是存在.config文件
需要读者有基础Makefile知识
分析只输入make命令时的情形,只分析主要流程,其它的像变量赋值等部分只分析会影响流程执行的内容。
不会讲解Makefile文件中出现的函数,如果不懂,可以bing。
分析顺序为:先分析框架,再慢慢细化。分析每个模块时,也是先框架再细化的顺序。
2. 先看看哪些主语句块是有效的
Makefile中存在很长的if语句块,需要确定哪些行的语句是有效的。
(1) line 1 ~ line 117 有效
主要是变量的赋值,环境变量的设置
(2) line 118 ~ line 158,其中line 137 ~ line 157的语句无效
由于只输入了make,因此KBUILD_SRC为空,会解析line 118 ~ line 158的语句。这部分中,line 137 ~ line 157的语句无效。原因是编译时只输入了make,导致line 122行条件为假,因此KBUILD_OUTPUT为空值,line 137行的语句为假,所以line 137 ~ line 157的语句无效。
(3) line 161 ~ line 1698,其中line 516 ~ line 549、line 1184 ~ line 1245、line 1457 ~ line 1533语句无效
在上述(2)中的line 118 ~ line 158部分中,line 137 ~ line 157的语句无效,而skip-makefile在line 156行赋值,所以skip-makefile为空值,因此line 161行的条件为真,所以line 161 ~ line 1698的语句有效。
在这部分中,line 516 ~ line 549语句无效。原因是编译时只输入了make,因此line 495,line 502,line 510为假,所以config-targets,mixed-targets,dot-config的值不会改变,还是line 491 ~ line 493的初始值,即config-targets = 0,mixed-targets =0,dot-config = 1,因此line 516 ~ line 549无效
CONFIG_MODULES未定义,line 1184行条件为假,line 1184 ~ line 1245的语句不会被处理,line 1247 ~ line 1259的会被处理
在line 188行之前,SUBDIRS没有被定义,并且执行Makefile时只输入了make,所以SUBDIRS为空值,后续的line 189,line 193都不会执行,因此KBUILD_EXTMOD为空值,line 926条件为真,而line 1456对应于line 926的ifeq语句,因此从line 1457 ~ line 1533的语句不会被处理
3. 主目标介绍
寻找主目标时只需要关注上述2.中介绍的有效的语句块。
(1) 源码根目录下Makefile line 128 _all:
这是第一目标
(2) 源码根目录下Makefile line 200 _all: all
重载了第一目标。line 200行在ifeq语句中,下面分析为什么line200行会生效。
在line 188行之前,SUBDIRS没有被定义,执行Makefile时只输入了make,所以SUBDIRS为空值,后续的line 189,line 193都不会执行,因此KBUILD_EXTMOD 为空值。KBUILD_EXTMOD为空值,line 200行语句有效会重载目标all
(3) 源码根目录下Makefile line 623 all: vmlinux
定义目标all的依赖
(4) arch/x86/Makefile line 271 all: bzImage
line 230设置SUBARCH值。SUBARCH值会赋给line 257行的ARCH(若编译时输入了make ARCH=...,则line 257行不会赋值),ARCH值会决定SRCARCH的值,而后续的line 630会根据SRCARCH的值决定引入哪一个架构的Makefile文件。在x86架构下编译内核时,前述的line 230 SUBARCH=x86,line 630行会引入arch/x86/Makefile。
arch/x86/Makefile文件line 271行会重载目标all:bzImage
(5) arch/x86/Makefile line 276 bzImage: vmlinux
目标bzImage依赖目标vmlinux
(6) 源代码根目录下的Makefile line 982 vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE
目标vmlinux在源代码根目录下Makefile的line 982行声明
综上所述,Makefile中第一目标是源代码根目录下Makefile line 200行的 _all:all,
而目标all定义在arch/x86/Makefile line 271 行all: bzImage,
bzImage定义在arch/x86/Makefile line 276 行bzImage: vmlinux,
目标vmlinux定义在源代码根目录下的Makefile line 982行 vmlinux:
4. 生成主目标过程分析
在前述分析中,目标依赖是
_all:allall:bzImagebzImage:vmlinux
vmlinux:scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE
从vmlinux目标所需的依赖可知,依赖生效的顺序是
[1] scripts/link-vmlinux.sh =>[2] vmlinux_prereq =>[3] $(vmlinux-deps) =>[4] FORCE
4.1 vmlinux的依赖scripts/link-vmlinux.sh存在于源代码中,不需要分析这一依赖。
4.2 处理vmlinux的依赖vmlinux_prereq
vmlinux的依赖vmlinux_prereq是一个目标,定义于源码根目录Makefile的
line 959 vmlinux_prereq: $(vmlinux-deps) FORCE
4.2.1 vmlinux_prereq
vmlinux_prereq的依赖$(vmlinux-deps)的值定义于源码根目录Makefile的
line 953 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
而$(vmlinux-deps)目标定义于源码根目录Makefile的
line 992 $(sort $(vmlinux-deps)): $(vmlinux-dirs)
这行语句后面没有对应的命令,$(vmlinux-dirs)在后续内容中分析,而目标vmlinux_prereq对应的命令比较简单,不进行分析。对vmlinux_prereq生成过程的分析结束。
下面分析一下vmlinux-dirs。
4.2.1.1 vmlinux-dirs的值
vmlinux-deps的依赖是$(vmlinux-dirs),$(vmlinux-dirs)是文件夹,它的值定义于源码根目录Makefile的
line 929 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \line 930 $(core-y) $(core-m) $(drivers-y) $(drivers-m) \line 931 $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))
从中可以看出vmlinux-dirs的值依赖于init-y,init-m,core-y,core-m,drivers-y,drivers-m,net-y,net-m,libs-y,libs-m,virt-y的值,这些变量在以下位置处赋值(忽略内核配置项的值y,n,m的影响)
源码根目录Makefile:
line 565 init-y := init/
line 566 drivers-y := drivers/ sound/ firmware/
line 567 net-y := net/
line 568 libs-y := lib/line 569 core-y := usr/line 570 virt-y := virt/line 927 core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
arch/x86/Makefile:line 248 drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/line 249 drivers-$(CONFIG_PCI) += arch/x86/pci/
line 250
line 251 # must be linked after kernel/
line 252 drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/
line 253line 254 # suspend and hibernation supportline 255 drivers-$(CONFIG_PM) += arch/x86/power/line 256line 257 drivers-$(CONFIG_FB) += arch/x86/video/line 258line 259 drivers-$(CONFIG_RAS) += arch/x86/ras/
arch/x86/Makefile:
line 242 libs-y += arch/x86/lib/
arch/x86/Makefile:
line 245 core-y += arch/x86/
不会包括下述内容
arch/x86/Makefile.um:
line 1 core-y += arch/x86/crypto/
原因:
arch/x86/Makefile.um会在文件arch/um/Makefile中引入,位置在line 47 include $(HOST_DIR)/Makefile.um。在arch/um/Makefile中有如下语句:
line 34 HEADER_ARCH := $(SUBARCH)
line 44 HOST_DIR := arch/$(HEADER_ARCH)
SUBARCH的值在源码根目录Makefile line 230赋值
而引入arch/um/Makefile的情形是在编译时输入make ARCH=um,此时源码根目录Makefile的line 257 ARCH ?= $(SUBARCH)不会生效,导致后续的源码根目录Makefile的line 262 SRCARCH := $(ARCH)的值为um,进而源码根目录Makefile的line 630 include arch/$(SRCARCH)/Makefile引入了arch/um/Makefile。而在编译时只输入了make的情形下,ARCH!=um,因此不会引入arch/um/Makefile,进而不会引入arch/x86/Makefile.um。
注:um指的是User-mode Linux,是一种虚拟化机制。
4.2.1.2 $(vmlinux-dirs)处理过程分析
$(vmlinux-dirs)目标定义于源码根目录Makefile的
line 1001 $(vmlinux-dirs): prepare scripts
line 1002 $(Q)$(MAKE) $(build)=$@
在依赖prepare scripts生成后,会执行line 1002行的$(Q)$(MAKE) $(build)=$@其中
(1) $(Q)的值决定了是否简化make过程中的输出,不需要过多分析。
(2) $(MAKE) MAKE不是Makefile里面的变量,是make命令内置的环境变量,它的值是"make"
(3) $(build) build 定义于scripts/Kbuild.include的
line 184 build := -f $(srctree)/scripts/Makefile.build obj
注:scripts/Kbuild.include在源代码根目录Makefile中line 346
行通过include引入
srctree的值定义于源码根目录Makefile的line 205 ~ line 215,因为KBUILD_SRC的值为空,因此srctree的值为“.”,所以build的值为
line 184 build := -f ./scripts/Makefile.build obj
(4) $@代表的是目标,详细含义及用法可以网上搜索。
关于prepare,scripts,$(vmlinux-dirs)的生成过程,后续会以示例的形式分析部分内容,未提及的部分可以参考示例,举一反三来理解。
4.2.1.2.1 prepare
prepare目标定义于源码根目录Makefile的下述行
line 1050 prepare: prepare0 prepare-objtool
这里以目标prepares0的命令执行过程为例来分析,其它依赖的生成过程可以以此类推来理解。
4.2.1.2.1.1 prepare0
这里分析目标prepare0的生成命令,对于prepare0的依赖的生成过程,比较简单的部分不进行分析,其它的可以参考生成目标prepare0的命令的解析来理解。
prepare0目标定义于源码根目录Makefile的下述行
line 1046 prepare0: archprepare gcc-plugins
line 1047 $(Q)$(MAKE) $(build)=.
前面介绍过build和MAKE的值,因此line 1047的形式为
$(Q)make -f ./scripts/Makefile.build obj=.
./scripts/Makefile.build文件中的目标为
line 8 __build:
目标__build在./scripts/Makefile.build后面内容中被重载
line 95 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
line 96 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \line 97 $(subdir-ym) $(always)
line 98 @:
KBUILD_BUILTIN赋值的地方在源码根目录Makefile的line 318 KBUILD_BUILTIN := 1,后续赋值的语句由于相关变量值的原因都不会生效
KBUILD_MODULES赋值的地方在源码根目录Makefile的line 338 KBUILD_MODULES := 1,同样由于相关变量值的原因,其它赋值语句都不会生效。
则目标__build展开形式为
__build: $(builtin-target) $(lib-target) $(extra-y) $(obj-m) $(modorder-target) $(subdir-ym) $(always)
@:
由于目标__build的依赖中只有always有值(参见下述<<__build的依赖的分析>>),则目标__build形式为
__build: $(always)
@:
命令部分中的“@”表示取消回显命令部分中的“:”是shell的内建命令,表示不做任何事
4.2.1.2.1.1.1 __build的依赖的分析
因为源码根目录Makefile中目标prepare0规则如下
line 1046 prepare0: archprepare gcc-plugins
line 1047 $(Q)make -f ./scripts/Makefile.build obj=.
所以在./scripts/Makefile.build文件中,
line 5 src := .
line 42 kbuild-dir := ./. (srctree的值参见前述内容)
line 43 kbuild-file := ././Kbuild (./.目录下存在Kbuild文件)
line 44 include ././Kbuild
line 53 include scripts/Makefile.lib
在文件././Kbuild文件中,对always赋值的位置
line 38 bounds-file := include/generated/bounds.h
line 39
line 40 always := $(bounds-file)line 73 offsets-file := include/generated/asm-offsets.hline 74line 75 always += $(offsets-file)
line 91 always += missing-syscalls
在文件scripts/Makefile.lib中对always赋值的地方在
line 75 always := $(addprefix $(obj)/,$(always))
最终,always的值为"./include/generated/bounds.h ./include/generated/asm-offsets.h ./missing-syscalls"__build的其它依赖综合分析././Kbuild,scripts/Makefile.lib,scripts/Makefile.build后可以很容易的知道为空值
always各成员生成规则在源码根目录的Kbuild中:
line 48 $(obj)/$(bounds-file): kernel/bounds.s FORCE
line 49 $(call filechk,offsets,__LINUX_BOUNDS_H__)
line 84 $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE
line 85 $(call filechk,offsets,__ASM_OFFSETS_H__)
line 97 missing-syscalls: scripts/checksyscalls.sh $(offsets-file) FORCEline 98 $(call cmd,syscalls)
4.2.1.2.2 scripts
scripts的生成过程,与prepare类似,不再花费过多篇幅分析。
4.2.1.2.3 目标$(vmlinux-dirs)对应的命令的分析
源码根目录Makefile line 1002 $(Q)$(MAKE) $(build)=$@执行流程分析 (注:以arch/x86为例分析)
line 1002行展开部分变量后形式如下:
$(Q)make -f ./scripts/Makefile.build obj=$@
$(vmlinux-dirs)的值有多个成员,根据$@的含义及用法,选取其中一个值来进行说明。
例如arch/x86,则line 1002展开后形式为
$(Q)make -f ./scripts/Makefile.build obj=arch/x86
./scripts/Makefile.build的目标为
line 8 __build:
目标__build在后面内容中被重载
line 95 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \line 96 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \line 97 $(subdir-ym) $(always)line 98 @:
KBUILD_BUILTIN赋值的地方在源码根目录Makefile的line 318 KBUILD_BUILTIN := 1,后续赋值的语句由于相关变量值的原因都不会生效
KBUILD_MODULES赋值的地方在源码根目录Makefile的line 338 KBUILD_MODULES := 1,同样由于相关变量值的原因,其它赋值语句都不会生效。
则目标__build展开形式为
__build: $(builtin-target) $(lib-target) $(extra-y) $(obj-m) $(modorder-target) $(subdir-ym) $(always)
@:
__build的依赖$(builtin-target)参见下述<<builtin-target值的来源>>,其它依赖的值也可参照$(builtin-target)的赋值过程进行类推来确认。
命令部分中的“@”表示取消回显命令部分中的“:”是shell的内建命令,表示不做任何事
4.2.1.2.3.1 builtin-target值的来源
源码根目录Makefile line 1002行在以arxh/x86为例展开时形式如下
$(Q)make -f ./scripts/Makefile.build obj=arch/x86
因此在./scripts/Makefile.build文件中,
line 5 src := arch/x86line 42 kbuild-dir := ./arch/x86 (srctree的值参见前述内容)line 43 kbuild-file := ./arch/x86/Kbuild (./arch/x86目录下存在Kbuild文件)
line 44 include ./arch/x86/Kbuild
在文件./arch/x86/Kbuild文件中,对obj-y,obj-*赋值(*的值根据内核相关配置项来决定)的位置在文件./scripts/Makefile.build中(这个文件由命令行引入:$(Q)make -f ./scripts/Makefile.build obj=arch/x86),
line 53 include scripts/Makefile.lib
文件scripts/Makefile.lib中
line 42 obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
line 78 obj-y := $(addprefix $(obj)/,$(obj-y)) (obj的值为arch/x86,由命令行传入:$(Q)make -f ./scripts/Makefile.build obj=arch/x86)
文件scripts/Makefile.build中
line 87 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
line 88 builtin-target := $(obj)/built-in.o
line 89 endif
obj-y变量为非空值(obj-m,obj-,subdir-m,lib-target是否有值可参照上述obj-y的赋值过程确认),因此scripts/Makefile.build中
line 88 builtin-target := arch/x86/built-in.o
4.2.1.2.3.2 $(builtin-target)的生成过程
$(builtin-target)有值,则scripts/Makefile.build文件中line 429 ~ line 451有效
447 $(builtin-target): $(obj-y) FORCE448 $(call if_changed,link_o_target)
obj-y变量的值可查看前述<<builtin-target值的来源>>章节。obj-y有多个值,以kernel目录为例说明(注:源码根目录Makefile line 1002 $(Q)$(MAKE) $(build)=$@执行流程以arch/x86为例分析)。
在经过arch/x86/Kbuild,scripts/Makefile.lib(这两个文件的引入位置参看<<builtin-target值的来源>>)的处理后,obj-y中与"kernel/"相关的部分变为了arch/x86/kernel/built-in.o,则目标$(buildin-target)规则的部分形式为
arch/x86/built-in.o: arch/x86/kernel/built-in.o
$(call if_changed,link_o_target)
而在scripts/Makefile.lib中,
line 42 obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
line 63 subdir-obj-y := $(filter %/built-in.o, $(obj-y))
那么变量obj-y中包含的kernel/built-in.o,变量subdir-obj-y中也包含。在经过scripts/Makefile.lib中下述语句的处理后,
line 81 subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y))
subdir-obj-y中包含了值arch/x86/kernel/built-in.o(obj的值由命令行引入:$(Q)make -f ./scripts/Makefile.build obj=arch/x86,参见前述章节<<builtin-target值的来源>>)
在scripts/Makefile.build中,有下述目标
line 424 $(sort $(subdir-obj-y)): $(subdir-ym) ;
对于arch/x86/kernel/built-in.o来说,line 424行的规则变为了如下形式
arch/x86/kernel/built-in.o:$(subdir-ym);
这样一来,scripts/Makefile.build文件中下述目标的建立过程就可以继续探索了。
arch/x86/built-in.o: arch/x86/kernel/built-in.o(对应于line 447 $(builtin-target): $(obj-y) FORCE)
$(call if_changed,link_o_target)
在文件scripts/Makefile.build中,下述行定义了目标subdir-ym的建立方法
line 552 $(subdir-ym):line 553 $(Q)$(MAKE) $(build)=$@
subdir-ym的值定义于文件scripts/Makefile.lib的下述行
line 38 __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))line 39 subdir-y += $(__subdir-y)line 40 __subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))line 41 subdir-m += $(__subdir-m)line 44line 45 # Subdirectories we need to descend intoline 46line 47 subdir-ym := $(sort $(subdir-y) $(subdir-m))line 89 subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
在经过上述行处理后,subdir-ym中包含成员arch/x86/kernel,则文件scripts/Makefile.build中目标subdir-ym部分形式为
arch/x86/kernel:
@(Q)make -f $(srctree)/scripts/Makefile.build obj=arch/x86/kernel
而上述目标subdir-ym的生成过程样式的语句,正是当前正在分析的内容。至此,以obj-y中成员kernel为例进行的分析就结束了,obj-y中的其它成员可以依此类推来进行分析。
源码根目录Makefile中下述line 1001,line 1002规则中以obj=arch/x86为例进行的分析也结束了,obj中的其它成员,也可依据上述内容来进行分析。
line 1001 $(vmlinux-dirs): prepare scripts
line 1002 $(Q)$(MAKE) $(build)=$@
源码根目录Makefile line 1002 $(Q)$(MAKE) $(build)=$@执行流程的分析到这里也就结束了。
4.3 处理vmlinux的依赖$(vmlinux-deps)
在章节<<处理vmlinux的依赖vmlinux_prereq>>中,已经介绍了对$(vmlinux-deps)的处理,这里不再进行说明。
4.4 vmlinux链接过程
vmlinux的链接命令位于源码根目录Makefile中:
line 982 vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE
line 983 +$(call if_changed,link-vmlinux)
if_changed定义在文件scripts/Kbuild.include的下述位置
line 260 if_changed = $(if $(strip $(any-prereq) $(arg-check)), \line 261 @set -e; \line 262 $(echo-cmd) $(cmd_$(1)); \line 263 printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
注:源代码根目录下的Makefile在下述位置引入了scripts/Kbuild.include
line 346 include scripts/Kbuild.include
link-vmlinux命令定义在源码根目录Makefile的下述位置
line 978 cmd_link-vmlinux = \line 979 $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ; \line 980 $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)4.5 bzImage生成过程分析由上述源码根目录Makefile line 982行及line 979行可知,链接vmlinux过程中执行了shell脚本scripts/link-vmlinux.sh,在脚本内的函数vmlinux_link将vmlinux所需的文件链接为了一个整体,期间使用了ld的配置文件arch/x86/kernel/vmlinux.lds。配置文件arch/x86/kernel/vmlinux.lds是在处理目标$(vmlinux-dirs)过程中生成的。
目标bzImage的规则位于arch/x86/Makefile文件:
line 276 bzImage: vmlinuxline 277 ifeq ($(CONFIG_X86_DECODER_SELFTEST),y)line 278 $(Q)$(MAKE) $(build)=arch/x86/tools posttestline 279 endifline 280 $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)line 281 $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/bootline 282 $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@目标bzImage的生成命令中,主要关注
line 280 $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)其中
boot变量定义在arch/x86/Makefile的
line 264 boot := arch/x86/boot
KBUILD_IMAGE变量定义在arch/x86/Makefile的
line 274 KBUILD_IMAGE := $(boot)/bzImage
build变量的值在前述内容已经介绍过,因此line 280行形式如下
line 280 $(Q)make -f ./scripts/Makefile.build obj=arch/x86/boot/ arch/x86/boot/bzImage
由前述章节<<prepare0>>的分析可知line 280会引入文件arch/x86/boot/Makefile。
在arch/x86/boot/Makefile文件中,定义了目标arch/x86/boot/bzImage
line 75 quiet_cmd_image = BUILD $@line 76 cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \line 77 $(obj)/zoffset.h $@line 78line 79 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCEline 80 $(call if_changed,image)line 81 @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
由上述arch/x86/boot/Makefile文件的line 75 ~ line 81行可知,bzImage是由arch/x86/boot/tools/build程序处理文件arch/x86/boot/setup.bin,arch/x86/boot/vmlinux.bin,arch/x86/boot/zoffset.h后生成的。
4.5.1 arch/x86/boot/setup.bin的生成
在文件arch/x86/boot/Makefile中有如下内容
line 107 $(obj)/setup.bin: $(obj)/setup.elf FORCEline 108 $(call if_changed,objcopy)
line 103 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
line 104 $(call if_changed,ld)
line 87 SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
line 33 setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o
line 34 setup-y += early_serial_console.o edd.o header.o main.o memory.oline 35 setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.oline 36 setup-y += video-mode.o version.oline 37 setup-$(CONFIG_X86_APM_BOOT) += apm.o
line 43 setup-y += video-vga.o
line 44 setup-y += video-vesa.oline 45 setup-y += video-bios.o
上述语句中,$(src)/setup.ld=arch/x86/boot/setup.ld,而setup.ld中描述了setup.bin中各个段的分布。
由上述语句,可以很容易的知道setup.bin的生成过程。
4.5.2 arch/x86/boot/vmlinux.bin的生成
在文件arch/x86/boot/Makefile中,有如下内容:
line 84 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCEline 85 $(call if_changed,objcopy)line 110 $(obj)/compressed/vmlinux: FORCEline 111 $(Q)$(MAKE) $(build)=$(obj)/compressed $@
由前述关于build的内容可知arch/x86/boot/Makefile的line 111形式如下
line 111 $(Q)make -f ./scripts/Makefile.build obj=arch/x86/boot/compressed arch/x86/boot/compressed/vmlinux
由前述章节<<prepare0>>可知arch/x86/boot/Makefile的line 111行会引入文件arch/x86/boot/compressed/Makefile。下面会介绍依赖$(obj)/compressed/vmlinux,即arch/x86/boot/compressed/vmlinux的生成过程。在生成$arch/x86/boot/compressed/vmlinux后,会调用函数cmd_objcopy(位于文件scripts/Makefile.lib的line 268行,scripts/Makefile.lib在文件./scripts/Makefile.build文件中引入)来生成$(obj)/vmlinux.bin,即arch/x86/boot/vmlinux.bin
4.5.2.1 arch/x86/boot/compressed/vmlinux生成过程
在文件arch/x86/boot/compressed/Makefile中,有如下内容:
line 104 $(obj)/vmlinux: $(vmlinux-objs-y) FORCEline 105 $(call if_changed,check_data_rel)line 106 $(call if_changed,ld)
line 71 vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
line 72 $(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \line 73 $(obj)/piggy.o $(obj)/cpuflags.o
除了$(obj)/piggy.o外,其它的文件在目录$(obj)下都有对应的源文件,因此可以很容易的知道除piggy.o外其它文件的生成过程。
在文件arch/x86/boot/compressed/Makefile中,有如下内容:
line 143 quiet_cmd_mkpiggy = MKPIGGY $@line 144 cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )line 147 $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCEline 148 $(call if_changed,mkpiggy)
line 136 suffix-$(CONFIG_KERNEL_GZIP) := gz
line 137 suffix-$(CONFIG_KERNEL_BZIP2) := bz2line 138 suffix-$(CONFIG_KERNEL_LZMA) := lzmaline 139 suffix-$(CONFIG_KERNEL_XZ) := xzline 140 suffix-$(CONFIG_KERNEL_LZO) := lzoline 141 suffix-$(CONFIG_KERNEL_LZ4) := lz4
line 123 $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
line 124 $(call if_changed,gzip)line 125 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCEline 126 $(call if_changed,bzip2)line 127 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCEline 128 $(call if_changed,lzma)line 129 $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCEline 130 $(call if_changed,xzkern)line 131 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCEline 132 $(call if_changed,lzo)line 133 $(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCEline 134 $(call if_changed,lz4)
line 120 vmlinux.bin.all-y := $(obj)/vmlinux.bin
line 121 vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs
line 109 $(obj)/vmlinux.bin: vmlinux FORCE
line 110 $(call if_changed,objcopy)
由上述语句可知arch/x86/boot/compressed/vmlinux的生成过程。
上述line 109中的依赖vmlinux,是源代码根目录中生成的vmlinux(生成arch/x86/boot/compressed/vmlinux过程中的所有make命令没有选项-C,因此都是在源代码根目录下执行的,所以line 109中依赖的vmlinux是源代码根目录中的vmlinux),与arch/x86/boot/compressed/vmlinux不同。由上述语句可知,$(obj)/piggy.S是由$(obj)/vmlinux.bin.$(suffix-y)转化而来,进而由$(obj)/piggy.S生成了$(obj)/piggy.o
至此,整个Makefile的分析就结束了。
bzImage组成概览
arch/x86/boot/bzImage
|
|
|--arch/x86/boot/setup.bin ...........由arch/x86/boot目录下文件编译得到
|
|
|--arch/x86/boot/vmlinux.bin
*
*
*--arch/x86/boot/compressed/vmlinux
|
|
|--arch/x86/boot/compressed目录下相关文件
|
|
|--piggy.o
*
*
*--arch/x86/boot/compressed/vmlinux.bin.$(suffix-y) ........后缀名取决于配置的压缩方式
|
|
|--源代码根目录中的vmlinux