堆栈必须在函数结束语混淆之前清理干净
Stack must be clean before function epilogue confusion
我正在学习书中的汇编语言"汇编语言循序渐进:用Linux编程";作者:Jeff Dunteman,我在书中看到了一段有趣的话,我很可能误解了这段话,因此我希望能澄清一下:
"在销毁堆栈框架并返回控制之前,堆栈必须是干净的。这只是意味着,在程序运行期间,我们可能推送到堆栈上的任何临时值都必须消失。堆栈上剩下的应该是调用者的EBP、EBX、ESI和EDI值。
一旦堆栈清理干净,要销毁堆栈帧,我们必须首先将调用方的寄存器值弹出到它们的寄存器中,确保弹出的顺序正确。
我们通过将值从EBP移动到ESP来恢复调用者的ESP,并最终将调用者的EBP值从堆栈中弹出"
考虑以下从VisualStudio2008生成的代码:
int myFuncSum( int a, int b)
{
001B1020 push ebp
001B1021 mov ebp,esp
001B1023 push ecx <------------------
int c;
c = a + b;
001B1024 mov eax,dword ptr [ebp+8]
001B1027 add eax,dword ptr [ebp+0Ch]
001B102A mov dword ptr [ebp-4],eax
return c;
001B102D mov eax,dword ptr [ebp-4]
}
001B1030 mov esp,ebp
001B1032 pop ebp
001B1033 ret
ecx(指示)的值,被推到堆栈上为我的变量c腾出空间,据我所见,只有当我们重置ESP时,它才从堆栈中消失;然而,正如所引用的,书中指出,在我们重置ESP之前,堆栈必须是干净的。有人能澄清我是否遗漏了什么吗?
Visual Studio 2008中的示例与本书并不矛盾。这本书涵盖了一个电话中最复杂的案例。请参阅x86-32调用约定作为交叉参考,并用图片说明。
在您的示例中,堆栈上没有保存调用方寄存器,因此没有要执行的pop
指令。这是本书所指的mov esp, ebp
之前必须进行的"清理"的一部分。因此,更具体地说,假设被调用者为调用者保存si
和di
,那么函数的前奏和尾曲可能如下所示:
push ebp ; save base pointer
mov ebp, esp ; setup stack frame in base pointer
sub esp, 4 ; reserve 4 bytes of local data
push si ; save caller's registers
push di
; do some stuff, reference 32-bit local variable -4(%ebp), etc
; Use si and di for our own purposes...
; clean up
pop di ; do the stack clean up
pop si ; restoring the caller's values
mov esp, ebp ; restore the stack pointer
pop ebp
ret
在您的简单示例中,没有保存调用方寄存器,因此最后不需要最后的pop
指令。
也许是因为它更简单或更快,编译器选择执行以下指令来代替sub esp, 4
:
push ecx
但效果是一样的:为一个局部变量保留4个字节。
注意指令:
push ebp
mov ebp,esp ; <<<<=== saves the stack base pointer
和指令:
mov esp,ebp ; <<<<<== restore the stack base pointer
pop ebp
因此,在该序列之后,堆栈再次清洁
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 堆栈必须在函数结束语混淆之前清理干净