zImage目录linux,zImage文件结构

从后往前看下编译生成zImage的过程,我们可以找到程序的入口还是那个很重要

链接文件,找到它,生成zImage所在的目录是kernel\arch\arm\boot\compressed\

Make过程为....ld -p -X -T vmlinux.lds head.o misc.o head-s3c2410.o piggy.o

libgcc.o -o vmlinux

然后是用二进制工具objcopy把vmlinux制作成可执行的二进制映像文件zImage

这样在我们就去kernel\arch\arm\boot\compressed\目录下去找到vmlinux.lds文件

如果没有编译就不会有这个文件,因为它也是在编译过程生成的,由同一目录下的

vmlinux.lds.in生成,打开这个文件

ENTRY(_start)

SECTIONS

{

. = LOAD_ADDR;

_load_addr = .;

. = TEXT_START;

_text = .;

.text : {

_start = .;

*(.start)

*(.text)

........

入口是_start,而且入口就直接定义在这个文件中了

入口直接接着.start段,所以程序开始是从.start段开始执行的

如果看看vmlinux.lds的生成过程就应该能找到LOAD_ADDR和TEXT_START的值

实际上这两个值是由其他两个变量赋给的 ZRELADDR 和 ZTEXTADDR

在kernel\arch\arm\boot\Makefile中我们可以找到这两个变量的值

ifeq ($(CONFIG_ARCH_S3C2410),y)

ZTEXTADDR  = 0x30008000

ZRELADDR  = 0x30008000

endif

所以

LOAD_ADDR = 0x30008000

TEXT_START = 0x30008000

看一下vmlinux.lds吧

ENTRY(_start)

SECTIONS

{

. = 0x30008000;

_load_addr = .;

. = 0;

_text = .;

显然LOAD_ADDR被赋值了0x30008000

看一下TEXT_START怎么成0了,我想这应该是一个偏移吧,偏移是0

所以它还是0x30008000

接着下来就从head.s来开始看代码吧

.section ".start", #alloc, #execinstr

/*

* sort out different calling conventions

*/

.align

start:

.type start,#function

.rept 8

mov r0, r0

.endr

b 1f

.word 0x016f2818  @ Magic numbers to help the loader

.word start   @ absolute load/run zImage address

.word _edata   @ zImage end address

1:  mov r7, r1   @ save architecture ID

这里一定就是程序的入口了,一般汇编程序的含义就看看英文注释就是了

有一个要注意的地方,不是一个汇编文件就是属于一个段的,不是说先执行完了

head.s再去执行head-s3c2410.s,还是要注意链接的段,显然head.s

不一会就开始了另一个段.text

.text

adr r0, LC0

ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}

subs r0, r0, r1  @ calculate the delta offset

而我们的head-s3c2410.s呢

.section ".start", #alloc, #execinstr

__S3C2410_start:

bic r2, pc, #0x1f

add r3, r2, #0x4000  @ 16 kb is quite enough...

还是属于.start段的,所以顺序执行下来时先执行head-s3c2410.s,然后再去执行

.text段。head-s3c2410.s主要是cpu的一些初始化工作。接着下来我们会需要把内核

接压缩,先说说为什么吧。还是注意到上面生成zImage的文件中有一个piggy.o,往上

追寻可以看到是piggy.o由那个真正的内核vmlinux生成的,这个vmlinux才是启动后一直在

运行的内核,原本很大,压缩以后可以方便地放在flash中,当然其实不压缩跳到它的

入口也就可以运行了。解压的内核是准备从LOAD_ADDR = 0x30008000开始的4M空间,会覆盖

我们的当前运行的代码,那样就先把内核解压到我们这个zImage+分配堆栈0x10000的最后

cmp r4, r2  //r4 是LOAD_ADDR=0x30008000

bhs wont_overwrite //r2 是当前代码的最底部    这里当然不会跳转

add r0, r4, #4096*1024 @ 4MB largest kernel size

cmp r0, r5  //r5 也是0x30008000

bls wont_overwrite //不会跳转

mov r5, r2  //r2是(user_stack+4096)在zImage的最后+0x10000

mov r0, r5

mov r3, r7  //machine type

bl decompress_kernel

有了r5,r0,r7作为参数,就可以调用misc.c中的decompress_kernel函数进行解压缩了

这个函数调用的gunzip函数时gcc的库函数,所以在源码中找不到的

解压在r5开始的地方,函数返回的是r0解压得到的长度。这时候我们需要对代码经行调整

add r1, r5, r0  @ end of decompressed kernel

adr r2, reloc_start

ldr r3, LC1   //LC1: .word reloc_end - reloc_start

add r3, r2, r3

1:  ldmia r2!, {r8 - r13}  @ copy relocation code

stmia r1!, {r8 - r13}

ldmia r2!, {r8 - r13}

stmia r1!, {r8 - r13}

cmp r2, r3  //这里就把从reloc_start到reloc_end这段我们需要的代码放到了

blo 1b  //解压内核的最后,而在下面我们会将zImage都覆盖掉

bl cache_clean_flush

add pc, r5, r0 //调到调整后的reloc_start,在decompressed kernel后

reloc_start: add r8, r5, r0 //r5解压内核开始的地方 r0解压内核的长度

debug_reloc_start

mov r1, r4  //r4=0x30008000

1:

.rept 4

ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel

stmia r1!, {r0, r2, r3, r9 - r13}

.endr

cmp r5, r8

blo 1b  //这样就又把解压的真正内核移到了0x30008000处

call_kernel: bl cache_clean_flush

bl cache_off

mov r0, #0

mov r1, r7   @ restore architecture number

mov pc, r4   @ call kernel

上面就是跳到0x30008000这里去执行真正的内核了吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值