汇编——堆栈平衡

基础定义

栈由操作系统为进程预先分配,承担函数参数传递、保存返回地址、存放局部临时数据、寄存器现场等工作

堆栈平衡:调用函数前与函数完全执行完毕后,ESP 栈指针数值必须一模一样,栈整体状态完全还原

核心要求:函数内部临时增减 ESP 没关系,但 RET 返回前必须抵消掉参数压栈带来的 ESP 偏移;失衡会栈错乱、数据读取错误、程序崩溃

失衡危害

调用前 push 了若干参数,函数返回后 ESP 没有复原:

1.后续栈读写拿到错误内存数据

2.多层函数嵌套调用时,返回地址错位,EIP 跳飞

3.严重直接程序异常崩溃

标准准则:调用点执行 call 前后 ESP 数值相等

两种堆栈平衡方案(外平衡、内平衡)

外平衡(调用方平衡,对应 C 语言 cdecl 约定)

平衡代码写在call 指令之后、函数外部

原理:调用端 push 参数,函数 ret 单纯只弹出返回地址,外部手动 add esp 回收参数占用空间

示例

cpp 复制代码
;调用端
push 10
push 20
call MyFunc
add esp,8   ;外平衡:外部修正ESP,回收两个参数8字节空间

;函数内部
MyFunc:
mov eax,[esp+4]
add eax,[esp+8]
ret         ;只弹出返回地址,不处理参数

内平衡(被调函数内部平衡,stdcall 约定)

平衡逻辑放在函数内部,依靠ret n指令实现

ret n动作:弹出返回地址给 EIP 后,自动执行 ESP = ESP + n,一次性清空 n 字节参数空间

示例

cpp 复制代码
;调用端只负责压参、调用,无后续平衡代码
push 10
push 20
call MyFunc

;函数内部内平衡
MyFunc:
mov eax,[esp+4]
add eax,[esp+8]
ret 8       ;内平衡:弹返回地址 + ESP+=8,清理两个参数

执行流程对比

外平衡流程: push 参数 → call 压返回地址 → 函数运算 → ret 回到 call 下一行 → 外部 add esp 修正栈

内平衡流程: push 参数 → call 压返回地址 → 函数运算 → ret n 一步完成返回 + 栈平衡,调用端无需额外代码

细节

1.函数内部开栈(sub esp 分配局部变量)、push 保存寄存器,只要在 ret 前原样 pop 恢复寄存器、恢复 ESP,不影响整体堆栈平衡

2.返回值统一存 EAX,平衡操作不改变 EAX 结果

3.平衡数值计算:参数个数×4 字节(32 位)

约定 平衡方式 返回指令 可变参数

cdecl 调用方外平衡 ret 支持

stdcall 函数内平衡 ret n 不支持

相关推荐
mayaairi2 小时前
JS循环语句深度解析:嵌套for、while与do...while
开发语言·前端·javascript
kite01212 小时前
Go语言Map深度解析与最佳实践
开发语言·后端·golang
l156469484 小时前
突围!图文混合知识库难以解析,Kimi-K3 原生视觉架构深耕知识工作,DMXAPI 统一接口,缩短项目开发周期
java·大数据·开发语言
charlie1145141914 小时前
现代C++工程实践 WeakPtr 实战(三):WeakPtrFactory 与「最后成员」惯用法
开发语言·c++·开源项目·现代c++
IT小盘6 小时前
04-大模型流式输出原理-SSE与Python实现
开发语言·网络·人工智能·python
腾霄星月6 小时前
Cobalt Strike(CS)内网渗透工具核心重点知识总结
网络安全·cs·cobalt strike
不如语冰6 小时前
AI大模型入门-Python进阶-上下文管理与with语句
开发语言·数据结构·数据库·人工智能·pytorch·redis·python
阿童木写作7 小时前
Python批量翻译亚马逊商品图实战教程
开发语言·python·xcode
会飞的大鱼人8 小时前
一文搞懂 Java HashSet:把它想成游乐园里只允许一次入场的盖章名单
java·开发语言·windows
jiay28 小时前
【.net10】顶级程序语句
java·开发语言