函数栈帧(详解)

news2025/1/15 6:36:37

一、前言:

环境:X86+Vs2013

我们C语言学习过程中是否遇到过如下问题或者疑惑:

1、局部变量是如何创建的?

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

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

4、形参和实参是什么关系?

5、函数调用是怎么做的?

6、函数调用完后怎么返回的?

看完这篇关于函数栈帧的博客,我相信你对这些问题会有一些进一步的理解,希望能帮助你解决一些学习中的困惑。

二、预备知识了解

2.1、寄存器的种类和作用

eax累加寄存器,相对于其他寄存器,在运算方面比较常用。
ebx基地址寄存器,在内存寻址时存放基地址。
ecx计数寄存器,用于循环操作,比如重复的字符存储操作,或者数字统计。
edx作为EAX的溢出寄存器,总是被用来放整数除法产生的余数。
esi变址寄存器,主要用于存放存储单元在段内的偏移量。通常在内存操作指令中作为“源地址指针”使用
edi目的变址寄存器,主要用于存放存储单元在段内的偏移量。
eip控制寄存器,存储CPU下次所执行的指令地址(存放指令偏移地址)。
esp栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,esp也就越来越小。在32位平台上,esp每次减少4字节。栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。是CPU机制决定的,push、pop指令会自动调整esp的值。
ebp基址指针,指栈的栈底指针。基址指针寄存器(extended base pointer),一般与esp配合使用,可以存取某时刻的esp,这个时刻就是进入一个函数内后,CPU会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数,局部变量等。其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

2.2、汇编指令

1、push:在栈的顶端开辟地址并存放变量,然后减少esp的值,32位机器上esp每次减少4个字节,64位机器上esp每次减少8字节。

2、pop:在栈顶端去掉一个地址,然后增加esp的值,2位机器上esp每次增加4个字节,64位机器上esp每次增加8字节。

3、mov:用于将一个数据的源地址传送到目标地址,原操作地址不变。将esp值赋给ebp。

4、sub:从寄存器上减去<shifter_operand>表示的数值,并将结果保存到寄存器上。

5、lea(load effective address):将一个内存地址直接付给目标的操作数。

6、rep(repeat):引发字符串指令被重复使用。

7、stos(store string):将exc的值拷贝到es:[edi]指向的地址。

8、call:将程序下一条指令的位置的IP压入堆栈,并调用的子程序。

9、jmp:跳转指令。

10、add:将两个数相加,结果写入第一个数中。

11、ret:终止函数执行,当前栈帧所开辟的空间收回。

2.3、例子

为了能够看清楚全部细节,我们把函数写的尽量细一点。

#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;
}

汇编码

int main() {
002718A0  push        ebp  
002718A1  mov         ebp,esp  
002718A3  sub         esp,0E4h  
002718A9  push        ebx  
002718AA  push        esi  
002718AB  push        edi  
002718AC  lea         edi,[ebp-24h]  
002718AF  mov         ecx,9  
002718B4  mov         eax,0CCCCCCCCh  
002718B9  rep stos    dword ptr es:[edi]  
002718BB  mov         ecx,27C003h  
002718C0  call        0027131B  
	int a = 10;
002718C5  mov         dword ptr [ebp-8],0Ah  
	int b = 20;
002718CC  mov         dword ptr [ebp-14h],14h  
	int c = 0;
002718D3  mov         dword ptr [ebp-20h],0  
	c = Add(a, b);
002718DA  mov         eax,dword ptr [ebp-14h]  
002718DD  push        eax  
002718DE  mov         ecx,dword ptr [ebp-8]  
002718E1  push        ecx  
002718E2  call        002710B4  
002718E7  add         esp,8  
002718EA  mov         dword ptr [ebp-20h],eax  
	printf("%d", c);
002718ED  mov         eax,dword ptr [ebp-20h]  
002718F0  push        eax  
002718F1  push        277B30h  
002718F6  call        002710D2  
002718FB  add         esp,8  
	return 0;
002718FE  xor         eax,eax  
}
00271900  pop         edi  
00271901  pop         esi  
00271902  pop         ebx  
00271903  add         esp,0E4h  
00271909  cmp         ebp,esp  
0027190B  call        00271244  
00271910  mov         esp,ebp  
00271912  pop         ebp  
00271913  ret  

2.4、内存模型

在栈区创建函数栈帧

三、栈帧的创建

