Intel x86 Assembly Language & Microarchitecture
Flusso di controllo
Ricerca…
Salti incondizionati
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
Relativo vicino a salti
jmp a_label è:
- vicino
Specifica solo la parte offset dell'indirizzo logico di destinazione. Si presume che il segmento siaCS. - parente
La semantica delle istruzioni è di salto rel byte 1 avanti dal prossimo indirizzo di istruzione oIP = IP + rel.
L'istruzione è codificata come EB <rel8> o EB <rel16/32> , l'assemblatore EB <rel16/32> il modulo più appropriato, di solito preferendo uno più corto.
Per l'override dell'assemblatore è possibile, ad esempio con NASM jmp SHORT a_label , jmp WORD a_label e jmp DWORD a_label generano le tre possibili forme.
Salto assoluto indiretto vicino
jmp bx e jmp WORD [aPointer] sono:
- vicino
Specificano solo la parte di offset dell'indirizzo logico di destinazione. Si presume che il segmento siaCS. - assoluto indiretto
La semantica delle istruzioni è il salto all'indirizzo in reg o mem oIP = reg,IP = mem.
L'istruzione è codificata come FF /4 , per la memoria indiretta la dimensione dell'operando è determinata come per ogni altro accesso alla memoria.
Salti assoluti assoluti
jmp 7c0h:0000h è:
lontano
Specifica entrambe le parti dell'indirizzo logico : il segmento e l'offset.absolute La semantica dell'istruzione è il salto al segmento dell'indirizzo : offset o
CS = segment, IP = offset.
L'istruzione è codificata come EA <imm32/48> seconda delle dimensioni del codice.
È possibile scegliere tra le due forme in alcuni assembler, ad esempio con NASM jmp 7c0h: WORD 0000h e jmp 7c0h: DWORD 0000h genera il primo e il secondo modulo.
Salti estremi indiretti assoluti
jmp FAR WORD [aFarPointer] è:
lontano Specifica entrambe le parti dell'indirizzo logico : il segmento e l'offset.
Assoluto indiretto La semantica dell'istruzione è il salto al segmento: offset memorizzato in mem 2 o
CS = mem[23:16/32], IP = [15/31:0].
L'istruzione è codificata come FF /5 , la dimensione dell'operando può essere il controller con gli identificatori di dimensione.
In NASM, un po 'non intuitivo, sono jmp FAR WORD [aFarPointer] per un operando 16:16 e jmp FAR DWORD [aFarPointer] per un operando 16:32 .
Salti mancanti
vicino assoluto
Può essere emulato con un salto quasi indiretto.mov bx, target ;BX = absolute address of target jmp bxlontano parente
In ogni caso, non ha senso o è troppo stretto.
1 Due complemento è usato per specificare un offset firmato e quindi saltare all'indietro.
2 Che può essere un seg16: off16 o un seg16: off32 , di dimensioni 16:16 e 16:32 .
Condizioni di prova
Per poter utilizzare un salto condizionale, è necessario testare una condizione. Il test di una condizione qui si riferisce solo all'atto di controllare le bandiere, il salto effettivo è descritto in Salti condizionali .
x86 verifica le condizioni facendo affidamento sul registro EFLAGS, che contiene una serie di flag che ogni istruzione può potenzialmente impostare.
Istruzioni aritmetiche, come sub o add , e le istruzioni logiche, come xor o and , ovviamente "impostare le bandiere". Ciò significa che i flag CF , OF , SF , ZF , AF , PF sono modificati da quelle istruzioni. Qualsiasi istruzione è autorizzata a modificare i flag, ad esempio, cmpxchg modifica lo ZF .
Controllare sempre il riferimento alle istruzioni per sapere quali bandiere sono state modificate da una specifica istruzione.
x86 ha una serie di salti condizionali , a cui si fa riferimento in precedenza, che salta se e solo se alcuni flag sono impostati o alcuni sono chiari o entrambi.
bandiere
Le operazioni aritmetiche e logiche sono molto utili nell'impostazione delle bandiere. Ad esempio, dopo un sub eax, ebx , per ora in possesso di valori senza segno , abbiamo:
| Bandiera | Quando impostato | Quando è chiaro |
|---|---|---|
| ZF | Quando il risultato è zero. EAX - EBX = 0 ⇒ EAX = EBX | Quando il risultato non è zero. EAX - EBX ≠ 0 ⇒ EAX ≠ EBX |
| CF | Quando il risultato ha avuto bisogno di trasportare per il MSb. EAX - EBX <0 ⇒ EAX <EBX | Quando il risultato non ha avuto bisogno di portare per il MSb. EAX - EBX ≮ 0 ⇒ EAX ≮ EBX |
| SF | Quando viene impostato il risultato MSb. | Quando il risultato MSb non è impostato. |
| DI | Quando si è verificato un overflow firmato. | Quando non si verifica un overflow con segno. |
| PF | Quando il numero di bit impostato nel byte di risultato meno significativo è pari. | Quando il numero di bit impostato nel byte di risultato meno significativo è dispari. |
| AF | Quando la cifra BCD inferiore ha generato un carry. È il 4 ° carry. | Quando la cifra BCD inferiore non ha generato un carry. È il 4 ° carry. |
Test non distruttivi
Il sub e and istruzioni modificano la loro operando destinazione e richiederebbe due copie extra (salvataggio e ripristino) per mantenere la destinazione non modificato.
Per eseguire un test non distruttivo ci sono le istruzioni cmp e test . Sono identici alla loro controparte distruttiva, tranne che il risultato dell'operazione viene scartato e vengono salvate solo le bandiere .
| Distruttivo | Non distruttivo |
|---|---|
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
Prove firmate e non firmate
La CPU non dà alcun significato speciale per registrare i valori 1 , il segno è un costrutto programmatore. Non c'è alcuna differenza quando si testano i valori firmati e non firmati. Il processore calcola abbastanza flag per testare le solite relazioni aritmetiche (uguali, minori di, maggiori di, ecc.) Sia se gli operandi dovessero essere considerati firmati e non firmati.
1 Sebbene abbia alcune istruzioni che hanno senso solo con formati specifici, come il complemento a due. Questo per rendere il codice più efficiente poiché l'implementazione dell'algoritmo nel software richiederebbe molto codice.
Salti condizionati
In base allo stato dei flag, la CPU può eseguire o ignorare un salto. Un'istruzione che esegue un salto basato sui flag rientra nel nome generico di Jcc - Jump on Condition Code 1 .
Sinonimi e terminologia
Al fine di migliorare la leggibilità del codice assembly, Intel ha definito diversi sinonimi per lo stesso codice di condizione. Ad esempio, jae , jnb e jnc sono tutti lo stesso codice di condizione CF = 0 .
Mentre il nome dell'istruzione può dare un forte suggerimento su quando usarlo o meno, l'unico approccio significativo è riconoscere le bandiere che devono essere testate e quindi scegliere le istruzioni in modo appropriato.
Intel ha tuttavia fornito i nomi delle istruzioni che hanno perfettamente senso quando vengono utilizzati dopo un'istruzione cmp . Ai fini di questa discussione, si presume che cmp abbia impostato i flag prima di un salto condizionato.
Uguaglianza
L'operando è uguale se ZF è stato impostato, diversamente si differenziano. Per testare l'uguaglianza abbiamo bisogno di 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)
| istruzione | bandiere |
|---|---|
je , jz | ZF = 1 |
jne , jnz | ZF = 0 |
Più grande di
Per gli operandi senza segno , la destinazione è maggiore della sorgente se carry non era necessaria, ovvero CF = 0 . Quando CF = 0 è possibile che gli operandi fossero uguali, testando ZF si disambiguerebbe.
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)
| istruzione | bandiere |
|---|---|
jae , jnc , jnb | CF = 0 |
ja , jnbe | CF = 0, ZF = 0 |
Per gli operandi firmati è necessario verificare che SF = 0 , a meno che non vi sia stato un overflow con segno, nel qual caso l' SF risultante viene invertito. Poiché OF = 0 se non si è verificato un overflow con segno e 1 in caso contrario, è necessario verificare che SF = OF .
ZF può essere utilizzato per implementare un test rigoroso / non rigoroso.
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)
| istruzione | bandiere |
|---|---|
jge , jnl | SF = OF |
jg , jnle | SF = OF, ZF = 0 |
Meno di
Questi usano le condizioni invertite di sopra.
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)
| istruzione | bandiere |
|---|---|
jbe , jna | CF = 1 o ZF = 1 |
jb , jc , jnae | CF = 1 |
jle , jng | SF! = OF o ZF = 1 |
jl , jnge | SF! = OF |
Bandiere specifiche
Ogni flag può essere testato individualmente con j<flag_name> dove flag_name non contiene il finale F (ad esempio CF → C , PF → P ).
I codici rimanenti non trattati in precedenza sono:
| istruzione | Bandiera |
|---|---|
js | SF = 1 |
jns | SF = 0 |
jo | OF = 1 |
jno | OF = 0 |
jp , jpe (e = even) | PF = 1 |
jnp , jpo (o = dispari) | PF = 0 |
Un altro salto condizionale (uno extra)
Un salto condizionale x86 speciale non verifica il flag. Invece esegue il test del valore del registro cx o ecx (in base alla modalità corrente dell'indirizzo della CPU 16 o 32 bit) e il salto viene eseguito quando il registro contiene zero.
Questa istruzione è stata progettata per la convalida del registro contatore ( cx/ecx ) prima delle istruzioni simili a rep o prima dei loop 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)
| istruzione | Registrati (non flag) |
|---|---|
jcxz , jecxz | cx = 0 (modalità 16b) |
jcxz , jecxz | ecx = 0 (modalità 32b) |
1 O qualcosa del genere.
Testare le relazioni aritmetiche
Numeri interi senza segno
Più grande di
cmp eax, ebx
ja a_label
Maggiore o uguale
cmp eax, ebx
jae a_label
Meno di
cmp eax, ebx
jb a_label
Meno o uguale
cmp eax, ebx
jbe a_label
Pari
cmp eax, ebx
je a_label
Non uguale
cmp eax, ebx
jne a_label
Interi firmati
Più grande di
cmp eax, ebx
jg a_label
Maggiore o uguale
cmp eax, ebx
jge a_label
Meno di
cmp eax, ebx
jl a_label
Meno o uguale
cmp eax, ebx
jle a_label
Pari
cmp eax, ebx
je a_label
Non uguale
cmp eax, ebx
jne a_label
a_label
Negli esempi sopra la a_label è la destinazione target per la CPU quando la condizione testata è "vera". Quando la condizione testata è "false", la CPU continuerà con l'istruzione successiva successiva al salto condizionato.
Sinonimi
Esistono sinonimi di istruzioni che possono essere utilizzati per migliorare la leggibilità del codice.
Ad esempio ja e jnbe (salto non inferiore o uguale) sono la stessa istruzione.
Codici companion non firmati firmati
| operazione | unsigned | firmato |
|---|---|---|
| > | ja | jg |
| > = | jae | jge |
| < | jb | jl |
| <= | jbe | jle |
| = | je | je |
| ≠,! =, <> | jne | jne |