函数调用过程以及栈帧详解
函数的调用是一个过程,那么在函数的调用过程中要开辟栈空间,用来对本次函数的调用中需要的临时变量保存。这块空间叫栈帧。这个过程调用包括将数据和控制从代码的一部分传递到另一部分。过程调用的任务:为过程的局部变量分配空间,并在退出时释放这些空间,俗称保存现场/恢复现场。栈的作用:参数传递、局部变量分配、保存调用的返回地址、保存寄存器以供恢复栈帧:为单个过程分配的那部分栈称为栈帧
这是代码在内存的分布:
一般栈形图如下:
下面,我们用一个简单的函数调用过程来看这个过程。我们写了一段简单的代码:
#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 ret = Add(a, b);
printf("result: %d\n", ret);
return 0;
}
对应的反汇编为:
int main()
{
008C17D0 push ebp //把ebp压入栈中,方便返回
008C17D1 mov ebp,esp //把esp赋值给ebp
008C17D3 sub esp,0E4h //产生新的esp
(这一部分的功能就是开辟新的栈帧)
008C17D9 push ebx
008C17DA push esi
008C17DB push edi
008C17DC lea edi,[ebp-0E4h]
008C17E2 mov ecx,39h
008C17E7 mov eax,0CCCCCCCCh
008C17EC rep stos dword ptr es:[edi]
(把栈帧中开辟的空间初始化)
int a = 10;
008C17EE mov dword ptr [a],0Ah
int b = 20;
008C17F5 mov dword ptr [b],14h
(局部变量的创建)
int ret = Add(a, b);
008C17FC mov eax,dword ptr [b]
008C17FF push eax
008C1800 mov ecx,dword ptr [a]
008C1803 push ecx
008C1804 call _Add (08C10FAh) //call指令有两个作用把call下一条指令存进去,来方便下一次查找,然后:jmp,跳转到_add
(把中间变量存储)
#include<stdio.h>
int Add(int x,int y)
{
008C16C0 push ebp
008C16C1 mov ebp,esp
008C16C3 sub esp,0CCh
008C16C9 push ebx
008C16CA push esi
008C16CB push edi
008C16CC lea edi,[ebp-0CCh]
008C16D2 mov ecx,33h
008C16D7 mov eax,0CCCCCCCCh
008C16DC rep stos dword ptr es:[edi]
(类似于main函数,自己给自己开辟新的栈帧,然后初始化)
int z = 0;
008C16DE mov dword ptr [z],0 //创建z变量
z = x + y;
008C16E5 mov eax,dword ptr [x]
008C16E8 add eax,dword ptr [y]
008C16EB mov dword ptr [z],eax
(进行a,b相加并把结果存在eax中,通过eax寄存器待会a+b的值)
return z;
008C16EE mov eax,dword ptr [z]
}
008C16F1 pop edi
008C16F2 pop esi
008C16F3 pop ebx //pop 使esp下移
008C16F4 mov esp,ebp
008C16F6 pop ebp
008C16F7 ret //ret要进行两个步骤,pop把pop的内容保存在ebp中,然后jump到call命令的下一跳。
008C1809 add esp,8
008C180C mov dword ptr [ret],eax
printf("result: %d\n", ret);
008C180F mov eax,dword ptr [ret]
008C1812 push eax
008C1813 push offset string "result: %d\n" (08C6B30h)
008C1818 call _printf (08C1325h)
008C181D add esp,8
return 0;
008C1820 xor eax,eax
}
008C1822 pop edi
008C1823 pop esi
008C1824 pop ebx
}
008C1825 add esp,0E4h
008C182B cmp ebp,esp
008C182D call __RTC_CheckEsp (08C1118h)
008C1832 mov esp,ebp
008C1834 pop ebp
008C1835 ret
从中我们发现
中间变量存在两个栈帧之间,
形参的读取是从右向左的~如图,先b后a
临时变量存在自己的栈帧中用完,随着栈帧一起释放,
自己的栈帧是自己开辟的。
返回值是通过寄存器如eax带回返回值的。
pc指针及elp存的是当前指令的下一条指令。
我们知道函数是通过call实现跳转,ret进行返回
然后我们观察栈帧发现,call的下一跳指令存在自定义变量的上第2个(指针p+=2),所以只要我们自己定义一个变量,顺着就可以找到call的下一跳指令,然后通过指针对地址进行修改。
同样的,我们可以观察main返回存储在栈帧中的位置我们可以发现,我们可以通过找到形参(这里要是最后一个形参,及最左的),(指针P--)就可以找到。
我们可以在vc6.0上试一下这个程序。
_________________________________________________________________________________
#include<stdio.h>
#include<windows.h>
int main_ret = 0;
int bug()
{
int i = 0;
int *p = &i;
p += 2;
*p = main_ret;
Sleep(1000);
//system("cls");
printf("joke,you,now you are in bug!\n\n");
//system("pause");
return 1;
}
int Add(int x,int y)
{
int z = 0;
int *p = &x;
p--;
main_ret =*p;
*p = (int)bug;
printf("now is in Add\n");
z = x + y;
printf("jump out Add\n");
return z;
}
int main()
{
printf("begin in main\n");
int a = 10;
int b = 20;
int ret = Add(a, b);
_asm {
sub esp, 4;
}
printf("result: %d\n", ret);
printf("return to main\n");
system("pause");
return 0;
}
_____________________________________________________________________
运行结果如下~
函数调用过程以及栈帧详解相关推荐
- C语言的函数调用过程(栈帧的创建与销毁)
从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: 1 int Add(int x,int y)2 {3 int sum = 0;4 sum = x + y;5 return sum;6 ...
- 帧栈使用的基本用法c语言,栈帧详解
一. 理解栈帧 栈帧是什么,我们基本的理解是栈帧是栈帧也叫过程 活动记录,是 编译器用来实现过程/ 函数调用的一种数据结构.通俗来说栈帧就时C语言函数在调用的过程中的调用原理,就是当我们执行一个函数操 ...
- 栈帧详解ebp、esp
一. 理解栈帧 栈帧是什么,我们基本的理解是栈帧也叫活动记录过程,是编译器用来实现过程 函数调用的一种数据结构.通俗来说栈帧就时C语言函数在调用的过程中的调用原理,就是当我们执行一个函数操作的时候,它 ...
- C语言编程宏定义的优缺点,C语言重要知识点总结(二)--内存结构、函数调用过程(栈帧)、宏的优缺点以及##和#的使用...
一.内存结构 内存大致可以分为四个部分:代码段,静态存储区,堆,栈. 具体划分如下图所示: 栈:在执行函数时,函数内部局部变量的存储单元都可以在栈上创建,函数执行结束后会自动释放内存.栈内存的分配运算 ...
- 函数调用过程,栈帧的一点理解
栈帧图例一张 寄存器理解 程序寄存器组是唯一能被所有函数共享的资源.虽然某一时刻只有一个函数在执行,但需保证当某个函数调用其他函数时,被调函数不会修改或覆盖主调函数稍后会使用到的寄存器值.因此,IA3 ...
- 过程(栈帧结构是干货)
[0]写在前面 过程(栈帧结构是干货):本文总结于csapp, 加上自己的理解: [1]栈帧结构 每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息. 过程调用:函数调用另 ...
- (栈帧和函数调用一)栈帧,函数调用与栈的关系
(栈帧和函数调用一)栈帧,函数调用与栈的关系 一,栈帧的介绍 二,函数调用与栈的关系 三,汇编演示 四,总结 在计算机科学中,栈是一个特殊的容器,用户可以将数据压入栈中(入栈,push),也可以将已经 ...
- java语言链栈_Java语言实现数据结构栈代码详解
近来复习数据结构,自己动手实现了栈.栈是一种限制插入和删除只能在一个位置上的表.最基本的操作是进栈和出栈,因此,又被叫作"先进后出"表. 首先了解下栈的概念: 栈是限定仅在表头进行 ...
- http\https的连接过程及数字证书详解
http\https的连接过程及数字证书详解 内推军p185 http连接过程(相当于输入url会发生什么) 1.域名解析 2.发起TCP的三次握手 3.Web浏览器向服务器发送http请求命令 4. ...
最新文章
- 接口入参形式_极光小课堂|手把手教你做接口测试
- Dreamwear如何创建javascript_JavaScript还可以处理日期?你只需要这样做
- python无法识别vim中文代码
- 机房系统(五)——【Excel表导出】
- sqlyog如何设置.时提示字段名_雷神新用户手册:拿到新电脑时如何简易设置参数!...
- iOS 如果刷新TableViewCell上得数据是空的 添加尾部暂无数据提示
- 中国开发者数量全球第二,C 语言一跌再跌!GitHub 年度报告重磅发布
- flume监听服务器文件,flume监听服务器端口数据库
- oracle中脚本是什么意思,ORACLE常用脚本命令
- [云计算]网线的标签格式
- oracle odi 目标数据存储: 临时目标数据存储未与连接关联,ODI知识模块--IKM Oracle Incremental Update...
- selenium chromedriver 下载地址
- 微信小程序支持分享到朋友圈了
- 华为服务器进入系统怎么退出安全模式,华为手机怎么进入和退出安全模式?华为手机进入安全模式按哪个键...
- 二维坐标基本变换(平移、旋转、缩放、镜像、阵列)
- UTF-8/16/32编码
- java编写分数加减法_JAVA 分数加减法
- PTA 使我精神焕发
- 光流.flo文件处理
- js 图片上传传给后台的几种格式,formData,base64,file,blob流
热门文章
- Revit获取平面视图参照标高及视图范围
- terminal的常用快捷键
- IDEA学生免费申请教程
- 古典密码(单表密码,维吉尼亚密码,普莱费尔密码,一次一密)
- html5无法播放腾讯视频教程,电脑中无法打开腾讯视频的解决方法
- java 打印机类printer_GitHub - 505058216/thermal_printer: Java实现网络小票打印机自定义无驱打印...
- EBS R12多组织访问控制
- ORB-SLAM3笔记(编译、踩坑、论文、看代码)
- java对象的内存布局
- 运满满服务器繁忙显示500,运满满上线两年多 听听货车司机怎么说