2008-09-29 17 views
101

Próbuję zrozumieć niektóre zgromadzenia.`testl` eax przeciwko eax?

Zespół następująco, jestem zainteresowany w linii testl:

000319df 8b4508  movl 0x08(%ebp), %eax 
000319e2 8b4004  movl 0x04(%eax), %eax 
000319e5 85c0   testl %eax, %eax 
000319e7 7407   je  0x000319f0 

Próbuję zrozumieć tego punktu testl między %eax i %eax? Myślę, że specyfikę tego, co ten kod nie jest ważny, próbuję po prostu zrozumieć test sam w sobie - czy wartość nie zawsze byłaby prawdziwa?

Odpowiedz

73

Testuje, czy eax ma wartość 0 lub więcej, lub mniej. W tym przypadku, skok jest wykonywany, jeśli eax jest równy 0.

+0

Zrobiłem edycję, aby zmienić tę popularną odpowiedź w lepszą kanoniczną odpowiedź na pytanie "czym jest ta TEST, a czym różni się od CMP", co jest w pewien sposób dorozumiane. Zobacz moją własną odpowiedź na dalsze komentarze dotyczące semantycznego znaczenia synonimicznego JE i JZ. Przejrzyj moją edycję, ponieważ jest dość poważna i wciąż jest twoją odpowiedzią. –

+0

@PeterCordes Doceniam zamiar, ale zamierzam przywrócić twoją edycję. 1. Twój "głos" bardzo różni się od mojego, a teraz brzmi znacznie bardziej jak twoja odpowiedź niż moja. 2. Bardziej problematyczne jest pogrubione twierdzenie, że flagi wychodzą dokładnie tak samo pomiędzy 'test' i' cmp'. Tak, rozumiem, że to twoje przekonanie oparte na twoich komentarzach do Cody'ego. Jednak umieszczenie go w moim poście to inna sprawa; nie jest to stwierdzenie, które chcę podtrzymać, po prostu dlatego, że nie wiem, czy jest identyczne we wszystkich przypadkach. –

+0

@PeterCordes Rozumiem chęć posiadania "kanonicznej" odpowiedzi, ale myślę, że twoja odpowiedź musi pływać lub zatapiać się na własnych zaletach, zamiast piggyback na zaakceptowanej odpowiedzi. Musiałem to zrobić również w przypadku niektórych moich odpowiedzi na bardzo popularne pytania, takie jak [zmiennoprzecinkowe] (http://stackoverflow.com/a/27030789/13), które w momencie publikacji mojego Odpowiedź już zawierała inne odpowiedzi z ponad 500 wyższymi nagrodami. –

82

Znaczenie test to razem argumenty i sprawdzenie wyniku na zero. Ten kod testuje, czy EAX ma wartość zero, czy nie. je przeskoczy jeśli zero.

BTW generuje mniejszą instrukcję niż cmp eax, 0, co jest powodem, że kompilatory będą generalnie robić to w ten sposób.

3

Jeśli EAX jest zerowy będzie wykonać skok warunkowy, inaczej będzie kontynuować wykonywanie w 319e9

31

Dyspozycja testy robi logiczną AND-działanie pomiędzy argumentami, ale nie pisze wynik z powrotem do rejestru. Aktualizowane są tylko flagi.

W twoim przykładzie test eax, eax ustawi flagę zero, jeśli eax wynosi zero, flagę znaku, jeśli ustawiono najwyższy bit i kilka innych flag.

Instrukcja Jump, Equal (je) przeskakuje, jeśli ustawiona jest flaga zero.

można przetłumaczyć kod do bardziej czytelnego kodu:

cmp eax, 0 
je somewhere 

który ma taką samą funkcjonalność, ale wymaga pewnych bajtów więcej kodu przestrzeni. Z tego powodu kompilator emitował test zamiast porównywania.

+3

W rzeczywistości, cmp może tam nie działać. Oznacza to, że działa dla konkretnego przedstawionego przypadku, ale cmp wpływa na flagi inaczej niż test, ponieważ jest to wewnętrzny sub, zamiast i. Coś, o czym należy pamiętać. –

+4

dla testu zerowego jest całkowicie poprawny. –

+3

Ale nie wiesz, co jeszcze patrzy na flagi później. Efekty na flagach są bardzo różne, więc może to stanowić problem i bardzo często jest. –

5

Ten fragment kodu pochodzi z podprogramu, któremu nadano wskaźnik do czegoś, prawdopodobnie do jakiejś struktury lub obiektu. Druga linia oddziela ten wskaźnik, pobierając wartość z tej rzeczy - być może sam wskaźnik lub może tylko int, przechowywany jako drugi element (przesunięcie +4). Trzecia i czwarta linia testują tę wartość na zero (NULL, jeśli jest wskaźnikiem) i pomijają kilka następujących operacji (nie pokazano), jeśli są zerowe.

Test na zero czasami jest kodowany jako porównanie z bezpośrednią dosłowną wartością zerową, ale kompilator (lub człowiek?), Który to napisał, mógł pomyśleć, że testl op przebiegnie szybciej - biorąc pod uwagę wszystkie nowoczesne elementy procesora jak pipelining i zmiana nazwy. To z tego samego worka sztuczek, który trzyma pomysł wyczyszczenia rejestru za pomocą XOR EAX, EAX (który widziałem na czyjejś tablicy rejestracyjnej w Kolorado!) Zamiast oczywistego, ale może wolniej MOV EAX, # 0 (używam starszej notacji).

W ASM, jak perl, TMTOWTDI.

15

jest podobny do and, z wyjątkiem tego, że zapisuje tylko FLAGI, pozostawiając oba wejścia niezmodyfikowane. Z dwoma różnymi wejściami , jest to przydatne do testowania, czy niektóre bity są zerowe, lub jeśli przynajmniej jeden jest ustawiony. (na przykład.test al, 3 ustawia ZF, jeśli EAX jest wielokrotnością 4 (a zatem ma oba niskie 2 bity wyzerowane).


test eax,eax zestawy Wszystkie flagi dokładnie taki sam sposób, w jaki cmp eax, 0 by:

  • CF i rozjaśniająca (i/TEST zawsze to robi, a odjęcie zera nigdy produkuje carry)
  • ZF, SF i PF zgodnie z wartością w EAX. (a = a&a = a-0)

(wyjątkiem przestarzałego flagą AF (pomocniczy carry, wykorzystywanych przez instrukcje ASCII/BCD). TEST leaves it undefined, ale CMP sets it "according to the result". Od odjęcie zera nie może produkować carry od 4 do 5 bitów, CMP powinien zawsze usuwać AF).


TEST jest mniejsza (natychmiastowego), a czasem szybciej (można makro-bezpiecznik w UOP porównać i-oddział na więcej procesorów w większej liczbie przypadków niż CMP). That makes test the preferred idiom for testing a register for zero or not.

Jedynym częstym powodem używania CMP z bezpośrednim 0 jest porównanie z operandem pamięci (na przykład cmpb $0, (%esi), aby sprawdzić końcowy bajt zerowy na końcu ciągu znaków w stylu C o niejawnej długości) .


AVX512F dodaje kortestw k1, k2 i AVX512DQ/BW (Skylake ale nie KNL) dodać ktestb/w/d/q k1, k2, które działają na rejestrach AVX512 Maska (k0..k7), ale nadal określonych regularnych FLAGI jak test robi, w taki sam sposób, że liczby całkowite OR lub AND do zrobienia.

kortestw k1,k1 jest idiomatycznych sposobem na Oddziale/cmovcc/setcc oparciu o AVX512 porównać wynik, zastępując SSE/AVX2 (v)pmovmskb/ps/pd + test lub cmp.


Zastosowanie jz vs. je może być mylące.

jz and je are literally the same instruction, tj. Ten sam kod operacji w kodzie maszynowym. Robią to samo, ale mają inne znaczenie semantyczne dla ludzi. Dezasemblery (i zazwyczaj asm wyprowadzane z kompilatorów) użyją tylko jednego, więc rozróżnienie semantyczne zostanie utracone.

cmp i sub ustawić ZF, gdy ich dwa wejścia są równe (tj. Wynik odejmowania wynosi 0). je (jump if equal) jest semantycznie istotnym synonimem.

test %eax,%eax/and %eax,%eax ponownie ustawia ZF, gdy wynik wynosi zero, ale nie ma testu "równości". ZF po teście nie mówi, czy oba argumenty były równe. Tak więc jz (przeskok, jeśli zero) jest semantycznie istotnym synonimem.

+0

Uważam, że dodanie podstawowych informacji o operacji 'test' bitwise' i 'operacja, może nie być oczywiste dla ludzi, którzy dopiero uczą się montażu (i są leniwi/nieświadomi sprawdzanie instrukcji obsługi instrukcji co 60 sekund;) :)). – Ped7g

