我在这里有一个非常基本的疑问。我有两个非常简单的C代码及其汇编代码:
计划1:
main()
{
int temp1, temp2, temp3;
char temp5, temp6, temp7, temp8, temp9;
temp1 = 5;
temp1 = 9 - temp1;
}
大会:
0x080483b4 <+0>: push ebp
0x080483b5 <+1>: mov ebp,esp
0x080483b7 <+3>: sub esp,0x20
0x080483ba <+6>: mov DWORD PTR [ebp-0xc],0x5
0x080483c1 <+13>: mov eax,0x9
0x080483c6 <+18>: sub eax,DWORD PTR [ebp-0xc]
0x080483c9 <+21>: mov DWORD PTR [ebp-0xc],eax
0x080483cc <+24>: leave
0x080483cd <+25>: ret
计划2:
main()
{
int temp1, temp2, temp3;
char temp5, temp6, temp7, temp8, temp9;
temp1 = 5;
temp1 = 9 + temp1;
}
大会:
0x080483b4 <+0>: push ebp
0x080483b5 <+1>: mov ebp,esp
0x080483b7 <+3>: sub esp,0x20
0x080483ba <+6>: mov DWORD PTR [ebp-0xc],0x5
0x080483c1 <+13>: add DWORD PTR [ebp-0xc],0x9
0x080483c5 <+17>: leave
0x080483c6 <+18>: ret
为什么在减法的情况下,需要使用eax寄存器而不是在添加的情况下。不能这样:
0x080483c1 <+13>: sub DWORD PTR [ebp-0xc],0x9
而不是 -
0x080483c1 <+13>: mov eax,0x9
0x080483c6 <+18>: sub eax,DWORD PTR [ebp-0xc]
答案 0 :(得分:10)
我猜是因为加法是可交换的( A + B == B + A ),而减法则不是( A - B!= B - A ) 。因此,9 + temp1
的添加与temp1 + 9
相同,因此组装器序列更简单。 9 - temp1
涉及创建临时变量。
答案 1 :(得分:2)
temp1 = 9 - temp1;
与temp1 = - temp1 + 9;
相同。这进行了2次操作:
temp1
eax
用作保存中间值的临时位置。
在添加的情况下,没有“中间值”,操作可以直接进行。
答案 2 :(得分:2)
其他答案暗示了观察到的行为的实际原因,但从未明确提及:
通用指令集具有以下计算的运算:
%register := %register + $immediate [1]
%register := %register - $immediate [2]
由于交换性,[1]
也可用于计算
%register := $immediate + %register
但是,
的专用操作%register := $immediate - %register
通常不可用,这意味着它必须被模拟,例如通过序列
%temp := %register
%register := $immediate
%register := %register - %temp
答案 3 :(得分:1)
原因是x86指令集缺乏对称性,它不包含从常量中减去寄存器的指令。
例如,ARM指令集完全包含RSB
(反向SuBtract)指令。