96SEO 2026-02-20 01:21 0
令上会有点不同指令不多简单记忆一下即可在我前些年的学习中学的这几句汇编指令对我调试找错误起了不小的作用。

那接来下就开始进入正题。
栈帧也就是内存空间函数栈帧也就是了解函数的内存空间也就是我们来从内存来理解函数个人感受在理解完后感觉看代码好像有一点看内存那感觉了。
我们首先要了解今天要解决的六个问题
我们大致知道数据都是放在栈区上的而栈区内是先用高地址再用地址的当我们调用一个函数就会在栈上开辟一块空间这块空间就是该函数的栈帧一块空间总得标志一下起始和终点把也就有了两个寄存器来保存esp存栈顶指针ebp存栈底指针这两个指针维护的就是当前调用函数的栈帧。
我们总说main函数是个函数那我们的这个main的返回值是给谁又是被谁调用的呢?
我们在调试模式下F11并且在窗口中查看调用堆栈就可以看到如下的图而那个黄色箭头是当前调用的函数所以调用顺序是mainCRTStartup()调用_
_tmainCRTStartup()最后才调用的main函数所以main函数返回值是给上述函数的之前一直说不用管main函数的参数和返回值现在我们就可以稍微理解main的返回值是给谁的了至于参数则需要在其它环境才能引出来解释了。
下面每一行都是一句指令等会会一句一句说清楚首先我们可以发现我们写代码第一句是int
x2,定义一个变量但是对于编译器来说它要做很多的前期工作不是直接就帮局部变量的定义原因是我们先前提到main函数首先也是个函数也就是说被编译器调用的那一开始ebp和esp维护的就不是main函数的栈帧空间所以编译器要做的前期工作之一那就是将ebp和esp转为维护main函数栈帧。
(这里已经大致解释了问题5后面调用Add函数编译器做的工作和现在调用main函数做的准备工作一模一样)
ebp就是向栈顶存放一个ebp的变量那这个时候esp就要上移了因为存放了一个变量后栈顶上移了esp也要变。
esp也就是把esp的值赋值给ebp那此时ebp和esp就指向同一个位置了然后是第三句sub
0E4h是对esp减去一个值-0E4h结果如下esp就又上移了。
此时esp和ebp已经开始维护新的空间了此时ebp和esp就已经开始维护被调用的main函数栈帧了。
(后面会提如何在回去维护_
紧接着的几句都是push三个寄存器元素ebx和esi的作用先不用管而edi是提供给后面的rep
stos指令的我们先看看编译器往edi放了什么ebp-0E4h不就是我们执行了sub指令后esp的位置吗,当然此时esp的位置是如下图的。
stos指令这三句指令作用可以记忆一下就是把edi地址向下的的ecx个空间全部初始化为eax中存的值也就是说ecx存了初始化次数eax存了初始化的值而每个空间单位是dword指示的四个字节。
论证:0E4h十进制是228,而39h(这个h好像是没啥用的)十进制是57,恰好分为了57个四个字节空间。
这就是为什么我们的局部变量未初始化的空间内存的是一个特别小的一个负数就是因为我们一开始存的就是这么一个数而且不同平台可能不一样所以又称为随机数。
(可以解释问题2为什么未初始化的局部变量内是随机值)。
如果汇编不显示符号名那其实创建一个局部变量就是往一个空间内存一个值当后面这块空间销毁了局部变量也就没了。
(问题1解释)
虽然我们写代码是连续定义了两个变量但是这两个变量在内存的位置不是紧挨的是有空隙的这个空隙的大小由编译器来定。
我们往ebp-8位置开始向下使用四个字节来存放2,这说明栈区的内存是先用高地址再用低地址但是变量内部是先用低地址再用高地址。
然后我们再来看看调用Add函数是如何传参的首先是将ebp-14h中的值存入存到寄存器再push到栈顶而ebp-14h的值就是y的值这说明传参顺序是右到左(问题3的解释)。
我们push了两个参数到栈上而且只是把x,y的值拷贝了一份放到栈顶上。
push寄存器到栈上的意思是把寄存器的值放到栈顶上不是将寄存器放到上面为了更好地展示栈上是什么才没有用数据代替。
然后我们就看到了一句call指令这个时候会在栈顶上保存call指令下一条指令的地址这个非常隐秘我是从内存窗口才发现F11执行call指令时esp向上移动了四个字节。
所以这个时候栈区的图应该为下图
还有call不是直接找到函数而找到一句jump指令jump指令才能找到函数。
此时调用Add函数又是一堆前置工作就像调用main函数一样都要改变ebp和esp。
我们可以看到最后我们把值都放到了eax中去这就是Add函数栈帧都销毁了还可以返回值的原因(问题6后面有后续)。
此时就又使得esp和ebp去维护新调用的函数栈帧。
(问题5的再解释函数调用就是通过ebp和esp的两个指针的配合)
还有就是我们的实参和形参的关系从下面这张图应该可以理解吧传值传参的时候我们在Add函数找参数是ebp8找的ecx,这就是x的值的拷贝ebp12找的就是y变量的拷贝。
而且我们之前说ebp到esp之间是调用函数的栈帧显而易见的是形参不在对应函数栈帧内。
问题4传值传参中形参是实参的临时拷贝。
当我们调用完了Add就要使得esp和ebp返回去维护main函数栈帧而如何返回的请看下图。
pop就是从栈顶拿走一个元素push的时候esp要上移那pop的时候esp就要下移。
ebp还会把ebp(而这里的ebp存的是原先main的栈底指针存的地址)弹出并且存到ebp。
那ebp不就直接去维护main函数的栈底了吗。
此时我们的ebp和esp基本回到维护main函数栈帧的状态但是我们一开始是跳转到函数内去执行的指令执行完后要回到main函数的那怎么回来呢?就是这个ret指令的作用了。
而且使用完后也会被pop掉
最后一步:esp8就完成了对Add函数栈帧的销毁也对形参进行了销毁。
而我们再回到main函数中可以发现ret[ebp-20h]接收的就是eax中的值(问题6后续)
这就是个人对函数栈帧的全部理解之前学了觉得理解了但是时间久了反而有点忘了所以就狠下心来写了这篇博客因为画很多图来结合分析。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback