Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
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-registres de 16 bits ou de 8 bits.
ax |
Les 16 bits inférieurs de eax |
Bx |
Inférieurs 16 bits de ebx |
cx |
Les 16 bits inférieurs de ecx |
Dx |
Partie basse sur 16 bits de edx |
si |
Faible 16 bits de esi |
di |
Bas 16 bits de edi |
Bp |
Faible 16 bits de ebp |
sp |
Les 16 bits inférieurs de ESP |
Al |
Bas 8 bits eax |
|
Les 8 bits de poids fort de ax |
bl |
Les 8 bits de poids faible de ebx |
Bh |
8 bits élevés de bx |
Cl |
Les 8 bits de poids faible de ecx |
Ch |
8 bits élevés de cx |
Dl |
Faible 8 bits de edx |
Dh |
8 bits élevés de dx |
Le fonctionnement d’un sous-registre affecte uniquement le sous-registre et aucune des parties à l'extérieur du sous-registre. 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 |
indicateurs |
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 de droite à 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, empilés de droite à gauche, puis le pointeur « this » est empilé 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 de droite à gauche. L’appelé nettoie la pile.
__cdecl
Les paramètres de fonction sont transmis sur la pile, poussés de droite à 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 fanions
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. Ces registres à bit unique ont une variété d'utilisations.
Le tableau suivant répertorie les indicateurs x86 :
| Code de Balise | Nom du drapeau | Valeur | État du drapeau | Descriptif |
|---|---|---|---|---|
| de | Indicateur de dépassement de capacité | 0 1 | nvov | Pas de dépassement de capacité - Dépassement de capacité |
| Df | Balise de direction | 0 1 | updn | Direction vers le haut - Direction vers le bas |
| si | Indicateur d’interruption | 0 1 | diei | Interruptions désactivées - Interruptions activées |
| Sf | Drapeau de Signe | 0 1 | plng | Positif (ou zéro) - Négatif |
| zf | Indicateur zéro | 0 1 | nzzr | Non nul - Zéro |
| Af | Indicateur de report auxiliaire | 0 1 | naac | Pas de transport auxiliaire - Transport auxiliaire |
| Pf | Indicateur de parité | 0 1 | Pepo | Parité impaire - Parité même |
| cf | Indicatif de retenue | 0 1 | nccy | Pas de transport - Porter |
| tf | Indicateur de piège | 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 de commande du débogueur, c’est le statut du drapeau qui est 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 à zéro. Si vous effectuez un autre affichage du registre, le code d’état ng n’apparaîtra pas. Au lieu de cela, le code d’état pl s’affiche.
L’indicateur de signe, l’indicateur zéro et l’indicateur de retenue 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 condition | Drapeaux | Sens |
|---|---|---|
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 nécessité de retenue ni d'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. |
NON |
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 condition | Drapeaux | Signification après une opération CMP. |
|---|---|---|
E |
ZF=1 |
value1 == valeur2. |
NE |
ZF=0 |
value1 != value2. |
| GE NL | SF=OF |
value1>= valeur2. Les valeurs sont traitées comme des entiers signés. |
| LE NG | ZF=1 ou SF !=OF |
value1<= valeur2. Les valeurs sont traitées comme des entiers signés. |
| G NLE | ZF=0 et SF=OF |
value1>valeur2. Les valeurs sont traitées comme des entiers signés. |
| L NGE | SF !=OF |
value1<valeur2. Les valeurs sont traitées comme des entiers signés. |
| AE NB | CF=0 |
value1>= valeur2. Les valeurs sont traitées comme des entiers non signés. |
| BE NA | CF=1 ou ZF=1 |
value1<= valeur2. Les valeurs sont traitées comme des entiers non signés. |
| Un NBE | CF=0 et ZF=0 |
value1>valeur2. Les valeurs sont traitées comme des entiers non signés. |
| B NAE | CF=1 |
value1<valeur2. 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 (comprend les doubles en 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 | Sens |
|---|---|
r, r1, r2... |
Registres |
m |
Adresse mémoire (consultez la section Modes d’adressage suivante pour plus d’informations.) |
#n |
Constante immédiate |
r/m |
Registre ou mémoire |
r/#n |
Registre ou constante immédiate |
r/m/#n |
registre, mémoire ou une constante immédiate |
cc |
Code de condition répertorié dans la section Conditions précédentes. |
T |
« B », « W » ou « D » (octet, mot ou double 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 émission, ce qui signifie qu’il peut effectuer jusqu’à deux actions en un cycle d'horloge. Toutefois, les règles sur le moment où il est capable d’effectuer deux actions à la fois (appelées appairage) sont très compliquées.
Étant donné que le x86 est un processeur CISC, vous n'avez pas besoin de vous soucier des délais de saut.
Accès à la mémoire synchronisée
Les instructions de chargement, de modification et de stockage peuvent recevoir un préfixe de verrou, qui modifie l’instruction comme suit :
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échargements de données sont abandonnés.
Lors de l’émission de l’instruction, le processeur 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-bloquantes.
Prédiction de saut
Les sauts inconditionnels sont prédits pour être réalisés.
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 pour l'historique de navigation 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, au détriment des 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 lock ne doit pas être utilisé pour les accès à la mémoire non alignés.