从汇编的角度去审视函数的调用【函数栈帧】

news2024/12/30 3:48:14

文章目录

  • 函数栈帧
  • 寄存器
  • 相关汇编指令
  • 函数栈帧的创建
  • 函数栈帧的销毁

在这里插入图片描述

函数栈帧

我们在写C语言代码的时候,经常会把一个独立的功能抽象为函数,所以C程序是以函数为基本单位的。
那函数是如何调用的?函数的返回值又是如何待会的?函数参数是如何传递的?这些问题都和函数栈帧有关系。

函数栈帧就是函数调用过程中在程序的调用栈所开辟的空间,这些空间是用来存放:

  • 函数参数和函数返回值
  • 临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)
  • 保存上下文信息(包括在函数调用前后需要保持不变的寄存器)

栈(stack)是现代计算机程序里最为重要的概念之一,几乎每一个程序都使用了栈,没有栈就没有函数,没有局部变量,也就没有我们如今看到的所有的计算机语言。

栈被定义为一种特殊的容器,用户可以将数据压入栈中(入栈,push),也可以将已经压入栈中的数据弹出(出栈,pop),但是栈这个容器必须遵守一条规则:先入栈的数据后出栈(First In Last Out, FIFO)。

在计算机系统中,栈则是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增大,而弹出操作使得栈减小。

在经典的操作系统中,栈总是向下增长(由高地址向低地址)的。
在我们常见的i386或者x86-64下,栈顶由成为 esp 的寄存器进行定位的

寄存器

  • eax:通用寄存器,保留临时数据,常用于返回值
  • ebx:通用寄存器,保留临时数据
  • ebp:栈底寄存器
  • esp:栈顶寄存器
  • eip:指令寄存器,保存当前指令的下一条指令的地址

相关汇编指令

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

每一次函数调用,都要为本次函数调用开辟空间,就是函数栈帧的空间

这块空间的维护是使用了2个寄存器: esp 和 ebp , ebp 记录的是栈底的地址, esp 记录的是栈顶的地址

函数栈帧的创建和销毁过程,在不同的编译器上实现的方法大同小异,本次演示以VS2019为例

以下代码作分析:

#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 函数之前的函数调用我们就暂时不考虑了

右击鼠标,转到反汇编
在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


从内存中可以清楚地观察,ebp被压入栈中

move指令会把esp的值存放到ebp中,相当于产生了main函数的ebp,这个值就是invoke_main函数栈帧的esp


在这里插入图片描述

在这里插入图片描述

move指令会把esp的值存放到ebp中,相当于产生了main函数的ebp,这个值就是invoke_main函数栈帧的esp


在这里插入图片描述


在这里插入图片描述

esp 减去0E4h(228) ,为main函数开辟一块空间

sub会让esp中的地址减去一个16进制数字0xe4,产生新的esp

此时的esp是main函数栈帧的esp,此时结合上一条指令的ebp和当前的esp,ebp和esp之间维护了一个块栈空间,这块栈空间就是为main函数开辟的,就是main函数的栈帧空间

这一段空间中将存储main函数中的局部变量,临时数据已经调试信息等。

在这里插入图片描述

在这里插入图片描述

将寄存器ebx的值压栈
将寄存器esi的值压栈
将寄存器edi的值压栈
面3条指令保存了3个寄存器的值在栈区,这3个寄存器的在函数随后执行中可能会被修改,所以先保存寄存器原来的值,以便在退出函数时恢复


在这里插入图片描述

在这里插入图片描述

lea 就是 load effective address,加载有效地址
最后4句,等价于下面的伪代码

edi = ebp-0x24;
ecx = 9;
eax = 0xCCCCCCCC;
for(; ecx = 0; --ecx,edi+=4)
{
  *(int*)edi = eax;
}

接下来我们再分析main函数中的核心代码:
在这里插入图片描述

在这里插入图片描述

将3存储到ebp-8的地址处,ebp-8的位置其实就是a变量
如果不初始化a 变量 , 就会出现“烫”这么一个奇怪的字

是因为main函数调用时,在栈区开辟的空间的其中每一个字节都被初始化为0xCC

而arr数组是一个未初始化的数组,恰好在这块空间上创建的,0xCCCC(两个连续排列的0xCC)的汉字编码就是“烫”,所以0xCCCC被当作文本就是“烫”

在这里插入图片描述

在这里插入图片描述

将5存储到ebp-14h的地址处,ebp-14h的位置其实是b变量

在这里插入图片描述

在这里插入图片描述

将0存储到ebp-20h的地址处,ebp-20h的位置其实是ret变量

以上汇编代码表示的变量a,b,ret的创建和初始化,这就是局部的变量的创建和初始化其实是局部变量的创建时在局部变量所在函数的栈帧空间中创建的

在这里插入图片描述

在这里插入图片描述

传递b,将ebp-14h处放的5放在eax寄存器

在这里插入图片描述

将eax的值压栈

在这里插入图片描述

在这里插入图片描述

传递a,将ebp-8处放的3放在ecx寄存器中

在这里插入图片描述

将ecx的值压栈

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

将main函数栈帧的ebp保存
在这里插入图片描述

