为什么编译器会生成此代码?

时间:2012-01-25 00:12:07

标签: c visual-c++ assembly disassembly

我使用DumpBin反汇编了一个目标文件(很可能是使用Visual C ++编译器生成的)并看到了以下代码:

...         ...
mov         dword ptr [ebp-4],eax       // Why save EAX?
push        dword ptr [ebp+14h]
push        dword ptr [ebp+10h]
push        dword ptr [ebp+0Ch]
push        dword ptr [ebp+8]
mov         eax,dword ptr [ebp-4]       // Why restore EAX? Did it change at all?
call        <function>
...         ...

有人可以解释为什么EAX寄存器正在这4条push指令中保存和恢复吗?

3 个答案:

答案 0 :(得分:10)

另外,也许它是在发布模式下编译的,但是该变量已被标记为volatile,它告诉编译器这个变量可能会在它不知情的情况下发生变化,因此它被强制连续写入/恢复/从堆栈

答案 1 :(得分:6)

这是内置调试模式吗?如果是这样,编译器会将每个局部变量存储在堆栈中,以便调试器可以以一致的方式找到它们。

这种不必要的存储和重新加载的省略是构成“释放”模式的优化之一。

答案 2 :(得分:2)

volatile或不是,在Windows上进行函数调用之前, EAX声明为function,即使用Windows CS_SYSCALL调用约定。从概念上讲,这有点类似于UN * X x86_64约定,其中__syscall包含%al寄存器中传递的浮点类型args的数量。

Windows上的系统调用约定与%xmm相同,即堆栈上的函数args以相反的顺序排列,但添加__cdecl包含参数个数的计数;这样做是为了通常在最后一端的内核代码知道从用户堆栈读取到内核堆栈以检索args的数据量。

AL是32位Windows上所有调用约定的临时寄存器,它的值永远不会保留在函数调用上,在进行调用之前直接初始化它是多余的。即使它所拥有的变量是EAX - 因为简单的重新加载不是内存屏障,也不会“提交”前一个商店。此外,位置volatile位于堆栈内,因此变量是 local (并且[EBP - 4]限定符没有意义。)

如果它不是错过的优化,那么它可能是一个volatile的调用,具有不同数量的参数,例如,假设,

__syscall function(...)

这可以设想像你的那样创建组装输出。