【函数栈帧解析:代码的迷人堆积和无限嵌套】

本章重点

一、何为函数栈帧

二、函数栈帧特性 - 同栈 - 后进先出

三、认识内存空间布局图

四、认识相关寄存器

五、认识相关汇编命令

六、测试代码:

七、函数栈帧全过程

要解决的问题​​​​​​​

  • 局部变量是怎么创建的?
  • 为什么局部变量的值是随机值?
  • 函数是怎么传参的?传参的顺序是怎么样的?
  • 形参和实参是什么关系?
  • 函数调用是怎么做的?
  • 函数调用结束后怎么返回的?

一、何为函数栈帧

        函数栈帧(Function Stack Frame),也被称为调用栈帧(Call Stack Frame),是在计算机程序中用于管理函数调用和执行的一种数据结构。每当函数被调用时,都会创建一个新的函数栈帧,用于存储该函数的局部变量、参数、返回地址和其他执行相关的信息。当函数执行完毕或返回时,相应的函数栈帧将被销毁,控制权回到上一个函数的栈帧中。

二、函数栈帧特性 - 同栈 - 后进先出

        函数栈帧的管理遵循一种后进先出(Last-In, First-Out,LIFO)的原则。这意味着最后调用的函数的栈帧会首先被执行,然后在函数返回时销毁,程序控制权回到上一个函数的栈帧中,以此类推,直到回到主程序的栈帧,整个程序执行完毕。

三、认识内存空间布局图

  1. 栈(Stack)

    • 栈是一种线性数据结构,用于存储函数调用时的局部变量、函数参数以及函数调用的返回地址。
    • 栈内存是有限的,以栈帧的方式分配和释放,遵循后进先出(Last-In, First-Out,LIFO)原则。
    • 栈内存的生命周期与函数调用关联,当函数返回时,其栈帧上的数据会被销毁。
  2. 堆(Heap)

    • 堆是一块较大的、动态分配的内存区域,用于存储程序运行时动态分配的数据,如动态分配的对象和数组。
    • 堆内存的生命周期不受函数调用的影响,需要手动分配和释放,否则可能导致内存泄漏。
    • 在C中,通常使用malloc()calloc()realloc()等函数来分配堆内存,使用free()来释放堆内存。
  3. 全局变量区(Global Variables)

    • 全局变量区存储程序中的全局变量,这些变量在整个程序的生命周期内都可访问。
    • 全局变量在程序启动时被分配,在程序结束时被释放。
  4. 常量区(Constants)

    • 常量区存储常量数据,如字符串文字和全局常量。
    • 这些数据在程序运行期间是只读的。
  5. 代码区(Code)

    • 代码区存储程序的二进制代码,包括所有函数的机器代码。
    • 代码区通常是只读的,不允许修改程序代码。

四、认识相关寄存器

注:ebp和esp主要用于维护当前存在的这个函数栈帧。

问:函数是被调用的,那main函数呢???它是谁调用的???

        在VS2013,main函数也是被其他函数调用的,该函数是_tmainCRTStartup,而该函数又是mainCRTStartup函数调用的,而mainCRTStartup函数则是由操作系统调用的。所以从编程者的角度来看,main函数似乎是程序的入口点,但实际上,在特定的编程环境中,它是由启动代码调用的。这些启动代码负责设置程序环境并确保main函数能够正确执行。

五、认识相关汇编命令

  • mov:数据转移指令
  • push:数据入栈,同时esp栈顶寄存器也要发生改变
  • pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
  • sub:减法命令
  • add:加法命令
  • call:函数调用,1. 压入返回地址 2. 转入目标函数
  • jump:通过修改eip,转入目标函数,进行调用
  • ret:恢复返回地址,压入eip,类似pop eip命令
  • lea:将表达式addr的值放入寄存器

六、测试代码:

#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 c = 0;c = Add(a, b);printf("%d\n", c);return 0;
}

