在汇编程序中,为什么寄存器的使用在加法和减法之间有所不同?

时间:2011-11-13 11:21:36

标签: c assembly x86

我在这里有一个非常基本的疑问。我有两个非常简单的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]

4 个答案:

答案 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次操作:

  1. 否定temp1
  2. 执行添加
  3. 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)指令。