每个函数都是在栈上创建,同时在执行程序之后被自动销毁。
在执行程序调用该函数的过程中,由两个寄存器 esp , ebp来存放该函数地址(一个是该函数的最高位的地址,一个是该函数最低位的地址),这两个地址是用来维护函数在栈上开辟的空间(该空间又称为函数栈帧)。
程序总是从main函数开始,但其实main函数也是被其他函数调用;
#include <stdio.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int c = 0;
c = Add(a, b);
printf("%d\n",c);
return 0;
}
就拿上面简单的程序说一下创建和销毁的过程:
最开始时:
程序开始执行,先进入main函数,进入main函数时就得为main函数开辟空间,此时将栈顶指针的值赋给栈底指针,而栈顶指针将指向一个更小的地址,两指针之间就是main函数的函数栈帧;确定后空间之后,就把里面的单位赋上随机值。
现在开始执行main函数语句,开辟整形a,b,c,并赋上值;
下一指令是调用Add函数,首先传参(我使用vs2013版本)Add(a,b) ,先传b(在当前栈顶放一个元素,用来存放b),同理再传a ,栈顶指针也跟着向低地址下两个单元;
进入Add函数之前 1. 还要记住main函数中下一指令的地址,为了出Add函数之后便于找到下一指令;也是在栈顶放一个元素存放Add函数后面指令单地址, 栈顶指针也跟着向低地址下一个单元;
进入Add函数之前 2.进入Add函数,esp,ebp 将会维护Add函数,还要在栈顶开辟一个单元存放目前main函数的ebp,栈顶指针也跟着向低地址下一个单元;然后此时将栈顶指针的值赋给栈底指针,而栈顶指针将指向一个更小的地址,两指针之间就是Add函数的函数栈帧;确定后空间之后,就把里面的单位赋上随机值。
开始执行Add函数,开辟整型变量z,并赋值;
接着往下走执行 z = x+y;最后返回 z 值;先把z的值传给寄存器eax(因为释放空间之后找不到z值);然后释放Add函数空间,把ebp赋值给esp;
此时把栈顶释放一个单元,ebp回到了main函数的栈底,esp向高位移一个单元 ;
而注意Add函数下面一个指令的地址以保存,得到地址后也将释放空间,Add函数的形参也被释放(函数形参是实参的临时拷贝);
接着往下走,直到结束,main函数的空间释放和Add函数一样;