在这里插入图片描述

将main函数的esp赋值给新的ebp,ebp现在是Add函数的ebp

在这里插入图片描述

在这里插入图片描述

给esp-0xCC,求出Add函数的esp

在这里插入图片描述

在这里插入图片描述

将ebx的值压栈
将esi的值压栈
将edi的值压栈

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

将0放在ebp-8的地址处,其实就是创建z
接下来计算的是x+y,结果保存到z中

在这里插入图片描述

在这里插入图片描述

将ebp+8地址处的数字存储到eax中

将ebp+12地址处的数字加到eax寄存中

将eax的结果保存到ebp-8的地址处,其实就是放到z中

图片中的 a’ 和 b’ 其实就是 Add 函数的形参 x , y 。这里的分析很好的说明了函数的传参过程,以及函数在进行值传递调用的时候,形参其实是实参的一份拷贝。对形参的修改不会影响实参

在这里插入图片描述

将ebp-8地址处的值放在eax中,其实就是把z的值存储到eax寄存器中,这里是想通过eax寄存器带回计算的结果,做函数的返回值

函数栈帧的销毁

在这里插入图片描述

在这里插入图片描述

在栈顶弹出一个值,存放到edi中
在栈顶弹出一个值,存放到esi中
在栈顶弹出一个值,存放到ebx中

在这里插入图片描述
在这里插入图片描述

再将Add函数的ebp的值赋值给esp,相当于回收了Add函数的栈帧空间

在这里插入图片描述

在这里插入图片描述

弹出栈顶的值存放到ebp,栈顶此时的值恰好就是main函数的ebp,esp+4,此时恢复了main函数的栈帧维护,esp指向main函数栈帧的栈顶,ebp指向了main函数栈帧的栈底

在这里插入图片描述

在这里插入图片描述

ret指令的执行,首先是从栈顶弹出一个值,此时栈顶的值就是call指令下一条指令的地址,此时esp+4,然后直接跳转到call指令下一条指令的地址处,继续往下执行

在这里插入图片描述

在这里插入图片描述

esp直接+8,相当于跳过了main函数中压栈的a’和b’

在这里插入图片描述

在这里插入图片描述

将eax中的值,存档到ebp-0x20的地址处,其实就是存储到main函数中ret变量中,而此时eax中就是Add函数中计算的x和y的和,可以看出来,本次函数的返回值是由eax寄存器带回来的。程序是在函数调用返回之后,在eax中去读取返回值的

其实返回对象时内置类型时,一般都是通过寄存器来带回返回值的
返回对象如果时较大的对象时,
一般会在主调函数的栈帧中开辟一块空间,然后把这块空间的地址,隐式传递给被调函数,在被调函数中通过地址找到主调函数中预留的空间,将返回值直接保存到主调函数的

在这里插入图片描述

如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注
你们的每一次支持都将转化为我前进的动力!!!

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

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

相关文章

17种编程语言实现排序算法-冒泡排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、前…

离散数学-集合论-函数(10)

函数 1 函数的概念 1.1 函数的定义 设&#x1d453;是非空集A到B的关系, 如果对每个&#x1d465;∈A, 都存在唯一的&#x1d466;∈B, 使得<&#x1d465;, &#x1d466;>∈&#x1d453;, 则称关系&#x1d453;为A到B的函数(Function), 也可称为映射(Mapping)或变…

PID优化系列之给定值斜坡函数(PLC代码+Simulink仿真测试)

