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.
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.
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.
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.
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:
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.
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.
Wenn eax Null ist, wird der bedingte Sprung ausgeführt, andernfalls wird die Ausführung bei 319e9 fortgesetzt
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