webentwicklung-frage-antwort-db.com.de

`testl` eax gegen eax?

Ich versuche, eine Versammlung zu verstehen.

Die Versammlung wie folgt, ich interessiere mich für die testl-Linie:

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

Ich versuche diesen Punkt von testl zwischen %eax und %eax zu verstehen. Ich denke, die Besonderheiten des Codes sind nicht wichtig. Ich versuche nur, den Test mit sich selbst zu verstehen.

108
maxpenguin

Es wird geprüft, ob eax 0 oder darüber oder darunter ist. In diesem Fall wird der Sprung ausgeführt, wenn eax 0 ist.

80

Die Bedeutung von test besteht darin, die Argumente UND zu verknüpfen und das Ergebnis auf Null zu prüfen. Dieser Code testet also, ob EAX Null ist oder nicht. je springt bei Null.

Übrigens, dies erzeugt eine kleinere Anweisung als cmp eax, 0, weshalb Compiler dies normalerweise tun.

86
Mike F

Der Testbefehl führt eine logische UND-Verknüpfung zwischen den Operanden aus, schreibt das Ergebnis jedoch nicht in ein Register zurück. Nur die Flags werden aktualisiert.

In Ihrem Beispiel wird der Test eax, eax das Null-Flag setzen, wenn eax Null ist, das Vorzeichen-Flag, wenn das höchste gesetzte Bit gesetzt ist, und einige andere Flags.

Der Befehl Jump if Equal (je) springt, wenn das Null-Flag gesetzt ist.

Sie können den Code in einen besser lesbaren Code wie folgt übersetzen:

cmp eax, 0
je  somewhere

Das hat die gleiche Funktionalität, erfordert aber einige Bytes mehr Code-Platz. Aus diesem Grund hat der Compiler einen Test ausgegeben, anstatt einen Vergleich durchzuführen. 

32

test ist wie and , es werden jedoch nur FLAGS geschrieben, wobei beide Eingänge unverändert bleiben. Bei zwei verschiedenen-Eingängen ist es hilfreich, um zu testen, ob einige Bits alle Null sind oder mindestens eines gesetzt ist. (z. B. setzt test al, 3 ZF, wenn EAX ein Vielfaches von 4 ist (und somit beide niedrigen 2 Bits auf Null gesetzt sind).


test eax,eax setzt alle Flags genau auf dieselbe Weise wie cmp eax, 0 würde:

  • CF und OF gelöscht (AND/TEST macht das immer; das Subtrahieren von Null erzeugt nie einen Übertrag)
  • ZF, SF und PF entsprechend dem Wert in EAX. (a = a&a = a-0)

(Mit Ausnahme des veralteten AF (Auxiliary-Carry-Flag, das von ASCII-/BCD-Befehlen verwendet wird). TEST lässt undefined , aber CMP setzt es "gemäß dem Ergebnis" . Da das Subtrahieren von Null nicht möglich ist einen Carry vom 4. bis zum 5. Bit erzeugen, CMP sollte immer den AF löschen.


TEST ist kleiner (nicht unmittelbar) und manchmal auch schneller (kann in mehr Fällen als CMP auf mehr CPUs Makro-Fuse in einen Compare-and-Branch-Betrieb aufnehmen). Das macht test zum bevorzugten Ausdruck für das Testen eines Registers auf Null oder nicht .

Der einzige häufige Grund für die Verwendung von CMP mit einer direkten 0 ist der Vergleich mit einem Speicheroperanden (z. B. cmpb $0, (%esi), um nach einem abschließenden Null-Byte am Ende einer impliziten Zeichenfolge im C-Stil zu suchen).


AVX512F fügt kortestw k1, k2 und AVX512DQ/BW (Skylake, aber nicht KNL) fügt ktestb/w/d/q k1, k2 hinzu, die mit den AVX512-Maskenregistern (k0..k7) arbeiten, aber weiterhin reguläre FLAGS wie test verwenden Genauso wie die Ganzzahl OR- oder AND-Anweisungen.

kortestw k1,k1 ist die idiomatische Methode zum Verzweigen von/cmovcc/setcc basierend auf einem AVX512-Vergleichsergebnis und ersetzt SSE/AVX2 (v)pmovmskb/ps/pd + test oder cmp.


Die Verwendung von jz vs. je kann verwirrend sein.

jz und je sind buchstäblich die gleiche Anweisung , d. h. der gleiche Opcode im Maschinencode. Sie tun das Gleiche, haben aber für den Menschen eine andere semantische Bedeutung. Disassembler (und normalerweise als Ausgabe von Compilern) verwenden immer nur einen, so dass die semantische Unterscheidung verloren geht.

cmp und sub setzen ZF, wenn ihre beiden Eingänge gleich sind (d. h. das Ergebnis der Subtraktion ist 0). je (Sprung wenn gleich) ist das semantisch relevante Synonym.

test %eax,%eax/and %eax,%eax setzt erneut ZF, wenn das Ergebnis Null ist, es gibt jedoch keinen "Gleichheitstest". ZF after test sagt Ihnen nicht, ob die beiden Operanden gleich waren. jz (Sprung, wenn Null) ist das semantisch relevante Synonym.

19
Peter Cordes

Dieses Codefragment stammt aus einer Subroutine, der ein Zeiger auf etwas gegeben wurde, wahrscheinlich auf eine Struktur oder ein Objekt. In der zweiten Zeile wird der Zeiger dereferenziert, wobei ein Wert von diesem Objekt abgerufen wird - möglicherweise selbst ein Zeiger oder möglicherweise nur ein Int., Das als sein zweites Glied (Offset +4) gespeichert wird. Die 3. und 4. Zeile testen diesen Wert auf Null (NULL, wenn es sich um einen Zeiger handelt) und überspringt die folgenden wenigen Operationen (nicht gezeigt), wenn er Null ist.

Der Test auf Null ist manchmal als Vergleich mit einem direkten literalen Nullwert codiert, aber der Compiler (oder ein Mensch?), Der dies geschrieben hat, hätte gedacht, dass ein Testlop schneller laufen würde - unter Berücksichtigung aller modernen CPU-Dinge wie Pipelining und Register Umbenennung. Aus demselben Trickkoffer folgt die Idee, ein Register mit XOR EAX, EAX (was ich auf einem Nummernschild in Colorado gesehen habe!) Zu löschen, anstatt den offensichtlichen, aber möglicherweise langsameren MOV EAX # 0 (i Verwenden Sie eine ältere Notation). 

In asm wie in Perl TMTOWTDI.

5
DarenW

Wenn eax Null ist, wird der bedingte Sprung ausgeführt, andernfalls wird die Ausführung bei 319e9 fortgesetzt

3
Mike Thompson

In einigen Programmen können sie zur Überprüfung eines Pufferüberlaufs verwendet werden. Ganz oben auf dem zugewiesenen Platz wird eine 0 gesetzt. Nach der Eingabe von Daten in den Stack sucht er ganz am Anfang des zugewiesenen Speicherplatzes nach 0, um sicherzustellen, dass der zugewiesene Speicherplatz nicht überläuft. 

Es wurde in der stack0-Übung von Exploits-Übungen verwendet, um zu überprüfen, ob es überläuft und wenn es keine und dort eine Null gab, würde es "Try again" anzeigen.

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
user7259278