分享
 
 
 

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

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

概述

----

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.

* We need to move the move-in-place routine down to 0x1000

* and then start it with the buffer addresses in registers,

* which we got from the stack.

*/

3:

movl $move_routine_start,%esi

movl $0x1000,%edi

movl $move_routine_end,%ecx

subl %esi,%ecx

addl $3,%ecx

shrl $2,%ecx # 按字取整

cld

rep

movsl # 将内核片断合并代码复制到0x1000区域, 内核的片段起始为0x2000

popl %esi # discard the address

popl %ebx # real mode pointer

popl %esi # low_buffer_start 内核低端片段的起始地址

popl %ecx # lcount 内核低端片段的字节数量

popl %edx # high_buffer_start 内核高端片段的起始地址

popl %eax # hcount 内核高端片段的字节数量

movl $0x100000,%edi 内核合并的起始地址

cli # make sure we don't get interrupted

ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine

/*

* Routine (template) for moving the decompressed kernel in place,

* if we were high loaded. This _must_ PIC-code !

*/

move_routine_start:

movl %ecx,%ebp

shrl $2,%ecx

rep

movsl # 按字拷贝第1个片段

movl %ebp,%ecx

andl $3,%ecx

rep

movsb # 传送不完全字

movl %edx,%esi

movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0

addl $3,%ecx

shrl $2,%ecx # 按字对齐

rep

movsl # 按字拷贝第2个片段

movl %ebx,%esi # Restore setup pointer

xorl %ebx,%ebx

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

move_routine_end:

; arch/i386/boot/compressed/misc.c

/*

* gzip declarations

*/

#define OF(args) args

#define STATIC static

#undef memset

#undef memcpy

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

typedef unsigned char uch;

typedef unsigned short ush;

typedef unsigned long ulg;

#define WSIZE 0x8000 /* Window size must be at least 32k, */

/* and a power of two */

static uch *inbuf; /* input buffer */

static uch window[WSIZE]; /* Sliding window buffer */

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

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

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

/* gzip flag byte */

#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */

#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */

#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */

#define ORIG_NAME 0x08 /* bit 3 set: original file name present */

#define COMMENT 0x10 /* bit 4 set: file comment present */

#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */

#define RESERVED 0xC0 /* bit 6,7: reserved */

#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())

/* Diagnostic functions */

#ifdef DEBUG

# define Assert(cond,msg) {if(!(cond)) error(msg);}

# define Trace(x) fprintf x

# define Tracev(x) {if (verbose) fprintf x ;}

# define Tracevv(x) {if (verbose>1) fprintf x ;}

# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}

# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}

#else

# define Assert(cond,msg)

# define Trace(x)

# define Tracev(x)

# define Tracevv(x)

# define Tracec(c,x)

# define Tracecv(c,x)

#endif

static int fill_inbuf(void);

static void flush_window(void);

stat

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有