一、什么是栈帧
大多数CPU上的程序实现使用栈来支持函数调用操作。栈被用来传递函数参数、存储返回信息、临时保存寄存器原有值以备恢复以及用来存储局部数据。单个函数调用操作所使用的栈部分被称为栈帧。
c语言中每个栈帧对应一个未运行的函数。用逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。
那么接下来就来了解一下栈帧的结构吧!
二、栈帧的结构
在说占帧结构之前呢,还是先来说几个重点的指针吧:
ebp是当前函数的存取指针,即存储或者读取数时的指针基地址;esp就是当前函数的栈顶指针。每一次发生函数的调用(主函数调用子函数)时,在被调用函数初始时,都会把当前函数(主函数)的ebp压栈,以便从子函数返回到主函数时可以获取ebp。
还有一个就是pc指针了,他是一个程序计数器,总是指向正在运行的下一个程序的地址。
下面简单说一下这个过程:
假设P是调用者,Q是被调用者,那么Q的参数放在P的栈帧中。
当P调用Q时,P中的返回地址被压入栈中,形成P的栈帧末尾(返回地址就是当程序从 Q返回是应该继续执行的地方)。Q栈帧从保存的帧指针的值(%ebp)开始,后面是保存的其他寄存器的值。
在被调养的过程中,第一个参数放在相对于%ebp偏移量为8的位置处,剩下的参数存储在后续的4歌字节块中。所以参数 n 就相对于%ebp偏移量为4+4n的地方。
函数的调用
下面是一个简单的程序代码,反应的函数的调用过程:
#include<stdio.h>
#include<stdlib.h>
int fun(intx, inty)
{
int c = 0xcccccccc;
return c;
}
intmain()
{
int a = 0xaaaaaaaa;
int b = 0xbbbbbbbb;
int ret = fun(a, b);
printf("you should run here!\n");
system("pause");
return 0;
}
接下来就来看一下反汇编的情况,额,还是先来说一下几个指令吧:
call指令:指明被调用过程起始的指令地址,它的作用有两个,一是保存ebp,esp,pc,以及下一条指令的地址;另外就是修改pc指针,使其跳转到下一函数。
ret指令:这个指令同样也有两个作用,一是恢复ebp,esp,pc;另外是修复一系列的指针,让其重新指向上一条指令。