wake-up-neo.com

Der Testpunkt% eax% eax

Mögliches Duplikat:
x86 Assembly - ‘testl’ eax gegen eax?

Ich bin sehr, sehr neu in der Assembler-Programmierung und versuche gerade, die Assembler-Sprache zu lesen, die aus einer Binärdatei generiert wurde. Ich bin rüber gelaufen

 test   %eax,%eax

oder test %rdi, %rdi usw. usw. Ich bin sehr verwirrt darüber, was dies tut. Sind die Werte in %eax, %eax das Gleiche? Was testet es? Ich habe irgendwo gelesen, dass es die AND -Operation ausführt ... aber da sie denselben Wert haben, würde es nicht einfach %eax?

Das Folgende ist nur eine Instanz, in der ich diese Verwendung gefunden habe:

   400e6e:       85 c0                   test   %eax,%eax
   400e70:       74 05                   je     400e77 <phase_1+0x23>

Ich dachte, je springt, wenn die beiden verglichenen Werte gleich sind ...... na ja, weil %eax Ist es gut, in welcher Situation würden wir NICHT springen?

Ich bin ein Anfänger in der Programmierung im Allgemeinen, daher würde ich es sehr begrüßen, wenn mir jemand dies erklären könnte. Vielen Dank!

116
pauliwago

CMP subtrahiert die Operanden und setzt die Flags. Es setzt nämlich das Null-Flag, wenn die Differenz Null ist (Operanden sind gleich).

TEST setzt das Null-Flag ZF, wenn das Ergebnis der AND-Operation Null ist. Wenn zwei Operanden gleich sind, ist ihr bitweises UND Null, wenn beide Null sind. TEST setzt auch das Vorzeichen-Flag SF, wenn das höchstwertige Bit im Ergebnis gesetzt ist, und das Paritäts-Flag PF, wenn die Anzahl der gesetzten Bits gerade ist .

JE [Jump if Equals] testet das Null-Flag und springt, wenn das Flag gesetzt ist. JE ist ein Alias ​​von JZ [Jump if Zero], sodass der Disassembler basierend auf dem Opcode keinen auswählen kann. JE heißt so, weil das Null-Flag gesetzt wird, wenn die Argumente für CMP gleich sind.

So,

TEST %eax, %eax
JE   400e77 <phase_1+0x23>

springt, wenn der %eax ist Null.

134
John Dvorak

Einige x86-Befehle sind so konzipiert, dass der Inhalt der Operanden (Register) unverändert bleibt und nur bestimmte interne CPU-Flags wie das Zero-Flag (ZF) gesetzt/deaktiviert werden. Sie können sich das ZF als ein wahr/falsch-Boolesches Flag vorstellen, das sich in der CPU befindet.

In diesem speziellen Fall führt der TEST-Befehl ein bitweises logisches UND aus, verwirft das tatsächliche Ergebnis und setzt/deaktiviert das ZF gemäß dem Ergebnis des logischen und: Wenn das Ergebnis Null ist, setzt es ZF = 1, andernfalls setzt es ZF = 1 setzt ZF = 0.

Anweisungen für bedingte Sprünge wie JE dienen dazu, den ZF auf Sprünge/Sprünge zu untersuchen. Wenn Sie also TEST und JE zusammen verwenden, können Sie einen bedingten Sprung ausführen, der auf dem Wert eines bestimmten Registers basiert:

Beispiel:

TEST EAX, EAX
JE irgendeine_Adresse

springt die CPU genau dann auf "some_address", wenn ZF = 1, also genau dann, wenn AND (EAX, EAX) = 0, was wiederum genau dann vorkommen kann, wenn EAX == 0

Der entsprechende C-Code lautet:

if(eax == 0)
{
    goto some_address
}
46

Dies prüft, ob EAX Null ist. Die Anweisung test fügt die Argumente bitweise in AND ein, und wenn EAX Null enthält, setzt das Ergebnis ZF oder ZeroFlag.

12
ppeterka

Sie haben Recht, dass test "und" die beiden Operanden sind. Aber das Ergebnis wird verworfen, das einzige, was bleibt, und das ist der wichtige Teil, sind die Flags. Sie werden gesetzt und das ist der Grund, warum die Anweisung test verwendet wird (und existiert).

JE springt nicht, wenn es gleich ist (es hat die Bedeutung, als die Anweisung zuvor ein Vergleich war), was es wirklich tut, es springt, wenn das Flag ZF gesetzt ist. Und da es eines der Flags ist, das von test gesetzt wird, hat diese Befehlssequenz (test x, x; je ...) die Bedeutung, dass es übersprungen wird, wenn x 0 ist.

Bei Fragen wie diesen (und für weitere Details) kann ich nur ein Buch über x86-Anweisungen empfehlen, z. Auch wenn es wirklich groß ist, ist die Intel-Dokumentation sehr gut und präzise.

4
flolo

test ist ein zerstörungsfreies and, gibt das Ergebnis der Operation nicht zurück, setzt aber das Flags-Register entsprechend. Um zu wissen, was es wirklich testet, müssen Sie die folgenden Anweisungen überprüfen. Oft wird out verwendet, um ein Register gegen 0 zu prüfen, möglicherweise gekoppelt mit einem jz -bedingten Sprung.

3