zoukankan      html  css  js  c++  java
  • 基于linux2.6.38.8内核zImage文件的自解压详解

    转载:http://blog.csdn.net/wavemcu/article/details/7270439

    ***************************************************************************************************************************
    作者:EasyWave                                                                                 时间:2012.02.18

    类别:linux驱动开发                                                                           声明:转载,请保留链接

    ***************************************************************************************************************************

    内核编译完成后会生成zImage内核镜像文件。zImage是如何解压的呢?本文将结合关键代码,讲解zImage的解压过程。还是先来看看zImage的组成吧。在内核编译完成后会在arch/arm/boot/下生成zImage。 

    在arch/arm/boot/Makefile中,如下代码:

    #
    # arch/arm/boot/Makefile
    #
    # This file is included by the global makefile so that you can add your own
    # architecture-specific flags and dependencies.
    #
    # This file is subject to the terms and conditions of the GNU General Public
    # License.  See the file "COPYING" in the main directory of this archive
    # for more details.
    #
    # Copyright (C) 1995-2002 Russell King
    #
    
    MKIMAGE         := $(srctree)/scripts/mkuboot.sh
    
    ifneq ($(MACHINE),)
    include $(srctree)/$(MACHINE)/Makefile.boot
    endif
    
    # Note: the following conditions must always be true:
    #   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
    #   PARAMS_PHYS must be within 4MB of ZRELADDR
    #   INITRD_PHYS must be in RAM
    ZRELADDR    := $(zreladdr-y)
    PARAMS_PHYS := $(params_phys-y)
    INITRD_PHYS := $(initrd_phys-y)
    
    export ZRELADDR INITRD_PHYS PARAMS_PHYS
    
    targets := Image zImage xipImage bootpImage uImage
    
    ifeq ($(CONFIG_XIP_KERNEL),y)
    
    $(obj)/xipImage: vmlinux FORCE
        $(call if_changed,objcopy)
        @echo '  Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'
    
    $(obj)/Image $(obj)/zImage: FORCE
        @echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)'
        @echo 'Only the xipImage target is available in this case'
        @false
    
    else
    
    $(obj)/xipImage: FORCE
        @echo 'Kernel not configured for XIP (CONFIG_XIP_KERNEL!=y)'
        @false
    
    $(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'
    
    endif
    
    quiet_cmd_uimage = UIMAGE  $@
          cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel 
               -C none -a $(LOADADDR) -e $(STARTADDR) 
               -n 'Linux-$(KERNELRELEASE)' -d {1}lt; $@
    
    ifeq ($(CONFIG_ZBOOT_ROM),y)
    $(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
    else
    $(obj)/uImage: LOADADDR=$(ZRELADDR)
    endif
    
    $(obj)/uImage: STARTADDR=$(LOADADDR)
    
    $(obj)/uImage:    $(obj)/zImage FORCE
        $(call if_changed,uimage)
        @echo '  Image $@ is ready'
    
    $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE
        $(Q)$(MAKE) $(build)=$(obj)/bootp $@
        @:
    
    $(obj)/bootpImage: $(obj)/bootp/bootp FORCE
        $(call if_changed,objcopy)
        @echo '  Kernel: $@ is ready'
    
    PHONY += initrd FORCE
    initrd:
        @test "$(INITRD_PHYS)" != "" || 
        (echo This machine does not support INITRD; exit -1)
        @test "$(INITRD)" != "" || 
        (echo You must specify INITRD; exit -1)
    
    install: $(obj)/Image
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) 
        $(obj)/Image System.map "$(INSTALL_PATH)"
    
    zinstall: $(obj)/zImage
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) 
        $(obj)/zImage System.map "$(INSTALL_PATH)"
    
    zi:
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) 
        $(obj)/zImage System.map "$(INSTALL_PATH)"
    
    i:
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) 
        $(obj)/Image System.map "$(INSTALL_PATH)"
    
    subdir-        := bootp compressed

    我们将上面的部分内容抓取出来,独立来分析,这样就不会被其它的代码干扰到,见下面的代码:

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

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

    由此可见,zImage是由arch/arm/boot/compressed/vmlinux二进制化得到的,与此同时在arch/armboot/compressed/Makefile中:
    $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o
    $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
    $(call if_changed,ld)
    @:

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

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

    其中Image是由内核顶层目录下的vmlinux二进制化后得到的[见上面蓝色加粗部分代码],其中在arch/armboot/compressed/Makefile链接选项中有个 –fpic参数:
    EXTRA_CFLAGS  := -fpic -fno-builtin
    EXTRA_AFLAGS  := -Wa,-march=all

    总结一下zImage的组成,它是由一个压缩后的内核piggy.o,连接上一段初始化及解压功能的代码(head.o misc.o),组成的。见下面的代码:

    #
    # linux/arch/arm/boot/compressed/Makefile
    #
    # create a compressed vmlinuz image from the original vmlinux
    #
    ......................
    ......................
    #
    # We now have a PIC decompressor implementation.  Decompressors running
    # from RAM should not define ZTEXTADDR.  Decompressors running directly
    # from ROM or Flash must define ZTEXTADDR (preferably via the config)
    # FIXME: Previous assignment to ztextaddr-y is lost here. See SHARK
    ifeq ($(CONFIG_ZBOOT_ROM),y)
    ZTEXTADDR    := $(CONFIG_ZBOOT_ROM_TEXT)
    ZBSSADDR    := $(CONFIG_ZBOOT_ROM_BSS)
    else
    ZTEXTADDR    := 0
    ZBSSADDR    := ALIGN(8)
    endif
    
    SEDFLAGS    = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
    
    suffix_$(CONFIG_KERNEL_GZIP) = gzip
    suffix_$(CONFIG_KERNEL_LZO)  = lzo
    suffix_$(CONFIG_KERNEL_LZMA) = lzma
    
    targets       := vmlinux vmlinux.lds 
             piggy.$(suffix_y) piggy.$(suffix_y).o 
             font.o font.c head.o misc.o $(OBJS)
    
    # Make sure files are removed during clean
    extra-y       += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S

    targets       := vmlinux vmlinux.lds
    piggy.$(suffix_y) piggy.$(suffix_y).o
    font.o font.c head.o misc.o $(OBJS)

    那么内核是从什么地方开始运行的呢?这个要看lds文件。其实zImage的生成经历了两次链接过程:一是顶层vmlinux的生成,在arch/arm /boot/vmlinux.lds(这个lds文件是由arch/arm/kernel/vmlinux.lds.S生成的)中;另一次是arch /arm/boot/compressed/vmlinux的生成,在arch/arm/boot/compressed/vmlinux.lds.in 中。zImage的入口点应该由arch/arm/boot/compressed/vmlinux.lds.in决定。从中可以看出入口点为 ‘_start’

    /*
     *  linux/arch/arm/boot/compressed/vmlinux.lds.in
     *
     *  Copyright (C) 2000 Russell King
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     */
    OUTPUT_ARCH(arm)
    ENTRY(_start)
    SECTIONS
    {
      /DISCARD/ : {
        *(.ARM.exidx*)
        *(.ARM.extab*)
        /*
         * Discard any r/w data - this produces a link error if we have any,
         * which is required for PIC decompression.  Local data generates
         * GOTOFF relocations, which prevents it being relocated independently
         * of the text/got segments.
         */
        *(.data)
      }
    
      . = TEXT_START;
      _text = .;
    
      .text : {
        _start = .;
        *(.start)
        *(.text)
        *(.text.*)
        *(.fixup)
        *(.gnu.warning)
        *(.rodata)
        *(.rodata.*)
        *(.glue_7)
        *(.glue_7t)
        *(.piggydata)
        . = ALIGN(4);
      }
    
      _etext = .;
    
      /* Assume size of decompressed image is 4x the compressed image */
      _image_size = (_etext - _text) * 4;
    
      _got_start = .;
      .got            : { *(.got) }
      _got_end = .;
      .got.plt        : { *(.got.plt) }
      _edata = .;
    
      . = BSS_START;
      __bss_start = .;
      .bss            : { *(.bss) }
      _end = .;
    
      . = ALIGN(8);        /* the stack must be 64-bit aligned */
      .stack        : { *(.stack) }
    
      .stab 0        : { *(.stab) }
      .stabstr 0        : { *(.stabstr) }
      .stab.excl 0        : { *(.stab.excl) }
      .stab.exclstr 0    : { *(.stab.exclstr) }
      .stab.index 0        : { *(.stab.index) }
      .stab.indexstr 0    : { *(.stab.indexstr) }
      .comment 0        : { *(.comment) }
    }

    在arch/arm/boot/compressed/head.S中找到入口点。
    看看head.S会做些什么样的工作:[下面是从网络上摘录]
    1: 对于各种Arm CPU的DEBUG输出设定,通过定义宏来统一操作;
    2: 设置kernel开始和结束地址,保存architecture ID;
    3: 如果在ARM2以上的CPU中,用的是普通用户模式,则升到超级用户模式,然后关中断
    4: 分析LC0结构delta offset,判断是否需要重载内核地址(r0存入偏移量,判断r0是否为零)。
    5: 需要重载内核地址,将r0的偏移量加到BSS region和GOT table中的每一项。
       对于位置无关的代码,程序是通过GOT表访问全局数据目标的,也就是说GOT表中中记录的是全局数据目标的绝对地址,所以其中的每一项也需要重载。
    6: 清空bss堆栈空间r2-r3
    7: 建立C程序运行需要的缓存
    8: 这时r2是缓存的结束地址,r4是kernel的最后执行地址,r5是kernel境象文件的开始地址
    9: 用文件misc.c的函数decompress_kernel(),解压内核于缓存结束的地方(r2地址之后)。

  • 相关阅读:
    MVC HtmlHelper用法大全
    非常完善的Log4net详细说明
    SQLSERVER2008R2正确使用索引
    DataReader和DataSet区别
    淘宝下单高并发解决方案
    承接小程序外包 微信小程序外包 H5外包 就找北京动点软件
    H5外包 微信小程序外包 小程序外包 就找北京动点开发团队
    NGUI外包开发总结一下今天的收获
    祝大家2018事业有事,大吉大利!
    AR图像识别 AR识别图像 AR摄像头识别 外包开发 AR识别应用开发就找北京动点软件
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/3631348.html
Copyright © 2011-2022 走看看