Instructions x86
Dans les listes de cette section, les instructions marquées d’un astérisque (*) sont particulièrement importantes. Les instructions qui ne sont pas aussi marquées ne sont pas critiques.
Sur le processeur x86, les instructions sont de taille variable. Le désassemblement vers l’arrière est donc un exercice de correspondance de modèle. Pour procéder au désassemblage à partir d’une adresse, vous devez commencer le désassemblage à un point plus en arrière que vous voulez vraiment aller, puis regarder vers l’avant jusqu’à ce que les instructions commencent à avoir du sens. Les premières instructions peuvent ne pas avoir de sens, car vous avez peut-être commencé le démontage au milieu d’une instruction. Il est possible, malheureusement, que le désassemblement ne se synchronise jamais avec le flux d’instructions et que vous devrez essayer le désassemblement à un autre point de départ jusqu’à ce que vous trouviez un point de départ qui fonctionne.
Pour les instructions switch bien remplies, le compilateur émet des données directement dans le flux de code, de sorte que le désassemblage via une instruction switch va généralement tomber sur des instructions qui n’ont aucun sens (car il s’agit en fait de données). Recherchez la fin des données et continuez le désassemblement.
Notation d’instruction
La notation générale pour les instructions consiste à placer le registre de destination à gauche et la source à droite. Toutefois, il peut y avoir quelques exceptions à cette règle.
Les instructions arithmétiques sont généralement à deux registres avec les registres source et de destination combinant. Le résultat est stocké dans la destination.
Certaines instructions ont des versions 16 bits et 32 bits, mais seules les versions 32 bits sont répertoriées ici. Les instructions à virgule flottante, les instructions privilégiées et les instructions utilisées uniquement dans les modèles segmentés (que Microsoft Win32 n’utilise pas) ne sont pas répertoriées ici.
Pour économiser de l’espace, de nombreuses instructions sont exprimées sous forme combinée, comme illustré dans l’exemple suivant.
* |
MOV |
r1, r/m/#n |
r1 = r/m/#n |
signifie que le premier paramètre doit être un registre, mais que le second peut être un registre, une référence de mémoire ou une valeur immédiate.
Pour économiser encore plus d’espace, les instructions peuvent également être exprimées comme indiqué dans la section suivante.
* |
MOV |
r1/m, r/m/#n |
r1/m = r/m/#n |
ce qui signifie que le premier paramètre peut être un registre ou une référence mémoire, et le second peut être un registre, une référence mémoire ou une valeur immédiate.
Sauf indication contraire, lorsque cette abréviation est utilisée, vous ne pouvez pas choisir la mémoire pour la source et la destination.
En outre, un suffixe de taille de bits (8, 16, 32) peut être ajouté à la source ou à la destination pour indiquer que le paramètre doit être de cette taille. Par exemple, r8 signifie un registre 8 bits.
Mémoire, transfert de données et conversion de données
Les instructions de transfert de mémoire et de données n’affectent pas les indicateurs.
Adresse effective
* |
LEA |
r, m |
Adresse effective de chargement. (r = adresse de m) |
Par exemple, LEA eax, [esi+4] signifie eax = esi + 4. Cette instruction est souvent utilisée pour effectuer des opérations arithmétiques.
Transfert de données
MOV |
r1/m, r2/m/#n |
r1/m = r/m/#n |
|
MOVSX |
r1, r/m |
Déplacer avec l’extension de signe. |
|
* |
MOVZX |
r1, r/m |
Déplacer avec aucune extension. |
MOVSX et MOVZX sont des versions spéciales de l’instruction mov qui effectuent une extension de signe ou une extension zéro de la source vers la destination. Il s’agit de la seule instruction qui permet à la source et à la destination d’avoir des tailles différentes. (Et en fait, ils doivent être de tailles différentes.
Manipulation de pile
La pile est pointée vers le registre esp . La valeur au niveau esp est le haut de la pile (dernièrement poussé, premier à faire éclater) ; les éléments de pile plus anciens se trouvent à des adresses plus élevées.
PUSH |
r/m/#n |
Pousser la valeur sur la pile. |
|
POP |
r/m |
Valeur contextuelle de la pile. |
|
PUSHFD |
Pousser les indicateurs sur la pile. |
||
POPFD |
Afficher des indicateurs de la pile. |
||
PUSHAD |
Envoyer (push) tous les registres d’entiers. |
||
POPAD |
Afficher tous les registres d’entiers. |
||
ENTRÉE |
#n, #n |
Build stack frame. |
|
* |
LAISSER |
Supprimer le cadre de la pile |
Le compilateur C/C++ n’utilise pas l’instruction Enter . (L’instruction Enter est utilisée pour implémenter des procédures imbriquées dans des langages tels que Algol ou Pascal.)
L’instruction de congé équivaut à :
mov esp, ebp
pop ebp
Conversion de données
CBW |
Convertir l’octet (al) en mot (ax). |
CWD |
Convertir word (ax) en dword (dx:ax). |
CWDE |
Convertir word (ax) en dword (eax). |
CDQ |
convertir dword (eax) en qword (edx:eax). |
Toutes les conversions effectuent une extension de signe.
Arithmétique et manipulation de bits
Toutes les instructions arithmétiques et de manipulation de bits modifient les indicateurs.
Arithmétique
ADD |
r1/m, r2/m/#n |
r1/m += r2/m/#n |
|
ADC |
r1/m, r2/m/#n |
r1/m += r2/m/#n + transport |
|
SUB |
r1/m, r2/m/#n |
r1/m -= r2/m/#n |
|
CFF |
r1/m, r2/m/#n |
r1/m -= r2/m/#n + carry |
|
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 |
Calcul r1/m - r2/m/#n |
L’instruction cmp calcule la soustraction et définit les indicateurs en fonction du résultat, mais supprime le résultat. Il est généralement suivi d’une instruction de saut conditionnel qui teste le résultat de la soustraction.
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 |
Multiplication non signée et non signée. L’état des indicateurs après la multiplication n’est pas défini.
DIV |
r/m8 |
(ah, al) = (ax % r/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 |
Division non signée et non signée. Le premier registre de l’explication pseudocode reçoit le reste et le second reçoit le quotient. Si le résultat dépasse la destination, une exception de dépassement de capacité de division est générée.
L’état des indicateurs après la division n’est pas défini.
* |
SETcc |
r/m8 |
Définissez r/m8 sur 0 ou 1 |
Si la condition cc est true, la valeur 8 bits est définie sur 1. Sinon, la valeur 8 bits est définie sur zéro.
Décimal codé en binaire
Vous ne verrez pas ces instructions, sauf si vous déboguez du code écrit dans COBOL.
DAA |
Ajustement décimal après l’ajout. |
|
DAS |
Ajustement décimal après soustraction. |
Ces instructions ajustent le registre al après avoir effectué une opération décimale à code binaire empaqueté.
AAA |
Ajustez ASCII après l’ajout. |
AAS |
Ajustez ASCII après soustraction. |
Ces instructions ajustent le registre al après avoir effectué une opération décimale à code binaire décompressée.
AAM |
Ajustez ASCII après la multiplication. |
AAD |
Ajustez ASCII après division. |
Ces instructions ajustent les registres al et ah après avoir effectué une opération décimale codée binaire décompressée.
Bits
AND |
r1/m, r2/m/#n |
r1/m = r1/m et r2/m/#n |
|
OR |
r1/m, r2/m/#n |
r1/m = r1/m ou r2/m/#n |
|
XOR |
r1/m, r2/m/#n |
r1/m = r1/m xor r2/m/#n |
|
NOT |
r1/m |
r1/m = au niveau du bit et non r1/m |
|
* |
TEST |
r1/m, r2/m/#n |
Calcul r1/m et r2/m/#n |
L’instruction de test calcule l’opérateur AND logique et définit les indicateurs en fonction du résultat, mais supprime le résultat. Elle est généralement suivie d’une instruction de saut conditionnel qui teste le résultat du AND logique.
SHL |
r1/m, cl/#n |
r1/m <<= cl/#n |
|
SHR |
r1/m, cl/#n |
r1/m >>= cl/#n remplissage zéro |
|
* |
SAR |
r1/m, cl/#n |
r1/m >>= cl/#n sign-fill |
Le dernier bit décalé est placé dans le transport.
SHLD |
r1, r2/m, cl/#n |
Double décalage vers la gauche. |
Décaler r1 vers la gauche par cl/#n, en remplit avec les bits supérieurs de r2/m. Le dernier bit décalé est placé dans le transport.
SHRD |
r1, r2/m, cl/#n |
Double décalage vers la droite. |
Déplacez r1 vers la droite par cl/#n, en remplissant avec les bits inférieurs de r2/m. Le dernier bit décalé est placé dans le transport.
ROL |
r1, cl/#n |
Faites pivoter r1 vers la gauche de cl/#n. |
ROR |
r1, cl/#n |
Faire pivoter r1 vers la droite de cl/#n. |
RCL |
r1, cl/#n |
Faites pivoter r1/C vers la gauche de cl/#n. |
RCR |
r1, cl/#n |
Faites pivoter r1/C vers la droite de cl/#n. |
La rotation est semblable au décalage, sauf que les bits qui sont déplacés vers l’extérieur réapparaissent en tant que bits de remplissage entrants. La version en langage C des instructions de rotation incorpore le bit de transport dans la rotation.
BT |
r1, r2/#n |
Copiez le bit r2/#n de r1 dans carry. |
BTS |
r1, r2/#n |
Définissez le bit r2/#n de r1, copiez la valeur précédente dans carry. |
BTC |
r1, r2/#n |
Effacez le bit r2/#n de r1, copiez la valeur précédente dans carry. |
Flux de contrôle
Jcc |
Dest |
Branche conditionnelle. |
|
JMP |
Dest |
Saut direct. |
|
JMP |
r/m |
Saut indirect. |
|
CALL |
Dest |
Appel direct. |
|
* |
CALL |
r/m |
Appel indirect. |
L’instruction d’appel envoie (push) l’adresse de retour sur la pile, puis passe à la destination.
* |
RET |
#n |
Renvoie |
L’instruction ret s’affiche et passe à l’adresse de retour sur la pile. Une #n différente de zéro dans l’instruction RET indique qu’après avoir fait éclater l’adresse de retour, la valeur #n doit être ajoutée au pointeur de pile.
BOUCLE |
Décrémentez ecx et sautez si le résultat est différent de zéro. |
LOOPZ |
Décrémentez ecx et sautez si le résultat est différent de zéro et que zr a été défini. |
LOOPNZ |
Décrémentez ecx et sautez si le résultat est différent de zéro et que zr était clair. |
JECXZ |
Sautez si ecx est égal à zéro. |
Ces instructions sont des vestiges de l’héritage CISC du x86 et dans les processeurs récents sont en fait plus lents que les instructions équivalentes écrites à long terme.
Manipulation de chaînes
MOVST |
Déplacer Td’esi vers edi. |
|
CMPST |
Comparez T à partir d’esi avec edi. |
|
SCAST |
Analysez T à partir d’edi pour rechercher accT. |
|
LODST |
Charger T à partir d’esi dans accT. |
|
STOST |
Stockez T dans edi à partir de l’accT. |
Après avoir effectué l’opération, le registre source et de destination sont incrémentés ou décrémentés par sizeof(T), en fonction du paramètre de l’indicateur de direction (haut ou bas).
L’instruction peut être préfixée par REP pour répéter l’opération le nombre de fois spécifié par le registre ecx .
L’instruction rep mov est utilisée pour copier des blocs de mémoire.
L’instruction rep stos est utilisée pour remplir un bloc de mémoire avec accT.
Drapeaux
LAHF |
Charger ah à partir d’indicateurs. |
SAHF |
Stockez ah dans les indicateurs. |
STC |
Définissez carry. |
SIC |
Clear carry. |
CMC |
Complément porter. |
STD |
Définissez la direction vers le bas. |
CLD |
Définissez la direction vers le haut. |
STI |
Activez les interruptions. |
Interface de ligne de commande |
Désactivez les interruptions. |
Instructions verrouillées
XCHG |
r1, r/m |
Échangez r1 et r/m. |
XADD |
r1, r/m |
Ajoutez r1 à r/m, puis placez la valeur d’origine dans r1. |
CMPXCHG |
r1, r/m |
Comparer et échanger des conditions. |
L’instruction cmpxchg est la version atomique des éléments suivants :
cmp accT, r/m
jz match
mov accT, r/m
jmp done
match:
mov r/m, r1
done:
Divers
INT |
#n |
Intercepter dans le noyau. |
|
LIÉ |
r, m |
Intercepter si r n’est pas dans la plage. |
|
* |
NOP |
Pas d'opération. |
|
XLATB |
al = [ebx + al] |
||
BSWAP |
r |
Échanger l’ordre des octets dans le registre. |
Voici un cas particulier de l’instruction int .
INT |
3 |
Piège de point d’arrêt du débogueur. |
L’opcode pour INT 3 est 0xCC. L’opcode pour NOP est 0x90.
Lors du débogage de code, vous devrez peut-être corriger du code. Pour ce faire, remplacez les octets incriminés par 0x90.
Idiomes
XOR |
r, r |
r = 0 |
|
TEST |
r, r |
Vérifiez si r = 0. |
|
* |
ADD |
r, r |
Décaler r vers la gauche par 1. |