Langage d'assemblage - Registres

Un registre est une unité de stockage à grande vitesse à l'intérieur du CPU, et est l'objet le plus fréquemment manipulé en programmation en assembleur. Comprendre les registres est la première étape clé pour bien apprendre le langage d'assemblage.


Qu'est-ce qu'un registre

Les registres sont intégrés à l'intérieur de la puce du CPUStockage mémoire petit et ultra-rapide, utilisés pour stocker temporairement des instructions, des données et des adresses.

Contrairement à la mémoire, les registres sont intégrés dans le CPU. Le CPU peut accéder aux registres avec une latence quasi nulle, tandis que l'accès à la mémoire nécessite des dizaines à des centaines de cycles d'horloge.

En langage d'assemblage, la grande majorité des opérations tournent autour des registres—les données sont chargées depuis la mémoire vers les registres, les opérations sont effectuées dans les registres, puis les résultats sont stockés à nouveau en mémoire.

Vous pouvez considérer les registres comme l'« établi » du CPU. Les outils sur l'établi sont disponibles à tout moment, tandis que la mémoire est comme un entrepôt vers lequel vous devez vous déplacer pour aller chercher et ranger des éléments.


Classification des registres x86 32 bits

L'architecture x86 32 bits fournit de nombreux types de registres, chacun ayant des usages différents. La figure suivante montre la classification complète des registres :

x86 32位寄存器分类概览

Ci-dessous, nous présentons en détail chaque type de registre :


Registres à usage général

Registres à usage généralCe sont les registres les plus couramment utilisés, servant à stocker des données d'opération et des résultats temporaires.

x86 fournit 8 registres généraux de 32 bits :

32 bits16 bits8 bits de poids faible8 bits de poids fort (des 16 bits de poids faible)Objectif principal
EAXAXALAHAccumulateur, stocke les valeurs de retour de fonction et les résultats des opérations arithmétiques
EBXBXBLBHRegistre de base, souvent utilisé pour stocker les adresses de base mémoire
ECXCXCLCHCompteur, souvent utilisé pour le comptage de boucles et les décalages
EDXDXDLDHRegistre de données, stocke les résultats de poids fort de la multiplication et de la division
ESISISIL-Registre d'index source, adresse source pour les opérations sur les chaînes
EDIDIDIL-Registre d'index de destination, adresse de destination pour les opérations sur chaînes
EBPBPBPL-Pointeur de base, pointe vers le bas du cadre de pile actuel
ESPSPSPL-Pointeur de pile, pointe toujours vers le sommet de la pile

Convention de nommage : le préfixe E signifie Extended (étendu à 32 bits), et le suffixe X indique qu'il peut être divisé en octets haut et bas.

Exemple

; Chemin du fichier : register_parts.asm
; Démontrer l'accès aux différentes parties des registres

section .text
    global _start

_start:
    mov eax, 0x12345678     ; Registre 32 bits complet
    ; À ce stade : EAX = 0x12345678
    ; AX = 0x5678 (16 bits de poids faible)
    ; AH = 0x56 (8 bits de poids fort, c.-à-d. les 8 bits de poids fort de AX)
    ; AL = 0x78 (8 bits de poids faible)

    mov ax, 0xAABB          ; Modifier AX (16 bits de poids faible)
    ; À ce stade : EAX = 0x1234AABB (les 16 bits de poids fort restent inchangés !)
    ; AX = 0xAABB
    ; AL = 0xBB

    mov al, 0xCC            ; Modifier AL (les 8 bits les moins significatifs)
    ; À ce stade : EAX = 0x1234AACC (seuls les 8 bits de poids faible ont changé)
    ; AX = 0xAACC
    ; AL = 0xCC

    mov eax, 1
    mov ebx, 0
    int 0x80

Lors de la modification des 16 bits de poids faible d'un registre 32 bits (tel que AX), les 16 bits de poids fort restent inchangés. Cependant, lorsqu'un registre 32 bits est utilisé comme opérande de destination, les 32 bits entiers sont écrasés. C'est une source fréquente d'erreurs pour les débutants.


Registres de segment

Les registres de segment servent à spécifier le segment de mémoire utilisé actuellement :

