2

在 C++ 中调用函数时 push rdi 和 pop rdi 的目的是什么?VS2010,x64,调试,无优化

C++

int calc()
{
    return 8 + 7;
}

拆卸:

int calc()
{
000000013F0B1020  push        rdi  
    return 8 + 7;
000000013F0B1022  mov         eax,0Fh  
}
000000013F0B1027  pop         rdi  
000000013F0B1028  ret 
4

2 回答 2

7

它没有任何目的。这是未优化代码的常见工件。代码生成器发出push edi指令以预期必须执行加法。必须在函数调用之间保留 EDI 寄存器。但后来,发现添加可以在编译时执行。

摆脱这样的无关代码需要“窥视孔优化”。但是调试版本中没有启用该优化。要知道真正的代码是什么样子,您必须打开优化器,最好通过构建发布版本来完成。它实际上会完全消除该功能,您可以通过以下方式阻止它:

__declspec(noline) int calc()
{
    return 8 + 7;
}

在发布版本中产生:

    return 8 + 7;
000007F7038E1000  mov         eax,0Fh  
000007F7038E1005  ret  
于 2013-02-03T22:21:14.267 回答
3

你听说过“caller-save”和“callee-save”寄存器吗?

由于您的 CPU 只有少量有限数量的寄存器,因此调用者/被调用函数通常不可能始终使用不同的寄存器。如果调用者函数和被调用函数都想使用同一个寄存器,这意味着调用者中的值必须在调用之前/之后保存/恢复。

保存/恢复寄存器值可以由调用者或被调用者完成 - 这样做是一个约定问题。“调用者保存”寄存器的好处是,如果调用者知道调用后它不需要寄存器 XYZ 中的值,它可以省略保存/恢复操作。“被调用者保存”寄存器的好处是,如果被调用者知道它不会修改寄存器 XYZ 中的值,它可以省略保存/恢复操作。

我猜您的编译器将 RDI 视为被调用者保存寄存器,但不会省略不必要的保存/恢复操作,除非您打开了编译器优化。(如果有人知道这是不正确的,请发布另一个答案!)

更新:我发现了一篇关于 x86 调用约定的文章:http ://en.wikipedia.org/wiki/X86_calling_conventions

似乎证实了大多数调用约定,RDI 将被调用者保存。这并不能解释为什么它没有推送和弹出所有其他被调用者保存寄存器。也许这里还有其他事情发生。

于 2013-02-03T21:58:25.797 回答