2011-11-13 7 views
7

Mam tu podstawową wątpliwość. Mam dwóch bardzo prostych kodów C oraz kodów montażu:Dlaczego w asemblerach korzystanie z rejestrów różni się od dodawania i odejmowania?

Program 1:

main() 

{ 

    int temp1, temp2, temp3; 
    char temp5, temp6, temp7, temp8, temp9; 
    temp1 = 5; 
    temp1 = 9 - temp1; 
} 

Montaż:

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 

Program 2:

main()  
{  
    int temp1, temp2, temp3; 
    char temp5, temp6, temp7, temp8, temp9; 
    temp1 = 5; 
    temp1 = 9 + temp1;  
} 

Montaż:

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 

Dlaczego w przypadku odejmowania należy użyć rejestru eax, a nie w przypadku dodawania. Nie może być tak:

0x080483c1 <+13>: sub DWORD PTR [ebp-0xc],0x9 

zamiast -

0x080483c1 <+13>: mov eax,0x9 

0x080483c6 <+18>: sub eax,DWORD PTR [ebp-0xc] 
+0

nr. W kodzie C odejmujesz zmienną od 9. W twoim zestawie powinieneś odjąć rejestr od 9, czyli od kodu zespołu, a nie pod DWORD PTR [ebp-0xc], 0x9 . Na kodzie zestawu, eax jest odejmowany z 5. W twoim założeniu odejmujesz 5 za pomocą 9. –

+0

czy kompilowałeś z włączonymi optymalizacjami? – ninjalj

+0

@ninjalj: Oczywiście, że nie. Ponieważ w przeciwnym razie cała rzecz z pewnością zostałaby zoptymalizowana do pojedynczego "ret". – celtschk

Odpowiedz

10

Zgaduję, ponieważ dodawanie jest przemienne (A + B + A == B), natomiast nie jest odejmowanie (A - B! = B - A). Z tego powodu dodanie 9 + temp1 jest takie samo jak temp1 + 9, stąd prostsza sekwencja asemblera. 9 - temp1 polega na tworzeniu zmiennej tymczasowej.

+4

miałeś na myśli przemówienie: asocjacyjne * (A + B) + C == A + (B + C) * – Christoph

+4

Rzeczywiście zrobiłem Cristoph, dwie dekady od mojej ostatniej lekcji matematyki i dwóch piw między tym a następnym. –

2

temp1 = 9 - temp1; jest taki sam jak temp1 = - temp1 + 9;. To prowadzi 2 operacje:

  1. negować temp1
  2. wykonaj dodawanie

eax służy jako tymczasowej lokalizacji, aby zapisać wartość środkową.

W przypadku dodawania nie ma "wartości średniej", operację można wykonać bezpośrednio.

+0

Ta odpowiedź nie wyjaśnia, co jest zadawane w pytaniu. Ponadto kod zespołu nie zawiera instrukcji negacji. – Nayuki

2

Rzeczywista przyczyna obserwowanego zachowania została implikowane przez innych odpowiedzi, ale nigdy wyraźnie wymienione:

ustala wspólne instrukcje wyposażone ops dla następujących obliczeń:

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

powodu przemienności, [1] mogą być również wykorzystywane do obliczania

%register := $immediate + %register 

jednak dedykowany op dla

%register := $immediate - %register 

na ogół nie są dostępne, co oznacza, że ​​musi być emulowane, na przykład przez sekwencję

%temp  := %register 
%register := $immediate 
%register := %register - %temp 
1

powodem jest brak symetrii zestawu instrukcji x 86, który nie zawiera instrukcja odejmowania rejestru od stałej.

Na przykład zestaw instrukcji ARM zawiera dokładnie instrukcję RSB (Reverse SuBtract) do tego celu.

+0

W rzeczywistości zestaw instrukcji ARM jest w tym przypadku niesymetryczny - brakuje mu (oczywiście bezużytecznego) instrukcji 'reverse add', gdzie x86 w tym przypadku jest symetryczny - brak w nim obu instrukcji, użytecznego odwrotnego odejmowania i bezużytecznego odwrotnego dodania . Głębszym tego powodem (i potrzebą odwróconego suba) jest oczywiście brak symetrii w odejmowaniu - nie jest przemienny. – hirschhornsalz

+0

Symetria w tym przypadku jest między dwoma sposobami odejmowania. – starblue

+1

Nawiasem mówiąc, mikrokontrolery marki PIC mają instrukcję "odejmowanie W od stałej", ale nie "odejmuj stałej od rejestru W", ponieważ ostatnia instrukcja może być symulowana przez dodanie 256-stałej. – supercat

Powiązane problemy