按下F10,在视图中打开调用堆栈窗口,我们发现main()函数被调用了。

那么main()函数被谁调用调用了呢?

当我们调试到 return 0 之后;再按F10,我们发现程序跳转到了调用main()函数的函数内,

原来main()函数是被__tmainCRTStartup函数调用的,而 __tmainCRTStartup又是被mainCRTStartup调用的。

3.1、为main函数开辟栈帧

 3.2、在main函数中创建变量

3.3、调用add函数前做准备

函数传参从右向左

 3.4、为add函数开辟栈帧

 3.5、Add()函数中创建变量并运算

形参是实参的一份临时拷贝

四、函数栈帧的销毁

4.1、Add()栈帧的销毁

过程一:pop    edi / esi / ebx

过程二:mov    esp, ebp 】

过程三:pop ebp】

过程四:ret】

过程五:mov     dword ptr [ebp-20h],eax】

4.2、返回main()函数栈帧

可以看到这里返回到了(3.3调用Add()函数前的准备),最后指令call的下一条指令。

之后的过程还很复杂,这里就不详细展示了。

五、总结:

对此我们对刚开始的问题是不是有了一点柳暗花明的感觉。

在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现。

友情提示:

不要使用太高级的编译器,越高级的编译器,越不容易学习和观察。

这篇博客有很多不足的地方,希望大家及时指出来!!!

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

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

相关文章

Python实现猎人猎物优化算法(HPO)优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的…

【Arduino25】液晶模拟值实验

硬件准备 LCD1602显示屏&#xff1a;1 个 220欧的电阻&#xff1a;1 个 旋钮电位器&#xff1a;1 个 面包板&#xff1a;1个 杜邦线&#xff1a;若干 硬件连线 软件程序 #include <LiquidCrystal.h>LiquidCrystal lcd(12,11,5,4,3,2);void setup(){lcd.begin(16,2);…

UNIX网络编程卷一 学习笔记 第三十一章 流

在大多数源自SVR 4的内核中&#xff0c;X/Open传输接口&#xff08;X/Open Transport Interface&#xff0c;XTI&#xff0c;是独立于套接字API的另一个网络编程API&#xff09;和网络协议通常就像终端IO系统那样也使用流系统&#xff08;STREAMS system&#xff09;实现。 我…

VS Code断点调式Cesium

