Intel x86 Assembly Language & Microarchitecture
Kontrollfluss
Suche…
Bedingungslose Sprünge
jmp a_label ;Jump to a_label
jmp bx ;Jump to address in BX
jmp WORD [aPointer] ;Jump to address in aPointer
jmp 7c0h:0000h ;Jump to segment 7c0h and offset 0000h
jmp FAR WORD [aFarPointer] ;Jump to segment:offset in aFarPointer
Relative Nahsprünge
jmp a_label ist:
- nahe
Es gibt nur den Offset-Teil der logischen Adresse des Ziels an. Das Segment wird alsCS. - relativ
Die Anweisungssemantik springt rel Bytes vorwärts von der nächsten Anweisungsadresse 1 oderIP = IP + rel.
Der Befehl wird entweder als EB <rel8> oder EB <rel16/32> , wobei der Assembler die am besten geeignete Form EB <rel16/32> , wobei er normalerweise eine kürzere Form bevorzugt.
Pro Assembler-Überschreibung ist möglich, zum Beispiel mit NASM jmp SHORT a_label , jmp WORD a_label und jmp DWORD a_label generieren die drei möglichen Formulare.
Absolute indirekte Nahsprünge
jmp bx und jmp WORD [aPointer] sind:
- nahe
Sie geben nur den Offset-Teil der logischen Adresse des Ziels an. Das Segment wird alsCS. - absolut indirekt
Die Semantik der Anweisungen ist an die Adresse in reg oder mem oderIP = reg,IP = memspringen.
Die Anweisung ist als FF /4 codiert, für indirekte Speicher wird die Größe des Operanden wie für jeden anderen Speicherzugriff bestimmt.
Absolute Weitsprünge
jmp 7c0h:0000h ist:
weit
Sie gibt beide Teile der logischen Adresse an: das Segment und den Offset.absolut Die Semantik der Anweisung springt in das Adresssegment : Offset oder
CS = segment, IP = offset.
Die Anweisung wird abhängig von der Codegröße als EA <imm32/48> codiert.
Es ist möglich, in einem Assembler zwischen den beiden Formularen zu wählen, beispielsweise mit NASM jmp 7c0h: WORD 0000h und jmp 7c0h: DWORD 0000h erzeugen das erste und das zweite Formular.
Absolute indirekte Weitsprünge
jmp FAR WORD [aFarPointer] ist:
far Gibt beide Teile der logischen Adresse an: das Segment und den Offset.
Absolut indirekt Die Semantik des Befehls springt in das Segment: Offset, gespeichert in Mem 2 oder
CS = mem[23:16/32], IP = [15/31:0].
Die Anweisung ist als FF /5 codiert, die Größe des Operanden kann mit den Größenangaben gesteuert werden.
In NASM, ein bisschen nicht intuitiv, sind sie jmp FAR WORD [aFarPointer] für einen 16.16 - Operanden und jmp FAR DWORD [aFarPointer] für einen 16.32 Operanden.
Fehlende Sprünge
fast absolut
Kann mit einem nahezu indirekten Sprung emuliert werden.mov bx, target ;BX = absolute address of target jmp bxweit relativ
Machen Sie sowieso keinen Sinn oder zu engen Gebrauch.
1 Zwei Komplemente werden verwendet, um einen vorzeichenbehafteten Versatz anzugeben und somit rückwärts zu springen.
2 Welches kann ein seg16: off16 oder ein seg16: off32 der Größen 16:16 und 16:32 sein .
Testbedingungen
Um einen bedingten Sprung zu verwenden, muss eine Bedingung getestet werden. Das Testen einer Bedingung bezieht sich hier nur auf das Prüfen der Flags. Das tatsächliche Springen wird unter Bedingte Sprünge beschrieben .
x86 testet Bedingungen, indem er sich auf das EFLAGS-Register stützt, das eine Reihe von Flags enthält, die jeder Befehl möglicherweise setzen kann.
Arithmetische Anweisungen wie sub oder add und logische Anweisungen wie xor oder and "setzen die Flags". Dies bedeutet, dass die Flags CF , OF , SF , ZF , AF , PF durch diese Anweisungen modifiziert werden. Jede Anweisung darf die Flags jedoch ändern, zum Beispiel ändert cmpxchg den ZF .
Überprüfen Sie immer die Anweisungsreferenz, um zu wissen, welche Flags von einer bestimmten Anweisung geändert werden.
x86 hat eine Reihe von bedingten Sprüngen , auf die zuvor Bezug genommen wurde, die nur dann springen, wenn einige Flags gesetzt oder einige gelöscht sind oder beides.
Flaggen
Arithmetische und logische Operationen sind sehr hilfreich beim Setzen der Flags. Zum Beispiel haben wir nach einem sub eax, ebx für jetzt vorzeichenlose Werte:
| Flagge | Wenn eingestellt | Wenn klar |
|---|---|---|
| ZF | Wenn das Ergebnis Null ist. EAX - EBX = 0 ⇒ EAX = EBX | Wenn das Ergebnis nicht Null ist. EAX - EBX ≠ 0 ⇒ EAX ≠ EBX |
| CF | Wann musste das Ergebnis für die MSB tragen. EAX - EBX <0 ⇒ EAX <EBX | Wenn das Ergebnis für die MSB nicht erforderlich war. EAX - EBX ≮ 0 ⇒ EAX ≮ EBX |
| SF | Wenn das Ergebnis MSb eingestellt ist. | Wenn das Ergebnis MSb nicht gesetzt ist. |
| VON | Wenn ein signierter Überlauf aufgetreten ist. | Wenn ein signierter Überlauf nicht auftreten. |
| PF | Wenn die Anzahl der Bits, die im niedrigstwertigen Byte des Ergebnisses gesetzt sind, gerade ist. | Wenn die Anzahl der Bits, die im niedrigstwertigen Byte des Ergebnisses gesetzt sind, ungerade ist. |
| AF | Wenn die untere BCD-Ziffer einen Carry generiert hat. Es ist Bit 4 Carry. | Wenn die untere BCD - Ziffer nicht erzeugte einen Übertrag. Es ist Bit 4 Carry. |
Zerstörungsfreie Prüfungen
Die Anweisungen sub und and ändern ihren Zieloperanden und würden zwei zusätzliche Kopien (Speichern und Wiederherstellen) erfordern, um das Ziel unverändert zu lassen.
Um einen zerstörungsfreien Test durchzuführen, gibt es die Anweisungen cmp und test . Sie sind identisch mit ihrem destruktiven Gegenstück, es sei denn, das Ergebnis der Operation wird verworfen und nur die Flags werden gespeichert .
| destruktiv | Nicht destruktiv |
|---|---|
sub | cmp |
and | test |
test eax, eax ;and eax, eax
;ZF = 1 iff EAX is zero
test eax, 03h ;and eax, 03h
;ZF = 1 if both bit[1:0] are clear
;ZF = 0 if at least one of bit[1:0] is set
cmp eax, 241d ;sub eax, 241d
;ZF = 1 iff EAX is 241
;CF = 1 iff EAX < 241
Signierte und nicht signierte Tests
Die CPU gibt den Werten 1 keine besondere Bedeutung, sign ist ein Programmer-Konstrukt. Beim Testen von vorzeichenbehafteten und nicht vorzeichenbehafteten Werten besteht kein Unterschied. Der Prozessor berechnet genug Flags, um die üblichen arithmetischen Beziehungen (gleich, kleiner als, größer als usw.) zu testen, sowohl wenn die Operanden als vorzeichenbehaftet und als nicht signiert betrachtet werden.
1 Es gibt zwar einige Anweisungen, die nur bei bestimmten Formaten sinnvoll sind, wie z. B. Zweierkomplement. Dies soll den Code effizienter machen, da die Implementierung des Algorithmus in Software viel Code erfordern würde.
Bedingte Sprünge
Basierend auf dem Zustand der Flags kann die CPU einen Sprung entweder ausführen oder ignorieren. Eine Anweisung, die basierend auf den Flags einen Sprung ausführt, fällt unter den generischen Namen Jcc - Jump on Condition Code 1 .
Synonyme und Terminologie
Um die Lesbarkeit des Assemblycodes zu verbessern, hat Intel mehrere Synonyme für denselben Bedingungscode definiert. Zum Beispiel sind jae , jnb und jnc derselbe Bedingungscode CF = 0 .
Während der Befehlsname einen sehr deutlichen Hinweis darauf geben kann, wann er verwendet werden soll oder nicht, besteht der einzige sinnvolle Ansatz darin, die Flags zu erkennen, die getestet werden müssen, und dann die Anweisungen entsprechend auszuwählen.
Intel gab den Anweisungen jedoch Namen, die nach einer cmp Anweisung cmp . Für die Zwecke dieser Diskussion wird angenommen, dass cmp die Flags vor einem bedingten Sprung gesetzt hat.
Gleichberechtigung
Die Operanden sind gleich, wenn ZF gesetzt wurde, sie unterscheiden sich ansonsten. Um die Gleichheit zu testen, benötigen wir ZF = 1 .
je a_label ;Jump if operands are equal
jz a_label ;Jump if zero (Synonym)
jne a_label ;Jump if operands are NOT equal
jnz a_label ;Jump if not zero (Synonym)
| Anweisung | Flaggen |
|---|---|
je , jz | ZF = 1 |
jne , jnz | ZF = 0 |
Größer als
Bei unsignierten Operanden ist das Ziel größer als die Quelle, wenn Carry nicht benötigt wurde, das heißt, wenn CF = 0 ist . Wenn CF = 0 ist , ist es möglich, dass die Operanden gleich sind, und der Test von ZF wird disambiguieren.
jae a_label ;Jump if above or equal (>=)
jnc a_label ;Jump if not carry (Synonym)
jnb a_label ;Jump if not below (Synonym)
ja a_label ;Jump if above (>)
jnbe a_label ;Jump if not below and not equal (Synonym)
| Anweisung | Flaggen |
|---|---|
jae , jnc , jnb | CF = 0 |
ja , jnbe | CF = 0, ZF = 0 |
Für signierte Operanden müssen wir prüfen, ob SF = 0 ist , es sei denn, es wurde ein signierter Überlauf ausgeführt. In diesem Fall wird der resultierende SF umgekehrt. Da OF = 0 ist, wenn kein vorzeichenbehafteter Überlauf aufgetreten ist, andernfalls müssen wir prüfen, ob SF = OF ist .
Mit ZF kann ein strenger / nicht strikter Test durchgeführt werden.
jge a_label ;Jump if greater or equal (>=)
jnl a_label ;Jump if not less (Synonym)
jg a_label ;Jump if greater (>)
jnle a_label ;Jump if not less and not equal (Synonym)
| Anweisung | Flaggen |
|---|---|
jge , jnl | SF = OF |
jg , jnle | SF = OF, ZF = 0 |
Weniger als
Diese verwenden die umgekehrten Bedingungen von oben.
jbe a_label ;Jump if below or equal (<=)
jna a_label ;Jump if not above (Synonym)
jb a_label ;Jump if below (<)
jc a_label ;Jump if carry (Synonym)
jnae a_label ;Jump if not above and not equal (Synonym)
;SIGNED
jle a_label ;Jump if less or equal (<=)
jng a_label ;Jump if not greater (Synonym)
jl a_label ;Jump if less (<)
jnge a_label ;Jump if not greater and not equal (Synonym)
| Anweisung | Flaggen |
|---|---|
jbe , jna | CF = 1 oder ZF = 1 |
jb , jc , jnae | CF = 1 |
jle , jng | SF! = OF oder ZF = 1 |
jl , jnge | SF! = OF |
Bestimmte Flaggen
Jedes Flag kann einzeln mit j<flag_name> getestet werden, wobei Flag_Name nicht das nachfolgende F enthält (z. B. CF → C , PF → P ).
Die übrigen Codes, die zuvor nicht behandelt wurden, sind:
| Anweisung | Flagge |
|---|---|
js | SF = 1 |
jns | SF = 0 |
jo | OF = 1 |
jno | OF = 0 |
jp , jpe (e = gerade) | PF = 1 |
jnp , jpo (o = ungerade) | PF = 0 |
Ein weiterer bedingter Sprung (extra)
Ein spezieller x86-bedingter Sprung testet keine Flagge. Stattdessen ecx es den Wert des Registers cx oder ecx (basierend auf dem aktuellen CPU- ecx , der 16 oder 32 Bit beträgt) und der Sprung wird ausgeführt, wenn das Register Null enthält.
Diese Anweisung wurde für die Validierung des Zählerregisters (entworfen cx/ecx ) vor rep -ähnlichen Anweisungen oder vor loop
jcxz a_label ; jump if cx (16b mode) or ecx (32b mode) is zero
jecxz a_label ; synonym of jcxz (recommended in source code for 32b target)
| Anweisung | Registrieren (nicht kennzeichnen) |
|---|---|
jcxz , jecxz | cx = 0 (16b-Modus) |
jcxz , jecxz | ecx = 0 (32b-Modus) |
1 oder so ähnlich.
Arithmetische Beziehungen testen
Vorzeichenlose Ganzzahlen
Größer als
cmp eax, ebx
ja a_label
Größer als oder gleich
cmp eax, ebx
jae a_label
Weniger als
cmp eax, ebx
jb a_label
Weniger als oder gleich
cmp eax, ebx
jbe a_label
Gleich
cmp eax, ebx
je a_label
Nicht gleich
cmp eax, ebx
jne a_label
Signierte Ganzzahlen
Größer als
cmp eax, ebx
jg a_label
Größer als oder gleich
cmp eax, ebx
jge a_label
Weniger als
cmp eax, ebx
jl a_label
Weniger als oder gleich
cmp eax, ebx
jle a_label
Gleich
cmp eax, ebx
je a_label
Nicht gleich
cmp eax, ebx
jne a_label
a_label
In den obigen a_label ist a_label das Ziel für die CPU, wenn die getestete Bedingung "true" ist. Wenn die getestete Bedingung "false" ist, fährt die CPU mit dem nächsten Befehl nach dem bedingten Sprung fort.
Synonyme
Es gibt Anweisungs-Synonyme, die verwendet werden können, um die Lesbarkeit des Codes zu verbessern.
Zum Beispiel sind ja und jnbe (Jump nicht unter oder gleich) die gleiche Anweisung.
Signierte nicht signierte Begleitcodes
| Operation | Ohne Vorzeichen | Unterzeichnet |
|---|---|---|
| > | ja | jg |
| > = | jae | jge |
| < | jb | jl |
| <= | jbe | jle |
| = | je | je |
| !,! =, <> | jne | jne |