125 PHONY := _all
126 _all:
......
192 PHONY += all
193 ifeq ($(KBUILD_EXTMOD),)
194 _all: all
195 else
196 _all: modules
197 endif
......
608 all: vmlinux
第 126 行, _all 是默认目标,如果使用命令“make”编译 Linux 的话此目标就会被匹配。
第 193 行,如果 KBUILD_EXTMOD 为空的话 194 行的代码成立。
第 194 行,默认目标_all 依赖 all。
第 608 行,目标 all 依赖 vmlinux,所以接下来的重点就是 vmlinux!
从第 920 行可以看出目标 vmlinux 依赖 scripts/link-vmlinux.sh $(vmlinux-deps) FORCE。第912 行定义了 vmlinux-deps,值为:
vmlinux-deps= $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
第 905 行, KBUILD_VMLINUX_INIT= $(head-y) $(init-y)。
第 906 行, KBUILD_VMLINUX_MAIN = $(core-y) $(libs-y) $(drivers-y)
(
n
e
t
−
y
)
。
第
907
行
,
K
B
U
I
L
D
L
D
S
=
a
r
c
h
/
(net-y)。 第 907 行, KBUILD_LDS= arch/
(net−y)。第907行,KBUILDLDS=arch/(SRCARCH)/kernel/vmlinux.lds,其中 SRCARCH=arm,因此 KBUILD_LDS= arch/arm/kernel/vmlinux.lds。
综上所述, vmlinux 的依赖为: scripts/link-vmlinux.sh、 $(head-y) 、 $(init-y)、
(
c
o
r
e
−
y
)
、
(core-y) 、
(core−y)、(libs-y) 、 $(drivers-y) 、 $(net-y)、 arch/arm/kernel/vmlinux.lds 和 FORCE。
第 933 行的命令用于链接生成 vmlinux。
1、 head-y
head-y 定义在文件 arch/arm/Makefile 中,内容如下:
135 head-y := arch/arm/kernel/head$(MMUEXT).o
当不使能 MMU 的话 MMUEXT=-nommu,如果使能 MMU 的话为空,因此 head-y 最终的值为:
head-y = arch/arm/kernel/head.o
2、 init-y、 drivers-y 和 net-y
558 init-y := init/
559 drivers-y := drivers/ sound/ firmware/
560 net-y := net/
......
896 init-y := $(patsubst %/, %/built-in.o, $(init-y))
898 drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
899 net-y := $(patsubst %/, %/built-in.o, $(net-y))
init-y、 libs-y、 drivers-y 和 net-y 最终的值为
init-y = init/built-in.o
drivers-y = drivers/built-in.o sound/built-in.o firmware/built-in.o
net-y = net/built-in.o
3、 libs-y
libs-y 基本和 init-y 一样,在顶层 Makefile 中存在如下代码:
561 libs-y := lib/
......
900 libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
901 libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
902 libs-y := $(libs-y1) $(libs-y2)
libs-y 应该等于“lib.a built-in.o”,这个只正确了一部分!因为在 arch/arm/Makefile 中会向 libs-y 中追加一些值
286 libs-y := arch/arm/lib/ $(libs-y)
arch/arm/Makefile 将 libs-y 的值改为了: arch/arm/lib $(libs-y),展开以后为:
libs-y = arch/arm/lib lib/
libs-y 最终应该为:
libs-y = arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o
4、 core-y
core-y 和 init-y 也一样,在顶层 Makefile 中有如下代码:
#顶层 Makefile 代码段
532 core-y := usr/
......
887 core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
但是在 arch/arm/Makefile 中会对 core-y 进行追加,代码如下:
arch/arm/Makefile 代码段
269 core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
270 core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
271 core-$(CONFIG_VFP) += arch/arm/vfp/
272 core-$(CONFIG_XEN) += arch/arm/xen/
273 core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
274 core-$(CONFIG_VDSO) += arch/arm/vdso/
275
276 # If we have a machine-specific directory, then include it in thebuild.
277 core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
278 core-y += arch/arm/probes/
279 core-y += arch/arm/net/
280 core-y += arch/arm/crypto/
281 core-y += arch/arm/firmware/
282 core-y += $(machdirs) $(platdirs)
第 269~274 行根据不同的配置向 core-y 追加不同的值,比如使能 VFP 的话就会在.config中有CONFIG_VFP=y 这一行,那么 core-y 就会追加“arch/arm/vfp/”。
第 277~282 行就是对 core-y 直接追加的值。
在顶层 Makefile 中有如下一行:
顶层 Makefile 代码段
897 core-y := $(patsubst %/, %/built-in.o, $(core-y))
经过上述代码的转换,最终 core-y 的值为:
core-y = 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
最终将这些 built-in.o 和.a 文件进行链接即可形成 ELF 格式的可执行文件,也就是 vmlinux!但是链接是需要连接脚本的,
vmlinux 的依赖 arch/arm/kernel/vmlinux.lds 就是整个 Linux 的链接脚本。
顶层 Makefile 代码段第 933 行的命令“ + ( c a l l i f c h a n g e d , l i n k − v m l i n u x ) ” 表 示 将 (call if_changed,link-vmlinux)”表示将 (callifchanged,link−vmlinux)”表示将(call if_changed,link-vmlinux)的结果作为最终生成 vmlinux 的命令,前面的“+”表示该命令结果不可忽略。 $(call if_changed,link-vmlinux)是调用函数 if_changed, link-vmlinux 是函数 if_changed 的参数,函数 if_changed 定义在文件 scripts/Kbuild.include 中
247 if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
248 @set -e; \
249 $(echo-cmd) $(cmd_$(1)); \
250 printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
any-prereq 用于检查依赖文件是否有变化,如果依赖文件有变化那么 any-prereq 就不为空,否则就为空。 arg-check 用于检查参数是否有变化,如果没有变化那么 arg-check 就为空。
第 248 行,“@set -e”告诉 bash,如果任何语句的执行结果不为 true(也就是执行出错)的话就直接退出。
第 249 行, $(echo-cmd)用于打印命令执行过程,比如在链接 vmlinux 的时候就会输出“LINK vmlinux”。 KaTeX parse error: Expected group after '_' at position 5: (cmd_̲(1))中的
(
1
)
表
示
参
数
,
也
就
是
l
i
n
k
−
v
m
l
i
n
u
x
,
因
此
(1)表示参数,也就是 link-vmlinux,因此
(1)表示参数,也就是link−vmlinux,因此(cmd_$(1))表示执行 cmd_link-vmlinux 的内容。 cmd_link-vmlinux 在顶层 Makefile 中有如下所示定义:
914 # Final link of vmlinux
915 cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
916 quiet_cmd_link-vmlinux = LINK $@
第 915 行就是 cmd_link-vmlinux 的值,其中 CONFIG_SHELL=/bin/bash, $<表示目标 vmlinux的第一个依赖文件,根据示例代码 35.5.3.2 可知,这个文件为 scripts/link-vmlinux.sh。LD= arm-linux-gnueabihf-ld -EL, LDFLAGS 为空。 LDFLAGS_vmlinux 的值由顶层 Makefile 和arch/arm/Makefile 这两个文件共同决定最终 LDFLAGS_vmlinux=-p --no-undefined -X --picveneer --build-id。因此 cmd_link-vmlinux 最终的值为:
`cmd_link-vmlinux = /bin/bash scripts/link-vmlinux.sh arm-linux-gnueabihf-ld -EL -p --noundefined -X --pic-veneer --build-id`
cmd_link-vmlinux 会调用 scripts/link-vmlinux.sh 这个脚本来链接出 vmlinux!
在 linkvmlinux.sh 中有如下所代码:
scripts/link-vmlinux.sh 代码段
51 vmlinux_link()
52 {
53 local lds="${objtree}/${KBUILD_LDS}"
54
55 if [ "${SRCARCH}" != "um" ]; then
56 ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
57 -T ${lds} ${KBUILD_VMLINUX_INIT} \
58 --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
59 else
60 ${CC} ${CFLAGS_vmlinux} -o ${2} \
61 -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \
62 -Wl,--start-group \
63 ${KBUILD_VMLINUX_MAIN} \
64 -Wl,--end-group \
65 -lutil ${1}
66 rm -f linux
67 fi
68 }
......
216 info LD vmlinux
217 vmlinux_link "${kallsymso}" vmlinux
vmliux_link 就是最终链接出 vmlinux 的函数,第 55 行判断 SRCARCH 是否等于“um”,如果不相等的话就执行 56~58 行的代码。因为 SRCARCH=arm,因此条件成立,执行 56~58 行的代 码 。 这 三 行 代 码 就 应 该 很 熟 悉 了 ! 就 是 普 通 的 链 接 操 作 , 连 接 脚 本 为lds= ./arch/arm/kernel/vmlinux.lds , 需 要 链 接 的 文 件 由 变 量 KBUILD_VMLINUX_INIT 和KBUILD_VMLINUX_MAIN 来决定,这两个变量在示例代码 35.5.3.2 中已经讲解过了。
第 217 行调用 vmlinux_link 函数来链接出 vmlinux。
使用命令“make V=1”编译 Linux,
make 的过程,重点就是将各个子目录下的 built-in.o、 .a 等文件链接在一起,最终生成 vmlinux 这个 ELF 格式的可执行文件。链接脚本为 arch/arm/kernel/vmlinux.lds,链接过程是由shell脚本scripts/link-vmlinux.s来完成的。