Partager via


Architecture x86

Le processeur Intel x86 utilise l’architecture CISC (Complex Instruction Set Computer), ce qui signifie qu’il existe un nombre modeste de registres à usage spécial au lieu de grandes quantités de registres à usage général. Cela signifie également que des instructions spéciales complexes prédomineront.

Le processeur x86 trace son héritage au moins jusqu’au processeur Intel 8080 8 bits. De nombreuses particularités dans le jeu d’instructions x86 sont dues à la compatibilité descendante avec ce processeur (et avec sa variante Zilog Z-80).

Microsoft Win32 utilise le processeur x86 en mode plat 32 bits. Cette documentation se concentre uniquement sur le mode plat.

Registres

L’architecture x86 se compose des registres entiers non privilégiés suivants.

eax

Accumulateur

ebx

Registre de base

ecx

Registre de compteurs

edx

Registre des données : peut être utilisé pour l’accès aux ports d’E/S et les fonctions arithmétiques

Esi

Registre d’index source

Edi

Registre d’index de destination

ebp

Registre de pointeur de base

Esp

Pointeur de pile

Tous les registres entiers sont 32 bits. Toutefois, beaucoup d’entre eux ont des sous-inscriptions 16 bits ou 8 bits.

hache

Faible 16 bits d’eax

Bx

Faible 16 bits d’ebx

cx

Faible 16 bits d’ecx

Dx

Faible 16 bits d’edx

si

Faible 16 bits d’esi

di

Faible 16 bits d’edi

Bp

Faible 16 bits d’ebp

Sp

Bas 16 bits d’esp

Al

Faible 8 bits d’eax

ah

8 bits élevés d’ax

bl

Faible 8 bits d’ebx

Bh

8 bits élevés de bx

Cl

Faible 8 bits d’ecx

Ch

8 bits élevés de cx

dl

Faible 8 bits d’edx

Dh

8 bits élevés de dx

L’exploitation d’une sous-inscription affecte uniquement la sous-inscription et aucune des parties en dehors de la sous-inscription. Par exemple, le stockage dans le registre ax laisse les 16 bits élevés du registre eax inchangé.

Quand vous utilisez le ? (Évaluer l’expression) commande, les registres doivent être précédés d’un signe « at » ( @ ). Par exemple, vous devez utiliser ? @ax plutôt que ? ax. Cela garantit que le débogueur reconnaît ax comme un registre plutôt qu’un symbole.

Toutefois, la commande r (@) n’est pas requise dans la commande r (Registers). Par exemple, r ax=5 est toujours interprété correctement.

Deux autres registres sont importants pour l’état actuel du processeur.

eip

pointeur d’instruction

flags

flags

Le pointeur d’instruction est l’adresse de l’instruction en cours d’exécution.

Le registre des indicateurs est une collection d’indicateurs mono bits. De nombreuses instructions modifient les indicateurs pour décrire le résultat de l’instruction. Ces indicateurs peuvent ensuite être testés par des instructions de saut conditionnel. Pour plus d’informations, consultez les indicateurs x86.

Conventions d’appel

L’architecture x86 a plusieurs conventions d’appel différentes. Heureusement, ils suivent tous les mêmes règles de préservation du registre et de retour de fonction :

  • Les fonctions doivent conserver tous les registres, à l’exception de eax, ecx et edx, qui peuvent être modifiés dans un appel de fonction, et esp, qui doivent être mis à jour en fonction de la convention d’appel.

  • Le registre eax reçoit des valeurs de retour de fonction si le résultat est de 32 bits ou plus petit. Si le résultat est de 64 bits, le résultat est stocké dans la paire edx :eax .

Voici une liste des conventions d’appel utilisées sur l’architecture x86 :

  • Win32 (__stdcall)

    Les paramètres de fonction sont transmis sur la pile, poussés vers la gauche, et l’appelé nettoie la pile.

  • Appel de méthode C++ natif (également appelé thiscall)

    Les paramètres de fonction sont transmis sur la pile, poussés vers la gauche, le pointeur « this » est passé dans le registre ecx et l’appelé nettoie la pile.

  • COM (__stdcall pour les appels de méthode C++)

    Les paramètres de fonction sont transmis sur la pile, poussés de droite à gauche, puis le pointeur « this » est envoyé (push) sur la pile, puis la fonction est appelée. L’appelé nettoie la pile.

  • __fastcall

    Les deux premiers arguments DWORD-or-smaller sont passés dans les registres ecx et edx . Les paramètres restants sont transmis sur la pile, poussés vers la gauche. L’appelé nettoie la pile.

  • __cdecl

    Les paramètres de fonction sont transmis sur la pile, poussés vers la gauche, et l’appelant nettoie la pile. La convention d’appel __cdecl est utilisée pour toutes les fonctions avec des paramètres de longueur variable.