+1

@ Ped7g: Wystarczająco, myślę, że nie zaszkodzi umieścić wszystko w tej odpowiedzi, zamiast pozostawiać tę część innym odpowiedziom. Dodano AVX512 'kortest *' i 'ktest *' podczas gdy byłem na tym. –

0

W niektórych programach mogą być używane do sprawdzania przepełnienia bufora. Na samej górze przydzielonego miejsca znajduje się 0.Po wprowadzeniu danych do stosu, wyszukuje wartość 0 na samym początku przydzielonego miejsca, aby upewnić się, że przydzielone miejsce nie zostało przepełnione.

Był on używany w wykonywaniu stack0 exploitów-ćwiczenia, aby sprawdzić czy to był przepełniony i jeśli tam nie było i nie było tam zero, to wyświetli „Spróbuj ponownie”

0x080483f4 <main+0>: push ebp 
0x080483f5 <main+1>: mov ebp,esp 
0x080483f7 <main+3>: and esp,0xfffffff0 
0x080483fa <main+6>: sub esp,0x60      
0x080483fd <main+9>: mov DWORD PTR [esp+0x5c],0x0 ;puts a zero on stack 
0x08048405 <main+17>: lea eax,[esp+0x1c] 
0x08048409 <main+21>: mov DWORD PTR [esp],eax 
0x0804840c <main+24>: call 0x804830c <[email protected]> 
0x08048411 <main+29>: mov eax,DWORD PTR [esp+0x5c] 
0x08048415 <main+33>: test eax,eax     ; checks if its zero 
0x08048417 <main+35>: je  0x8048427 <main+51> 
0x08048419 <main+37>: mov DWORD PTR [esp],0x8048500 
0x08048420 <main+44>: call 0x804832c <[email protected]> 
0x08048425 <main+49>: jmp 0x8048433 <main+63> 
0x08048427 <main+51>: mov DWORD PTR [esp],0x8048529 
0x0804842e <main+58>: call 0x804832c <[email protected]> 
0x08048433 <main+63>: leave 
0x08048434 <main+64>: ret 
+0

Nie widzę, co ten konkretny przypadek sprawdzania rejestru dla niezerowego dodaje do tego pytania i odpowiedzi. Zwłaszcza, gdy 'cmp DWORD PTR [esp + 0x5c], 0' /' 0x 0x8048427 'byłoby wydajniejsze niż oddzielne obciążenie MOV, a następnie TEST. Nie jest to typowy przypadek użycia do sprawdzania zerowego. –

-2

mogliśmy zobaczyć JG, JLE Jeśli testl %edx,%edx. jle .L3 możemy łatwo znaleźć JLE jest garnitur (SF^OF)|ZF, jeśli% EDX jest zero, ZF = 1, ale jeśli% edx nie wynosi zero i jest -1, po testl, OF = 0 i SF = 1, więc flaga = true, która implementuje skok .sorry, mój angielski jest słaby

Powiązane problemy