转载: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) - 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 {}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 -)
@test "$(INITRD)" != "" || \
(echo You must specify INITRD; exit -) 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 :=
ZBSSADDR := ALIGN()
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();
} _etext = .; /* Assume size of decompressed image is 4x the compressed image */
_image_size = (_etext - _text) * ; _got_start = .;
.got : { *(.got) }
_got_end = .;
.got.plt : { *(.got.plt) }
_edata = .; . = BSS_START;
__bss_start = .;
.bss : { *(.bss) }
_end = .; . = ALIGN(); /* the stack must be 64-bit aligned */
.stack : { *(.stack) } .stab : { *(.stab) }
.stabstr : { *(.stabstr) }
.stab.excl : { *(.stab.excl) }
.stab.exclstr : { *(.stab.exclstr) }
.stab.index : { *(.stab.index) }
.stab.indexstr : { *(.stab.indexstr) }
.comment : { *(.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地址之后)。

基于linux2.6.38.8内核zImage文件的自解压详解的更多相关文章

  1. 基于linux2.6.38.8内核启动过程完全解析[一]

    转载: ************************************************************************************************ ...

  2. linux-2.6.26内核中ARM中断实现详解(转)

    转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJ ...

  3. [转帖]技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

    技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解    http://www.52im.net/thread-1309-1-1.html   本文来自腾讯资深研发工程师罗成的技术分享, ...

  4. (转)Linux内核参数设置sysctl命令详解

    Linux内核参数设置sysctl命令详解 原文:https://www.zhukun.net/archives/8064 sysctl是一个允许您改变正在运行中的Linux系统的接口. 它包含一些 ...

  5. Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解

    Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解 (本文转自: http://blog.csdn.net/yinhaide/article/details/44756 ...

  6. C#文件后缀名详解

    C#文件后缀名详解 .sln:解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息. .csproj:项目文件,创建应用程序所需的引用.数据连接.文件夹和文件的信息. .aspx:W ...

  7. 9.proc目录下的文件和目录详解

    1./proc目录下的文件和目录详解 /proc:虚拟目录.是内存的映射,内核和进程的虚拟文件系统目录,每个进程会生成1个pid,而每个进程都有1个目录. /proc/Version:内核版本 /pr ...

  8. JPEG文件编/解码详解

    JPEG文件编/解码详解(1) JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写.它由国际电话与电报咨询委员会CCITT(The Interna ...

  9. Kubernetes YAML 文件全字段详解

    Kubernetes YAML 文件全字段详解 Deployment yaml 其中主要参数都在podTemplate 中,DaemonSet StatefulSet 中的pod部分一样. apiVe ...

随机推荐

  1. 自己封装的Socket组件,实现服务端多进程共享Socket对象,协同处理客户端请求

    DotNet.Net.MySocket是SLB.NET(Server Load Balance服务器负载均衡)项目中的核心组件. 在实际的项目中发现,单进程的服务端处理高并发的客户请求能力有限. 所以 ...

  2. xcode 6.4 安装Alcatraz失败解决方法

    Alcatraz Xcode6.4安装不了解决方法http://www.cocoachina.com/bbs/read.php?tid=310380 版权声明:本文为博主原创文章,未经博主允许不得转载 ...

  3. 使用gdb调试多线程程序总结

    转:使用gdb调试多线程程序总结 一直对GDB多线程调试接触不多,最近因为工作有了一些接触,简单作点记录吧. 先介绍一下GDB多线程调试的基本命令. info threads 显示当前可调试的所有线程 ...

  4. UVALive 5881 Unique Encryption Keys (DP)

    Unique Encryption Keys 题目链接: http://acm.hust.edu.cn/vjudge/problem/26633 Description http://7xjob4.c ...

  5. 树上的DP

    CF#196B http://codeforces.com/contest/338/problem/B 题意:在一颗树上,给m个点,求到所有m个点距离不超过d的点的个数,所有路径长度为1. 分析:问题 ...

  6. java getEnv不区分大小写 getProperty区分大小写

    System.out.println(System.getenv("JAVA_HOME")); System.out.println(System.getenv("Pat ...

  7. 【Cocos2d-X开发学习笔记】第18期:动作类之改变动作对象、函数回调动作以及过程动作的使用

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010 一.改变动作执行对象 CCTargetedAct ...

  8. 使用struts2实现文件上传

    action中 private File file;//文件 private String fileFileName;//文件名字 固定格式name+FileName private String f ...

  9. Unity3d:megaFierstext(翻书效果插件)

    附件中是一款翻书效果插件,由于附件上传大小限制,在下载完后,需要在megaFierstext_BHYF\Assets\Resources\Textures下添加图片精灵并修改属性为Texture,即可 ...

  10. Label & TextBlock

    I always thought it was odd that WPF has both TextBlock and Label.  They both are responsible for di ...