分享
 
 
 

Win32 环境下的堆栈(一)

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Win32 环境下的堆栈(一)

简介

在Win32环境下利用调试器调试应用程序的时候经常要和堆栈(Stack)打交道,尤其是在需要手工遍历堆栈(Manually Walking Stack)的时候我们需要对堆栈的工作过程有一个比较清晰的了解.接下来的这些文字将通过一个例子程序详细的讲解堆栈的工作过程.

关键字

调试 堆栈 Stack Stack-Frame

目录

1.堆栈是什么?

2.堆栈里面放的都是什么信息?

3.堆栈是在什么时候被建立起来的?它的默认大小是多少?

4.默认才1M??那要是我的程序使用超过了1M的堆栈怎么办?

5.什么叫Stack Frame?

6.在一次函数调用中,堆栈是如何工作的?

7.老大,结合一个例子讲讲吧?

1.堆栈是什么?

从内存管理角度看,堆栈是就是一块连续的内存空间,对它的操作采用先入后出的规则,他的生长方向与内存的生长方向正好相反,也就是说它是从高地址向低地址生长.

从Win32程序内部的角度看,每一个线程有自己的堆栈,它主要用来给线程提供一个暂时存放数据的区域,程序使用POP/PUSH指令来对堆栈进行操作.

2.堆栈里面放的都是什么信息?

堆栈中存放的信息包括:当前正在执行的函数的局部变量,函数返回地址,该函数的上层函数传给该函数的参数,EBP的值,一些通用寄存器(EDI,ESI…)的值,注意这里提到的正在执行的函数,比如有下面的一段C代码:

void B()

{

printf(“B\n”);

}

void A()

{

B();

}

那么当程序执行到B函数的printf函数的时候我们说正在执行的函数包括A和B而不仅仅是B函数,这一点需要注意.

3.堆栈是在什么时候被建立起来了?它的默认大小是多少?

堆栈是在我们的main主函数被系统调用之前被建立起来的,对于非主线程它是在线程被建立之前创建的,它的默认大小是1M,如果需要修改堆栈的大小的话可以在VC6++中通过使用/STACK编译项实现:

#pragma comment(linker,"/STACK:2048,1024") // 预约(Reserve)2M,提交(Commit)1M

关于预约(Reserve)和提交(Commit)的概念请参看”Programming Applications for Microsoft Windows“( Jeffrey Richter,Chapter 15 Using Virtual Memory in Your Own Applications)

4.默认才1M??那要是我的程序使用超过了1M的堆栈怎么办?

系统通过使用异常捕获(Exception Handling)机制来捕获应用程序企图去访问超过该程序提交(Commit)的堆栈范围这种异常,假如你程序预约了2M并且提交了1M大小的堆栈,那么当你的程序企图访问超过1M的范围的时候会产生一个异常并且被系统捕获,系统会帮你继续从另外1M预约的内存中提交内存来满足你的需求,如果你要求提交的大小甚至超过了2M(你一开始预约的大小)在 NT系统下(98除外)系统也会尝试去分配(allocate)内存来满足你,但是系统并不保证分配会成功

5.什么叫Stack Frame?

Stack Frame这个词你可以在各种各样的汇编书籍中看到,到底它表示什么意思呢?也许你看完文章的后半部分就会明白,在此我们先给它一个定义,你看完整篇文章在回过头来回味一下就会知道它的确切含义了,Stack Frame是堆栈中的一块区域,它保存着一个函数的返回地址,和该函数内部使用的局部数据(Local Data),它是由函数入口处的SUB ESP,48h之类的语句来建立的.

6.在一次函数调用中,堆栈是如何工作的?

假设我们的主角叫A函数…

a.首先上级函数传给A函数的参数被压入堆栈中(至于是谁来做这个压栈操作取决于A函数的调用方式:是__stdcall, __cdecl还是其他);

b.然后是返回地址(A函数执行完后接下来程序继续执行的地址)入栈;

