在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
答案 0 :(得分:7)
没有目的。这是未经优化的代码的常见工件。代码生成器在预期必须执行添加时发出push edi
指令。必须在函数调用之间保留EDI寄存器。但后来,他们发现可以在编译时执行添加。
摆脱这样的无关代码需要"peephole optimization"。但是在Debug构建中未启用该优化。要知道真正的代码是什么样的,你必须打开优化器,最好通过构建Release构建来完成。它实际上将完全消除该功能,您可以通过以下方式阻止它:
__declspec(noline) int calc()
{
return 8 + 7;
}
在Release版本中生成:
return 8 + 7;
000007F7038E1000 mov eax,0Fh
000007F7038E1005 ret
答案 1 :(得分:3)
您是否听说过“来电保存”和“被调用者保存”寄存器?
由于您的CPU只有少量有限数量的寄存器,因此调用者/被调用函数通常不可能始终使用不同的寄存器。如果调用者函数和被调用函数都想使用相同的寄存器,则意味着调用者中的值必须在调用之前/之后保存/恢复。
保存/恢复寄存器值可以由调用者或被调用者完成 - 这是一个常规问题。 “调用者保存”寄存器的好处是,如果调用者知道在调用后它不需要寄存器XYZ中的值,它可以省略保存/恢复操作。 “callee-save”寄存器的好处是,如果被调用者知道它不会修改寄存器XYZ中的值,它可以省略保存/恢复操作。
我猜你的编译器将RDI视为被调用者保存寄存器,但除非你打开了编译器优化,否则不会省略不必要的保存/恢复操作。 (如果有人知道这是不正确的,请发布另一个答案!)
更新:我发现了一篇关于x86调用约定的文章:http://en.wikipedia.org/wiki/X86_calling_conventions
似乎证实,对于大多数调用约定,RDI将是被调用者保存。这并不能解释为什么它不会推送和弹出所有其他被调用者保存寄存器。也许这里还有别的东西。