我试图更好地理解汇编,因此在调试代码时我一直关注 CDB 的汇编输出。我的平台是 Intel Xeon 和 Windows 7。
以下 C++ 代码:
int main()
{
int a = 30;
int b = 0;
b = ++a;
return 0;
}
使用增量运算符为该行生成以下汇编:
b = ++a;
0x13f441023 <+0x0013> mov eax,dword ptr [rsp]
0x13f441026 <+0x0016> inc eax
0x13f441028 <+0x0018> mov dword ptr [rsp],eax //Move eax to some memory address
0x13f44102b <+0x001b> mov eax,dword ptr [rsp] //Move it back to eax?
0x13f44102e <+0x001e> mov dword ptr [rsp+4],eax
我的问题是,将 eax
中的值移至内存,然后立即将相同的值移回 eax
中,如注释所示,目的是什么?这是为了线程安全,还是只是调试构建的一些工件?
最佳答案
编译器最初使用 static single assignment 将您的指令转换为汇编语言。值(SSA),这意味着每个操作都会获得一个临时值来存储其结果。仅在稍后的后端阶段,这些值才会根据您的目标机器被转换为机器寄存器,并且可能在必要时转换为内存位置(明确需要或由于缺少寄存器而溢出)。
在这些阶段之间,优化器可能会消除部分值,但最初++a 是一个操作,将 a(后增量)分配给 b 是第二个操作。由于 a 和 b 都是局部变量,因此它们将存储在堆栈中(并且必须在堆栈中可见,例如使用调试器单步执行),a 将驻留在 [rsp] 中,b 将驻留在 [rsp+4] 中。
所以你的编译器在某个时候可能有(以某种中间表示形式):
value1 = a
value2 = value1 + 1
a = value2 //self increment
b = a
或者类似的东西。 a 和 b 必须驻留在内存中,但操作通常在寄存器上完成,因此编译器首先会执行 -
value1 = a
value2 = value1 + 1
0x13f441023 <+0x0013> mov eax,dword ptr [rsp]
0x13f441026 <+0x0016> inc eax
a = value2
0x13f441028 <+0x0018> mov dword ptr [rsp],eax
b = a
0x13f44102b <+0x001b> mov eax,dword ptr [rsp]
0x13f44102e <+0x001e> mov dword ptr [rsp+4],eax
请注意,中间值保存在寄存器中 - 在正常编译中,它们可能会通过一次优化传递(在寄存器分配和代码生成之前)完全消除。
关于c++ - 对这段汇编代码感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32051085/