【C++庖丁解牛】函数栈帧的创建与销毁

目录
- 1. 寄存器
- 2. ebp和esp是如何对堆栈进行维护的,mian函数栈帧如何创建
- 2.1 push ebp
- 2.1 move ebp esp
- 2.2 sub esp, 0E4h
- 2.3 push exb
- 2.4 push exi
- 2.5 push edi
- 2.6 push edi
- 2.6 lea edi,[ebp+FFFFFF1Ch]
- 2.7 mov ecx,39h 以及mov eax,0CCCCCCCCh
- 2.8 rep stos dword ptr es : [edi]
- 3. 局部变量栈帧的创建
- 3.1 对a分配空间
- 3.2 对b分配空间
- 3.3 对c分配空间
- 4. 函数的调用
1. 寄存器
寄存器我们了解过有eax、ebx、ecx、edx、ebp、esp等等
本节的重点是我们的ebp、esp这两个寄存器,这两个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的
每一个函数的调用都要创建一块空间,这个空间创建在栈区上。
- esp则为我们的栈顶指针
- ebp就是我们的栈底指针
esp (EStack Pointer):栈顶指针,它指向当前栈帧中的栈顶位置。每当一个新的函数被调用时,esp会动态地更新以跟踪新参数的压入和局部变量的分配。当函数执行完毕,esp会回退到释放这些资源的位置。
ebp (EBase Pointer):栈底指针,又称为基指针,它通常用于存储当前函数的帧信息,比如函数的局部变量、参数和其他数据。ebp在函数开始时被设置为栈顶减去函数头部所需的空间,这样就可以作为访问栈中所有局部变量的基地址。
在函数调用过程中,esp和ebp经常被用来进行帧布局的操作,例如保存旧的esp值,然后将新的esp指向新的函数参数,而 ebp则保持不变,作为固定不变的局部变量基址。当函数返回时,esp通常会恢复到原来的值,释放栈帧,而ebp也会回到正确的基址,以便后续函数继续正确地访问局部变量。
2. ebp和esp是如何对堆栈进行维护的,mian函数栈帧如何创建
其实main函数也是被另一个内部系统函数调用的
具体调用为
mainCRTStartup
—>__tmainCRTStartup
—>main
前两个函数都是系统里的调用函数
程序在一开始运行时,ebp以及esp是维护__tmainCRTStartup的函数栈帧的
栈空间的使用是由高地址往低地址使用的
在执行main函数的时候就会往上进行创建栈帧
2.1 push ebp
我们将写的代码进行反汇编的操作,看到程序底层的汇编代码可以看到第一步就是对于ebp
的push
操作
push ebp
的作用是将ebp
的值压栈(Push the value of ebp onto the stack),这样在函数执行过程中,ebp
就不会被其他操作覆盖,保持对函数调用上下文的引用。
当函数开始执行时,push ebp 让 ebp 保存当前堆栈帧的状态,然后
mov ebp, esp
将esp
(栈指针)的内容赋给ebp
,从而esp
指向新的栈顶,用来作为新创建的局部变量的内存地址。这样做有助于维护函数调用的上下文,便于后续访问和管理局部变量、参数等。
也就是说将ebp此时的值存入栈中,以便后面进行查找,在此时就是__tmainCRTStartup的ebp值
当我们在没有执行push操作时,esp与ebp的值如下
在我们执行后esp的值从后两位为a8,变为了a4
这也说明了esp被压入栈。
此时的esp则往低地址走了几步,现在指向的就是__tmainCRTStartup的ebp
的地方了
2.1 move ebp esp
执行了 push ebp
之后,第二步就是move ebp esp
move ebp esp
的操作意味着将ebp
的值赋给esp
。这种操作经常发生在函数返回或异常处理时,因为当函数结束时,可能需要清空堆栈,将esp
回退到栈帧之前的状态,以便为下一次函数调用腾出空间。在清理过程中,ebp
通常会被用来保存堆栈的原有状态,然后将其位置替换到esp
,这样就可以清除函数调用时的信息。
也就是ebp与esp都指向__tmainCRTStartup的ebp
2.2 sub esp, 0E4h
第三步为sub esp, 0E4h
sub esp, 0E4h
是一个指令组合,它代表"从堆栈指针ESP(通常用于跟踪函数调用时的局部变量和参数)中减去0E4个字节(16进制的0E4等于十进制的220)"。这个操作常用于函数调用或内存分配,可能是为了为新的局部变量分配空间或者调整堆栈布局。
具体来说:
- sub是"subtract"的缩写,即减法操作。
- esp是堆栈指针,它指向栈顶,减去一个数意味着将栈顶地址向下移动。
- 0E4h是一个16进制数,转换成十进制就是220,所以实际上是将栈顶的220个字节移除或压入栈中。
这段空间其实就是为main函数预留的一段空间
在执行完这个操作后
2.3 push exb
push exb顾名思义也是将exb此时的数据存储到栈中
2.4 push exi
将esi此时的数据存储到栈中
2.5 push edi
2.6 push edi
2.6 lea edi,[ebp+FFFFFF1Ch]
lea edi, [ebp+FFFFFF1Ch]
是一条x86汇编指令,其中 “lea” 是load effective address
(有效地址加载)的缩写,它用于计算并存储一个内存地址到寄存器edi中。在这个指令中:
edi
是destination operand
(目标操作数),通常用于存放计算出的内存地址。[ebp+FFFFFF1Ch]
是source operand
(源操作数),它使用基址加变址寻址方式。ebp
是基指针(base pointer),用于访问栈帧中的数据。加上偏移量FFFFFF1Ch
,意味着从栈帧的当前位置向上偏移0xFFFFFF1Ch
处的内存位置。
这条指令的作用是将栈上某个特定位置的地址赋值给edi,这个位置通常是函数调用时为了后续操作需要而存储的数据地址。在分析程序代码时,这可能对应于函数的局部变量、参数或其他动态分配的数据结构的地址。
在这里其实就是mian函数的栈顶地址给了edi寄存器
2.7 mov ecx,39h 以及mov eax,0CCCCCCCCh
-
mov ecx, 39h
: 这行指令将立即数39h
(十六进制,等于十进制的 57)传送到名为 ecx 的寄存器中。ecx 通常用于索引或循环计数。在这里,ecx 被设置为一个特定的值,可能用于控制某种循环次数或者作为数组操作的下标。 -
mov eax, 0CCCCCCCCh
: 这行指令将十六进制数值0CCCCCCCCh
(十进制的 -1073741821) 移动到 eax 寄存器。eax 在x86架构中是一个常用的通用寄存器,常用于存储操作数。0CCCCCCCCh
是一个特殊的值,有时在某些情况下用于测试内存是否已初始化(因为它几乎不会出现在正常的初始化中)。
相当于代码
ecx = 39h
eax = 0CCCCCCCCh
对这两个寄存器赋值
2.8 rep stos dword ptr es : [edi]
dword ptr es:[edi] ,edi(EAX的低16位)是一个寄存器,指向存储的起始位置,es(额外段寄存器)指定数据段,ptr表示是按字节偏移地址。因此,这整个指令组合的意思是:
从
edx寄存器
开始,重复执行存储操作,每次将源操作数中的两个字节写入es段的当前指定位,然后地址指针edi
递增指向下一个存储位置,直到所有数据都被写入。
也就是将ecx
中39h
个空间全部写入成eax
的0CCCCCCCCh
,相当于给我们开辟的空间进行初始化
以上这个部分main函数的函数栈帧就已经创建完成了
3. 局部变量栈帧的创建
3.1 对a分配空间
这里就是将a放入ebp-8的位置上去,a为int类型四个字节
3.2 对b分配空间
3.3 对c分配空间
4. 函数的调用
这里的步骤就是
- 将b的值放入eax中,再将eax压栈,放入栈中
- 将a的值放入ecx中,再将ecx压栈,放入栈中
- call指令调用add函数,call指令前面的地址为call指令的下一条地址
- 跳到add函数准备栈帧,并执行add函数
最后通过函数的调用返回结果,最后得到结果
相关文章:

【C++庖丁解牛】函数栈帧的创建与销毁
🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 1. 寄存器2. ebp和esp是如…...
Java基础16(集合框架 List ArrayList容器类 ArrayList底层源码解析及扩容机制)
目录 一、什么是集合? 二、集合接口 三、List集合 四、ArrayList容器类 1. 常用方法 1.1 增加 1.2 查找 int size() E get(int index) int indexOf(Object c) boolean contains(Object c) boolean isEmpty() List SubList(int fromindex,int …...
数组:移除元素
参考资料:代码随想录 本题思路:通过快慢指针将两次循环减少到一次 class Solution {public int removeElement(int[] nums, int val) {//0 1 2 2 2 2 3int fast 0;int slow 0;while(fast < nums.length){if(nums[fast] ! val){nums[slow] nums[f…...
胡说八道(24.6.22)——通信杂谈(完结)
上回书说到雷达和香农的信息论,今天来进行完结。 数字幅值调制或幅值键控(ASK)调制方式是指载波信号的幅值随数字基带信号而变化,因此可以实现将基带信号搬移到载波频段。2ASK是利用代表数字信息0或1的基带矩形脉冲去键控一个连续…...

设计模式原则——里氏替换原则
设计模式原则 设计模式示例代码库地址: https://gitee.com/Jasonpupil/designPatterns 里氏替换原则 继承必须确保父类所拥有的性质在子类中依然成立 与开闭原则不同的是开闭原则可以改变父类原有的功能,里氏替换原则不能修改父类的原有的性质&#…...
详解 ClickHouse 的 SQL 操作
传统关系型数据库(以 MySQL 为例)的 SQL 语句,ClickHouse 基本都支持 一、插入 --语法: insert into table_name values(xxxxxx),(yyyyyyy),...;insert into table_name select xxxxx from table_name2 where yyyyy;二、更新和删…...
WPF与Winform,你的选择是?
概述 在桌面应用的发展历程中,Winform和WPF作为微软推出的两大框架,各自承载着不同的设计理念和技术特色。Winform以其稳定、成熟的技术基础,长期占据着企业级应用开发的重要地位。而WPF,作为后来者,以其现代化的UI设计…...

基于SpringBoot的实习管理系统设计与实现
你好呀,我是计算机学姐码农小野!如果有相关需求,可以私信联系我。 开发语言: Java 数据库: MySQL 技术: SpringBoot框架,B/S模式 工具: MyEclipse,Tomcat 系统展示 …...
编程用什么电脑不卡的:深度解析与推荐
编程用什么电脑不卡的:深度解析与推荐 在编程的世界里,一台流畅不卡的电脑无疑是每个开发者的得力助手。然而,面对市场上琳琅满目的电脑品牌和型号,如何选择一台适合编程的电脑却成为了一个令人困惑的问题。本文将从四个方面、五…...

优先级队列模拟实现
目录 1.堆的概念 2.堆性质堆中的某个元素小于或大于他的左右孩子 3.小根堆实例 4.堆创建 4.1调整思路 4.2向下调整思路 4.3代码实现(大根堆) 5.堆的删除 6.堆的插入 7.常用接口 7.1PriorityQueue和PriorityBlockingQueue 1.堆的概念 如果有一…...

记一次服务器崩溃事件
今天在安装Jenkins的时候,进行到插件安装这一步,本来一切顺利,结果最后安装完成之后一直进不去网页,显示连接超时,网上搜索了一圈也没发现什么相似的情况,当我疑惑的时候回到Linux控制台,发现命…...

神经网络 #数据挖掘 #Python
神经网络是一种受生物神经元系统启发的人工计算模型,用于模仿人脑的学习和决策过程。它由大量互相连接的节点(称为神经元)组成,这些节点处理和传递信息。神经网络通常包含输入层、隐藏层(可有多个)和输出层…...

营销复盘秘籍,6步法让你的活动效果翻倍
在营销的世界中,每一次活动都是一次探险,而复盘就是探险后的宝藏图,指引我们发现问题、提炼经验、优化策略。 想要学习如何复盘,只要了解以下复盘六大步骤,即可不断总结,逐渐走向卓越。 第一步࿱…...
Linux下命令行文件创建删除、目录创建删除
在Linux命令行下,文件和目录的创建与删除是通过一系列基础命令完成的,这些命令对于日常的系统管理和文件操作至关重要。 下面将详细介绍这些命令的功能和使用方法。 普通文件的创建与删除 创建文件 touch命令:主要用于创建一个空文件&…...
数字排列问题
题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 代码: #include <stdio.h> int main() { int count 0; // 计数器,记录生成的三位数的数量 // 使用三个嵌套的fo…...

CentOS Linux 7系统中离线安装MySQL5.7步骤
预计数据文件存储目录为:/opt/mysql/data 1、文件下载: 安装文件下载链接:https://downloads.mysql.com/archives/community/ 2、检查当前系统是否安装过MySQL [rootcnic51 mysql]# rpm -qa|grep mariadb mariadb-libs-5.5.68-1.el7.x86_6…...

XSS跨站攻击漏洞
XSS跨站攻击漏洞 一 概述 1 XSS概述 xss全称为:Cross Site Scripting,指跨站攻击脚本,XSS漏洞发生在前端,攻击的是浏览器的解析引擎,XSS就是让攻击者的JavaScript代码在受害者的浏览器上执行。 XSS攻击者的目的就是…...

PMP到底值不值得考?
首先,咱们得明白PMP是个啥。 PMP,全称Project Management Professional,是美国项目管理协会PMI颁发的一个项目管理专业人士资格认证。 PMP证书在项目管理领域可是有着举足轻重的地位,与MBA、MPA并驾齐驱,被称为“全球…...
redis面试总结
redis的数据类型? string字符串:类似于java中Map<String,String>。存储字符串、JSON数据、验证码等。 Hash字典:类似java中Map<String, Map<Spring,String>>。比较适合存储对象数据。 List列表:类似java中Ma…...
大模型日报2024-06-24
大模型日报 2024-06-24 大模型资讯 大模型产品 AI快速生成专业播客 摘要: MakePodcast.io使用AI语音,只需提供脚本并选择声音,即可在几分钟内生成专业质量的播客。 Sherloq:SQL用户的AI协作仓库 摘要: Sherloq为SQL查询提供一站式管理&#x…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...