函数栈帧的创建和销毁(编程底层原理)

news2024/11/16 16:01:56

        本篇的内容格外的难写,里面包含了许多的专业术语名和汇编指令等晦涩难懂的东西,既不利于讲解,也不利于读者的理解。但我会尽力去讲述出里面的底层逻辑,帮助大家去理解里面的过程,理解编程的底层原理可以为我们后续更为复杂的知识学习打下基础。

一、什么是函数栈帧?

        函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间是用来存放:1、函数参数和函数的返回值。2、临时变量(包括函数非静态的局部变量以及编译器自动产生的其他临时变量)。3、保存上下文信息(包括在函数调用前后需要保持不变的寄存器)。

二、函数栈帧的创建和销毁

        1、什么是栈?

                栈(stack)是现代计算机程序里最为重要的概念之一,几乎每一个程序都要使用栈,函数因栈而生,栈是函数存在的根基。在经典的计算机科学中,栈被定义为一种特殊的容器,用户可以将数据压入栈中(入栈,汇编指令为push),也可以将已经压入栈中的数据弹出(出栈,汇编指令为pop),这里存在一个顺序问题:先入栈的数据后出栈(First In Last Out)。就像堆书一样,先堆上去的书在最后才能取下来,因为它被堆在了最下面。

        实际上,栈在计算机系统中是一个动态内存区域,程序可以将数据压入栈中,也可以将数据从栈顶弹出,压栈操作是栈增大,而弹出操作时栈减小,栈总是向下增长(由高地址向低地址)的。在我们常见的i386或者x86-64下,栈顶由成为 esp 的寄存器进行定位的。

        2、相关的寄存器及汇编指令

相关寄存器

eax:通用寄存器,保留临时数据,常用于返回值。

ebx:通用寄存器,保留临时数据。

ebp:栈底寄存器。

esp:栈顶寄存器。

eip:指令寄存器,保存当前指令的下一条指令的地址。

相关汇编指令

mov:数据转移指令,实际上就是赋值/存放。

push:数据入栈。就是压栈操作,同时esp栈顶的寄存器的位置改变。

pop:数据弹出至指定位置。就是出栈操作,同时esp栈顶寄存器的位置改变。

sub:减法命令。

add:加法命令。

call:函数调用。1、压入返回地址。2、转入目标函数。

jump:通过修改eip,转入目标函数,进行调用。

ret:回复返回地址,压入eip,类似pop eip命令。

        3、解析过程

        在每次调用函数时,都要为本次函数的调用开辟空间,即函数栈帧创建的空间。这块空间的维护是由esp和ebp两个寄存器进行的,ebp记录的是栈底的地址,esp记录的是栈顶的地址。

        因讲解目的是理解代码编译的底层逻辑,本次使用的代码使比较简单的Add加法函数,如下:

#include <stdio.h>
int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int main()
{
    int a = 3;
    int b = 5;
    int ret = 0;
    ret = Add(a, b);
    printf("%d\n", ret);
    return 0;
}
         调用堆栈是反馈函数调用逻辑的,那我们可以清晰的观察到,main 函数调用之前,是由 invoke_main 函数来调用 main函数。 那我们就可以确定, invoke_main 函数应该会有自己的栈帧, main 函数和 Add 函数也会维护自己的栈 帧,每个函数栈帧都有自己的 ebp esp 来维护栈帧空间。接下来我们从 main 函数的栈帧创建开始讲解:
        开始之前我们要先进行一个操作, 为了让我们研究函数栈帧的过程足够清晰,不要太多干扰,我们可以关闭下面的选项,让汇编代码中排 除一些编译器附加的代码:

然后转到反汇编: 

        调试到main 函数开始执行的第一行,右击鼠标转到反汇编。
注: VS编译器每次调试都会为程序重新分配内存,截图中的反汇编代码是一次调试代码过程中数据,每次调试略有差异。
函数栈帧的创建
        接下来我们就一行行拆解汇编代码:

 这里插入一个小知识:

        之所以上面的程序输出“ 这么一个奇怪的字,是因为 main函数调用时,在栈区开辟的空间的其中每一个字节都被初始化为 0xCC ,而 arr 数组是一个未初始化的数组,恰好在这块空间上创建的, 0xCCCC(两个连续排列的 0xCC )的汉字编码就是 ,所以 0xCCCC 被当作文本就是

        我们继续, 接下来我们再分析main函数中的核心代码:

Add函数的传参

函数调用过程

        call 指令是要执行函数调用逻辑的,在执行 call 指令之前先会把 call指令的下一条指令的地址进行压栈操作,这个操作是为了解决当函数调用结束后要回到 call 指令的下一条指令的地方,继续往后执行。

接下来跳转到Add函数,开始观察Add函数的反汇编代码

        代码执行到Add 函数的时候,就要开始创建 Add函数的栈帧空间了。在 Add 函数中创建栈帧的方法和在 main 函数中是相似的,只在栈帧空间的大小上略有差异。
1. main 函数的 ebp 压栈。
2. 计算新的 ebp 和 esp。
3. ebx esi edi 寄存器的值保存。
4. 计算求和,在计算求和的时候,我们是通过 ebp 中的地址进行偏移访问到了函数调用前压栈进去的参数,这就是形参访问。
5. 将求出的和放在 eax 寄存器尊准备带回

函数栈帧的销毁

         当函数调用要结束返回的时候,前面创建的函数栈帧也开始销毁。让我们来看一下反汇编代码,去体会函数栈帧的销毁过程。

但调用完 Add 函数,回到 main 函数的时候,继续往下执行,可以看到:

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

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

相关文章

YOLOv8 | 代码逐行解析(一) | 项目目录构造分析

一、本文介绍 Hello&#xff0c;大家好这次给大家带来的不是改进&#xff0c;是整个YOLOv8项目的分析&#xff0c;整个系列大概会更新7-10篇左右的文章&#xff0c;从项目的目录到每一个功能代码的都会进行详细的讲解&#xff0c;同时YOLOv8改进系列也突破了三十篇文章&#x…

助力工业产品质检,基于yolov5l集成CBAM注意力机制开发构建智能PCB电路板质检分析系统

AI助力工业质检智能生产制造已经有很多成功的实践应用了&#xff0c;在我们前面的系列博文中也有很多对应的实践&#xff0c;感兴趣的话可以自行移步阅读前面的博文即可&#xff0c;这里本文的核心目的就是想要基于改进的yolov5l来开发构建用于PCB电路板智能检测分析的模型&…

GZ015 机器人系统集成应用技术样题1-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题1 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

【Trino权威指南(第二版)】Trino的架构、trino架构组件、 trino连接器架构的细节、trino的查询执行模型

文章目录 一. Trino架构1. 架构概览2. 协调器3. 发现服务4. 工作节点 二. 基于连接器的架构三. 查询执行模型1. 解析—>查询计划2. 查询计划 —> 分布式查询计划3. 运行阶段3.1. 基础概念切片&#xff1a;并行单元page 与 exchange算子pipeline切片的driverOperator 3.2.…

C#上位机与欧姆龙PLC的通信01----项目背景

最近&#xff0c;【西门庆】作为项目经理负责一个70万的北京项目&#xff0c;需要在工控系统集成软件开发中和欧 姆龙PLC对接&#xff0c;考虑项目现场情况优先想到了采用FinsTCP通讯协议&#xff0c;接下来就是记录如何一步步实现这些通讯过程的&#xff0c;希望给电气工程师&…

Netty常见的设计模式

简介 设计模式在软件开发中起着至关重要的作用&#xff0c;它们是解决常见问题的经过验证的解决方案。而Netty作为一个优秀的网络应用程序框架&#xff0c;同样也采用了许多设计模式来提供高性能和可扩展性。在本文中&#xff0c;我们将探讨Netty中使用的一些关键设计模式&…

探索Linux服务器配置信息的命令

目录 前言1 uname2 lscpu3 free4 df5 lspci6 lsusb7 lshw结语 前言 Linux系统提供了许多命令&#xff0c;用于获取和查看服务器的软硬件配置信息。这些命令可以帮助管理员和用户了解系统的状态、资源使用情况以及硬件设备的相关信息。以下是一些常用的命令以及它们的作用、使用…

【单调栈]LeetCode84: 柱状图中最大的矩形

作者推荐 【动态规划】【广度优先搜索】LeetCode:2617 网格图中最少访问的格子数 本文涉及的知识点 单调栈 题目 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形…