七、函数栈帧全过程

1.ebp寄存器push压栈,同时esp栈顶寄存器地址值改变 - 变小

2.ebp寄存器数据转移到esp寄存器

3.0E4h的十进制是288,sub减法指令,此时开始创建main函数栈帧,main函数此时空间大小就是ebp寄存器-esp寄存器的差 = 0E4h

4.ebx寄存器,esi寄存器和edi寄存器push压栈,同时esp栈顶寄存器地址值改变 - 变小

5. 将表达式ebp-24h的值放入edi寄存器

6.word一个字两个字节,dword表示双字四个字节,刚好表示一个整型变量的大小。move将表达式9移入到ecx寄存器中,代表重复的次数,move将表达式CCCCCCCCh移入eax寄存器中,代表数值。rep stos就是重复执行stos指令,stos指令将eax中的值拷贝到ES:EDI指向的地址,所以这串指令就是在main函数中找到9个连续的4字节空间,将其值设置为CCCCCCCCh。

7.局部变量a,b,c开始创建,并进行初始化

8.函数传参过程,传参过程仍然是在main函数,且传参的过程是从右到左,先传y,后传x。

9.call函数调用,1. 压入返回地址 00682297,方便函数调用后返回到main函数栈帧,2. 转入目标Add函数

10.Add函数栈帧形成,这个过程同mian函数栈帧形成的过程相同,唯一的区别是在Add函数中找到3个连续的4字节空间,将其值设置为CCCCCCCCh。

11.变量z创建,并被初始化为0.

12.将地址为ebp+8放到eax寄存器中,然后在将ebp+14h的值与eax寄存器之前存放的值相加放到eax寄存器中,再将eax寄存器的值放到ebp-8处,也就是z变量地址处。

13.将运算的结果放到寄存器中,由于变量z是局部变量,出了函数作用域就会被销毁,为了能顺利带回返回值,利用寄存器不会被销毁的特点,将运算的结果放到eax寄存器。

14.pop数据弹出至指定位置,同时esp栈顶寄存器也要发生改变,Add函数栈帧被释放。

15.ret是恢复返回地址,找到call指令压入的地址,返回到main函数栈帧。

16.局部变量被销毁,变量c接收返回值

17.后面就是main函数的栈帧销毁过程,同Add函数相同

要解决的问题​​​​​​​

  • 局部变量是怎么创建的?

        在栈帧中,会分配一块内存空间来存储函数的局部变量。这些局部变量是在函数内部定义的,只在函数的生命周期内可见。编译器会根据函数的局部变量声明来确定需要分配多少内存空间。

  • 为什么局部变量的值是随机值?

        局部变量的值可能会被认为是随机的主要是因为在栈帧创建过程中,这些变量并没有经过显式的初始化。当函数栈帧被分配内存并为局部变量分配空间时,这些变量的内容实际上是未定义的,vs编译器会自动为其初始化为0xcccccc。

  • 函数是怎么传参的?传参的顺序是怎么样的?

函数传参的过程,形参的实例化并不在新的函数栈帧内,而是在调用一方函数栈帧内实例化的,当该函数要使用该形参的时候,是通过地址的方法去寻找该形参变量,传参的顺序是从右到左。

  • 形参和实参是什么关系?

        当调用一个函数时,实参的值被传递给函数的形参。这发生在函数的栈帧创建阶段。形参在函数内部被视为局部变量,并且其值被初始化为相应的实参值。但是实参的地址和形参的地址是不同的,所以形参只是实参的一份临时拷贝,修改形参是不能改变实参的。

  • 函数调用是怎么做的?

        函数栈帧通过call指令先1. 压入返回地址 ,也就是调用完函数后要执行的下一条指令,然后call通过jump转入目标函数,待函数使用完,ret指令会找到call指令压入的地址值,通过这个值返回到main函数的栈帧,即调用完函数要执行的下一条指令。

  • 函数调用结束后怎么返回的?

        利用寄存器的值不会随着函数栈帧被销毁而被销毁的特点,利用寄存器将值返回。

