.
.
编译生成过程
首先,根目录下面生成了 vmlinux ,这个可以从根目录下的 Makefile 过程看到。当然,简单一些,也可以看根目录下的 .vmlinux.cmd 文件,其内容如下:
cmd_vmlinux := arm-iwmmxt-linux-gnueabi-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-pxa/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 是依赖于哪些文件的,这里我们可以看到每个目录下面都有一个 built-in.o ,这是因为系统对于每个目录会递归调用 scripts/Makefile.build ,而它里面定义的 builtin-target 就是 built-in.o ,如下:
builtin-target := $(obj)/built-in.o
平台相关过程
首先,编译链接过程会执行到: arch/arm/boot
分析它下面的 Makefile 文件,可知:
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
故而, Image 是从根目录下的 vmlinux 直接拷贝生成的。
首先,
如果是非压缩内核,则这一步骤就没有了。
当是压缩内核时,首先,编译链接过程还是会先执行到: arch/arm/boot
分析它下面的 Makefile 文件,可知:
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
故而可知, arch/arm/boot/vmlinux 会依赖于 arch/arm/boot/Image ,其实就是非压缩内核,也就是根目录下的 vmlinux ;而后,又会调用 kbuild 来执行 arch/arm/boot/compressed 下的 Makefile:
分析它下面的 Makefile 文件,可知:
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o /
$(addprefix $(obj)/, $(OBJS)) FORCE
即: compressed/vmlinux 除了依赖于 arch/arm/boot/Imag 外,还依赖于 vmlinux.lds , piggy.o 等,它们都在 compressed 目录下。
其实,如果看 compressed 目录下的 .vmlinux.cmd 文件,可以清楚知道 compressed/vmlinux 还依赖的文件有: libgcc.a vmlinux.lds head.o piggy.o misc.o head-xscale.o ;注意,因为对 arch/arm/boot/Image 的依赖是在 arch/arm/boot/ 目录里说明的,故而 compressed 目录下的 .vmlinux.cmd 文件没有包括这一项。
回到 arch/arm/boot/Makefile 文件,可以看到如下内容:
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
也就是说,压缩内核 zImage 就是从 compressed/vmlinux 直接拷贝生成的。
因为我们的内核要把开机 Logo 加进去,故而做了最后的处理,在 scripts/ mkImageLogo.sh 文件里:
imagefile=ImageLogo
logofile=./scripts/logo.bin
dd if=/dev/zero of=t0.img bs=1024k count=2
cp arch/arm/boot/zImage t1.img
cat t0.img >> t1.img
dd if=t1.img of=t2.img bs=512 count=6293 #4M:7317 3.5M: 6293 3M:5269,2M:3221
cat $logofile >> t2.img
mv t2.img ${imagefile}
可见,要么是从 Image 里生成 (M200 项目 ) ,要么是从 zImage 里生成的 (M201 项目 ) 。
链接过程
这一段指的就是非压缩内核了,因为非压缩内核直接拷贝的就是根目录里的 vmlinux ,故而只要看根目录里的 vmlinux 的生成过程就可以了。
首先,从根目录里 Makefile 可以得知,链接过程如下:
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
# Rule to link vmlinux - also used during CONFIG_KALLSYMS
# May be overridden by arch/$(ARCH)/Makefile
quiet_cmd_vmlinux__ ?= LD $@
cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ /
-T $(vmlinux-lds) $(vmlinux-init) /
--start-group $(vmlinux-main) --end-group /
$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
从以上黑体的部分可以看出,链接过程的依据文件是: arch/arm/kernel/vmlinux.lds ,在该文件中,可以看到如下内容:
ENTRY(stext)
jiffies = jiffies_64;
SECTIONS
{
. = (0xc0000000) + 0x00008000;
.init : { /* Init code and data */
_stext = .;
_sinittext = .;
*(.init.text)
_einittext = .;
也就是说,我们的非压缩内核要被装载到虚拟地址 0xc0008000 的地方,即物理地址 0x00008000 的地方 ( 当然也取决于我们设置的虚拟地址和物理地址的片选 ) 。同时, ENTRY 为 stext 就说明入口点就是代码段的开头,即 _stext 的起始点,从上面可以看到它就是 0xc0008000 这个地址;而从根目录的 .vmlinux.cmd 文件中,我们可以得知,第一个被链接的文件是: arch/arm/kernel/head.o
cmd_vmlinux := arm-iwmmxt-linux-gnueabi-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-pxa/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
故而,非压缩内核被 Boot Loader 装载后,从 arch/arm/kernel/head.S 开始执行。
压缩内核涉及到再次链接过程,故而就要看 vmlinux ,故而只要看目录 arch/arm/boot/compressed 下的 vmlinux.lds 文件了(因为这个目录下的 Makefile 文件在链接地时候,使用了它),在这个文件里,我们看到:
ENTRY(_start)
SECTIONS
{
. = 0;
_text = .;
.text : {
_start = .;
*(.start)
*(.text)
*(.text.*)
*(.fixup)
*(.gnu.warning)
*(.rodata)
*(.rodata.*)
*(.glue_7)
*(.glue_7t)
*(.piggydata)
. = ALIGN(4);
}
故而入口点是 _start ,而他就是代码段的开始处。
察看 arch/arm/boot/compressed 下的 .vmlinux.cmd 文件中,我们可以得知,第一个被链接的文件是: arch/arm/boot/compressed/head.o :
cmd_arch/arm/boot/compressed/vmlinux := arm-iwmmxt-linux-gnueabi-ld -EL --defsym zreladdr=0xb0008000 -p --no-undefined -X /opt/marvell/toolschain/arm-linux-4.1.1/bin/../lib/gcc/arm-iwmmxt-linux-gnueabi/4.1.1/libgcc.a -T arch/arm/boot/compressed/vmlinux.lds arch/arm/boot/compressed/head.o arch/arm/boot/compressed/piggy.o arch/arm/boot/compressed/misc.o arch/arm/boot/compressed/head-xscale.o -o arch/arm/boot/compressed/vmlinux
故而,压缩内核被 Boot Loader 装载后,是从 arch/arm/boot/compressed/head.S 开始执行的。