在一篇关于_cdecl调用约定的文章中,作者提到:
当函数分配本地临时空间时,
释放本地存储空间,它通过从堆栈点减少所需空间来释放本地存储,并且必须反转此过程才能恢复该空间。这通常是通过在堆栈指针中添加先前减去的相同数量的堆栈指针来完成的,尽管一系列POP指令可以实现相同的目标。
我的问题是:我是否可以简单地将ESP设置为当前的EBP值,而不是“添加到堆栈指针中减去的相同数量”或“一系列POP指令”?
比如:
mov esp, ebp对我来说,这似乎是一个更好的方法,因为如果我后来更改了这个函数的局部变量的数量,那么我就不必费心在以后增加这个值了。
发布于 2012-02-28 12:08:20
实际上,这正是leave instruction所做的,它是为了支持高级语言而引入的。但是,它并不经常使用;大多数编译器只是执行显式的mov esp, ebp; pop ebp序列。另见this question。
但是,有时您可以进行“省略帧指针”优化。这可以释放EBP作为通用寄存器,但是您(或编译器)必须在整个函数中跟踪ESP更改,并使用可能更改的偏移量来处理局部变量或传入参数。如果这样做,将不得不在返回之前使用使用pops或显式添加来恢复ESP的原始值。
请注意,上面涉及整个函数(即prolog/epilog);当您需要在函数中间调用特定的__cdecl函数时,不能只将ESP还原到EBP值,因为在为局部变量分配任何空间之前,该值仅在函数开始时才有效。这里有两种方法:
1)推送参数,调用后恢复ESP:
push offset msg
call _printf
pop ecx ; clobbers ECX but shorter than add esp, 42)将参数移至保留堆栈槽;在这种情况下不需要恢复ESP:
mov dword ptr [esp+0], offset msg
call _printf
; no need to change ESP如果选择第二个选项,则需要确保没有在这些插槽中存储任何局部变量。而且,这样的mov指令通常比推送长得多,所以您可能需要考虑如果代码大小是一个考虑因素。
发布于 2012-02-28 08:09:41
从技术上讲,这将是堆栈帧的滥用,而堆栈帧是用来捕获堆栈不平衡所产生的错误的,但这是完全合法的。
但是需要注意的是,如果您的堆栈空间非常有限,因为有大量的分配或嵌入式设备,那么在每次调用之后清理堆栈是值得的。它还使调试变得更容易一些,因为这样您就知道某些地方使用了错误数量的args。
此外,如果有人要维护您的代码,他们会发现它非常混乱。
https://stackoverflow.com/questions/9478317
复制相似问题