整个内核Makefile的分析过程与uboot的Makefile分析类似,最终都是找到链接文件lds和第一个文件.s是哪个,.S中可以看到内核的启动流程。
选择子目录下的Makefile,drivers/char/Makefile,-y表示被编译进内核,-m表示编译成模块
obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
组合成模块:
obj-m += ab.o
ab-objs := a.o b.o
a.c b.c生成a.0 b.o,最终ab.ko
顶层Makefile
根据命令和顶层Makefile顺藤摸瓜,编译内核时,make或make uImage
命令,在顶层Makefile中没有uImage,uImage在arch/arm/Makefile中,所以子目录下的M会被包含到顶层的M,
根目录下:
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
...
include $(srctree)/arch/$(ARCH)/Makefile
子目录下:
zImage Image xipImage bootpImage uImage: vmlinux
由上可知,ARCH也在顶层M目录下,include $(srctree)/arch/$(ARCH)/Makefile
--> include $(srctree)/arch/arm/Makefile
,也就是顶层M下包含了子层那个M,所以可以找到uImage。
之前由.config生成的auto.conf是Makefile的参数来源之一,所以它也被包含在顶层M中,
-include include/config/auto.conf
回到上上面,uImage依赖vmlinux(真内核),第一个目标是生成vmlinux。它依赖一堆东西,链接文件/初始化/主要文件等
all: vmlinux
...
# vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
...
vmlinux-init := $(head-y) $(init-y)
...
# Objects we will link into vmlinux / subdirs we need to visit
init-y := init/
...
init-y := $(patsubst %/, %/built-in.o, $(init-y))
...
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-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/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
...
net-y := net/
net-y := $(patsubst %/, %/built-in.o, $(net-y))
init-y那两句是将所有init/目录下的文件编成init/built-in.o文件。
在顶层找不到head-y,所以在arch/arm/Makefile中,可见head-y由两个文件组成,MMUEXT没有定义,就是head.o 和 init_task.o组成,
#Default value
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
vmlinux-main依赖核心/驱动/网络,vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
,
core-y最终是 usr/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
libs-y最终是 lib/lib.a lib/built-in.o
drivers-y最终是 drivers/built-in.o sound/built-in.o
net-y最终是 net/built-in.o
以上大堆垃圾怎么组合编译生成vmlinux的,还需看vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
其他,但是很庞大,
# vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
可以看编译内核最后的一些提示信息来反向分析,先删除rm vmlinux,再make uImage V=1,V=1表示详细列出信息,最终输出vmlinux,与
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
对应,
所以链接文件arch/arm/kernel/vmlinux.lds
,和第一个文件arch/arm/kernel/head.o
很重要,
arm-linux-ld -EL -p --no-undefined -X -o vmlinux
-T arch/arm/kernel/vmlinux.lds
arch/arm/kernel/head.o arch/arm/kernel/init_task.o
init/built-in.o --start-group
usr/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/mach-s3c2410/built-in.o arch/arm/mach-s3c2400/built-in.o arch/arm/mach-s3c2412/built-in.o arch/arm/mach-s3c2440/built-in.o arch/arm/mach-s3c2442/built-in.o arch/arm/mach-s3c2443/built-in.o arch/arm/nwfpe/built-in.o arch/arm/plat-s3c24xx/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
net/built-in.o
--end-group .tmp_kallsyms2.o
uImage依赖vmlinux,vmlinux依赖$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o)
,其中vmlinux-main由$(core-y) $(libs-y) $(drivers-y) $(net-y)
生成。
所以链接文件arch/arm/kernel/vmlinux.lds
,和第一个文件arch/arm/kernel/head.o
很重要,
arch/arm/kernel/vmlinux.lds内容如下,首先给出内核应该存放的位置,但这里是虚拟地址。下面接着放所有文件的(.text.head)段,然后所有文件的(.init.text)段。文件的顺序由.o的出现的顺序决定,.o内部的各个段存放的顺序由lds链接脚本决定,
SECTIONS
{
. = (0xc0000000) + 0x00008000;
.text.head : {
_stext = .;
_sinittext = .;
*(.text.head)
}
.init : { /* Init code and data */
*(.init.text)