解决kernel32.dll丢失的修复方式,kernel32.dll预防错误的方法

kernel32.dll文件是电脑中的一个重要文件&#xff0c;如果电脑出现kernel32.dll丢失的错误提示&#xff0c;那么电脑中的一些程序将不能正常使用&#xff0c;那么出现这样的问题有什么解决办法呢&#xff1f;那么今天就和大家说说解决kernel32.dll丢失的修复方式。 一.kernel32…

elasticsearch|大数据|kibana的安装(https+密码)

前言&#xff1a; kibana是比较好安装的&#xff0c;但https密码就比较麻烦一些了&#xff0c;下面将就如何安装一个可在生产使用的kibana做一个简单的讲述 一&#xff0c; kibana版本和下载地址 这里我想还是强调一下&#xff0c;kibana的版本需要和elasticsearch的版本一…

数据库基础(实体,管理系统,日志,数据类型,键与约束)

基本概念 数据&#xff08;Data&#xff09;&#xff1a; 数据是描述事物的信息&#xff0c;可以是数字、文字、图像、音频等形式。数据库中存储的就是这些数据&#xff0c;这些数据可以是具体的实体&#xff08;如一个人的信息&#xff09;&#xff0c;也可以是抽象的概念&…

数据持久化与临时存储的对决:localStorage 与 sessionStorage(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Elasticsearch的 8.x常用api汇总

ES的查询语法比较复杂,对于初学者需要在不断练习中才会逐渐掌握,本文汇总了ES各种查询语法以及常用api,可以作为新手的实用笔记 首先,安装 Kibana! 下载Elasticsearch,官方下载页面;Elasticsearch 参考,官方文档;<

智能优化算法应用:基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.静电放电算法4.实验参数设定5.算法结果6.…

目标检测图片截取目标分类图片

如果要训练一个分类模型却没有特定的分类数据集怎么办呢&#xff1f;可以换一种思路&#xff0c;将带有该目标的图片对所有想要的目标进行画标注框然后进行截图&#xff0c;就能得到特定的分类数据了。这么做的目的是&#xff1a;带有该目标的图片可能不会少&#xff0c;但是带…

【系统设计】如何确保消息不会丢失?

一、前言 对于大部分业务系统来说&#xff0c;丢消息意味着数据丢失&#xff0c;是完全无法接受的。其实&#xff0c;现在主流的消息队列产品都提供了非常完善的消息可靠性保证机制&#xff0c;完全可以做到在消息传递过程中&#xff0c;即使发生网络中断或者硬件故障&#xf…

Initial用法-FPGA入门3

Initial是什么 FPGA Initial是一种在FPGA中进行初始化的方法。在FPGA设备上&#xff0c;初始值决定了逻辑门的状态和寄存器的初始值。FPGA Initial可以通过设置初始值来控制电路在上电后的初始状态。 Initial的作用 2.1&#xff0c;控制电路启动时的初始状态 通过设置FPGA Ini…

迅为RK3568开发板使用OpenCV处理图像-ROI区域-位置提取ROI

在图像处理过程中&#xff0c;我们可能会对图像的某一个特定区域感兴趣&#xff0c;该区域被称为感兴趣区域&#xff08;Region of Interest, ROI&#xff09;。在设定感兴趣区域 ROI 后&#xff0c;就可以对该区域进行整体操作。 位置提取 ROI 本小节代码在配套资料“iTOP-3…

KVM虚拟机console使用

注意这些设置都在你要进入虚拟机里设置&#xff0c;不是在你的物理机设置 首先debian12 需要设置 grep ttyS0 /etc/securetty #没有则加上 echo ttyS0 >> /etc/securetty #启动 systemctl start serial-gettyttyS0 systemctl enable serial-gettyttyS0#CentOS Stream …

MIT18.06线性代数 笔记3

文章目录 对称矩阵及正定性复数矩阵和快速傅里叶变换正定矩阵和最小值相似矩阵和若尔当形奇异值分解线性变换及对应矩阵基变换和图像压缩单元检测3复习左右逆和伪逆期末复习 对称矩阵及正定性 特征值是实数特征向量垂直>标准正交 谱定理&#xff0c;主轴定理 为什么对称矩…