函数调用过程-函数栈帧

函数的调用过程(函数栈帧) C/C++编译的程序占用内存的分配如图: 程序在运行期间,地址空间一直都存在。程序的地址空间不是内存,是虚拟地址空间。接下来详细分析函数调用时在栈区形成栈帧的过程:1. 栈 : 后进先出,进栈push,出栈pop.2.寄存器:①通用计数器:eax ebx ecx ... ②栈顶寄存器:esp 栈底寄存器:ebp ③程序计数器:ei... 阅读详情

函数栈帧

  • 函数是程序中必不可少的一个部分,整个程序的运行几乎都是由一个个函数之间互相调用来完成的,我们的main函数,printf函数,还有编程时我们自己写的函数,它们时我们的程序简介高效。

那么一个函数在内存中到底是如何调用的?如何实现函数的种种功能的?

深度解析

看这样一段代码

#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("ret = %d\n", ret); 
    return 0;
}

这段简单代码实现加法,其中Add函数实现加法,参数为两个整型变量,Add函数被main函数调用。

铺垫

1.
解析前做这样一个铺垫:
我们的main函数其实也是被其他函数调用的

以vs2008为例,代码写好后按F10开始逐过程可以看到上方有一个堆栈帧点开后如图
这里写图片描述
- main函数是被__tmainCRTStartup(void)函数调用的,而这个函数又是被mainCRTStartup(void)函数调用的。点击可进入查看源代码。

2.
内存中的地址是由寄存器来维护的,主要的寄存器有

  • eax , ebx , ecx , edx 还有这次最主要用到的 ebp(开辟空间的低地址) , esp(开辟空间的高地址)。
  • 当在内存中为函数开辟空寂后,ebp 存这块空间的高地址, esp 存这块空间的低地址。
  • 函数和局部变量在栈空间中开辟,栈孔吉娜由高地址向低地址使用。

这里写图片描述

反汇编剖析

现在我们开始研究函数的调用过程,即刚才按F10后逐过程停留在main函数,如第一幅图。

鼠标放在main函数旁边右击转到反汇编,然后在主工具栏找到-> 调试-窗口-点击监视和内存。

在监视栏找到ebp和esp的地址,同样在内存中找到以便后面观察。

  • 看图体会

这里写图片描述

继续按F10逐步执行

  • push为压栈向顶端压入一个地址,mov移动,sub开辟空间。
  • 按F10向下执行,这几步看图解析。

这里写图片描述

  • 继续连续三次压站三个寄存器
  • lea寻找有效地址
  • rep重复,将开辟的空间全部初始化为 cc cc cc cc
    这里写图片描述

  • 这里地址统一发生了变化,因为刚才调试中断了,但效果是一样的大家注意

这里写图片描述

  • 紧接着就为 a 和 b 初始化了
    这里写图片描述

-在call前的两次push是将a,b形参压入栈中
- 继续向下,遇到call是按F11,call是调用call函数
- 紧接着可以看到将ebp压入了栈顶,这里的ebp是main的起始地址,为函数调用完返回main使用。

这里写图片描述

这里写图片描述

  • 这后面与之前main过程类似

这里写图片描述

  • 后面相加完成后将z的值放入eax中,为带回到main函数ret中
  • Add函数的空间就会被释放
    -后面的pop是出栈到相应的寄存器中

  • 最后pop ebp就是将之前main函数的地址又返回到ebp从而使寄存器维护的区域回到main函数

随后执行printf函数最终结束main函数程序结束,函数在内存中的调用过程就是这样

作用

了解了函数在内存中的调用过程之后,一个程序在我们眼前是不是就显得很透明了呢?
那明白这些有什么作用,他的重要性又在哪里呢?
我们通过这样一段代码来体会。

void fun()
{
int tmp = 10;
int *p = (int *)(*(&tmp+1)); 
*(p-1) = 20;
}
int main() {
int a =0;
fun();
printf("a = %d\n",a); return 0;
}
  • 试判断输出结果是什么?
  • 答案是20(可以猜到)但我们要知晓他的原理

