函数调用中栈帧内容
来源:互联网 发布:js获取上下文 编辑:程序博客网 时间:2024/06/14 16:41
转载:http://www.cnblogs.com/taek/archive/2012/02/05/2338877.html
当发生函数调用的时候,栈空间中存放的数据是这样的:
1、调用者函数把被调函数所需要的参数按照与被调函数的形参顺序相反的顺序压入栈中,即:从右向左依次把被调函数所需要的参数压入栈;2、调用者函数使用call指令调用被调函数,并把call指令的下一条指令的地址当成返回地址压入栈中(这个压栈操作隐含在call指令中);
3、在被调函数中,被调函数会先保存调用者函数的栈底地址(push ebp)(从高内在地址--》低内存地址),然后再保存调用者函数的栈顶地址,即:当前被调函数的栈底地址(mov ebp,esp);
4、在被调函数中,从ebp的位置处开始存放被调函数中的局部变量和临时变量,并且这些变量的地址按照定义时的顺序依次减小,即:这些变量的地址是按照栈的延伸方向排列的,先定义的变量先入栈,后定义的变量后入栈;
所以,发生函数调用时,入栈的顺序为:
参数N
参数N-1
参数N-2
.....
参数3
参数2
参数1
函数返回地址
上一层调用函数的EBP/BP
局部变量1
局部变量2
....
局部变量N
函数调用栈如下图所示:
![](http://pic002.cnblogs.com/images/2012/299846/2012020512105254.gif)
解释:
首先,将调用者函数的EBP入栈(push ebp),
然后将调用者函数的栈顶指针ESP赋值给被调函数的EBP(作为被调函数的栈底,mov ebp,esp),
此时,EBP寄存器处于一个非常重要的位置,该寄存器中存放着一个地址(原EBP入栈后的栈顶),
以该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数的局部变量值,而该地址处又存放着上一层函数调用时的EBP值;
一般而言,SS:[ebp+4]处为被调函数的返回地址,
SS:[EBP+8]处为传递给被调函数的第一个参数(最后一个入栈的参数,此处假设其占用4字节内存)的值,
SS:[EBP-4]处为被调函数中的第一个局部变量,
SS:[EBP]处为上一层EBP值;由于EBP中的地址处总是"上一层函数调用时的EBP值",
而在每一层函数调用中,都能通过当时的EBP值"向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取被调函数的局部变量值";
如此递归,就形成了函数调用栈;
函数内局部变量布局示例:
#include <stdio.h>
#include <string.h>
struct C
{
int a;
int b;
int c;
};
int test2(int x, int y, int z)
{
printf("hello,test2\n");
return 0;
}
int test(int x, int y, int z)
{
int a = 1;
int b = 2;
int c = 3;
struct C st;
printf("addr x = %u\n",(unsigned int)(&x));
printf("addr y = %u\n",(unsigned int)(&y));
printf("addr z = %u\n",(unsigned int)(&z));
printf("addr a = %u\n",(unsigned int)(&a));
printf("addr b = %u\n",(unsigned int)(&b));
printf("addr c = %u\n",(unsigned int)(&c));
printf("addr st = %u\n",(unsigned int)(&st));
printf("addr st.a = %u\n",(unsigned int)(&st.a));
printf("addr st.b = %u\n",(unsigned int)(&st.b));
printf("addr st.c = %u\n",(unsigned int)(&st.c));
return 0;
}
int main(int argc, char** argv)
{
int x = 1;
int y = 2;
int z = 3;
test(x,y,z);
printf("x = %d; y = %d; z = %d;\n", x,y,z);
memset(&y, 0, 8);
printf("x = %d; y = %d; z = %d;\n", x,y,z);
return 0;
}
打印输出如下:
addr x = 4288282272
addr y = 4288282276
addr z = 4288282280
addr a = 4288282260
addr b = 4288282256
addr c = 4288282252
addr st = 4288282240
addr st.a = 4288282240
addr st.b = 4288282244
addr st.c = 4288282248
a = 1; b = 2; c = 3;
a = 0; b = 0; c = 3;
示例效果图:
该图中的局部变量都是在该示例中定义的;
这个图片中反映的是一个典型的函数调用栈的内存布局;
- 函数调用中栈帧内容
- 内容自动分页函数调用
- 函数调用栈桢内容
- C函数调用的栈内容分析
- dll注入调用函数改变指针内容
- 根据日志内容分析函数调用堆栈(function stack)
- 【函数调用】上传文件并读取文件内容至内表
- Asp.net C# 实现内容页调用模板页函数
- 文本框onfocus()清空默认显示内容调用函数实现
- 编写一个递归调用函数,输出vector对象的内容
- dedecms 调用栏目内容
- 远程调用数据文件内容
- IOS通讯录内容调用
- OC调用JS内容
- 封面页内容调用
- 类中的虚函数,通过指针获得vtable内容,然后通过函数指针指向虚函数并调用
- SharePoint内容定制之XSLT高级用法——带返回值的函数调用
- 继承母版页的内容页运行Javascript onload事件调用函数
- 正则表达式30分钟入门教程
- 汇编-矩阵相乘
- 音乐播放器移植到开发板上
- 浙大PAT 1007题 1007. Maximum Subsequence Sum
- linux常用命令
- 函数调用中栈帧内容
- 浙大PAT 1008题 1008. Elevator
- SCTP相关术语
- 浙大PAT 1009题 1009. Product of Polynomials
- PHP中获取当前页面的完整URL
- Ext.grid.CheckColumn
- 自定义Button形状(圆形、椭圆)
- 浙大PAT 1011题 1011. World Cup Betting
- 81