您可以ESP
直接用作指针。
但是,如果发生任何推动或弹出,那么 ESP 就会变成一个移动的目标,使您的计算变得更加困难。
出于这个原因,我们将堆栈指针的副本放在 EBP 中,这样我们就不必担心 ESP 的变化。
但是,如果您不打算做任何事情来更改堆栈指针,那么使用它来ESP
代替EBP
.
如果你确实改变ESP
了,你当然可以相应地改变 ESP 的偏移量。
警告
你不应该这样做:
add esp,8
mov ecx,[esp-4] //never access data outside the actual stack.
pop eax
sub esp,12
请记住,中断可能随时发生。
中断将假定堆栈指针下方的任何内容都可以更改。如果您手动增加堆栈指针,然后访问它下面的数据,就好像它仍在堆栈中一样,您可能会发现那里的数据已经被中断处理程序替换(Oops)。
规则:ESP 以北的任何东西都是安全的,ESP 以南的任何东西都被标记为死亡
这就是例程创建stack frame
. 通过降低堆栈指针(记住堆栈向下增长),内存区域受到保护,因为它现在位于堆栈内部。
堆栈的语义意味着任何高于 ESP 的数据都是安全的,任何低于 ESP 的数据都是公平的游戏。
如果 A 违反这两个原则中的
任何一个 - 使用非固定 ESP 作为基指针,或者
B - 访问低于 ESP 的数据。
您将面临 A:损坏他人数据或 B:自己处理损坏数据的风险。
这是不好的做法吗?
add esp,8 //equivalent to pop anyreg, pop anyreg
pop eax //pop from the (new) top of the stack.
sub esp,12 //reset the stack back to where is was.
是的!这是不好的
sub esp,12
如果在此堆栈空间中存储的 3 个整数发生更改 之前发生中断,则会导致您的应用程序中的数据损坏。
请改用以下代码。
mov eax,[esp+8]
此代码是 A:安全,B:更快,C:不破坏标志寄存器,D:更短,E:以更少的字节编码。
关于 add/sub 的说明
如果你在 FLAGS 中有一些有用的东西,你可以通过使用LEA
for add 来避免破坏它。如果不是,add
/sub
至少也一样快(例如,在某些主流 CPU 上的更多执行端口上运行,而 LEA 只能在 Ryzen 和 Haswell 及更高版本的 4 个整数 ALU 执行单元中的 2 个上运行)。无论哪种方式,都没有代码大小优势。
lea esp,[esp+8] == add esp,8 (but without altering the flags).
lea edx, [esp+8] ; copy-and-add replacing mov + add is very useful
当 LEA 可以替换 2 个或更多其他指令时,一定要使用它,但不仅仅是替换添加/子指令,除非您有保留 FLAGS 的用途。