请参考倒数第三幅图理解

int *p = (int *)(*(&tmp+1));  
//tmp的地址加一指向了压入的ebp(main的地址),将这个地址给指针p,p就指向了main的开始。
*(p-1) = 20;
//p的地址减1,指向了为a开辟的空间从而改变了a的值。

从而可见函数栈帧的重要性

谢谢阅读欢迎留言~

函数调用栈帧过程(带图详解) 函数调用我们大家都很熟悉,我们都知道函数调用是发生在栈上的。首先,我们来了解一下程序对内存使用的分区情况: 区域 作用 栈区(stack) 由编译器自动分配和释放,存放函数的参数值,局部变量的值等。操作方式类似与数据结构中的栈 堆区(heap) 一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。与数据结构中的堆是两码事,分配方式类似于链表 静态区(sta 阅读详情

相关推荐

浅谈函数调用,开辟栈帧的过程

函数的调用过程其实就是开辟栈帧的过程,首先了解一下栈的特性和几个常用的寄存器。 栈:栈先进先出。 栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),我们称为栈底指针,寄存器esp指向当前的栈帧的顶部(低地址),我们称为栈顶指针。 通用寄存器:eax ebx ecx edx. eip(程序计数器...

IT小书生的博客 2170

C语言函数栈帧专题vs2013

1.寄存器中有eax,ebx,ecx,edx,ebp,esp。其中上述最后两个是存放地址的,这两个地址是来维护函数栈帧的。栈先使用高地址,再使用底地址。ebp指向栈低指针(高地址) ,esp指向栈顶指针(低地址)。 2.main函数也是被其它函数调用的,函数最后的return 0,返回给mainret。 3.push 压栈,pop出栈。 4.调用一个函数,在栈上开辟了一段空间,那一小段空间里面存的初始值都是cccccccc,如果定义了一个变量,但是没有给它赋值,它默认存放的就是cccccccc,打印出

m0_73345579的博客 257

函数调用过程以及栈帧详解

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

坚持不懈做贡献 956

VS2008 常用设置

修改text editor字体,默认字体的分号与冒号区别不明显,改成consolas可以解决这个问题 修改字号到15# 在alllanguage选项下的tabs中,勾选insert spaces,这样输入的的tab会被转为space形式。 显示行号: text Editor ==》C/C++ ==》line number 调试过程中显示变量的值 debug==》windows==》au...

李江龙的博客 1546

TPRI-DMP平台介绍

TPRI-DMP为华能集团西安热工院自主产权的工业云PaaS平台,已经过13年的发展和迭代,其具备大规模能源电力行业生产应用软件开发和运行能力

ashou706的专栏 2272

基于yolo11的BGA图像目标检测

15.YOLOv8的n/s版本(如YOLOv8n-1280),或通过TensorRT量化压缩模型。3.使用自适应batch_size(如根据GPU显存动态调整),推荐16-32。为采集分辨率整数倍(如原图2592×1944,训练时缩放为640×480),保持宽高比。14.采用余弦退火学习率(cos_lr)和早停(patience=50),防止过拟合。1.模型标注后,少量标注全部人工校验,大量数据抽检,部分人工检验。13.部署模型后持续收集困难样本(如模棱两可的预测结果),定期迭代更新模型。

qq_47798402的博客 1205

函数的调用过程(栈帧)及应用

在了解函数的调用过程之前,我们需要了解一些其他的知识。 每一次函数调用都是一个过程,这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存。而这块栈空间被我们称之为函数栈帧。栈帧的维护需要ebp和esp两个寄存器。在函数调用的过程中这两个寄存器存放了维护这个栈的栈底和栈顶指针,同时,栈的使用是由高地址向低地址使用的。 了解前面的知识后,我们将从汇编的角度,深入的了解函数...

木头的博客 1009

物理与工程中的‘黑话’:Kronecker delta和Levi-Civita符号到底简化了什么?

本文深入解析了物理与工程中常用的Kronecker delta和Levi-Civita符号的简化作用。通过对比传统表示与张量表示,展示了这些符号在向量运算、矩阵迹计算及流体力学模拟中的高效应用,显著提升计算效率和代码可读性。特别适合理论物理和工程数学领域的学习者与从业者。

weixin_27215403的博客 397

函数调用过程栈帧变化详解

函数调用过程栈帧变化详解 函数调用另一个词语表示叫作 过程。一个过程调用包括将数据和控制从代码的一部分传递到另一部分。另外,它还必须在进入时为过程的局部变量分配空间,并在推出时释放这些空间。而数据传递,局部变量的分配和释放通过操纵程序栈来实现。在了解本文章之前,您需要先对程序的进程空间有所了解,即对进程如何使用内存?如果你知道这些,下面的内容将是很easy的事情了。为了您的回顾还

chinaclock的专栏 3218

MuJoCo 关节角速度记录与可视化,监控机械臂运动状态

1. 手动计算关节速度,其中timestep为仿真步长。2. 使用data.qvel直接取得关节速度。

darcsdn 767

基于python的排课表系统,用python编写排课系统

实现一个具体的课程管理系统。(5) 学生可以查看自己选上的课的成绩,以及各个课程的得分、绩点,并给出其平均绩点,但不允许查看年级其他人的成绩。(2) 学生定制专属课表,可以查看整个学期本人的课程安排,包括课程名称、上课时间、上课地点、任课老师、学分等等。(13) 系主任可以查看整个系的全部学生以及他们的平均绩点,可以对每个班进行排名,或者也可以对整个系进行排名。(15) 系主任可以查看整个学期所开设的所有课程,包括这些课程的全部详细信息。(1) 学生基本信息的查询,学生可以对本人的系统登陆密码进行修改。

yang0728y的博客 1999

函数调用过程栈帧变化

某个函数运行时,机器需要分配一定内存去进行函数内的各种操作,这个过程包括将数据和控制从代码的一部分传递到另一部分,分配的这部分就是栈帧,栈帧其实就是是一段有界限的内存空间,它为函数局部变量分配空间,退出该函数时释放这些空间,回到调用它的地方执行下一条指令。 栈的作用:传递参数、局部变量分配、保存调用的返回地址、保存寄存器以供恢复上一栈帧 了解程序在内存中分布的都知道,栈是从高地址向低地址延伸的,每个函数的调用,都有它自己独立的一个栈帧 栈帧主要是有下面2个指针工作 ebp:帧指针...

夏天Alex 1389

3步搞定专利数据爬取:用Selenium绕过国家知识产权局反爬(附完整代码)

本文详细介绍了3种高效获取专利数据的技术方案,重点解析了使用Selenium绕过国家知识产权局反爬的实战方法,并提供了完整代码示例。文章还探讨了Requests+lxml轻量级方案和混合技术策略,帮助开发者根据需求选择最佳数据爬取方案,特别适合需要专利统计数据的开发者参考。

weixin_29029995的博客 1109

函数调用栈帧过程 图解

函数的调用栈帧过程的常用指令 1、add:加法指令,第一个是目标操作数,第二个是源操作数,格式为:目标操作数 = 目标操作数 + 源操作数; 2、call:调用函数,一般函数的参数放在寄存器中; 3、ret:跳转会调用函数的地方。对应于call,返回到对应的call调用的下一条指令,若有返回值,则放入eax中; 4、push:把一个32位的操作数压入堆栈中,这个操作在32位机中会使得e

qq_39380590的博客 1123

Visionpro 使用CogPMAlignTool工具提取匹配轮廓点

【代码】Visionpro 使用CogPMAlignTool工具提取匹配轮廓点。

weixin_43947315的博客 2091

数据资产可视化分析:PowerBI在大数据管理中的实战

目的:帮你搞懂“为什么数据资产需要可视化?”“PowerBI能帮企业解决什么问题?”,并掌握用PowerBI做大数据可视化的实战技巧。范围:覆盖数据资产定义、可视化分析原理、PowerBI核心功能(数据连接、建模、可视化)、零售企业实战案例,以及未来趋势与挑战。背景:为什么企业的数据像乱堆的玩具?核心概念:数据资产、可视化分析、PowerBI分别是什么?它们怎么配合?实战步骤:用PowerBI帮零售企业整理“销售玩具箱”,做出能指导决策的仪表盘;应用场景:不同部门怎么用这个“整理好的玩具箱”?

2501_92132293的博客 906

x86函数调用过程与栈帧

x86函数调用过程与栈帧 x86与x86-64在函数调用约定上有相当的不同,因此分开来讲 栈帧(stack frame) 先说一下栈帧的概念 函数每次被调用时,要在调用栈(call stack)上占用一段空间 在需要时保存调用者使用的寄存器值,保存本函数的局部变量、参数、返回地址等, 并且在函数结束后回到调用者的占用的空间与代码位置继续执行, 函数运行阶段在调用栈上占用的这段空间就叫做栈帧,是编译...

kafmws的博客 3548

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

图解函数调用过程(函数栈帧)

正在被执行push x指令:先将esp -"1"(1代表的不是数字1,而是一个最小单元),然后把x的值复制到esp指向的内存块中。pop x 指令:先将esp指向的内存块的内容赋值给x,然后esp+"1"。

2302_80221042的博客 631

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C++ 函数调用过程中栈区的变化——(栈帧、esp、ebp)

C++ 函数调用过程中栈区的变化C++ 函数调用过程中栈区的变化参考 C++ 函数调用过程中栈区的变化 参考 1、https://blog.youkuaiyun.com/m0_38087936/article/details/82938006 2、https://blog.youkuaiyun.com/fang92/article/details/46494665?utm_source=blogxgwz3 ...

JMW1407的博客 9010

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

函数调用过程中栈帧变化

转载自:https://blog.youkuaiyun.com/xbb224007/article/details/80106961 前言:本文旨在从汇编代码的角度出发,分析函数调用过程中栈帧的变化。 栈帧的简单介绍: 当某个函数运行时,机器需要分配一定的内存去进行函数内的各种操作,这个过程中分配的那部分栈称为栈帧。下图描述了栈帧的通用结构。栈帧是一段有界限的内存区间,由最顶端的两个指针界定,寄存器%ebp为帧指针,而寄存器%esp为栈指针(也就是说寄存器%ebp保存了所分配内存的最高地址,寄存器...

Liumotor的博客 962

详细解说函数调用过程中栈的活动(栈帧)

栈帧的解释 以下解释来自百度百科: 栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。 栈帧是编译器用来实现过程/函数调用的一种数据结构,也就是说,函数的每次调用都伴随着栈帧的创建与销毁。 栈的解释 栈在计算机上是有物理空间的,栈区的使用遵循先进后出、由高到低的规则。 ...

pigern的博客 1014

函数栈帧(函数调用执行过程剖析)

函数栈帧,(函数调用执行过程剖析)

weixin_65743593的博客 1855

C语言函数调用栈帧过程图解

返回地址 | ← main中调用add后的下一条指令。| 返回地址 | ← 调用者的下一条指令地址。| 旧ebp值 | ← 保存调用者的栈基址。| 旧ebp值 | ← main的ebp。| 局部变量 | ← 当前函数的局部变量。| 参数n || 旧ebp值 || 旧ebp值 || main的栈帧 |

liuxupaopao的博客 542
上一篇: 编程实现英语句子按单词倒叙-C语言
下一篇: main函数的参数
Ruichen_L
博客等级 码龄9年 5粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值