1.在VS Code中安装Debugger for Firefox插件 2.下载安Firefox Developer Edition 3. 创建launch.json 编辑并保存launch.json {// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, vis…

ETCD详解

一、etcd概念 ETCD 是一个高可用的分布式键值key-value数据库&#xff0c;可用于服务发现。 ETCD 采用raft 一致性算法&#xff0c;基于 Go语言实现。 etcd作为一个高可用键值存储系统&#xff0c;天生就是为集群化而设计的。由于Raft算法在做决策时需要多数节点的投票&…

06 科技英语|控制与优化学科词汇

maneuver n 策略&#xff1b;v 操控、调遣 manipulate vt 熟练控制 scalability n 可扩展性 leverage n 杠杆&#xff1b;v 促使...改变 flexibility n 弹性 dispatch n 急件&#xff1b;v 调度&#xff1b;派遣 leverage …

[TQLCTF 2022]simple_bypass

文章目录 涉及知识点解题过程 涉及知识点 无数字字母RCE自增马构造文件包含读取源码 解题过程 打开题目&#xff0c;随便注册一个用户为admin 登陆进去后&#xff0c;一眼发现杰哥图片有线索 我们F12看一下如何请求的 在这里发现可能存在文件包含漏洞 我们尝试读取下源码 …

深度优先搜索(dfs)--矩阵部分-leetcode以及常见题

介绍 深度优先搜索&#xff08;Depth-First Search&#xff0c;DFS&#xff09;是一种常用的图搜索算法&#xff0c;它用于查找图或树数据结构中的路径或解决问题。下面是深度优先搜索的常见步骤以及一个示例问题&#xff1a; 深度优先搜索的常见步骤&#xff1a; 选择起始节…

1分钟了解音频、语音数据和自然语言处理的关系

机器学习在日常场景中的应用 音频、语音数据和自然语言处理这三者正在不断促进人工智能技术的发展&#xff0c;人机交互也逐渐渗透进生活的每个角落。在各行各业包括零售业、银行、食品配送服务商&#xff09;的多样互动中&#xff0c;我们都能通过与某种形式的AI&#xff08;…

Flutter中系统Emoji通过substring裁切后无法识别导致渲染错误

Flutter中系统Emoji通过substring裁切无法识别、渲染错误 场景分析/思考寻找神马东西引起的渲染错误为什么 substring 之后就无法显示了 结论分析 substring 场景 在发布文章的时候&#xff0c;有标题和内容&#xff0c;标题可为空&#xff0c;在没有标题的情况下&#xff0c;…

大数据之MapReduce

MapReduce概述 是一个分布式的编程框架&#xff0c;MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序&#xff0c;并发运行在一个Hadoop集群上。 优点&#xff1a; 易于编程&#xff0c;简单的实现一些接口&#xff0c;就可以完成一…

CentOS 7删除virbr0虚拟网卡

在CentOS 7的安装过程中如果有选择相关虚拟化的的服务安装系统后&#xff0c;启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡&#xff0c;这个是因为在虚拟化中有使用到libvirtd服务生成的&#xff0c;如果不需要可以关闭后去掉&#xff1a; 一、查看IP及网桥设备 [r…

Ajax介绍、爬取案例实战 + MongoDB存储

Ajax介绍 Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种用于在Web应用程序中实现异步通信的技术。它允许在不刷新整个网页的情况下&#xff0c;通过在后台与服务器进行数据交换&#xff0c;实时更新网页的一部分。Ajax的主要特点包括&#xff1a; 异步通…

前端框架 vue-admin-template的搭建运行

一介绍 1.1 下载地址 vue-element-admin是基于element-ui 的一套后台管理系统集成方案。 GitHub - PanJiaChen/vue-element-admin: :tada: A magical vue admin https://panjiachen.github.io/vue-element-admin 1.2 node.js的安装 地址下载node.js 1.6版本 CNPM Binari…

2023 IntelliJ IDEA下载、安装教程, 附详细图解

文章目录 下载与安装IDEA推荐阅读 下载与安装IDEA 首先先到官网下载最新版的IntelliJ IDEA, 下载后傻瓜式安装就好了 官网下载地址&#xff1a;https://www.jetbrains.com/ 1、下载完后在本地找到该文件&#xff0c;双击运行 idea 安装程序 2、点击 Next 3、选择安装路径&…

sqlmap --os-shell(写入木马获取getshell)

在存在sql注入处&#xff0c;可以使用--os-shell 对存在SQL注入处抓包&#xff0c;查看报错暴露出绝对路径 将POST包放入TXT文本中 启动sqlmap 读取TXT文件 python sqlmap.py -r C:\Users\南倾\Desktop\222.txt --os-shell 写入木马到文件中 echo "<?php eval($_R…

复旦-华盛顿EMBA:AI时代掘金,科技进化里的挑战与机遇

如果从去年年底ChatGPT3.5发布算起&#xff0c;AI赛道的热度已经持续飙升了半年有余。      “AI的iPhone时刻”代表什么&#xff1f;AI驱动的商业时代已经到来&#xff1f;      我们能看到担忧、恐惧、憧憬&#xff0c;但唯独不缺狂飙突进、加速进化。人类制造AI&…

ES 集群常用排查命令

说明&#xff1a;集群使用非默认端口9200&#xff0c;使用的是7116端口举例 一、常用命令 #1.集群健康状态 [wlsadminelastic-01~]$ curl -XGET "http://10.219.27.00:7116/_cluster/health?pretty" { cluster name":"cluster" "status"…

线性代数的学习和整理19,特征值,特征向量,以及引入的正交化矩阵概念

目录 1 什么是特征值和特征向量&#xff1f; 1.1 特征值和特征向量这2个概念先放后 1.2 直观定义 1.3 严格定义 2 如何求特征值和特征向量 2.1 方法1&#xff1a;结合图形看&#xff0c;直观方法求 2.1.1 单位矩阵的特征值和特征向量 2.1.2 旋转矩阵 2.2 根据严格定义…

网络协议从入门到底层原理学习(三)—— 路由

网络协议从入门到底层原理学习&#xff08;三&#xff09;—— 路由 1、简介 路由&#xff08;routing&#xff09;是指分组从源到目的地时&#xff0c;决定端到端路径的网络范围的进程 在不同网段之间转发数据&#xff0c;需要有路由器的支持 默认情况下&#xff0c;路由器…