博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)
阅读量:2442 次
发布时间:2019-05-10

本文共 4407 字,大约阅读时间需要 14 分钟。

原文地址: 作者:

    此文为两年前为好友的书中帮忙写的章节的重新整理。如有雷同,纯属必然。经作者同意,将我写的部分重新整理后放入blog中。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     自己移植编译过内核的朋友都知道:生成的zImage内核的位置在arch/arm/boot目录下。但是这个映像是怎么产生的?下面简要地分析一下。
   
内核根目录下的vmlinux映像文件是内核Makefile的默认目标。这个vmlinux映像的生成可以通过阅读内核Makefile文件得知,简单的说:Makefile解析内核配置文件.config,递归到各目录下编译出.o文件,最后将其链接成vmlinux。而这个链接成的vmlinux文件
是一个包含内核代码的静态可执行ELF文件,你可以通过file命令来验证这一点。
她不能通过bootloader引导并启动,如果想要使其可引导,必须使用编译工具链中的objcopy命令把这个ELF格式的vmlinux转化为二进制格式才行。
而平常使用的zImage文件就是这个vmlinux文件经过多次的转换得到的。现在就来仔细研究一下她的生成过程。
(1)arch/$(ARCH)/Makefile
     首先嵌入式中经常使用的编译目标zImage并不在顶层Makefile文件中,而在被顶层Makefile包含的arch/$(ARCH)/Makefile文件中,对于ARM处理器来说就是arch/arm/Makefile文件。其中的部分规则如下:
  1. ……
  2. # Default target when executing plain make
  3. ifeq ($(CONFIG_XIP_KERNEL),y)
  4. KBUILD_IMAGE := xipImage
  5. else
  6. KBUILD_IMAGE := zImage
  7. endif
  8. all: $(KBUILD_IMAGE)
  9. boot := arch/arm/boot
  10. archprepare:
  11. $(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
  12. # Convert bzImage to zImage
  13. bzImage: zImage
  14. zImage Image xipImage bootpImage uImage: vmlinux
  15. $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
  16. ……
    从这里可以看出,zImage的依赖是顶层vmlinux文件,下面的命令展开得到:
  1. make -f scripts/Makefile.build obj= arch/arm/boot MACHINE=arch/arm/mach-* arch/arm/boot/ zImage
    可以看出zImage其实是make解析arch/arm/boot目录下的Makefile文件生成的,而参数传递了目标芯片信息和目标“arch/arm/boot/zImage”。所以zImage其实是在arch/arm/boot目录下完成编译的,这就是为什么可引导zImage映像会在arch/arm/boot目录下。
(2)arch/$(ARCH)/boot/Makefile
    现在来分析一下arch/arm/boot/Makefile中的部分规则,看看目标zImage的生成:
  1. $(obj)/Image: vmlinux FORCE
  2. $(call if_changed,objcopy)
  3. @echo ' Kernel: $@ is ready'
  4. $(obj)/compressed/vmlinux: $(obj)/Image FORCE
  5. $(Q)$(MAKE) $(build)=$(obj)/compressed $@
  6. $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
  7. $(call if_changed,objcopy)
  8. @echo ' Kernel: $@ is ready'
    先看最后一行,从中可以得知arch/arm/boot/zImage的依赖目标是arch/arm/boot/ compressed/vmlinux,且目标zImage是其二进制化的产物。
    而arch/arm/boot/compressed/vmlinux是如何得到的呢?再看上一规则,arch/arm/boot/compressed/vmlinux的依赖目标是arch/arm/boot/Image。这个依赖目标的生成由最上面的规则决定,显然arch/arm/boot/Image是由顶层vmlinux二进制化得到的。而中间这行规则的含义是arch/arm/boot/compressed/vmlinux由make解析arch/arm/boot/compressed/目录下的Makefile文件生成的,这条命令展开得到:
  1. make -f scripts/Makefile.build obj= arch/arm/boot/compressed arch/arm/boot/compressed/vmlinux
(3)arch/$(ARCH)/boot/compressed/Makefile
     最后就来分析一下arch/arm/boot/compressed/Makefile中的部分规则,看看arch/arm/boot/compressed/vmlinux 的生成:
  1. ......
  2. suffix_$(CONFIG_KERNEL_GZIP) = gzip
  3. suffix_$(CONFIG_KERNEL_LZO)  = lzo
  4. suffix_$(CONFIG_KERNEL_LZMA) = lzma
  5. ......
  6. $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
  7. $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
  8. $(call if_changed,ld)
  9. @$(check_for_bad_syms)
  10. $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
  11. $(call if_changed,$(suffix_y))
  12. $(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE
  13. ......
     上面的第一条规则就说明了:其实arch/arm/boot/compressed/vmlinux是由几个部分根据arch/arm/boot/compressed/vmlinux.lds 脚本链接而成的:
$(obj)/$(HEAD):arch/arm/boot/compressed/head.o,在链接时处于vmlinux的最前面,其主要作用就是做一些必要的初始化工作,如初始化CPU、中断描述符表IDT 和内存页目录表GDT等等,最后跳到misc.c中的decompress_kernel函数进行内核的自解压工作。
$(addprefix $(obj)/, $(OBJS)):arch/arm/boot/compressed/ misc.o,位于head.o之后,是内核自解压的实现代码。
以下假定是gzip模式压缩:
$(obj)/piggy.
$(suffix_y).
o:arch/arm/boot/compressed/ piggy.gzip.o,其实是arch/arm/boot/Image经过gzip压缩后(piggy.gzip),再借助piggy.gzip.S一起编译出的ELF可链接文件。其中的原理可以看看piggy.gzip.S源码:
  1. .section .piggydata,#alloc
  2. .globl input_data
  3. input_data:
  4. .incbin "arch/arm/boot/compressed/piggy.gzip"
  5. .globl input_data_end
  6. input_data_end:
    这里我还是要额外的提一下gzip压缩,也就是
$(call if_changed,$(suffix_y))这个过程。这个命令认真解析起来比较麻烦,这里如果有
兴趣的读者可以自行分析。这里介绍两篇经典的分析文档:《
kbuild
实现分析》、《
Kbuild
系统原理分析》,读者可自行上网下载学习。这里我直接给出了结果
,这条命令执行了在
Makefile.lib(scripts)中定义的
  
  1. cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
  2. (rm -f $@ ; false)
也就是说,
piggy.gzip是将arch/arm/boot/Image文件cat到标准输出,并通过管道传入gzip命令(gzip -n -f -9 )的标准输入,最后将gzip的输出重定向到目标piggy.gzip
   而这个piggy.gzip文件有一个重要的特性:最后的四个字节,是文件压缩前的大小数据,存放格式是小端模式。这个数据在zImage自解压时会被用于程序得到内核解压后所需要的空间!!!
    感兴趣的朋友可以自己随便用“
gzip -n -f -9”压缩一个文件试试,验证一下,我已亲自验证过了。
      这样跟踪下来,zImage的产生过程已经看完了,但是读者可能会被这有点复杂的关系绕晕了,所以现在可以结合一下的流程图简单地总结一下:
      首先顶层
vmlinux是ELF格式的可执行文件,必须将其二进制化生成
Image后才可以被bootloader引导。为了实现压缩的内核映像,arch/arm/boot/compressed/Makefile又将这个非压缩映像Image做gzip压缩,生成了
piggy.gzip。但要实现在启动时自解压,必须将这个
piggy.gzip转化为.o文件,并同初始化程序head.o和自解压程序misc.o一同链接,生成
arch/arm/boot/compressed/vmlinux。最后arch/arm/boot/Makefile将这个ELF格式的arch/arm/boot/compressed/vmlinux二进制化得到可被bootloader引导的映像文件
zImage

转载地址:http://xdsqb.baihongyu.com/

你可能感兴趣的文章
LINUX的系统内核空间的保护(转)
查看>>
在Visual C++中利用UDL文件建ADO连接(转)
查看>>
C++编程批评系列 继承的本质(转)
查看>>
unix下编写socket程序的一般步骤(转)
查看>>
共享软件中注册部分的简单实现(转)
查看>>
RedHat Linux 9下所有权和许可权限(转)
查看>>
C++程序设计从零开始之语句(转)
查看>>
利用Apache+PHP3+MySQL建立数据库驱动的动态网站(转)
查看>>
C#中实现DataGrid双向排序(转)
查看>>
利用C语言小程序来解决大问题(转)
查看>>
简单方法在C#中取得汉字的拼音的首字母(转)
查看>>
.NET开发之中的17种正则表达式小结(转)
查看>>
编程秘籍:使C语言高效的四大绝招(转)
查看>>
计算机加锁 把U盘变成打开电脑的钥匙(转)
查看>>
Fedora Core 4 基础教程 (上传完毕)(转)
查看>>
删除MSSQL危险存储过程的代码(转)
查看>>
红旗软件:树立国际的Linux品牌(转)
查看>>
Linux学习要点(转)
查看>>
影响mysqld安全的几个选项(转)
查看>>
最新版本Linux Flash 9 Beta开放发布(转)
查看>>