我们知道每一次函数的调用都是一个过程,这个过程我们通常称为:函数的调用过程。这个过程要为函数开辟栈空间,用于本次函数的调用过程中临时变量的保存、现场保护。这块栈空间被称为函数栈帧。
在理解函数的栈帧之前,我们需要了解几个特殊的寄存器和一些汇编指令。eip:程序计数器,存放当前指令的下一条指令的地址;ebp:存放指向函数栈帧栈底的地址;esp:存放指向函数栈帧栈顶的地址;call:1将当前指令的下一条指令保存,保存的目的是为了恢复(入栈保存);2跳转至目标函数的地址处;ret:1,将当前栈顶的内容出栈;2,用该内容修改eip。
下面来看这个例子:
#include<stdio.h>;
#include<windows.h>
int my_add(int a, int b)
{
int z = a + b;
return z;
}
int main()
{
int a = 0xAAAAAAAA;
int b = 0xBBBBBBBB;
int ret = my_add(a, b);
printf("%d\n", ret);
system("pause");
return 0;
}
当我们要详细研究函数的调用过程,必须的对应汇编代码。
从main函数的地方开始,要展开main函数的调用就得为main函数创建栈帧
![](https://i-blog.csdnimg.cn/blog_migrate/b1fbc5d9daf904509619391bea71e08b.png)
接下来是my_add函数的调用
![](https://i-blog.csdnimg.cn/blog_migrate/900a4d5a4cdf94728ad8035893d8d25d.png)
剩下的是函数返回部分
![](https://i-blog.csdnimg.cn/blog_migrate/5395168c2189c2b6245422874775899c.png)
所以说函数的调用就是函数的栈帧的开辟与释放。同时我们也可以看到栈是往下生长的。在函数调用完成后,我们看到并没有对所调用空间内数据的修改,而是这部分空间的内容可以被修改。