2.2.6 制作bzImage
回到顶层Makefile的849行,随着vmlinux的链接工作结束,在主目录下生成了vmlinux文件,vmlinux目标也就结束了。那么就会来到arch/x86/Makefile的155行bzImage目标。看到这个目标,就知道后面的工作就算打包压缩vmlinux并制作bzImage了。看到156行,因为CONFIG_X86_DECODER_SELFTEST没有设置,所以会直接执行159行以后的命令:
159 $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
160 $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
161 $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@
160行是建立一个arch/i386/boot目录,161行是建立一个符号链接,重中之重是159行,其中$(boot)宏来自143行,$(KBUILD_IMAGE)宏来自153行,所以翻译159行:
@make -f scripts/Makefile.build obj=arch/x86/boot arch/x86/boot/bzImage
前面提到vmlinux 的入口地址为phys_startup_32,该函数是工作在32-bit 段寻址的保护模式,但是问题是系统自加电那一刻起,就运行于16-bit 实模式。所以我们需要一些辅助程序从16-bit 实模式转到32-bit或64-bit保护模式,设置好必须的参数后才能开启分页模式转到32-bit或64-bit分页保护模式。前半部分是由arch/x86/boot/setup.bin 实现的,后半部分则是由arch/x86/kernel/head.o实现的。setup.bin除了向保护模式转换外,还有很多其它的事情要做。
从vmlinux 的链接过程来看vmlinux 是一个已编好的kernel,和普通的ELF 可执行文件没有什么区别:
[root@localhost linux-2.6.34.1]# file ./vmlinux
vmlinux: ELF 32-bit LSB executable, Intel i386, version 1 (SYSV), statically linked, not stripped
我们知道,C和汇编源文件被编译成ELF 文件后,通常会包含有连接器(Linker)或加载器(Loader)所需要的ELF header,Program header table或Section header table。这些ELF header 和一些section 的作用是告诉内核ELF Loader 如何载入ELF 可执行文件。但是, Linux内核作为一种特殊的ELF 文件,没有ELF Loader的帮助,需要特殊辅助程序去装载它。它的装载地址是固定的,前面讲了的,0xC0100000。
这时,为了保证通用性而存在的ELF header 和一些section对内核的装载就没有意义了。为了使内核尽可能小,可以把这些信息去掉。所以通常采用objcopy命令来去掉原来ELF文件中的header和section,同时转化为raw binary格式的文件。即便如此,通过objcopy 处理过的vmlinux 一般需要压缩以后再重新链接,当然必须把解压缩的程序也同时链接进来。
这个压缩的过程着实奇怪:压缩后,然后再解压缩,岂不是浪费启动时间?这还是因为当x86系列处理器启动初期,处于实模式状态,可以寻得的地址空间十分有限,仅仅是1MB,如果内核过大,就无法加载。更新的内核(从2.6.30开始)甚至提供了更高压缩率的格式:bzip或LZMA。
由上面的分析可以看出, bzImage 至少包含kernel booting 辅助程序和压缩的vmlinux。这可以从bzImage 的规则链得到验证:
刚才看到了,arch/x86/Makefile中关于bzImage的规则调用命令为:
make -f scripts/Makefile.build obj=arch/x86/boot arch/x86/boot/bzImage
注意:这个命令为Makefile.build 指定了目标arch/x86/boot/bzImage ,而不是使用缺省的__build。
arch/x86/boot/Makefile中bzImage的规则如下:
81 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
82 $(call if_changed,image)
83 @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
其中obj= arch/x86/boot,所以arch/x86/boot/bzImage 依赖的目标是:arch/x86/boot/setup.bin、arch/x86/boot/vmlinux.bin、arch/x86/boot/tools/build。tools/build 已加到<