基于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) - 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文件的自解压详解的更多相关文章
- 基于linux2.6.38.8内核启动过程完全解析[一]
转载: ************************************************************************************************ ...
- linux-2.6.26内核中ARM中断实现详解(转)
转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJ ...
- [转帖]技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解
技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解 http://www.52im.net/thread-1309-1-1.html 本文来自腾讯资深研发工程师罗成的技术分享, ...
- (转)Linux内核参数设置sysctl命令详解
Linux内核参数设置sysctl命令详解 原文:https://www.zhukun.net/archives/8064 sysctl是一个允许您改变正在运行中的Linux系统的接口. 它包含一些 ...
- Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解
Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解 (本文转自: http://blog.csdn.net/yinhaide/article/details/44756 ...
- C#文件后缀名详解
C#文件后缀名详解 .sln:解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息. .csproj:项目文件,创建应用程序所需的引用.数据连接.文件夹和文件的信息. .aspx:W ...
- 9.proc目录下的文件和目录详解
1./proc目录下的文件和目录详解 /proc:虚拟目录.是内存的映射,内核和进程的虚拟文件系统目录,每个进程会生成1个pid,而每个进程都有1个目录. /proc/Version:内核版本 /pr ...
- JPEG文件编/解码详解
JPEG文件编/解码详解(1) JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写.它由国际电话与电报咨询委员会CCITT(The Interna ...
- Kubernetes YAML 文件全字段详解
Kubernetes YAML 文件全字段详解 Deployment yaml 其中主要参数都在podTemplate 中,DaemonSet StatefulSet 中的pod部分一样. apiVe ...
随机推荐
- Java基础 —— HTML
HTML:超文本标记语言(HyperText Markup Language) --> 最基础的网页语言 基本结构: <html> //HTML文件的开始 <head> ...
- android系统的文件夹选择器
aFileChooser: https://github.com/iPaulPro/aFileChooser/issues, 这个是最适合android的文件选择器,看看有无可能改成文件夹选择器. f ...
- openstack-dbs
真正的服务器派生出线程 和子进程处理多个连接当允许客户端加入聊天室,他发送的任何一条文本都将广播给聊天室中的每个用户,除非文本是服务器CLI当广播一条消息,消息前面将加上发送者的昵称 以尖括号括住昵称 ...
- TBluetoothLE
delphi 蓝牙技术 D:\Users\Public\Documents\Embarcadero\Studio\17.0\Samples\Object Pascal\Multi-Device Sam ...
- [翻译]Behavior-Driven Development (BDD)行为驱动开发(二)
测试驱动开发体现了开发人员对软件产品各部分运作方式的理解,而行为驱动开发则关注于开发人员对软件产品最终表现的行为的预期. 行为驱动开发 TDD更像是一种范式而不是一个过程.它描述了一种先编写测试,然后 ...
- LeetCode 刷题记录(二)
写在前面:因为要准备面试,开始了在[LeetCode]上刷题的历程.LeetCode上一共有大约150道题目,本文记录我在<http://oj.leetcode.com>上AC的所有题目, ...
- ajax提交后台自动反序列化成对象
下面是ajax提交的方法,主要用到了$form.serializeArray()将表单序列化成json对象,然后用each处理一下,代码如下: var $form = $('<form>& ...
- CodeForces 709A Juicer (水题, 模拟)
题意:给定 n 个桔子的大小,一个杯子的容积,一个最大限度,挨着挤桔子汁,如果大小大于限度,扔掉,如果不杯子满了倒掉,问你要倒掉多少杯. 析:直接按要求模拟就好,满了就清空杯子. 代码如下: #pra ...
- 【待补】java开发Web Service
Java中WebService实例 http://blog.csdn.net/kardelpeng/article/details/6321019 java 调用webservice的各种方法总结 h ...
- Spring REST实践之客户端和测试
RestTemplate 可参考spring实战来写这部分. RestTemplate免于编写乏味的样板代码,RestTemplate定义了33个与REST资源交互的方法,涵盖了HTTP动作的各种形式 ...