Partager via


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.