很多变频器里的工艺PID,都有"PID给定值变化时间"这个参数,这里的给定值变化时间我们可以利用斜坡函数实现,当然也可以利用PT1 低通滤波器对给定值进行平滑。给定值缓慢变化在很多闭环控制系统里很重要,比如收放卷在初始建张阶段目标值不建议突变容易将卷材拉断(…

聊聊外包团队的高效管理机制

这是鼎叔的第四十七篇原创文章。行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。欢迎关注本人专栏和微信公众号《敏捷测试转型》&#xff0c;大量原创思考文章陆续推出。对于大规模的外包团队&#xff0c;需要一个易用的外包管理OA系统&#xff0c;才能提高日常交付效率。…

LINUX学习之时间日期类命令(五)

date命令 命令描述 date命令用于在Linux系统中显示或设置当前系统时间。它可以显示当前日期和时间&#xff0c;并允许用户格式化输出。它还可以用于将系统时间设置为指定的日期和时间。使用格式化字符串&#xff0c;可以自定义输出格式 以下是data命令的常用参数&#xff1a…

【Simulink】使用Model Explorer设置模块变量初值

问题背景 最近在学习滑模控制&#xff0c;看到b站上的视频和文章&#xff0c;打算自己照着做一遍&#xff1a; 1、滑模控制的基本原理实际仿真中却遇到了一个小问题&#xff0c;不知道怎么设置变量x1的初值&#xff08;不能用pulse generator给初始脉冲&#xff09; 这里的x1是…

【JavaEE】单例模式(饿汉懒汉)

目录 前言&#xff1a; 单线程下的单例模式 饿汉模式 懒汉模式 多线程下的单例模式 懒汉模式的修改 1.加锁 2.有条件的加锁 3.解决内存可见性和指令重排序 前言&#xff1a; 本片文章介绍设计模式中的一个模式——单例模式。 单例模式就是只允许创建出一个实例的类。…

离散数学-图论-树(13)

树 1 无向树及其性质 定义1&#xff1a;连通无回路的无向图称为无向树,简称树.每个连通分支都是树的无向图称为森林.平凡图称为平凡树.在无向树中,悬挂顶点称为树叶,度数大于或等于2的顶点称为分支点. 定义2 设G<V,E>是n阶m条边的无向图&#xff0c;则下面各命题是等价…

c语言attribute关键字参数(详细)总结附示例快速掌握

目录一、简介二、参数详解2.1 section&#xff1a;自定义段2.2 aligned&#xff1a;对齐2.3 packed&#xff1a;对齐2.4 format&#xff1a;检查函数变参格式2.5 used2.6 unused2.7 at 绝对定位2.8 constructor2.9 destructor2.10 weak&#xff1a;弱声明2.11 alias&#xff1a…

macOS spotlight 聚焦 搜索范围自定义

文章目录Intro禁用不需要的查找范围&#xff0c;减少 spotlight 工作量/资源损耗搜索结果中的每个分类各自代表什么&#xff1f;Intro MBA升级系统之后&#xff0c;第一次充满电用了12h&#xff0c;之后的使用过程中掉电也很快。 新版本信息&#xff1a;macOS Ventura 13.1 (2…

I.MX6ULL裸机开发笔记1:启动方式

目录 启动模式设置步骤 1、三大模式 2.选择内部介质 3.选择接口编号 4.介质属性 原理图 芯片手册截图 开机相关全部引脚 启动设置表 启动模式设置步骤 1、三大模式 熔丝模式&#xff1a;烧录一次&#xff0c;发布产品外部模式&#xff1a;USB、串口等内部&#xff1a…

Windows系统下利用Anaconda搭建MXNet框架

1、mxnet MXNet 是一个深度学习库&#xff0c;类似于Theano 和 TensorFlow。最近想搞下深度学习&#xff0c;于是便安装mxnet。之前安装过TensorFlow&#xff0c;也踩了很多坑&#xff0c;可谓是历经波折。有的时候&#xff0c;配置环境真的是一门玄学。 2、关于网上的一些教…

手把手教你学习单片机-硬件基础知识

去耦电容的应用 C16 和 C19 起到的作 用是一样的,C10 的作用和他们两个不一样。 容值比较大的电容,理论上可以理解成水缸或者水池子,同时,大家可以直接把电流理 解成水流。 作用一,缓冲作用。当上电的瞬间,电流从电源处流下来的时候,不稳定,容易冲击电 子器件,加个…

基于云的文档管理系统——随时随地办公

如果您正在建立现代数字业务&#xff0c;您需要灵活地移动和分配您的劳动力。 DocuWare 移动劳动力解决方案可帮助您构建新的生产力模式&#xff1a;随时随地、任何设备。 毫不费力地捕捉、即时访问、始终安全 DocuWare 文档管理和工作流程自动化意味着当前流程的业务信息。 访…

【shell教程】| 简介及基本使用案例

文章目录一、简介二、脚本1 格式2 执行方式3 变量自定义变量特殊变量4 运算符5 条件判断6 流程控制1 if判断2 case语句3 for循环4 while 循环七、read读取控制台输入八、函数1 basename2 dirname3 自定义函数九、正则表达式十、文本处理工具1 cut2 grep3 sed4 awk一、简介 常见…

在线支付系列【1】支付演变史

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录支付货币发展史物物交换实物货币纸质货币电子货币数字货币支付模式演变一方支付&#xff08;现金当面支付&#xff09;二方支付&#xff08;商家银行&#xff09;第三方支付&#xff08;商家、银…

【GD32F427开发板试用】工业级串口OTA实现----移植韦东山老师BootLoader项目

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;足球之路 一、综述 一款完善的工业产品往往需要支持在线更新程序的需求&#xff0c;业界最近火热的叫法叫做“OTA”。这篇文章记录我利用技术…

2001-2020年中国区域创新能力总、分指标效用值

中国区域创新能力总、分指标效用值2001-2020 1、时间&#xff1a;2001-2020年 2、范围&#xff1a;全国31个省份 3、来源&#xff1a;中国区域创新能力评价BG 4、指标包括&#xff1a; 区域创新能力综合效用值、知识创造效用值、知识获取效用值、企业创新效用值、创新环境…

《Composing Programs》(SICP python版) chap1 笔记(2)

《Composing Programs》(SICP python版) chap1 笔记(2) 文章目录《Composing Programs》(SICP python版) chap1 笔记(2)Chapter 1: Building Abstractions with Functions1.3 Defining New Functions1.3.1 EnvironmentsFunction Signatures&#xff08;看语境翻译为函数原型比较…

【论文翻译】ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation

【论文】https://arxiv.org/abs/2204.12484v3 【github】GitHub - ViTAE-Transformer/ViTPose: The official repo for [NeurIPS22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [Arxiv22] "ViTPose: Vision Transformer F…