【发布时间】:2017-08-16 22:07:27
【问题描述】:
在 x86 汇编语言中:
我假设我有一个正常的功能序言,阅读
push ebp
mov ebp,esp
我知道我可以通过访问内存目标操作数来读取或写入寄存器,假设我想要第一个参数。我会做的
mov eax,[ebp +8]
得到 f.e.堆栈中的整数参数。
那么我为什么不直接使用堆栈指针呢?
add esp,8 ; point ESP at the data we want
pop eax
sub esp,12 ; restore ESP to its original position
这会导致错误吗?这在任何情况下都使用吗?
我当然知道第一个操作的大小更小,因为它只有一个操作码,即mov,而不是三个,但这不是问题的重点。
(编者注:mov eax, [ebp+8] 是 x86 机器码中的 3 字节指令。add/sub esp,imm8 每个是 3 个字节,pop eax 是 1 个字节。mov eax, [esp+8] 是4 字节指令:与 16 位寻址模式不同,ESP 可以是基址寄存器。但它确实需要一个 SIB 字节来对其进行编码。
这些都是single-uop instructions on modern CPU,不包括额外的堆栈同步微指令。)
为什么这样做是不好的做法?
【问题讨论】:
-
我假设您的意思是
add而不是inc和sub而不是dec。与此相关的一个问题是,如果您在打开中断的情况下运行并且在pop eax和sub esp,12之间发生中断,那么低于 ESP 的任何内容都可能被破坏(中断将导致数据被推入堆栈)。出于同样的原因,inc esp, 8和pop eax之间的中断将成为潜在问题。如果您仍然需要将数据保留在 ESP 之下,那么这将是一个问题。不知道你在dec esp,12之后如何使用堆栈数据,所以很难说这是否会成为问题。
标签: assembly x86 callstack abi red-zone