В ассемблере, почему использование регистров отличается между сложением и вычитанием? - PullRequest
7 голосов
/ 13 ноября 2011

У меня есть очень основное сомнение здесь.У меня есть два очень простых кода 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 ]

10 голосов
/ 13 ноября 2011

Я предполагаю, потому что сложение коммутативно ( A + B == B + A ), а вычитание - нет ( A - B! = B - A ). Из-за этого добавление 9 + temp1 аналогично temp1 + 9, следовательно, более простая последовательность ассемблера. 9 - temp1 включает создание временной переменной.

2 голосов
/ 13 ноября 2011

Фактическая причина наблюдаемого поведения подразумевалась другими ответами, но никогда явно не упоминалась:

Типичные наборы команд для следующих вычислений:

%register := %register + $immediate [1]
%register := %register - $immediate [2]

Из-за коммутативности, [1] также может использоваться для вычисления

%register := $immediate + %register

Тем не менее, специальный оператор для

%register := $immediate - %register

обычно недоступен, что означает, что его нужно эмулировать, например, с помощью последовательности

%temp     := %register
%register := $immediate
%register := %register - %temp
2 голосов
/ 13 ноября 2011

temp1 = 9 - temp1; совпадает с temp1 = - temp1 + 9;. Это выполняет 2 операции:

  1. Отрицание temp1
  2. сделать сложение

eax используется как временное местоположение для сохранения среднего значения.

В дополнительном случае отсутствует «среднее значение», операцию можно выполнить напрямую.

1 голос
/ 13 ноября 2011

Причиной является отсутствие симметрии в наборе команд x86, который не содержит инструкции для вычитания регистра из константы.

Например, набор команд ARM содержит RSB (Обратный SuBtract) инструкция именно для этой цели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...