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

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

一、什么是函数栈帧?

        函数栈帧(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 函数的时候,继续往下执行,可以看到:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NLP项目实战02:英文文本识别

简介&#xff1a; 欢迎来到本篇文章&#xff01;今天我们将讨论一个新的自然语言处理任务——英文短文识别。具体而言&#xff0c;即通过分析输入的英文文本来判断其是比较消极的还是比较积极的。 展示&#xff1a; 1、项目界面 如下所示是项目启动后用户使用使用界面 2、布…

Redis常用内存淘汰策略?

从淘汰范围来说可以分为不淘汰任何数据、只从设置了到期时间的键中淘汰和从所有键中淘汰三类。而从淘汰算法来分&#xff0c;又主要分为 random&#xff08;随机&#xff09;&#xff0c;LRU&#xff08;最近最少使用&#xff09;&#xff0c;以及 LFU&#xff08;最近最不常使…

终端安全管理软件安装详细攻略来了

随着信息技术的不断发展&#xff0c;终端安全管理软件在企业和组织中发挥着越来越重要的作用。为了确保终端设备的安全和稳定运行&#xff0c;安装终端安全管理软件是必不可少的。以下是一份终端安全管理软件的安装详细攻略&#xff0c;供大家参考。 一、选择合适的软件 首先&…

有哪些好用的运维管理软件?哪个工单管理系统的操作简单一些?

运维管理软件可以帮助企业更有效地管理公司内外的事务&#xff0c;比如现在不少公司就引入了工单管理系统来处理后勤和售后的事务。那么&#xff0c;有哪些好用的运维管理软件&#xff1f;哪个的操作简单一些呢&#xff1f;   随着技术的发展和成熟&#xff0c;现在的工单管理…

如何禁止服务器自动休眠

如何禁止服务器自动休眠 有时候服务器自己休眠&#xff0c;导致系统web站点无法访问&#xff0c;下面是解决办法&#xff01; 禁止服务器自动进入休眠状态的具体方法可能会因使用的Linux发行版而有所不同。以下是一些通用的方法&#xff0c;你可以根据你的系统选择适用的&#…

lv12 uboot移植深化 9

u-boot-2013.01移植 【实验目的】 了解u-boot 的代码结构及移植的基本方法 【实验环境】 ubuntu 14.04发行版FS4412实验平台交叉编译工具arm-none-linux-gnueabi- 【注意事项】 实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行 【实验步骤】 1 建立自己的平台 1.…

如何安装LUT预设?达芬奇/FCP/PR怎么安装LUT预设.cube格式文件的教程

在下载的LUT调色预设压缩文件包中&#xff0c;通常两个包含不同格式的LUT文件&#xff1a; .cube 和 .xmp 包含的 .cube 文件几乎与主流的视频编辑和色彩校正软件兼容&#xff0c;并且还可以在 Adobe Photoshop 等一些照片应用程序中使用。如果主要是将这些 LUT 用于视频剪辑项…

2 使用postman进行接口测试

上一篇&#xff1a;1 接口测试介绍-CSDN博客 拿到开发提供的接口文档后&#xff0c;结合需求文档开始做接口测试用例设计&#xff0c;下面用最常见也最简单的注册功能介绍整个流程。 说明&#xff1a;以演示接口测试流程为主&#xff0c;不对演示功能做详细的测试&#xff0c;…

MC-30A (32.768 kHz用于汽车应用的晶体单元)

MC-30A 32.768 kHz用于汽车应用的晶体&#xff0c;车规晶振中的热销型号之一。该款石英晶体谐振器&#xff0c;可以在-40 to 85 C的温度内稳定工作&#xff0c;能满足起动振动的要求。同时满足AEC-Q200无源元件质量标准认证&#xff0c;满足汽车仪表系统的所有要求。 频率范围…

利用腾讯微搭平台连接MYSQL

首先&#xff0c;找到控制台 然后再控制台搜索&#xff1a;微搭 然后点击进入&#xff1a; 这里如果是第一次进入&#xff0c;他应该会提示要创建环境。 然后按照这个步骤&#xff1a; 然后进入这个页面&#xff0c;点击编辑器&#xff1a; 然后在这里搜索表格&#xff1a; 点…

基于springboot乐器视频学习网站设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

Vue3-21-组件-子组件给父组件发送事件

情景描述 【子组件】中有一个按钮&#xff0c;点击按钮&#xff0c;触发一个事件&#xff0c; 我们希望这个事件的处理逻辑是&#xff0c;给【父组件】发送一条消息过去&#xff0c; 从而实现 【子组件】给【父组件】通信的效果。这个问题的解决就是 “发送事件” 这个操作。 …

玩转大数据18:大规模数据处理与分布式任务调度

引言 在数字化时代&#xff0c;数据成为了一种宝贵的资源&#xff0c;对于企业和组织来说&#xff0c;如何有效地处理和分析这些数据成为了关键的竞争力。大规模数据处理与分布式任务调度作为大数据处理的核心技术&#xff0c;为解决这一问题提供了有效的解决方案。 随着数据…

36个校招网络原理面试题

1.如何理解 URI&#xff1f; URI, 全称为(Uniform Resource Identifier), 也就是统一资源标识符&#xff0c;它的作用很简单&#xff0c;就是区分互联网上不同的资源。但是&#xff0c;它并不是我们常说的网址, 网址指的是URL, 实际上URI包含了URN和URL两个部分&#xff0c;由…

gitbash下载安装

参考教程 零、下载 官网地址 2.43.0win64 链接&#xff1a;https://pan.baidu.com/s/16urs_nmky7j20-qNzUTTkg 提取码&#xff1a;7jaq 一、安装 图标组件&#xff08;Additional icons&#xff09;&#xff1a;选择是否创建桌面快捷方式&#xff1b;桌面浏览&#xff08;Win…

【后端卷前端3】

侦听器 监听的数据是 data()中的动态数据~响应式数据 <template><div><p>{{showHello}}</p><button click"updateHello">修改数据</button></div> </template><script>export default {name: "goodsTe…

GraphicsProfiler 使用教程

GraphicsProfiler 使用教程 1.工具简介&#xff1a;2.Navigation介绍2.1.打开安装好的Graphics Profiler。2.2.将手机连接到计算机&#xff0c;软件会在手机中安装一个GraphicsProfiler应用(该应用是无界面的&#xff09;。2.3.Show files list2.4.Record new trace2.4.1.Appli…

【Redis】Redis.conf详解

Redis.conf详解 启动的时候&#xff0c;就通过配置文件来启动&#xff01; 工作中&#xff0c;一些小小的配置&#xff0c;可以让你脱颖而出&#xff01; 单位 配置文件 unit单位 对大小写不敏感&#xff01;include包含其他配置文件 就是好比我们学习Spring、Improt&#x…

计算机网络考研辨析(后续整理入笔记)

考完研补充题目图片进来。 方老师课程还有一些细节不够到位&#xff0c;不影响学习&#xff0c;但是初期如果想得多了&#xff0c;会有一些迷惑&#xff0c;后续要把这些补进去文章里&#xff0c;让文章更加好。 这里做出细化&#xff0c;尤其是针对数字&#xff0c;计算&…

YOLOv7原创改进:一种新颖的跨通道交互的高效率通道注意力EMCA,ECA注意力改进版

💡💡💡本文原创自研创新改进:基于ECA注意力,提出了一种新颖的EMCA注意力(跨通道交互的高效率通道注意力),保持高效轻量级的同时,提升多尺度提取能力 强烈推荐,适合直接使用,paper创新级别 💡💡💡 在多个数据集验证涨点,尤其对存在多个尺度的数据集涨点明…