Affichage du débogueur des registres et des indicateurs

Voici un exemple d’affichage du registre du débogueur :

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

Dans le débogage en mode utilisateur, vous pouvez ignorer l’iopl et la dernière ligne de l’affichage du débogueur.

Indicateurs x86

Dans l’exemple précédent, les codes à deux lettres à la fin de la deuxième ligne sont des indicateurs. Il s’agit de registres à bits uniques et d’une variété d’utilisations.

Le tableau suivant répertorie les indicateurs x86 :

Code d’indicateur Nom de l’indicateur Valeur État de l’indicateur Description
de Indicateur de dépassement de capacité 0 1 nvov Aucun dépassement de capacité - Dépassement de capacité
df Balise de direction 0 1 updn Direction vers le haut - Direction vers le bas
if Indicateur d’interruption 0 1 diei Interruptions désactivées - Interruptions activées
sf Indicateur de signe 0 1 plng Positif (ou zéro) - Négatif
zf Indicateur zéro 0 1 nzzr Non égal à zéro - Zéro
af Indicateur de transport auxiliaire 0 1 naac Pas de transport auxiliaire - Transport auxiliaire
pf Indicateur de parité 0 1 Pepo Parité impaire - Parité même
cf Indicateur de transport 0 1 ccny Pas de transport - Porter
tf Indicateur d’interruption Si tf est égal à 1, le processeur déclenche une exception STATUS_SINGLE_STEP après l’exécution d’une instruction. Cet indicateur est utilisé par un débogueur pour implémenter le suivi en une seule étape. Elle ne doit pas être utilisée par d’autres applications.
iopl Niveau de privilège d’E/S Niveau de privilège d’E/S : entier à deux bits, avec des valeurs comprises entre zéro et 3. Il est utilisé par le système d’exploitation pour contrôler l’accès au matériel. Elle ne doit pas être utilisée par les applications.

Lorsque les registres sont affichés à la suite d’une commande dans la fenêtre Commande du débogueur, il s’agit de l’état de l’indicateur affiché. Toutefois, si vous souhaitez modifier un indicateur à l’aide de la commande r (Registers), vous devez vous y référer par le code de l’indicateur.

Dans la fenêtre Registres de WinDbg, le code d’indicateur est utilisé pour afficher ou modifier des indicateurs. L’état de l’indicateur n’est pas pris en charge.

Voici un exemple. Dans l’affichage du registre précédent, l’état de l’indicateur ng s’affiche. Cela signifie que l’indicateur de signe est actuellement défini sur 1. Pour modifier ce problème, utilisez la commande suivante :

r sf=0

Cela définit l’indicateur de signe sur zéro. Si vous effectuez un autre enregistrement, le code d’état ng n’apparaît pas. Au lieu de cela, le code d’état pl s’affiche.

L’indicateur de signe, l’indicateur zéro et l’indicateur de transport sont les indicateurs les plus couramment utilisés.

Conditions

Une condition décrit l’état d’un ou plusieurs indicateurs. Toutes les opérations conditionnelles sur le x86 sont exprimées en termes de conditions.

L’assembleur utilise une abréviation d’une ou deux lettres pour représenter une condition. Une condition peut être représentée par plusieurs abréviations. Par exemple, AE (« supérieur ou égal ») est la même condition que NB (« pas ci-dessous »). Le tableau suivant répertorie certaines conditions courantes et leur signification.

Nom de la condition Indicateurs Signification

Z

ZF=1

Le résultat de la dernière opération était égal à zéro.

NZ

ZF=0

Le résultat de la dernière opération n’a pas été égal à zéro.

C

CF=1

La dernière opération exigeait un transport ou un emprunt. (Pour les entiers non signés, cela indique un dépassement de capacité.)

NC

CF=0

La dernière opération n’a pas besoin d’un transport ou d’un emprunt. (Pour les entiers non signés, cela indique un dépassement de capacité.)

S

SF=1

Le résultat de la dernière opération a son jeu de bits élevé.

NS

SF=0

Le résultat de la dernière opération a son bit clair élevé.

O

OF=1

Lorsqu’elle est traitée comme une opération entière signée, la dernière opération a provoqué un dépassement de capacité ou un sous-flux.

NO

OF=0

Lorsqu’elle est traitée comme une opération entière signée, la dernière opération n’a pas déclenché de dépassement de capacité ou de sous-flux.

Les conditions peuvent également être utilisées pour comparer deux valeurs. L’instruction cmp compare ses deux opérandes, puis définit des indicateurs comme s’il était soustrait un opérande de l’autre. Les conditions suivantes peuvent être utilisées pour vérifier le résultat de la valeur cmp1, valeur2.

Nom de la condition Indicateurs Signification après une opération CMP.

E

ZF=1

value1 == value2.

NE

ZF=0

value1 != value2.

GE NL

SF=OF