c.接下来是当前的EBP;

d.如果A函数有局部变量,就在堆栈中开辟相应的空间以构造那些变量变量(A函数执行结束,这些局部变量的内容将被忽略/遗弃,但是不被清除,比如A函数中有一个变量int m存在于地址0x0012FFCC处,函数结束时9依然存在于0x0012FFCC处没有被清除,但是此时它已经没有任何意义了,

e.在函数返回的时候,弹出EBP,恢复堆栈到函数调用前的地址,弹出返回地址到EIP以继续执行程序。

7.老大,结合一个例子讲讲吧?

下面就是我们要拿来做模特的代码,程序很简单,wWinMain调用AFunc,AFunc再调用BFunc,下面的讲解过程中我们要观摩这个程序的汇编代码形式,可以通过在VC6++该工程的Debug模式中按F5然后Ctrl+Tab做到,我想这对于Win32程序员应该不是难事.

int BFunc(int i,int j)

{

int m = 1;

int n = 2;

m = i;

n = j;

return m;

}

int AFunc(int i,int j)

{

int m = 3;

int n = 4;

m = i;

n = j;

BFunc(m,n);

return 8;

}

int APIENTRY wWinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

AFunc(5,6);

return 0;

}

步骤1.我们从wWinMain调用AFunc函数开始

wWinMain调用AFunc的时候,先把参数压栈(至于为什么压栈顺序是6,5而不是5,6请参看附录.注解1)参数压栈结束后此时ESP = 0x0012FEDC,EBP = 0x0012FF30,

这是进入AFunc函数之前的堆栈形势图:

图 1

步骤2.记住进入AFcun函数之前的ESP,EBP的值,然后我们进入AFunc…

为方便大家观摩,先把AFunc函数的全貌贴出来

29: int AFunc(int i,int j)

30: {

004010D0 push ebp ; 先把EBP入栈保存

004010D1 mov ebp,esp ; 再把此时的ESP赋给EBP,这样EBP就可以拿来访问本函数的局部变量

004010D3 sub esp,48h ; 为AFunc函数在堆栈重开辟一块空间,一般来说开辟的空间大小是40+

; 函数内所有局部变量的大小;

004010D6 push ebx ; 通用寄存器入栈,算保存现场吧

004010D7 push esi

004010D8 push edi

004010D9 lea edi,[ebp-48h]

004010DC mov ecx,12h

004010E1 mov eax,0CCCCCCCCh

004010E6 rep stos dword ptr [edi]

31: int m = 3;

004010E8 mov dword ptr [ebp-4],3 ; 为什么局部变量m位于ebp-3处?

32: int n = 4;

004010EF mov dword ptr [ebp-8],4 ; 为什么局部变量n位于ebp-8处?

33:

34: m = i;

004010F6 mov eax,dword ptr [ebp+8] ; ebp+8处存的是什么?

004010F9 mov dword ptr [ebp-4],eax

35: n = j;

004010FC mov ecx,dword ptr [ebp+0Ch] ; ebp+0ch处存的是什么?

004010FF mov dword ptr [ebp-8],ecx

36:

37: BFunc(m,n);

00401102 mov edx,dword ptr [ebp-8] ; AFunc调用BFunc之前先把传给BFunc的参数入栈

00401105 push edx

00401106 mov eax,dword ptr [ebp-4]

00401109 push eax

0040110A call @ILT+25(BFunc) (0040101e)

0040110F add esp,8 ; 这个出栈操作为什么?

38:

39: return 8;

00401112 mov eax,8

40: }

00401117 pop edi ; 恢复现场

00401118 pop esi

00401119 pop ebx

0040111A add esp,48h ; 收回函数一开始在栈中开辟的空间

; 对应于一开始的sub esp,48h

0040111D cmp ebp,esp

0040111F call __chkesp (00401220)

00401124 mov esp,ebp

00401126 pop ebp ; 恢复调用前的EBP

00401127 ret

(未完待续)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有