​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/60640.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

韶音骨传导耳机好不好,韶音骨传导耳机值得入手吗

韶音耳机的质量还是很不错的&#xff0c;其实力相比于百元价位的耳机而言领先了不少&#xff0c;具备多种功能&#xff0c;佩戴起来也是有着舒适性。它自主研发了骨传导音频技术&#xff0c;不过在今年开始&#xff0c;似乎已经将方向开始往运动偏移。 而在韶音的骨传导耳机中&…

git clone 报SSL证书问题

git命令下运行 git config --global http.sslVerify false 然后再进行重新clone代码

设计模式备忘录+命令模式实现Word撤销恢复操作

文章目录 前言思路代码实现uml类图总结 前言 最近学习设计模式行为型的模式&#xff0c;学到了备忘录模式提到这个模式可以记录一个对象的状态属性值&#xff0c;用于下次复用&#xff0c;于是便想到了我们在Windows系统上使用的撤销操作&#xff0c;于是便想着使用这个模式进…

day28 异常

to{}catch{} try{}catch{}的流传输 try {fis new FileInputStream("file-APP\\fos.txt");fos new FileOutputStream("fos.txt");int a ;while ((a fis.read())! -1){fos.write(a);}System.out.println(a); } catch (IOException e) {e.printStackTrace()…

24.排序,插入排序,交换排序

目录 一. 插入排序 &#xff08;1&#xff09;直接插入排序 &#xff08;2&#xff09;折半插入排序 &#xff08;3&#xff09;希尔排序 二. 交换排序 &#xff08;1&#xff09;冒泡排序 &#xff08;2&#xff09;快速排序 排序&#xff1a;将一组杂乱无章的数据按一…

高可用集群介绍

一、高可用集群概念 高可用集群&#xff08; High Availability Cluster, HA 集群&#xff09;&#xff0c;其中高可用的含义是最大限度地可以使用。从集群 的名字上可以看出&#xff0c;此类集群实现的功能是保障用户的应用程序持久、不间断地提供服务。当应用程序出现故障或…

【笔记】PyCharm快捷键大全

PyCharm是一种Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;由JetBrains公司开发。它被认为是Python开发中最强大、最流行的IDE之一。PyCharm具有完整的Python开发工具链&#xff0c;包括先进的代码编辑器、代码分析工具、集成的调试器、版本控制系统集成、自动化…

前端将UTC时间格式转化为本地时间格式-uniapp写法

UTC时间格式是什么 首先我们先简单的了解一下&#xff1a;UTC时间&#xff08;协调世界时&#xff0c;Coordinated Universal Time&#xff09;使用24小时制&#xff0c;以小时、分钟、秒和毫秒来表示时间 HH:mm:ss.SSSHH 表示小时&#xff0c;取值范围为00到23。mm 表示分钟…

Python股票交易---均值回归

免责声明&#xff1a;本文提供的信息仅用于教育目的&#xff0c;不应被视为专业投资建议。在做出投资决策时进行自己的研究并谨慎行事非常重要。投资涉及风险&#xff0c;您做出的任何投资决定完全由您自己负责。 在本文中&#xff0c;您将了解什么是均值回归交易算法&#xff…

ChatGPT癌症治疗“困难重重”,真假混讲难辨真假,准确有待提高

近年来&#xff0c;人工智能在医疗领域的应用逐渐增多&#xff0c;其中自然语言处理模型如ChatGPT在提供医疗建议和信息方面引起了广泛关注。然而&#xff0c;最新的研究表明&#xff0c;尽管ChatGPT在许多领域取得了成功&#xff0c;但它在癌症治疗方案上的准确性仍有待提高。…

leetcode 392. 判断子序列

2023.8.25 本题要判断子序列&#xff0c;可以使用动态规划来做&#xff0c;定义一个二维dp数组。 接下来就是常规的动态规划求解子序列的过程。 给出两种定义dp数组的方法。 二维bool型dp数组&#xff1a; class Solution { public:bool isSubsequence(string s, string t) …

在云原生环境中构建可扩展的大数据平台:方法和策略

文章目录 1. **选择适当的云提供商&#xff1a;**2. **采用容器化和微服务架构&#xff1a;**3. **分层架构设计&#xff1a;**4. **弹性计算资源&#xff1a;**5. **使用分布式计算框架&#xff1a;**6. **数据分区和分片&#xff1a;**7. **使用列式存储&#xff1a;**8. **缓…

qt day 1

this->setWindowIcon(QIcon("D:\\zhuomian\\wodepeizhenshi.png"));//設置窗口的iconthis->setWindowTitle("鵬哥快聊");//更改名字this->setFixedSize(500,400);//設置尺寸QLabel *qlnew QLabel(this);//創建一個標簽ql->resize(QSize(500,20…

【计算机视觉|生成对抗】用于高保真自然图像合成的大规模GAN训练用于高保真自然图像合成的大规模GAN训练(BigGAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Large Scale GAN Training for High Fidelity Natural Image Synthesis 链接&#xff1a;[1809.11096] Large Scale GAN Training for High Fidelity Natural Image Synthesis (arxiv.org…

Rabbitmq消息积压问题如何解决以及如何进行限流

一、增加处理能力 优化系统架构、增加服务器资源、采用负载均衡等手段&#xff0c;以提高系统的处理能力和并发处理能力。通过增加服务器数量或者优化代码&#xff0c;确保系统能够及时处理所有的消息。 二、异步处理 将消息的处理过程设计为异步执行&#xff0c;即接收到消息…

基于机器学习的fNIRS信号质量控制方法

摘要 尽管功能性近红外光谱(fNIRS)在神经系统研究中的应用越来越广泛&#xff0c;但fNIRS信号处理仍未标准化&#xff0c;并且受到经验和手动操作的高度影响。在任何信号处理过程的开始阶段&#xff0c;信号质量控制(SQC)对于防止错误和不可靠结果至关重要。在fNIRS分析中&…

FreeSWITCH 1.10.10 简单图形化界面5 - 使用百度TTS

FreeSWITCH 1.10.10 简单图形化界面5 - 使用百度TTS 0、 界面预览1、注册百度AI开放平台&#xff0c;开通语音识别服务2、获取AppID/API Key/Secret Key3、 安装百度语音合成sdk4、合成代码5、在PBX中使用百度TTS6、音乐文件-TTS7、拨号规则-tts_command 0、 界面预览 http://…

网络有源号角(50W-100W)社区小区广播 工地语音播报,隧道广播,钢铁广播广播系统

网络有源号角&#xff08;50W-100W&#xff09;社区小区广播 工地语音播报&#xff0c;隧道广播&#xff0c;钢铁广播广播系统 SV-7042T 50W网络有源号角 SV-7042T是深圳锐科达电子有限公司的一款壁挂式网络有源号角&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音…

ceph源码阅读 erasure-code

1、ceph纠删码 纠删码(Erasure Code)是比较流行的数据冗余的存储方法&#xff0c;将原始数据分成k个数据块(data chunk)&#xff0c;通过k个数据块计算出m个校验块(coding chunk)。把nkm个数据块保存在不同的节点&#xff0c;通过n中的任意k个块还原出原始数据。EC包含编码和解…

解密Spring MVC异常处理:从局部到全局,打造稳固系统的关键步骤

&#x1f600;前言 在现代软件开发中&#xff0c;异常处理是不可或缺的一部分&#xff0c;它能够有效地提高系统的稳定性和健壮性。在Spring MVC框架中&#xff0c;异常处理机制起着至关重要的作用&#xff0c;它允许开发者在程序运行过程中捕获、处理和报告异常&#xff0c;从…