我是初学者学习一些程序集,在函数调用之前保留ESP寄存器是否重要,如果你通过加或减来做?很难解释,请考虑以下
mov esi, esp
sub esp, 12 // on 32bit OS this would mean that there are 3 arguments to the function
// push, function call etc
cmp esi, esp // should be the same
或
mov esi, esp
// push, function call etc
add esp, 12
cmp esi, esp // should be the same
另外如果由于某种原因cmp失败,可以安全地使用mov esp,esi来重新对齐堆栈吗?
由于
编辑:为了像sprintf这样的调用,我怎么还需要这样做,但MessageBox似乎为我修复了ESP?我怎么知道什么功能需要这个和什么不需要?答案 0 :(得分:4)
是的,重要的是在使用esp时使符号正确(在这种情况下,减去,但有时你需要在引用已经在堆栈上的东西时添加,比如函数内的参数)。原因是堆栈在内存中向下向下。这与我们通常认为的堆栈(你把东西置于顶部并从顶部移除它们)相反,在内存中随着stac k的增长,这将是越来越高的地址。但是X86(以及大多数其他)处理器上的调用堆栈实际上是向下增长的。这就像在堆栈底部添加板块,并从底部移除它们......在内存中,随着更多内容添加到堆栈中,地址越来越低。
是的,只要您确定要将其设置为堆栈内的有效位置,并且只要您确定不需要任何通过这样做你丢失的信息。在这种情况下,你正在将esp保存在esi中,正是出于这个原因...你可以从esi中恢复esp所以无论之前的函数调用是什么,你都知道esp就在你想要的地方。
sprint和MessageBox之间的区别在于“调用约定”。这告诉更高级语言(C)如何在调用它们时处理堆栈帧和寄存器。 sprintf是cdecl,而MessageBox是stdcall。
答案 1 :(得分:1)
另外我怎么需要为sprintf这样的调用做这个,但是MessageBox似乎为我修复了ESP?
这是因为MessageBox()
函数在返回时清除堆栈中的参数。它可以这样做,因为参数的数量是固定的。
但是,使用可变数量的参数调用sprintf()
函数。该函数不知道调用者可能已经向堆栈推送了多少,因此调用者有责任在调用返回时清除它们。