浅析栈帧

来源:互联网 发布:软件著作权范本 编辑:程序博客网 时间:2024/05/22 09:05

 

栈帧(stack Frame):即为函数的调用过程。我们知道每一次函数调用都是一个过程。
这个过程我们通常称之为函数的调用过程。这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存、现场保护。这块栈空间我们称之为函数栈帧。
一次函数调用包括将数据和控制从代码的一个部分传递到另外一个部分,栈帧与某个过程调用一一映射。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低址地)。

观察栈在其中的位置,如下图:

 

入栈操作:push eax; 等价于 esp=esp-4,eax->[esp];如下图:

出栈操作:pop eax; 等价于 [esp]->eax,esp=esp+4;如下图:

下面通过一个简单的实例来深入研究一下函数的调用过程:
#include<stdio.h>
intAdd(intx,inty)
{
intz =0;
z = x + y;
returnz;
}

intmain()
{
inta =10;
intb =20;
intret = Add(a, b);
printf("ret = %d\n", ret);
return0
}


当程序调试的时候,可以查看【调用堆栈】,如下图:


可以发现其实main函数是在__tmainCRTStartup函数中调用的,
__tmainCRTStartup函数是在mainCRTStartup中被调用的。
栈帧的维护必须了解ebpesp两个寄存器。在函数调用的过程中这两个寄
存器存放了维护这个栈的栈底指针和栈顶指针。
比如:
调用main函数,我们为main函数分配栈帧空间,那么栈帧维护如下:


要详细研究函数的调用过程,必须得对应汇编代码。
1.main函数开始,要展开main函数的调用就得为main函数创建栈
帧,下面先来看main函数栈帧的创建,如下图:


2.接下来是Add函数的调用。
参数传递过程如下图:


执行call指令的时候按F11,来到了这里,如下图:


再按F11就进入Add函数的执行代码处,如下图:

剩下的就是函数返回部分,如下图:

注:栈帧的实现在不同的编译器上存在差异,但是思想都是一致的。

栈帧部分已经描述了函数参数的保存位置,即保存在调用者栈帧的尾部固定长度偏移位置,程序运行时就根据函数的定义和该位置取参数进行相应的运算。

注:这里函数调用的参数显然存储在函数调用者的栈帧中,而不是被调用函数的栈帧中。


 


 

0 0
原创粉丝点击