linux 如何解压内核,分析内核对gzip压缩文件进行解压的方法

分析内核对gzip压缩文件进行解压的方法

发布时间:2006-08-13 09:38:38来源:红联作者:邱建元

概述

----

1) Linux的初始内核映象以gzip压缩文件的格式存放在zImage或bzImage之中, 内核的自举

代码将它解压到1M内存开始处. 在内核初始化时, 如果加载了压缩的initrd映象, 内核会将解压到内存盘中, 这两处解压过程都使用了lib/inflate.c文件.

2) inflate.c是从gzip源程序中分离出来的, 包含了一些对全局数据的直接引用, 在使用时

需要直接嵌入到代码中. gzip压缩文件时总是在前32K字节的范围内寻找重复的字符串进行

编码, 在解压时需要一个至少为32K字节的解压缓冲区, 它定义为window[WSIZE].

inflate.c使用get_byte()读取输入文件, 它被定义成宏来提高效率. 输入缓冲区指针必须

定义为inptr, inflate.c中对之有减量操作. inflate.c调用flush_window()来输出window

缓冲区中的解压出的字节串, 每次输出长度用outcnt变量表示. 在flush_window()中, 还必

须对输出字节串计算CRC并且刷新crc变量. 在调用gunzip()开始解压之前, 调用makecrc()

初始化CRC计算表. 最后gunzip()返回0表示解压成功.

3) zImage或bzImage由16位引导代码和32位内核自解压映象两个部分组成. 对于zImage, 内

核自解压映象被加载到物理地址0x1000, 内核被解压到1M的部位. 对于bzImage, 内核自解

压映象被加载到1M开始的地方, 内核被解压为两个片段, 一个起始于物理地址0x2000-0x90000,

另一个起始于高端解压映象之后, 离1M开始处不小于低端片段最大长度的区域. 解压完成后,

这两个片段被合并到1M的起始位置.

解压根内存盘映象文件的代码

--------------------------

代码:

; drivers/block/rd.c

#ifdef BUILD_CRAMDISK

/*

* gzip declarations

*/

#define OF(args) args ; 用于函数原型声明的宏

#ifndef memzero

#define memzero(s, n) memset ((s), 0, (n))

#endif

typedef unsigned char uch; 定义inflate.c所使用的3种数据类型

typedef unsigned short ush;

typedef unsigned long ulg;

#define INBUFSIZ 4096 用户输入缓冲区尺寸

#define WSIZE 0x8000 /* window size--must be a power of two, and */

/* at least 32K for zip's deflate method */

static uch *inbuf; 用户输入缓冲区,与inflate.c无关

static uch *window; 解压窗口

static unsigned insize; /* valid bytes in inbuf */

static unsigned inptr; /* index of next byte to be processed in inbuf */

static unsigned outcnt; /* bytes in output buffer */

static int exit_code;

static long bytes_out; 总解压输出长度,与inflate.c无关

static struct file *crd_infp, *crd_outfp;

#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) 读取输入缓冲区中一个字节

/* Diagnostic functions (stubbed out) */ 一些调试宏

#define Assert(cond,msg)

#define Trace(x)

#define Tracev(x)

#define Tracevv(x)

#define Tracec(c,x)

#define Tracecv(c,x)

#define STATIC static

static int fill_inbuf(void);

static void flush_window(void);

static void *malloc(int size);

static void free(void *where);

static void error(char *m);

static void gzip_mark(void **);

static void gzip_release(void **);

#include "../../lib/inflate.c"

static void __init *malloc(int size)

{

return kmalloc(size, GFP_KERNEL);

}

static void __init free(void *where)

{

kfree(where);

}

static void __init gzip_mark(void **ptr)

{

; 读取用户一个标记

}

static void __init gzip_release(void **ptr)

{

; 归还用户标记

}

/* ===========================================================================

* Fill the input buffer. This is called only when the buffer is empty

* and at least one byte is really needed.

*/

static int __init fill_inbuf(void) 填充输入缓冲区

{

if (exit_code) return -1;

insize = crd_infp->f_op->read(crd_infp, inbuf, INBUFSIZ,

&crd_infp->f_pos);

if (insize == 0) return -1;

inptr = 1;

return inbuf[0];

}

/* ===========================================================================

* Write the output window window[0..outcnt-1] and update crc and bytes_out.

* (Used for the decompressed data only.)

*/

static void __init flush_window(void) 输出window缓冲区中outcnt个字节串

{

ulg c = crc; /* temporary variable */

unsigned n;

uch *in, ch;

crd_outfp->f_op->write(crd_outfp, window, outcnt, &crd_outfp->f_pos);

in = window;

for (n = 0; n < outcnt; n++) {

ch = *in++;

c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 计算输出串的CRC

}

crc = c;

bytes_out += (ulg)outcnt; 刷新总字节数

outcnt = 0;

}

static void __init error(char *x) 解压出错调用的函数

{

printk(KERN_ERR "%s", x);

exit_code = 1;

}

static int __init

crd_load(struct file * fp, struct file *outfp)

{

int result;

insize = 0; /* valid bytes in inbuf */

inptr = 0; /* index of next byte to be processed in inbuf */

outcnt = 0; /* bytes in output buffer */

exit_code = 0;

bytes_out = 0;

crc = (ulg)0xffffffffL; /* shift register contents */

crd_infp = fp;

crd_outfp = outfp;

inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);

if (inbuf == 0) {

printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");

return -1;

}

window = kmalloc(WSIZE, GFP_KERNEL);

if (window == 0) {

printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");

kfree(inbuf);

return -1;

}

makecrc();

result = gunzip();

kfree(inbuf);

kfree(window);

return result;

}

#endif /* BUILD_CRAMDISK */

32位内核自解压代码

------------------

; arch/i386/boot/compressed/head.S

.text

#include

#include

.globl startup_32 对于zImage该入口地址为0x1000; 对于bzImage为0x101000

startup_32:

cld

cli

movl $(__KERNEL_DS),%eax

movl %eax,%ds

movl %eax,%es

movl %eax,%fs

movl %eax,%gs

lss SYMBOL_NAME(stack_start),%esp # 自解压代码的堆栈为misc.c中定义的16K字节的数组

xorl %eax,%eax

1: incl %eax # check that A20 really IS enabled

movl %eax,0x000000 # loop forever if it isn't

cmpl %eax,0x100000

je 1b

/*

* Initialize eflags. Some BIOS's leave bits like NT set. This would

* confuse the debugger if this code is traced.

* XXX - best to initialize before switching to protected mode.

*/

pushl $0

popfl

/*

* Clear BSS 清除解压程序的BSS段

*/

xorl %eax,%eax

movl $ SYMBOL_NAME(_edata),%edi

movl $ SYMBOL_NAME(_end),%ecx

subl %edi,%ecx

cld

rep

stosb

/*

* Do the decompression, and jump to the new kernel..

*/

subl $16,%esp # place for structure on the stack

movl %esp,%eax

pushl %esi # real mode pointer as second arg

pushl %eax # address of structure as first arg

call SYMBOL_NAME(decompress_kernel)

orl %eax,%eax # 如果返回非零,则表示为内核解压为低端和高端的两个片断

jnz 3f

popl %esi # discard address

popl %esi # real mode pointer

xorl %ebx,%ebx

ljmp $(__KERNEL_CS), $0x100000 # 运行start_kernel

/*

* We come here, if we were loaded high.

*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值