汇编——寻址方式

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++ 函数默认标准栈寻址方案

相关推荐
大模型码小白1 小时前
企业级检索增强后端集成:Java 服务如何管理知识库版本
java·服务器·开发语言·人工智能·python·microsoft
-银雾鸢尾-1 小时前
C#中的Dictionary相关方法
开发语言·c#
农村小镇哥1 小时前
Python3开发快速获取图片的文字
开发语言·python
geovindu1 小时前
go:Backtracking Algorithm
开发语言·后端·算法·golang·回溯算法
lzhdim2 小时前
C# 中读取CPU、硬盘和内存温度
开发语言·c#
Irene19912 小时前
Oracle PL/SQL Developer 版本差异(11g、14)实战总结
java·开发语言
qq_448011162 小时前
C语言中的getchar()
c语言·开发语言
肖志-AI全栈2 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
开发语言·javascript·排序算法
野生风长2 小时前
c++类和对象(this指针,重载operator,习题总结)
java·开发语言·c++