设为首页 收藏本站
查看: 801|回复: 0

[经验分享] Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)

[复制链接]

尚未签到

发表于 2015-12-10 01:35:52 | 显示全部楼层 |阅读模式
    此文为两年前为好友刘庆敏的书《嵌入式Linux开发详解--基于AT91RM9200和Linux 2.6》中帮忙写的章节的重新整理。如有雷同,纯属必然。经作者同意,将我写的部分重新整理后放入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文件。其中的部分规则如下:


  • ……
  • # Default target when executing plain make
  • ifeq ($(CONFIG_XIP_KERNEL),y)
  • KBUILD_IMAGE := xipImage
  • else
  • KBUILD_IMAGE := zImage
  • endif

  • all:$(KBUILD_IMAGE)

  • boot := arch/arm/boot

  • archprepare:
  • $(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h

  • # Convert bzImage to zImage
  • bzImage: zImage

  • zImage Image xipImage bootpImage uImage: vmlinux
  • $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
  • ……

    从这里可以看出,zImage的依赖是顶层vmlinux文件,下面的命令展开得到:


  • 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的生成:


  • $(obj)/Image: vmlinux FORCE
  • $(call if_changed,objcopy)
  • @echo '  Kernel: $@ is ready'

  • $(obj)/compressed/vmlinux: $(obj)/Image FORCE
  • $(Q)$(MAKE) $(build)=$(obj)/compressed $@

  • $(obj)/zImage:$(obj)/compressed/vmlinux FORCE
  • $(call if_changed,objcopy)
  • @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文件生成的,这条命令展开得到:


  • 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 的生成:



  • ......
  • suffix_$(CONFIG_KERNEL_GZIP) = gzip
  • suffix_$(CONFIG_KERNEL_LZO)  = lzo
  • suffix_$(CONFIG_KERNEL_LZMA) = lzma
  • ......
  • $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
  • $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
  • $(call if_changed,ld)
  • @$(check_for_bad_syms)

  • $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
  • $(call if_changed,$(suffix_y))

  • $(obj)/piggy.$(suffix_y).o:  $(obj)/piggy.$(suffix_y) FORCE
  • ......



     上面的第一条规则就说明了:其实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源码:




  • .section .piggydata,#alloc
  • .globlinput_data
  • input_data:
  • .incbin"arch/arm/boot/compressed/piggy.gzip"
  • .globlinput_data_end
  • input_data_end:

    这里我还是要额外的提一下gzip压缩,也就是$(call if_changed,$(suffix_y))这个过程。这个命令认真解析起来比较麻烦,这里如果有gzip -n -f -9 )的标准输入,最后将gzip的输出重定向到目标piggy.gzip
   而这个piggy.gzip文件有一个重要的特性:最后的四个字节,是文件压缩前的大小数据,存放格式是小端模式。这个数据在zImage自解压时会被用于程序得到内核解压后所需要的空间!!!
    感兴趣的朋友可以自己随便用“gzip -n -f -9”压缩一个文件试试,验证一下,我已亲自验证过了。


      这样跟踪下来,zImage的产生过程已经看完了,但是读者可能会被这有点复杂的关系绕晕了,所以现在可以结合一下的流程图简单地总结一下:
DSC0000.jpg
      首先顶层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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-148926-1-1.html 上篇帖子: Linux 的启动流程 以及 Linux中profile、bashrc、bash_profile之间的区别和联系 下篇帖子: Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表