栈帧(函数调用)

来源:互联网 发布:2017农村淘宝 编辑:程序博客网 时间:2024/06/18 00:27

我们都知道在写一个函数时会使用形参,形参实例化时会形成一份拷贝,调用这个函数时会把实参传进去,调用完之后那些临时拷贝又被释放,那么计算机在调用函数时是如何进行形参的保存和释放的呢?又如何返回形参?我们可以通过栈帧来理解函数的调用原理。

首先,栈是从高地址向低地址延伸的。每个函数的每次调用都有它自己独立的一个栈帧,这个栈帧中有它所需要的各种信息。每个函数都有自己的一份esp和ebp,而CPU只有一份esp和ebp。因为ebp和esp永远保存最新当前函数的值,所以每个函数都有自己的esp和ebp指向栈顶和栈底。

esp:栈顶寄存器,指向栈的低地址。

ebp:栈底寄存器,指向高地址。

pc指针:指向当前运行程序指令的下一条指令。


call指令: ①保存当前指令下一条指令的地址(方便返回)

②通过jmp跳到指定函数入口地址处(fun函数)

黑色线指的是main函数.

红色线指的是被调用者fun函数.

蓝色线指的是fun函数返回时,恢复到调用之前的状态.

CPU在重复的执行三个操作:取指令、分析指令、执行指令,取指令通过pc指针,分析指令通过CPU里的各种指令集。

接下来我们看一段代码:

#include<windows.h>

#include<iostream>

using namespace std;

int fun(int x,int y)

{

       intc = 0xcccccccc;

       returnc;

}

int main()

{

       inta = 0xaaaaaaaa;

       intb = 0xbbbbbbbb;

       intfir = fun(a, b);

       cout<< "lucky!" << endl;

       system("pause");

}

我们可以按F10进入调试,选择反汇编,请看截图


由图可看出参数实例化的时候是从右往左的

调用fun函数栈帧形成的过程:


push ebp  首先将pc指针下移然后把ebp寄存器的内容(main函数的栈底地址)

存到fun函数的当前栈顶(当前esp指向的地址);  

mov ebp esp    把esp的内容赋给ebp, fun函数的栈底;

sub  esp,0E4h   给esp减去一个随机值,指向一个新的fun函数栈顶;

fun函数返回时的过程:


mov   esp  ebp   把esp指向ebp的内容,形成新的栈顶
pop    ebp        将栈顶的内容(main:ebp)弹出来放在ebp(地址空间图上的第一个把esp指针上移
ret    把main:retaddr返回给pc ,esp上移;使pc指向main函数的下一条指令

fun函数返回后a和b就会被释放esp会回到之间的位置

这就是fun函数调用的原理(不是很详细)。

欢迎大家指出来当中的错误微笑微笑

原创粉丝点击