value1>= value2. Les valeurs sont traitées comme des entiers signés.

LE NG

ZF=1 ou SF !=OF

value1<= value2. Les valeurs sont traitées comme des entiers signés.

G NLE

ZF=0 et SF=OF

value1>value2. Les valeurs sont traitées comme des entiers signés.

L NGE

SF !=OF

value1<value2. Les valeurs sont traitées comme des entiers signés.

AE NB

CF=0

value1>= value2. Les valeurs sont traitées comme des entiers non signés.

BE NA

CF=1 ou ZF=1

value1<= value2. Les valeurs sont traitées comme des entiers non signés.

Un NBE

CF=0 et ZF=0

value1>value2. Les valeurs sont traitées comme des entiers non signés.

B NAE

CF=1

value1<value2. Les valeurs sont traitées comme des entiers non signés.

Les conditions sont généralement utilisées pour agir sur le résultat d’une instruction cmp ou de test . Par exemple,

cmp eax, 5
jz equal

compare le registre eax au nombre 5 en calculant l’expression (eax - 5) et en définissant des indicateurs en fonction du résultat. Si le résultat de la soustraction est égal à zéro, l’indicateur zr sera défini et la condition jz sera vraie afin que le saut soit pris.

Types de données

  • octets : 8 bits

  • word : 16 bits

  • dword : 32 bits

  • qword : 64 bits (inclut des doubles à virgule flottante)

  • deuxe : 80 bits (inclut des doubles étendus à virgule flottante)

  • oword : 128 bits

Notation

Le tableau suivant indique la notation utilisée pour décrire les instructions de langage d’assembly.

Notation Signification

r, r1, r2...

Caisses

m

Adresse mémoire (consultez la section Modes d’adressage réussis pour plus d’informations.)

#n

Constante immédiate

r/m

Inscrire ou mémoire

r/#n

Inscrire ou immédiatement une constante

r/m/#n

Inscrire, mémoire ou constante immédiate

cc

Code de condition répertorié dans la section Conditions précédentes.

T

« B », « W » ou « D » (octet, mot ou mot)

accT

Taille T accumulateur : al if T = « B », ax if T = « W », or eax if T = « D »

Modes d’adressage

Il existe plusieurs modes d’adressage différents, mais ils prennent tous la forme T ptr [expr], où T est un type de données (voir la section Types de données précédent) et expr est une expression impliquant des constantes et des registres.

La notation pour la plupart des modes peut être déduite sans beaucoup de difficulté. Par exemple, BYTE PTR [esi+edx*8+3] signifie « prendre la valeur du registre esi , l’ajouter huit fois la valeur du registre edx , ajouter trois, puis accéder à l’octet à l’adresse résultante ».

Pipelining

Le Pentium est double problème, ce qui signifie qu’il peut effectuer jusqu’à deux actions en une tique d’horloge. Toutefois, les règles sur le moment où il est capable d’effectuer deux actions à la fois (appelée appairage) sont très compliquées.

Étant donné que x86 est un processeur CISC, vous n’avez pas à vous soucier des emplacements de délai de saut.

Accès à la mémoire synchronisée

Les instructions de chargement, de modification et de magasin peuvent recevoir un préfixe de verrou , qui modifie l’instruction comme suit :

  1. Avant d’émettre l’instruction, le processeur vide toutes les opérations de mémoire en attente pour garantir la cohérence. Toutes les prérécupérations de données sont abandonnées.

  2. Lors de l’émission de l’instruction, l’UC aura un accès exclusif au bus. Cela garantit l’atomicité de l’opération de chargement/modification/magasin.

L’instruction xchg obéit automatiquement aux règles précédentes chaque fois qu’elle échange une valeur avec la mémoire.

Toutes les autres instructions sont par défaut non verrouillées.

Prédiction de saut

Les sauts inconditionnels sont prévus pour être pris.

Les sauts conditionnels sont prédits comme étant pris ou non, selon qu’ils ont été pris la dernière fois qu’ils ont été exécutés. Le cache de l’historique des sauts d’enregistrement est limité en taille.

Si le processeur n’a pas d’enregistrement indiquant si le saut conditionnel a été pris ou non la dernière fois qu’il a été exécuté, il prédit les sauts conditionnels vers l’arrière comme pris et les sauts conditionnels vers l’avant comme non pris.

Alignement

Le processeur x86 corrige automatiquement l’accès à la mémoire non alignée, à une pénalité de performances. Aucune exception n’est levée.

Un accès à la mémoire est considéré comme aligné si l’adresse est un multiple entier de la taille de l’objet. Par exemple, tous les accès BYTE sont alignés (tout est un multiple entier de 1), les accès WORD aux adresses paires sont alignés et les adresses DWORD doivent être un multiple de 4 pour être alignées.

Le préfixe de verrou ne doit pas être utilisé pour les accès à la mémoire non alignés.