Verwenden Sie spezielle Kurzformkodierungen für AL / AX / EAX sowie andere Kurzformen und Einzelbyte-Anweisungen
Bei den Beispielen wird der 32/64-Bit-Modus angenommen, bei dem die Standardoperandengröße 32 Bit beträgt. Ein Präfix mit Operandengröße ändert den Befehl in AX anstelle von EAX (oder umgekehrt im 16-Bit-Modus).
inc/dec
ein Register (außer 8-Bit): inc eax
/ dec ebp
. (Nicht x86-64: Die 0x4x
Opcode-Bytes wurden als REX-Präfixe verwendet. Dies inc r/m32
ist die einzige Codierung.)
8-Bit - inc bl
2 Byte, unter Verwendung des inc r/m8
opcode + ModR / M - Operanden kodieren . So verwenden inc ebx
zu erhöhen bl
, wenn es sicher ist. (zB wenn Sie das ZF-Ergebnis nicht benötigen, wenn die oberen Bytes möglicherweise nicht Null sind).
scasd
: e/rdi+=4
, erfordert, dass das Register auf einen lesbaren Speicher zeigt. Manchmal nützlich, auch wenn Sie sich nicht für das FLAGS-Ergebnis interessieren (wie cmp eax,[rdi]
/ rdi+=4
). Und im 64-Bit-Modus scasb
kann als 1-Byte arbeiteninc rdi
, wenn lodsb oder stosb nicht nützlich sind.
xchg eax, r32
: Hier wird von 0x90 NOP kam: xchg eax,eax
. Beispiel: 3 Register mit zwei xchg
Befehlen in einer cdq
/ idiv
-Schleife für GCD in 8 Bytes neu anordnen, wobei die meisten Befehle Einzelbytes sind, einschließlich eines Missbrauchs von inc ecx
/ loop
anstelle von test ecx,ecx
/jnz
cdq
: Vorzeichenerweiterung von EAX in EDX: EAX, dh Kopieren des hohen EAX-Bits in alle EDX-Bits. Um eine Null mit bekannten nicht-negativen Werten zu erstellen, oder um eine 0 / -1 zu erhalten, mit der / sub oder maskiert wird. x86-Geschichtsstunde: cltq
vs.movslq
, und auch AT & T vs. Intel-Mnemonics für diese und die verwandten cdqe
.
lodsb / d : like mov eax, [rsi]
/ rsi += 4
without clobbering flags. (Angenommen, DF ist klar, welche Standardaufrufkonventionen für die Funktionseingabe erforderlich sind.) Außerdem stosb / d, manchmal scas und seltener movs / cmps.
push
/ pop reg
. ZB im 64-Bit-Modus ist push rsp
/ pop rdi
2 Byte, mov rdi, rsp
benötigt aber ein REX-Präfix und ist 3 Byte.
xlatb
existiert, ist aber selten nützlich. Eine große Nachschlagetabelle sollte vermieden werden. Ich habe auch noch nie eine Verwendung für AAA / DAA oder andere gepackte BCD- oder 2-ASCII-Ziffern-Anweisungen gefunden.
1 Byte lahf
/ sahf
sind selten nützlich. Sie könnten lahf
/ and ah, 1
als Alternative zu setc ah
, aber es ist in der Regel nicht nützlich.
Und speziell für CF gibt sbb eax,eax
es eine 0 / -1 oder sogar eine nicht dokumentierte, aber universell unterstützte 1-Byte-Größe salc
(setze AL von Carry), die effektiv keine sbb al,al
Auswirkung auf Flags hat. (In x86-64 entfernt). Ich habe SALC in der User Appreciation Challenge # 1 verwendet: Dennis ♦ .
1-Byte cmc
/ clc
/ stc
(Flip ("Komplement"), Clear oder Set CF) sind selten nützlich, obwohl ich eine Verwendung für einecmc
Addition mit erweiterter Genauigkeit mit Basis 10 ^ 9-Chunks gefunden habe. Um CF bedingungslos zu setzen / löschen, lassen Sie dies normalerweise als Teil eines anderen Befehls geschehen, z. B. xor eax,eax
CF und EAX löschen. Es gibt keine entsprechenden Anweisungen für andere Bedingungsflags, nur DF (Zeichenfolgenrichtung) und IF (Interrupts). Das Carry Flag ist speziell für viele Anweisungen. Shifts setzen es, adc al, 0
können es in 2 Byte zu AL hinzufügen, und ich erwähnte zuvor die undokumentierte SALC.
std
/ cld
Scheinen selten wert . Insbesondere im 32-Bit-Code ist es besser, nur dec
einen Zeiger und einen mov
oder einen Speicherquellenoperanden für einen ALU-Befehl zu verwenden, anstatt DF so zu setzen lodsb
/ stosb
nach unten statt nach oben zu gehen. Normalerweise , wenn Sie nach unten überhaupt brauchen, haben Sie noch einen anderen Zeiger geht nach oben, so dass Sie mehr brauchen würden als eine std
und cld
in der gesamten Funktion Verwendung lods
/ stos
für beide. Verwenden Sie stattdessen einfach die Zeichenfolgenanweisungen für die Aufwärtsrichtung. (Die Standardaufrufkonventionen garantieren DF = 0 bei der Funktionseingabe, sodass Sie davon ausgehen können, dass dies ohne Verwendung von kostenlos ist cld
.)
8086 history: Warum gibt es diese Kodierungen?
Im Original 8086 war AX ganz Besonderes: Anweisungen wie lodsb
/ stosb
, cbw
, mul
/ div
und andere implizit verwenden. Das ist natürlich immer noch der Fall; Der aktuelle x86 hat keinen der 8086-Opcodes gelöscht (zumindest keinen der offiziell dokumentierten). Spätere CPUs fügten neue Anweisungen hinzu, die bessere / effizientere Möglichkeiten boten, Dinge zu erledigen, ohne sie zuerst in AX zu kopieren oder zu tauschen. (Oder zu EAX im 32-Bit-Modus.)
Zum Beispiel fehlten bei 8086 spätere Zusätze wie movsx
/ movzx
zum Laden oder Verschieben + Vorzeichen-Erweitern oder 2- und 3-Operanden imul cx, bx, 1234
, die kein High-Half-Ergebnis liefern und keine impliziten Operanden haben.
Auch 8086 Haupt Engpass war Befehl holen, so die Optimierung für die Code-Größe wichtig war für die Leistung damals . Der ISA-Designer von 8086 (Stephen Morse) hat viel Opcode -Code für Sonderfälle für AX / AL ausgegeben, einschließlich spezieller (E) AX / AL-Ziel-Opcodes für alle grundlegenden ALU-Anweisungen von src , nur opcode + instant ohne ModR / M-Byte. 2 Byte add/sub/and/or/xor/cmp/test/... AL,imm8
oder AX,imm16
oder (im 32-Bit-Modus) EAX,imm32
.
Es gibt jedoch keinen Sonderfall für EAX,imm8
, sodass die reguläre ModR / M-Codierung add eax,4
kürzer ist.
Es wird davon ausgegangen, dass Sie einige Daten in AX / AL bearbeiten möchten. Daher sollten Sie ein Register mit AX tauschen, vielleicht sogar öfter, als ein Register mit AX zu kopierenmov
.
Alles, was mit der 8086-Befehlskodierung zu tun hat, unterstützt dieses Paradigma, angefangen von Befehlen lodsb/w
über alle Sonderfallkodierungen für Direktbefehle mit EAX bis hin zur impliziten Verwendung auch für Multiplikationen / Divisionen.
Lass dich nicht mitreißen; Es ist nicht automatisch ein Gewinn, alles zu EAX zu tauschen, besonders wenn Sie Sofort mit 32-Bit-Registern anstelle von 8-Bit verwenden müssen. Oder wenn Sie Operationen mit mehreren Variablen in Registern gleichzeitig verschachteln müssen. Oder wenn Sie Anweisungen mit 2 Registern verwenden, nicht sofort.
Aber denken Sie immer daran: Tue ich irgendetwas, das in EAX / AL kürzer wäre? Kann ich neu anordnen, damit ich dies in AL habe, oder nutze ich derzeit AL besser mit dem, wofür ich es bereits benutze?
Mischen Sie 8-Bit- und 32-Bit-Operationen frei, um die Vorteile zu nutzen, wann immer dies sicher ist (Sie müssen nicht in das vollständige Register oder was auch immer übertragen).
push 200; pop edx
zu initialisieren, verwenden Sie zB - 3 Byte für die Initialisierung.