RegistreNameObjectif
CSRegistre de segment de codePointe vers le segment où se trouve l'instruction en cours
DSRegistre de segment de donnéesPointe vers le segment où se trouvent les données
SSRegistre de segment de pilePointe vers le segment où se trouve la pile
ESRegistre de segment supplémentaireSegment de données supplémentaire
FSRegistre de segment supplémentaireUsage général, souvent utilisé pour le stockage local au thread
GSRegistre de segment supplémentaireÀ usage général, couramment utilisé pour le stockage local au thread

Lors de la programmation en mode protégé 32 bits, le système d'exploitation a déjà configuré les registres de segment, donc vous n'avez généralement pas besoin de les modifier manuellement.


Registres de pointeur et d'index

Ces registres sont principalement utilisés pour accéder à la mémoire et stocker des adresses mémoire :

RegistreNom completObjectif
EIPPointeur d'instructionPointe vers l'adresse de la prochaine instruction à exécuter par le CPU (non directement accessible)
ESPPointeur de pilePointe vers le sommet de la pile ; les instructions PUSH/POP l'ajustent automatiquement
EBPPointeur de basePointe vers le bas du cadre de pile de la fonction courante, utilisé pour accéder aux paramètres de fonction et aux variables locales
ESIIndex sourceAdresse source pour les opérations sur chaînes/mémoire
EDIIndex destinationAdresse de destination pour les opérations sur chaînes/mémoire

ESP et EBP ne peuvent pas être utilisés librement comme des registres généraux ordinaires. ESP pointe vers le sommet de la pile, et push/pop/call/ret le modifient tous ; EBP est essentiel pour accéder aux paramètres de fonction. Les modifier arbitrairement fera planter le programme.


Registre des drapeaux (EFLAGS)

EFLAGSIl s'agit d'un registre de 32 bits, chaque bit représente un drapeau d'état.

Vous ne pouvez pas lire ou écrire directement l'intégralité du registre EFLAGS, mais le CPU met automatiquement à jour ces bits de drapeau en fonction des résultats des opérations, et les instructions de saut conditionnel les utilisent pour décider si elles doivent sauter.

Bit de drapeauNameSignification
CFDrapeau de retenueMis à 1 lorsque l'arithmétique non signée produit une retenue/un emprunt
PFIndicateur de paritéMis à 1 lorsque le nombre de 1 dans les 8 bits de poids faible du résultat est pair
AFIndicateur de retenue auxiliaireMis à 1 lorsqu'il y a une retenue/un emprunt des 4 bits de poids faible vers les 4 bits de poids fort
ZFIndicateur zéroMis à 1 lorsque le résultat de l'opération est 0
SFIndicateur de signeMis à 1 lorsque le résultat de l'opération est négatif (égal au bit de poids fort du résultat)
OFIndicateur de débordementMis à 1 lorsque l'arithmétique signée produit un débordement

Exemple

; Chemin du fichier : flags_demo.asm
; Illustre l'effet de l'arithmétique sur les bits d'indicateur

section .text
    global _start

_start:
    mov eax, 10
    sub eax, 10         ; 10 - 10 = 0
    ; ZF = 1 (le résultat est zéro)
    ; SF = 0 (le résultat est non négatif)
    ; CF = 0 (pas d'emprunt)

    mov eax, 0xFFFFFFFF
    add eax, 1          ; 0xFFFFFFFF + 1 = 0x100000000 (dépasse 32 bits)
    ; ZF = 1 (le résultat sur 32 bits est 0)
    ; CF = 1 (retenue générée)
    ; OF = 0 (pas de débordement du point de vue signé)

    mov eax, 1
    mov ebx, 0
    int 0x80

Conventions d'utilisation des registres

En programmation réelle, certains registres ont des usages conventionnels — appelésConvention d'appel:

RegistreRôle dans la convention d'appel
EAXStocker la valeur de retour de la fonction
ECXCompteur (nombre de boucles)
EDXStocker la partie haute des résultats de division, étendre EAX
EBX、ESI、EDI、EBPSauvegardés par l'appelé : la fonction appelée doit les sauvegarder et les restaurer
EAX、ECX、EDXSauvegardés par l'appelant : l'appelant est responsable de la sauvegarde

Lorsque vous écrivez vos propres programmes en assembleur, vous n'êtes pas obligé de suivre strictement la convention d'appel. Mais si vous mélangez avec du C, vous devez suivre la convention d'appel cdecl.

Autres extensions