Ich versuche eine Versammlung zu verstehen.
Die Montage wie folgt interessiert mich an der 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 testl
zwischen %eax
und zu verstehen %eax
? Ich denke, die Einzelheiten dieses Codes sind nicht wichtig. Ich versuche nur, den Test mit sich selbst zu verstehen. Wäre der Wert nicht immer wahr?
assembly
x86
instructions
Maxpenguin
quelle
quelle
test
und genau gleich herauskommencmp
. Ja, ich verstehe, dass dies Ihre Überzeugung ist, basierend auf Ihren Kommentaren zu Cody. Es ist jedoch eine andere Sache, es in meinen Beitrag aufzunehmen. Es ist keine Behauptung, zu der ich bereit bin, einfach weil ich nicht weiß, ob sie in allen Fällen identisch ist.je
,jz
,cmp
, undtest
, und nicht JE, JZ, CMP oder TEST. Ich bin so wählerisch.test a,a
undcmp $0,a
Flags identisch zu setzen. Vielen Dank für den Hinweis, dass dies eine nicht triviale Behauptung ist. re: TEST vs.: Vortest
kurzem habe ich angefangen, All-Caps wie Intels Handbücher zu verwenden. Aber wenn ich über AT & T-Mnemonik im Vergleich zu Intel-Mnemonik spreche, verwende ichtestb
Stil für AT & T. IDK, wenn dies die Lesbarkeit verbessert.Die Bedeutung von
test
ist, die Argumente zusammen UND zu verknüpfen und das Ergebnis auf Null zu überprüfen. Dieser Code testet also, ob EAX Null ist oder nicht.je
wird springen, wenn Null.Übrigens erzeugt dies einen kleineren Befehl als
cmp eax, 0
der Grund, warum Compiler dies im Allgemeinen auf diese Weise tun.quelle
Der Testbefehl führt eine logische UND-Verknüpfung zwischen den Operanden durch, schreibt das Ergebnis jedoch nicht zurück in ein Register. Nur die Flags werden aktualisiert.
In Ihrem Beispiel setzt der Test eax, eax das Null-Flag, wenn eax Null ist, das Vorzeichen-Flag, wenn das höchste 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:
Das hat die gleiche Funktionalität, erfordert aber einige Bytes mehr Code-Speicherplatz. Aus diesem Grund hat der Compiler einen Test anstelle eines Vergleichs ausgegeben.
quelle
test eax, eax
undcmp eax, 0
beide setzen alle Flags und setzen sie auf identische Werte. Beide Anweisungen setzen alle Flags "entsprechend dem Ergebnis". Das Subtrahieren0
kann niemals zu einem Übertrag oder Überlauf führen. Ihr Argument ist korrekt für alle anderen als 0, aber nicht für 0.test
ist wieand
, außer dass es nur FLAGS schreibt und beide Eingaben unverändert lässt. Mit zwei verschiedenen Eingängen ist es nützlich zu testen, ob einige Bits alle Null sind oder ob mindestens eines gesetzt ist. (z. B.test al, 3
setzt 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 die gleiche Art und Weise,cmp eax, 0
würde :a = a&a = a-0
).(PF wird wie gewohnt nur auf die niedrigen 8 Bits eingestellt )
Mit Ausnahme des veralteten AF (Auxiliary-Carry-Flag, das von ASCII / BCD-Anweisungen verwendet wird). TEST lässt es undefiniert , aber CMP setzt es "entsprechend dem Ergebnis" . Da das Subtrahieren von Null keinen Übertrag vom 4. zum 5. Bit erzeugen kann, sollte CMP immer AF löschen.
TEST ist kleiner (kein sofortiger) und manchmal schneller (kann in mehr Fällen als CMP auf mehr CPUs zu einem Vergleichs- und Verzweigungs-UOP verschmelzen). Das macht
test
die bevorzugte Redewendung zum Vergleichen eines Registers mit Null . Es ist eine Gucklochoptimierungcmp reg,0
, die Sie unabhängig von der semantischen Bedeutung verwenden können.Der einzige häufige Grund für die Verwendung von CMP mit einer unmittelbaren 0 ist, wenn Sie mit einem Speicheroperanden vergleichen möchten. Zum Beispiel,
cmpb $0, (%esi)
um am Ende einer Zeichenfolge im C-Stil mit impliziter Länge nach einem abschließenden Null-Byte zu suchen.AVX512F fügt hinzu
kortestw k1, k2
und AVX512DQ / BW (Skylake-X, aber nicht KNL) fügt hinzuktestb/w/d/q k1, k2
, die mit AVX512-Maskenregistern (k0..k7) arbeiten, aber weiterhin reguläre FLAGS setzen, wietest
dies bei GanzzahlenOR
oderAND
Anweisungen der Fall ist . (Ähnlich wie SSE4ptest
oder SSEucomiss
: Eingaben in die SIMD-Domäne und Ergebnis in ganzzahligen FLAGS.)kortestw k1,k1
ist die idiomatische Methode zum Verzweigen von / cmovcc / setcc basierend auf einem AVX512-Vergleichsergebnis, wobei SSE / AVX2(v)pmovmskb/ps/pd
+test
oder ersetzt werdencmp
.Die Verwendung von
jz
vs.je
kann verwirrend sein.jz
undje
sind buchstäblich die gleiche Anweisung , dh der gleiche Opcode im Maschinencode. Sie tun dasselbe, haben aber für den Menschen eine andere semantische Bedeutung . Disassembler (und normalerweise Asm-Ausgaben von Compilern) verwenden immer nur einen, sodass die semantische Unterscheidung verloren geht.cmp
undsub
setze ZF, wenn ihre zwei Eingänge gleich sind (dh das Subtraktionsergebnis 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, aber es gibt keinen "Gleichheitstest". ZF nach dem Test sagt Ihnen nicht, ob die beiden Operanden gleich waren. Alsojz
(Sprung wenn Null) ist das semantisch relevante Synonym.quelle
test
den bitweisenand
Betrieb hinzuzufügen. Dies ist möglicherweise nicht offensichtlich für Leute, die nur das Zusammenbauen lernen (und faul sind / nicht wissen, dass sie alle 60 Sekunden die Referenzanleitung überprüfen müssen;) :)).kortest*
undktest*
während ich dabei war.Dieser Codeausschnitt stammt aus einer Unterroutine, die einen Zeiger auf etwas erhalten hat, wahrscheinlich auf eine Struktur oder ein Objekt. Die 2. Zeile dereferenziert diesen Zeiger und ruft einen Wert von diesem Ding ab - möglicherweise selbst einen Zeiger oder nur ein Int, der als 2. Element gespeichert ist (Offset +4). Die 3. und 4. Zeile testen diesen Wert auf Null (NULL, wenn es sich um einen Zeiger handelt) und überspringen die folgenden wenigen Operationen (nicht gezeigt), wenn er Null ist.
Der Test für Null wird manchmal als Vergleich mit einem unmittelbaren wörtlichen Nullwert codiert, aber der Compiler (oder Mensch?), Der dies geschrieben hat, könnte gedacht haben, dass ein Testlop schneller laufen würde - unter Berücksichtigung aller modernen CPU-Dinge wie Pipelining und Register Umbenennung. Es ist aus der gleichen Trickkiste, die die Idee enthält, ein Register mit XOR EAX, EAX (das ich auf einem Nummernschild in Colorado gesehen habe!) Zu löschen, anstatt mit dem offensichtlichen, aber vielleicht langsameren MOV EAX, # 0 (ich verwende eine ältere Notation) ).
In asm, wie Perl, TMTOWTDI.
quelle
Wenn eax Null ist, wird der bedingte Sprung ausgeführt, andernfalls wird die Ausführung bei 319e9 fortgesetzt
quelle
In einigen Programmen können sie verwendet werden, um nach einem Pufferüberlauf zu suchen. Ganz oben auf dem zugewiesenen Platz wird eine 0 platziert. Nach der Eingabe von Daten in den Stapel wird ganz am Anfang des zugewiesenen Speicherplatzes nach der 0 gesucht, 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 übergelaufen ist und wenn es keine Null gibt und dort eine Null angezeigt wird, wird "Erneut versuchen" angezeigt.
quelle
cmp DWORD PTR [esp+0x5c], 0
/jz 0x8048427 <main+51>
wäre effizienter gewesen als eine separate MOV-Last und dann TEST. Dies ist kaum ein üblicher Anwendungsfall für die Überprüfung auf eine Null.wir könnten das jg,jle sehen Wenn
testl %edx,%edx. jle .L3
wir leicht herausfinden könnten, dass jle passt(SF^OF)|ZF
, wenn% edx Null ist, ist ZF = 1, aber wenn% edx nicht Null ist und -1 ist, nach dem Test, dem OF = 0 und dem SF = 1, also das Flag = true, das den Sprung implementiert. Tut mir leid, mein Englisch ist schlechtquelle