函数的调用是一个过程,那么在函数的调用过程中要开辟栈空间,用来对本次函数的调用中需要的临时变量保存。这块空间叫栈帧。这个过程调用包括将数据和控制从代码的一部分传递到另一部分。过程调用的任务:为过程的局部变量分配空间,并在退出时释放这些空间,俗称保存现场/恢复现场。栈的作用:参数传递、局部变量分配、保存调用的返回地址、保存寄存器以供恢复栈帧:为单个过程分配的那部分栈称为栈帧

这是代码在内存的分布:

一般栈形图如下:

下面,我们用一个简单的函数调用过程来看这个过程。我们写了一段简单的代码:

#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;
}

_____________________________________________________________________

运行结果如下~

函数调用过程以及栈帧详解相关推荐

  1. C语言的函数调用过程(栈帧的创建与销毁)

    从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: 1 int Add(int x,int y)2 {3 int sum = 0;4 sum = x + y;5 return sum;6 ...

  2. 帧栈使用的基本用法c语言,栈帧详解

    一. 理解栈帧 栈帧是什么,我们基本的理解是栈帧是栈帧也叫过程 活动记录,是 编译器用来实现过程/ 函数调用的一种数据结构.通俗来说栈帧就时C语言函数在调用的过程中的调用原理,就是当我们执行一个函数操 ...

  3. 栈帧详解ebp、esp

    一. 理解栈帧 栈帧是什么,我们基本的理解是栈帧也叫活动记录过程,是编译器用来实现过程 函数调用的一种数据结构.通俗来说栈帧就时C语言函数在调用的过程中的调用原理,就是当我们执行一个函数操作的时候,它 ...

  4. C语言编程宏定义的优缺点,C语言重要知识点总结(二)--内存结构、函数调用过程(栈帧)、宏的优缺点以及##和#的使用...

    一.内存结构 内存大致可以分为四个部分:代码段,静态存储区,堆,栈. 具体划分如下图所示: 栈:在执行函数时,函数内部局部变量的存储单元都可以在栈上创建,函数执行结束后会自动释放内存.栈内存的分配运算 ...

  5. 函数调用过程,栈帧的一点理解

    栈帧图例一张 寄存器理解 程序寄存器组是唯一能被所有函数共享的资源.虽然某一时刻只有一个函数在执行,但需保证当某个函数调用其他函数时,被调函数不会修改或覆盖主调函数稍后会使用到的寄存器值.因此,IA3 ...

  6. 过程(栈帧结构是干货)

    [0]写在前面 过程(栈帧结构是干货):本文总结于csapp, 加上自己的理解: [1]栈帧结构 每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息. 过程调用:函数调用另 ...

  7. (栈帧和函数调用一)栈帧,函数调用与栈的关系

    (栈帧和函数调用一)栈帧,函数调用与栈的关系 一,栈帧的介绍 二,函数调用与栈的关系 三,汇编演示 四,总结 在计算机科学中,栈是一个特殊的容器,用户可以将数据压入栈中(入栈,push),也可以将已经 ...

  8. java语言链栈_Java语言实现数据结构栈代码详解

    近来复习数据结构,自己动手实现了栈.栈是一种限制插入和删除只能在一个位置上的表.最基本的操作是进栈和出栈,因此,又被叫作"先进后出"表. 首先了解下栈的概念: 栈是限定仅在表头进行 ...

  9. http\https的连接过程及数字证书详解

    http\https的连接过程及数字证书详解 内推军p185 http连接过程(相当于输入url会发生什么) 1.域名解析 2.发起TCP的三次握手 3.Web浏览器向服务器发送http请求命令 4. ...

最新文章

  1. 接口入参形式_极光小课堂|手把手教你做接口测试
  2. Dreamwear如何创建javascript_JavaScript还可以处理日期?你只需要这样做
  3. python无法识别vim中文代码
  4. 机房系统(五)——【Excel表导出】
  5. sqlyog如何设置.时提示字段名_雷神新用户手册:拿到新电脑时如何简易设置参数!...
  6. iOS 如果刷新TableViewCell上得数据是空的 添加尾部暂无数据提示
  7. 中国开发者数量全球第二,C 语言一跌再跌!GitHub 年度报告重磅发布
  8. flume监听服务器文件,flume监听服务器端口数据库
  9. oracle中脚本是什么意思,ORACLE常用脚本命令
  10. [云计算]网线的标签格式
  11. oracle odi 目标数据存储: 临时目标数据存储未与连接关联,ODI知识模块--IKM Oracle Incremental Update...
  12. selenium chromedriver 下载地址
  13. 微信小程序支持分享到朋友圈了
  14. 华为服务器进入系统怎么退出安全模式,华为手机怎么进入和退出安全模式?华为手机进入安全模式按哪个键...
  15. 二维坐标基本变换(平移、旋转、缩放、镜像、阵列)
  16. UTF-8/16/32编码
  17. java编写分数加减法_JAVA 分数加减法
  18. PTA 使我精神焕发
  19. 光流.flo文件处理
  20. js 图片上传传给后台的几种格式,formData,base64,file,blob流

热门文章

  1. Revit获取平面视图参照标高及视图范围
  2. terminal的常用快捷键
  3. IDEA学生免费申请教程
  4. 古典密码(单表密码,维吉尼亚密码,普莱费尔密码,一次一密)
  5. html5无法播放腾讯视频教程,电脑中无法打开腾讯视频的解决方法
  6. java 打印机类printer_GitHub - 505058216/thermal_printer: Java实现网络小票打印机自定义无驱打印...
  7. EBS R12多组织访问控制
  8. ORB-SLAM3笔记(编译、踩坑、论文、看代码)
  9. java对象的内存布局
  10. 运满满服务器繁忙显示500,运满满上线两年多 听听货车司机怎么说