汇编——寻址方式

ESP寻址

ESP 寻址定义

ESP 寻址是以栈指针ESP作为基准地址,搭配固定偏移量 ESP+数值 读写栈内参数、临时数据的寻址方式,是堆栈传参函数读取入参的核心手段

学习前提:掌握寄存器传参、堆栈压参调用逻辑

两种传参对照铺垫

  1. 寄存器传参(少参数)
    参数直接放进通用寄存器,无需栈、不用 ESP 寻址读参
cpp 复制代码
;调用
mov ecx,10
mov edx,20
call AddReg
;函数
AddReg:
mov eax,ecx
add eax,edx
ret
  1. 堆栈传参(多参数标配)
    调用方 push 压参数,函数内部依靠 ESP 偏移取值,也就是 ESP 寻址
cpp 复制代码
push 20
push 10
call AddStack
add esp,8 ;外平衡

ESP 寻址底层原理

执行 call 瞬间,栈布局固定:

ESP:call 自动压入的返回地址(占 4 字节)

ESP+4:第一个压入的参数

ESP+8:第二个压入的参数 每多一个参数,偏移额外 + 4

函数内部取值示例:

cpp 复制代码
AddStack:
mov eax,[esp+4]   ;ESP寻址取参数1
add eax,[esp+8]   ;ESP寻址取参数2
ret

配套堆栈平衡规则

平衡标准:call 执行前 和 call 结束后 ESP 数值完全一致

外平衡 (cdecl):函数只用普通 ret,call 后add esp,总参数字节

内平衡 (stdcall):函数结尾ret n,自动弹返回地址 + 抬高 ESP 清理参数 失衡后果:栈地址错乱、返回地址读取错误、程序崩溃

ESP 寻址优缺点

优点

1.写法简单,仅用 ESP 加固定偏移就能读取所有栈参数

2.无需额外基址寄存器,节省 EBX/EBP 等通用寄存器

缺点

1.ESP 是动态变化的:函数内 push 寄存器、sub esp 开局部变量都会改变 ESP 值,偏移量跟着变大,计算繁琐

2.复杂多层逻辑、大量局部变量时,偏移极易算错,读错参数

3.若中途频繁改动 ESP,必须手动重新换算偏移,稳定性差

EBP寻址

EBP 寻址核心优势

1.EBP 是栈基址(栈底指针),专门用作稳定寻址基准

2.ESP 会因为 push、sub esp、局部变量分配持续变动,EBP 一经初始化全程固定不变

3.偏移值EBP±数值从头到尾统一,不会因为栈操作改来改去,大幅降低寻址计算失误

EBP 标准初始化流程(函数固定开头序言 prolog)

1.push ebp:把上层函数原来的 EBP 压栈保存,防止覆盖丢失

2.mov ebp, esp:让 EBP 定格在进入函数那一刻的 ESP 位置,锁定基准

3.sub esp, N:抬高 ESP,向下开辟 N 字节栈空间,存放局部变量

执行完这三步,EBP 数值永久固定,不管后面怎么 push、读写栈,基准不动

栈布局(EBP 锁定后)

以 2 个栈传参举例:

内存位置 存放内容
EBP+0 保存的上层旧 EBP
EBP+4 CALL 压入的返回地址
EBP+8 第一个传入参数
EBP+12 第二个传入参数
EBP-4EBP-8 ...... 函数内部局部变量

加法函数代码演示(EBP 寻址)

cpp 复制代码
;调用端 cdecl外平衡
push 20
push 10
call AddEbp
add esp,8

;函数主体
AddEbp:
push ebp            ;1.保存旧ebp
mov ebp,esp         ;2.ebp锁定当前esp基准
sub esp,0x8         ;3.开辟8字节局部变量空间

mov eax,[ebp+8]     ;取参数1=10
mov [ebp-4],eax     ;存入局部变量1
mov eax,[ebp+12]    ;取参数2=20
mov [ebp-8],eax     ;存入局部变量2

mov eax,[ebp-4]
add eax,[ebp-8]     ;求和,结果放eax

;函数收尾epilog,恢复栈平衡
mov esp,ebp         ;把esp还原回ebp基准,清空局部变量空间
pop ebp             ;弹出上层旧ebp,恢复
ret                 ;返回,外部平衡栈

EBP 寻址配套栈平衡收尾(epilog 尾声)

固定恢复步骤:

1.mov esp, ebp:直接把 ESP 拉回 EBP 的基准位置,一次性释放所有 sub esp 开辟的局部栈空间,不用逐次加减修正

2.pop ebp:还原调用方原本的 EBP 值

3.ret / ret n 完成返回

平衡作用

1.一键抹平函数内部所有局部变量、临时 push 带来的 ESP 变动

2.保证退出函数时栈状态和进入时匹配,杜绝寻址错乱、栈失衡崩溃

3.对比纯 ESP 寻址:复杂多层代码、多局部变量场景下,EBP 偏移全程稳定,几乎不会算错偏移量

对比 ESP 与 EBP 寻址

ESP:基准动态变化,每一次栈操作都要重算偏移,简单小函数能用,复杂函数极易出错

EBP:基准永久固定,参数、局部变量偏移全程不变,是编译器 C/C++ 函数默认标准栈寻址方案

相关推荐
大白同学42139 分钟前
初识Qt——创建第一个Qt项目
开发语言·qt
祈禾41 分钟前
计算机组成原理之编译、汇编、链接、解释
开发语言·汇编·笔记·学习
吴声子夜歌1 小时前
正则指引——Ruby
开发语言·正则表达式·ruby
nnerddboy1 小时前
Rust教程06:ESP32-rust环境搭建
开发语言·后端·rust
nnerddboy1 小时前
Rust教程03:函数,控制流与所有权
开发语言·后端·rust
linux修理工1 小时前
内存占用 99% 且 Java 程序较多的优化建议
java·开发语言
weixin_460443561 小时前
企业考试系统如何对接OA、钉钉和企业微信?SSO单点登录、组织同步与权限一致性设计
java·开发语言·数据库
nnerddboy2 小时前
Rust教程05:结构体,枚举与模式匹配
开发语言·网络·rust
小小尚@2 小时前
AE脚本-AE Actions v1.1.8 操作动作记录器
开发语言·前端·javascript·jupyter·postman
程序员雷欧2 小时前
Java 反射深度解析:从原理到源码的全面剖析
java·开发语言·python