Istruzioni x86
Negli elenchi di questa sezione le istruzioni contrassegnate con un asterisco (*) sono particolarmente importanti. Le istruzioni non contrassegnate non sono critiche.
Nel processore x86 le istruzioni sono di dimensioni variabili, quindi il disassembling indietro è un esercizio nella corrispondenza dei modelli. Per smontare indietro da un indirizzo, è consigliabile iniziare a smontare a un punto più indietro di quello che si vuole veramente andare, quindi guardare avanti fino a quando le istruzioni iniziano a prendere senso. Le prime istruzioni potrebbero non avere senso perché potrebbe essere stato avviato il disassembling al centro di un'istruzione. C'è una possibilità, purtroppo, che il disassembly non si sincronizza mai con il flusso di istruzioni e sarà necessario provare a smontare in un punto di partenza diverso fino a trovare un punto di partenza che funziona.
Per istruzioni switch ben raggruppate, il compilatore genera dati direttamente nel flusso di codice, quindi il disassembling tramite un'istruzione switch in genere si scompone tra le istruzioni che non hanno senso (perché sono davvero dati). Trovare la fine dei dati e continuare a disassemblare lì.
Notazione istruzione
La notazione generale per le istruzioni consiste nell'inserire il registro di destinazione a sinistra e l'origine a destra. Tuttavia, possono essere presenti alcune eccezioni a questa regola.
Le istruzioni aritmetiche sono in genere due registri con i registri di origine e di destinazione che combinano. Il risultato viene archiviato nella destinazione.
Alcune delle istruzioni hanno sia versioni a 16 bit che a 32 bit, ma sono elencate qui solo le versioni a 32 bit. Non elencato qui sono istruzioni a virgola mobile, istruzioni con privilegi e istruzioni usate solo nei modelli segmentati (che Microsoft Win32 non usa).
Per risparmiare spazio, molte delle istruzioni vengono espresse in formato combinato, come illustrato nell'esempio seguente.
* |
MOV |
r1, r/m/#n |
r1 = r/m/#n |
significa che il primo parametro deve essere un registro, ma il secondo può essere un registro, un riferimento alla memoria o un valore immediato.
Per risparmiare ancora più spazio, le istruzioni possono essere espresse anche come illustrato di seguito.
* |
MOV |
r1/m, r/m/#n |
r1/m = r/m/#n |
ciò significa che il primo parametro può essere un registro o un riferimento alla memoria e il secondo può essere un registro, un riferimento alla memoria o un valore immediato.
Se non diversamente indicato, quando questa abbreviazione viene usata, non è possibile scegliere la memoria sia per l'origine che per la destinazione.
Inoltre, è possibile aggiungere un suffisso a dimensioni bit (8, 16, 32) all'origine o alla destinazione per indicare che il parametro deve essere di tale dimensione. Ad esempio, r8 indica un registro a 8 bit.
Memoria, trasferimento dati e conversione dati
Le istruzioni per il trasferimento dei dati e della memoria non influiscono sui flag.
Indirizzo effettivo
* |
LEA |
r, m |
Caricare l'indirizzo effettivo. (r = indirizzo di m) |
Ad esempio, LEA eax, [esi+4] significa eax = esi + 4. Questa istruzione viene spesso usata per eseguire aritmetica.
Trasferimento dati
MOV |
r1/m, r2/m/#n |
r1/m = r/m/#n |
|
MOVSX |
r1, r/m |
Spostare con estensione di firma. |
|
* |
MOVZX |
r1, r/m |
Spostarsi con estensione zero. |
MOVSX e MOVZX sono versioni speciali dell'istruzione mov che eseguono l'estensione di firma o zero dall'origine alla destinazione. Questa è l'unica istruzione che consente all'origine e alla destinazione di essere dimensioni diverse. (E infatti, devono essere dimensioni diverse.
Manipolazione dello stack
Lo stack è indicato dal registro esp . Il valore in esp è la parte superiore dello stack (più di recente push, prima da visualizzare); gli elementi dello stack meno recenti risiedono in indirizzi superiori.
PUSH |
r/m/#n |
Eseguire il push del valore nello stack. |
|
POP |
r/m |
Valore pop dallo stack. |
|
PUSHFD |
Eseguire il push dei flag nello stack. |
||
POPFD |
Flag pop dallo stack. |
||
PUSHAD |
Eseguire il push di tutti i registri interi. |
||
POPAD |
Pop all integer registers(Pop all integer registers). |
||
INVIO |
#n, #n |
Frame dello stack di compilazione. |
|
* |
LASCIARE |
Fotogramma dello stack di rimozione |
Il compilatore C/C++ non usa l'istruzione invio . L'istruzione invio viene usata per implementare procedure annidate in lingue come Algol o Pascal.
L'istruzione di uscita equivale a:
mov esp, ebp
pop ebp
Conversione dei dati
CBW |
Convertire byte (al) in word (ax). |
CWD |
Convertire la parola (ax) in dword (dx:ax). |
CWDE |
Convertire la parola (ax) in dword (eax). |
CDQ |
convertire dword (eax) in qword (edx:eax). |
Tutte le conversioni eseguono l'estensione di firma.
Manipolazione aritmetica e bit
Tutte le istruzioni di manipolazione aritmetica e bit modificano i flag.
Aritmetica
ADD |
r1/m, r2/m/#n |
r1/m += r2/m/#n |
|
ADC |
r1/m, r2/m/#n |
r1/m += r2/m/#n + trasporto |
|
INV |
r1/m, r2/m/#n |
r1/m -= r2/m/#n |
|
FFS |
r1/m, r2/m/#n |
r1/m -= r2/m/#n + trasporto |
|
NEG |
r1/m |
r1/m = -r1/m |
|
INC |
r/m |
r/m += 1 |
|
DEC |
r/m |
r/m -= 1 |
|
CMP |
r1/m, r2/m/#n |
Calcolo r1/m - r2/m/#n |
L'istruzione cmp calcola la sottrazione e imposta i flag in base al risultato, ma genera il risultato. In genere è seguito da un'istruzione di salto condizionale che verifica il risultato della sottrazione.
MUL |
r/m8 |
Ax = al * r/m8 |
|
MUL |
r/m16 |
dx:ax ax = * r/m16 |
|
MUL |
r/m32 |
edx:eax eax = * r/m32 |
|
IMUL |
r/m8 |
Ax = al * r/m8 |
|
IMUL |
r/m16 |
dx:ax ax = * r/m16 |
|
IMUL |
r/m32 |
edx:eax eax = * r/m32 |
|
IMUL |
r1, r2/m |
r1 *= r2/m |
|
IMUL |
r1, r2/m, #n |
r1 = r2/m * #n |
Moltiplicazione senza segno e firmata. Lo stato dei flag dopo la moltiplicazione non è definito.
DIV |
r/m8 |
(ah, al) = (axr/m8, ax / % r/m8) |
|
DIV |
r/m16 |
(dx, ax) = dx:ax / r/m16 |
|
DIV |
r/m32 |
(edx, eax) = edx:eax / r/m32 |
|
IDIV |
r/m8 |
(ah, al) = ax / r/m8 |
|
IDIV |
r/m16 |
(dx, ax) = dx:ax / r/m16 |
|
IDIV |
r/m32 |
(edx, eax) = edx:eax / r/m32 |
Divisione senza segno e firmato. Il primo registro nella spiegazione pseudocodice riceve il resto e il secondo riceve il quoziente. Se il risultato esegue il overflow della destinazione, viene generata un'eccezione di overflow di divisione.
Lo stato dei flag dopo la divisione non è definito.
* |
SETcc |
r/m8 |
Impostare r/m8 su 0 o 1 |
Se la condizione cc è true, il valore a 8 bit è impostato su 1. In caso contrario, il valore a 8 bit è impostato su zero.
Decimale codificato in codice binario
Queste istruzioni non verranno visualizzate a meno che non si stia eseguendo il debug del codice scritto in COBOL.
DAA |
Regolazione decimale dopo l'aggiunta. |
|
DAS |
Regolazione decimale dopo la sottrazione. |
Queste istruzioni regolano il registro al dopo aver eseguito un'operazione decimale con codice binario con pacchetto.
AAA |
ASCII regola dopo l'aggiunta. |
AAS |
ASCII regola dopo la sottrazione. |
Queste istruzioni regolano il registro al dopo aver eseguito un'operazione decimale con codice binario non compresso.
AAM |
ASCII regola dopo la moltiplicazione. |
AAD |
ASCII regolare dopo la divisione. |
Queste istruzioni regolano i registri al e ah dopo l'esecuzione di un'operazione decimale con codice binario non compresso.
Bit
AND |
r1/m, r2/m/#n |
r1/m = r1/m e r2/m/#n |
|
OR |
r1/m, r2/m/#n |
r1/m = r1/m o r2/m/#n |
|
XOR |
r1/m, r2/m/#n |
r1/m = r1/m xor r2/m/#n |
|
NOT |
r1/m |
r1/m = bit per bit non r1/m |
|
* |
TEST |
r1/m, r2/m/#n |
Calcolo r1/m e r2/m/#n |
L'istruzione di test calcola l'operatore AND logico e imposta i flag in base al risultato, ma genera il risultato. In genere è seguito da un'istruzione di salto condizionale che verifica il risultato dell'and logico.
SHL |
r1/m, cl/#n |
r1/m <<= cl/#n |
|
SHR |
r1/m, cl/#n |
r1/m >>= cl/#n riempimento zero |
|
* |
SAR |
r1/m, cl/#n |
r1/m >>= cl/#n riempimento dei segni |
L'ultimo bit spostato fuori è posizionato nel trasporto.
SHLD |
r1, r2/m, cl/#n |
Maiusc a sinistra doppio. |
Maiusc r1 lasciato da cl/#n, riempimento con i bit superiore di r2/m. L'ultimo bit spostato fuori è posizionato nel trasporto.
SHRD |
r1, r2/m, cl/#n |
Sposta a destra doppio. |
Sposta r1 a destra per cl/#n, riempiendo con i bit inferiori di r2/m. L'ultimo bit spostato fuori è posizionato nel trasporto.
ROL |
r1, cl/#n |
Ruotare r1 a sinistra da cl/#n. |
ROR |
r1, cl/#n |
Ruotare r1 a destra per cl/#n. |
RCL |
r1, cl/#n |
Ruotare r1/C a sinistra per cl/#n. |
RCR |
r1, cl/#n |
Ruotare r1/C a destra per cl/#n. |
La rotazione è simile allo spostamento, ad eccezione del fatto che i bit spostati vengono visualizzati nuovamente come bit di riempimento in ingresso. La versione in linguaggio C delle istruzioni di rotazione incorpora il bit di trasporto nella rotazione.
BT |
r1, r2/#n |
Copiare bit r2/#n di r1 nel trasporto. |
BTS |
r1, r2/#n |
Impostare bit r2/#n di r1, copiare il valore precedente nel trasporto. |
BTC |
r1, r2/#n |
Cancella bit r2/#n di r1, copiare il valore precedente nel trasporto. |
Flusso di controllo
Jcc |
Dest |
Condizionale ramo. |
|
JMP |
Dest |
Saltare direttamente. |
|
JMP |
r/m |
Saltare indiretto. |
|
CALL |
Dest |
Chiamare direttamente. |
|
* |
CALL |
r/m |
Chiamare indiretto. |
L'istruzione di chiamata esegue il push dell'indirizzo restituito nello stack e quindi passa alla destinazione.
* |
RET |
#n |
Return |
L'istruzione ret viene visualizzata e passa all'indirizzo restituito nello stack. Un #n diverso da zero nell'istruzione RET indica che dopo aver visualizzato l'indirizzo restituito, il valore #n deve essere aggiunto al puntatore dello stack.
CICLO |
Decrement ecx e jump se il risultato è diverso da zero. |
LOOPZ |
Decrement ecx e jump se il risultato è diverso da zero e zr è stato impostato. |
LOOPNZ |
Decrement ecx e jump se il risultato è diverso da zero e zr era chiaro. |
JECXZ |
Saltare se ecx è zero. |
Queste istruzioni sono resti dell'eredità CISC di x86 e nei processori recenti sono effettivamente più lente rispetto alle istruzioni equivalenti scritte per lungo tempo.
Manipolazione delle stringhe
MOVST |
Sposta T da esi a edi. |
|
CMPST |
Confrontare T da esi con edi. |
|
SCAST |
Analizzare T da edi per accT. |
|
LODS T |
Caricare T da esi in accT. |
|
STOST |
Archiviare T a edi da accT. |
Dopo aver eseguito l'operazione, il registro di origine e destinazione viene incrementato o decrementato da sizeof(T), in base all'impostazione del flag di direzione (su o giù).
L'istruzione può essere preceduta da REP per ripetere l'operazione il numero di volte specificato dal registro ecx .
L'istruzione rep mov viene usata per copiare blocchi di memoria.
L'istruzione rep stos viene usata per riempire un blocco di memoria con accT.
Bandiere
LAHF |
Caricare ah dai flag. |
SAHF |
Archiviare ah per contrassegnare. |
STC |
Impostare il trasporto. |
CLC |
Porta libera. |
CMC |
Complemento porta. |
STD |
Impostare la direzione verso il basso. |
CLD |
Impostare la direzione verso l'alto. |
STI |
Abilitare gli interrupt. |
CLI |
Disabilitare gli interrupt. |
Istruzioni interlocked
XCHG |
r1, r/m |
Scambia r1 e r/m. |
XADD |
r1, r/m |
Aggiungere r1 a r/m, inserire il valore originale in r1. |
CMPXCHG |
r1, r/m |
Confronto e scambio condizionale. |
L'istruzione cmpxchg è la versione atomica del seguente:
cmp accT, r/m
jz match
mov accT, r/m
jmp done
match:
mov r/m, r1
done:
Varie
INT |
#n |
Trap per il kernel. |
|
ASSOCIATO |
r, m |
Trap se r non è compreso nell'intervallo. |
|
* |
NOP |
Nessuna operazione. |
|
XLATB |
al = [ebx + al] |
||
BSWAP |
r |
Scambia l'ordine dei byte nel registro. |
Ecco un caso speciale dell'istruzione int .
INT |
3 |
Trap del punto di interruzione del debugger. |
Il codice operativo per INT 3 è 0xCC. Il codice operativo per NOP è 0x90.
Quando si esegue il debug del codice, potrebbe essere necessario applicare patch ad alcuni codice. A tale scopo, sostituire i byte che causano l'offesa con 0x90.
Idiomi
XOR |
r, r |
r = 0 |
|
TEST |
r, r |
Controllare se r = 0. |
|
* |
ADD |
r, r |
Maiusc r a sinistra di 1. |