windows stack分析

本文深入探讨了栈(stack)在程序中的重要性及其管理方式,包括如何通过编译器设置栈大小、避免栈溢出的方法,以及栈在函数调用中的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从Stack说开去
 从我个人的经验看,谈到内存时说堆的文章最多,说stack的最少。我这里反其道而行的原因是stack其实要比堆更重要,可以有不使用堆的程序,但你不可能不使用stack,虽然由于对stack的管理是由编译器确定了的,进而他较少出错。
 
通过链接开关/STACK:reserve[,commit]可以指定进程主线程的stack大小,当你建立其他线程时如果不指定dwStackSize参数,则也将使用/STACK所指定的值。微软说,如果指定较大的commit值将有利于提升程序的速度,我没验证过,但理应如此。通常并不需要对STACK进行什么设定,缺省的情况下将保留1M空间,并提交两个页(8K for x86)。而1M空间对于大多数程序而言是足够的,但为防止stack overflow有三点需要指出一是当需要非常大的空间时最好用全局数组或用VirtualAlloc进行分配,二是引用传递或用指针传递尺寸较大的函数参数(这点恐怕地球人都知道),三是进行深度递归时一定要考虑会不会产生stack溢出,如果有可能,可以采用我在《递归与goto》一文中提到的办法来仿真递归,这时候可以使用堆或自由存储来代替stack。同时结构化异常被用来控制是否为stack提交新的页面。(这部分写的比较简略因为很多人都写过,推荐阅读Jeffery Ritcher《Windows核心编程》第16章)
 
下面我们来看一下stack的使用。
假设我们有这样一个简单之极的函数:
 
 
int __stdcall add_s(int x,int y)
{
int sum;
 
sum=x+y;
 
return sum;
}
 
这样在调用函数前,通常我们会看到这样的指令。
mov         eax,dword ptr [ebp-8]
push        eax
mov         ecx,dword ptr [ebp-4]
push        ecx
此时把函数参数压入堆栈,而stack指针ESP递减,stack空间减小。
 
在进入函数后,你将会看到如下指令:
push        ebp
mov         ebp,esp
sub         esp,44h
这三句建立stack框架,并减小esp为局部变量预留空间。建立stack框架后,[ebp+*]指向函数参数,[ebp-*]指向局部变量。
 
另外在很多情况下你会看到如下三条指令
push        ebx
push        esi
push        edi
这三句把三个通用寄存器压入堆栈,这样这三个寄存器就可以用来存放一些变量,进而提升运行速度。
很奇怪,我这个函数根本用不到这三个寄存器,可编译器也生成了上述三条指令。
 
对stack中内容的读取,是靠基址指针ebp进行的。所以对应于sum=x+y;一句你会看到
mov         eax,dword ptr [ebp+8]
add         eax,dword ptr [ebp+0Ch]
mov         dword ptr [ebp-4],eax
其中[ebp+8]是x,[ebp+0Ch]是y,记住压栈方向为从右向左,所以y要在x上边。
 
我们再看一下函数退出时的情况:
pop         edi
pop         esi
pop         ebx
mov         esp,ebp
pop         ebp
ret         8
此时恢复stack框架,使esp与刚进入这个函数时相同,ret 8使esp再加8,使esp与没调用这个函数的时候一致。如果使用__cdecl调用规则,则由调用方以类似add  esp,8进行清场工作,使stack的大小与未进行函数调用时一致。Stack的使用就这样完全被编译器实现了,只要不溢出就和我们无关,也许也算一种内存的智能管理。最后要补充的两点是:首先stack不像heap会自动扩充,如果你用光了储备,他会准时溢出。其次是不要以为你使用了缺省参数进行链接,你就有1M的stack,看看启动代码你就知道在你拥有stack之前,C Run –Time 
    Library以用去了一小部分stack的空间。
阅读(298) | 评论(0) | 转发(0) |
0

上一篇:windbg调试kvm windows虚机

下一篇:VS2010

给主人留下些什么吧!~~
评论热议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值