分析Makefile,主要是:
找到第1个文件,从这个文件入手分析启动流程;
链接脚本,分析文件分布情况。
涉及的文件分类如下:
kbuild Makefile
首先来看子目录下面的Makefile,也就是kbuild Makefile,每个子目录下面都会有一个Makefile,它们的主要功能是设置该目录的文件的编译选项。
选取一个子目录下的Makefile来研究一下。
其中大部分的内容是设置文件的编译选项。
假设有两个文件a.c和b.c,如果需要单独的将它们编译进内核,可以使用如下语句:
obj-y += a.o b.o
那么,如果要将这两个文件编成一个模块呢?
在内核的Document/kbuild目录下有一个makefile.txt文件,查看makefile.txt,可以发现下图描述。
内核需要知道你想要生成的模块由哪些文件组成,因此你需要通过一个$( 在这个例子中,模块名字叫做isdn.o。Kbuild会编译 $ (isdn-objs)变量中的文件,然后对这些文件使用"$(LD) -r"来生成isdn.o。 也就是说,如果要将a.c和b.c编成一个模块,那么需要使用如下指令: obj-y += ab.o(这个名字不重要) ab-objs := a.o b.o 另外,使用后缀-y也是可以的,指令如下: obj-y += ab.o(这个名字不重要) ab-y := a.o b.o makefiles.txt中还提到,如果需要在编译时再决定一个文件是否加入这个模块,也是可以实现的。具体实现如上图的第二个例子所描述。(如果不想编入内核,只是变成一个动态库,那么-y参数就替换为-m即可,生成的模块类型则是.ko类型) 子目录下的Makefile就先理解到这里,规则先不看,接下来是架构相关的Makefile(arch/ $(ARCH)/Makefile)。 arch/ $(ARCH)/Makefile 架构相关的Makefile主要决定哪些体系结构相关的文件参与内核的生成,并提供一些规则来生成特定格式的内核映像。 查看一下arch/arm目录下的Makefile。 编译内核时,我们使用make或者make uImage指令,直接从指令分析入手,就不单独看这个Makefile了,不然思路不够清晰。 根据make uImage分析Makefile,在arch/arm目录下找到uImage(2440是arm架构,使用的arch/arm目录下的Makefile,如果是其他架构,则使用对应架构下的Makefile)。 可以看到,uImage的编译依赖于vmlinux,再查找vmlinux,在顶层Makefile找到了它的依赖关系。 暂时知道arch/arm/的Makefile是被包含到顶层Makefile,先来看一下.config。 .config 之前分析的时候说过,.config文件会生成autoconf.h和auto.conf文件,查找顶层Makefile,可以看到这两个文件也被包含进来了。 打开.config,可以看到里面全部都是这样的定义语句,表示的意思就不赘述了,之前已经有详细的说明了。 顶层Makefile 还是以指令make uImage来分析,根据上面的分析,可以知道uImage依赖于vmlinux,vmlinux又依赖于 $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE。 从名字可以看出,init应该是初始化相关,lds应该是链接,main应该是主函数。 我们前面分析uImage的时候知道,uImage是由 “头部(64字节)+真正的内核”组成的,其中真正的内核就是vmlinux。 查找vmlinux-init,得到如下信息。 对于vmlinux-init的分析如下: vmlinux-init := $(head-y) $(init-y) head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o 其中,$(MMUEXT)在arch/arm/Makefile前面定义,对于没有MMU的处理器,MMUEXT的值为-nommu,使用文件head-nommu.S;对于有MMU的处理器,其值为空,使用head.S文件。 所以:head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o 还有一个$(init-y)。 init-y := init/ init-y := $ (patsubst %/, %/built-in.o, $(init-y)),其中, $(patsubst 原模式, 目标模式, 文件列表)。 所以,init-y := init/t/built-in.o,它的意思是所有init文件夹下的目标文件会被编程进一个模块叫build-in.o 综上,vmlinux-init := arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o 然后是vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y),从名字分析,分别是核心,库,驱动,网络。 查找core-y,得: core-y := usr/ core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ // If we have a machine-specific directory, then include it in the build. core-y += $(MACHINE) core-y := $(patsubst %/, %/built-in.o, $(core-y)) 也就是:core-y := usr/ kernel/ mm/ fs/ ipc/ security/ crypto/ block/ arch/arm/kernel/ arch/arm/mm/ arch/arm/common/,然后和上面一样生成各个文件夹的built-in.o,也就是将各个目录下的目标文件一起编译成一个模块。 其他 $(libs-y) $(drivers-y) $(net-y) 也是类似的操作。 最后是链接脚本,vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds,其中ARCH表示的是MCU架构,所以ARCH = arm,也就是: vmlinux-lds := arch/arm/kernel/vmlinux.lds 打开arch/arm/kernel/vmlinux.lds,可以看到,其中开始的地址应该是一个虚拟地址,存放的是所有文件的head段,然后是初始化相关的代码段。顺序由链接时出现的文件顺序来决定。 直接查看编译信息可以更方便的了解这些信息,rm vmlinux先删除vmlinux,然后再make uImage V=1编译,V=1会将调试信息更详细的打印出来。 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 echo ‘cmd_vmlinux := 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’ > ./.vmlinux.cmd 通过编译信息,可以知道,使用的链接脚本是arch/arm/kernel/vmlinux.lds(由arch/arm/kernel/vmlinux.lds.S编译生成),第一个文件应该是一个汇编文件head.S,文件顺序与之前分析的vmlinux-init := arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o也相同。 所以,我们知道了: 找到第1个文件,从这个文件入手分析启动流程;(arch/arm/kernel/head.S) 链接脚本,分析文件分布情况。(arch/arm/kernel/vmlinux.lds)
上一篇:1_5.3.2_内核配置裁剪及启动流程_内核启动流程分析之配置_P
下一篇:1_5.3.4_内核配置裁剪及启动流程_内核启动流程分析之内核启
推荐阅读最新更新时间:2024-10-29 11:16