Instructions Basiques#

Catégorie

Opérations

Opcodes

Description

Mouvement de données

Copie de registre/mémoire

mov

Transfère des données entre des registres, dans la mémoire ou charge des valeurs immédiates

Copie Conditionnelle

cmovcc

Déplace les données uniquement si le code de condition (cc) est rempli (par exemple, cmove, cmovg)

Copie avec extension

movsx, movzx

Étend le signe (movsx) ou étend avec zéro (movzx) les valeurs plus petites vers des tailles plus grandes

La Pile

Push

push

Décrémente RSP et stocke l’opérande dans la pile

Pop

pop

Charge la valeur depuis la pile et incrémente RSP

Enter/Leave

enter, leave

Crée/supprime une stack frame

Arithmetique

Math Basique

add, sub

Addition et soustraction

Multiplication

mul, imul

Multiplication non signée (mul) et signée (imul)

Division

div, idiv

Division non signée (div) et signée (idiv)

Math Rapide

inc, dec

Incrémente ou décrémente de 1

Math Complexe

lea

Load Effective Address, calcule l’adresse pointée, et la charge dans le registre

Bitwise

Logique

and, or, xor

Opérations booléennes de base

Shifts

shl, shr

Décalage logique à gauche/à droite

Arithmetic Shifts

sal, sar

Décalage arithmétique à gauche/à droite

Rotatation

rol, ror, rcl, rcr

Rotation des bits

Comparaison

Compare

cmp

Soustrait les opérandes et définit les indicateurs

Test

test

Fait un bitwise ANDs, met à jour les flags sans charger le résultat dans le registre destination

Structure de contrôle

Jump Unconditionnel

jmp

Jump direct (unconditionnel)

Jump Conditionnel

jcc

Jump si (condition)

Call/Return

call, ret

Appel et retour de fonction

Contrôle des Flags

Carry Flag

clc, stc

Clear/Set CF

Direction Flag

cld, std

Clear/Set DF

Interrupt Flag

cli, sti

Clear/Set IF

Système

Appel Système

syscall

Appel système

Interruption

int

Interruption logicielle

Exemple avec lea:

; Récupérer l'adresse d'un élément dans un tableau contigue (array)
leal (%ebx, %ecx, 4), %eax    # eax = ebx + ecx*4 (tableau de dwords, i.e. 4 octets)
leaq (%rbx, %rcx, 8), %rax    # rax = rbx + rcx*8 (tableau de qwords, i.e. 8 octets)

; Addition de valeurs multiples
leal 5(%rax, %rbx), %eax      # eax = rax + rbx + 5 (addition à trois opérands)

; Multiplication et addition combinées
leal 5(%rax, %rax, 2), %eax   # eax = rax * 3 + 5

Optimisations courantes

  • xor %rax, %rax est plus efficace que mov $0, %rax pour mettre à zéro un registre.

  • test %rax, %rax est plus efficace que cmp $0, %rax pour tester si un registre est à zéro.

  • Le compilateur peut ajouter des instructions nop (qui font rien) pour optimiser l’alignement en mémoire et l’utilisation du cache d’instructions.

Notes pour le mode 64 bits

  • Les opérations 32 bits sur les registres étends implicitement leur valeur à 64 bits avec des zéros. Par exemple, charger une valeur de 32-bits dans %rax va forcer les 32 bits de poids fort à zéro même si la valeur est négative.

  • movslq/movsxd sont nécessaire pour l’extension de signe 32→64 bits.

  • Vous pouvez écrire movq pour charger une valeur immédiate de 8 octets (64 bits) dans un registre. Par contre, si vous dumpez le binaire obtenu via objdump vous verez que l’instruction s’est changée en movabs. C’est une particularité de la syntaxe AT&T, movabs est utilisée lors du chargement d’immédiats de 8 octets à la place de movq. C’est pour faire la différence entre le mov qui va charger des immédiats de 4 octets ou moins dans un register 8 octets en rajoutant des zéros, du mov qui charge réellement un immédiat de 8 octets.

Operations Mémoires#

(RDI) veut dire la case mémoire pointée par RDI. Autrement dit, on déréférence l’adresse stockée dans RDI. Comparer avec (RDI), veut dire comparer avec la valeur dans la case mémoire (RDI).

Instruction

Opération

Taille

Description

stosb

Store AL

1Byte

Charger AL dans (RDI)

stosw

Store AX

2Bytes

Charger AX dans (RDI)

stosd

Store EAX

4Bytes

Charger EAX dans (RDI)

stosq

Store RAX

8Bytes

Charger RAX dans (RDI)

scasb

Scan Byte

1Byte

Comparer le byte AL avec (RDI)

scasw

Scan Word

2Bytes

Comparer le word AX avec (RDI)

scasd

Scan Double Word

4Bytes

Comparer le dword EAX avec (RDI)

scasq

Scan Quad Word

8Bytes

Comparer le qword RAX avec dans (RDI)

cmpsb

Compare Byte

1Byte

Comparer (RSI) avec (RDI)

cmpsw

Compare Word

2Bytes

Comparer (RSI) avec (RDI)

cmpsd

Compare Double Word

4Bytes

Comparer (RSI) avec (RDI)

cmpsq

Compare Quad Word

8Bytes

Comparer (RSI) avec (RDI)

movsb

Move Byte

1Byte

Copier (RSI) dans (RDI)

movsw

Move Word

2Bytes

Copier (RSI) dans (RDI)

movsd

Move Double Word

4Bytes

Copier (RSI) dans (RDI)

movsq

Move Quad Word

8Bytes

Copier (RSI) dans (RDI)

Instructions MOVS et préfixes REP#

movsb/movsw/movsd/movsq permet de copier une donnée d’une taille donnée (b:1 octet, w: 2 octets, d: 4 octets, q: 8 octets) depuis l’adresse spécifiée par le registre rsi vers l’adresse spécifiée par le registre rdi. Après chaque opération, ces registres sont automatiquement mis à jour pour pointer vers l’adresse suivante. La nature de cette mise à jour est contrôlée par le flag de direction (DF) dans le registre RFLAGS. L’instruction cld (Clear Direction Flag) configure le cpu à incrémenter rsi et rdi, permettant une copie vers l’avant. À l’inverse, std (Set Direction Flag) les fait décrémenter pour une copie vers l’arrière.

Le préfixe rep transforme une simple instruction de copie en une puissante opération de copie en bloc. Il utilise le registre rcx comme compteur et répète l’instruction autant de fois que spécifié. Par exemple, rep movsb copiera exactement rcx octets de la source vers la destination.

Il existe également des variantes plus sophistiquées : REPE/REPZ et REPNE/REPNZ. Ces préfixes ajoutent une condition supplémentaire à la répétition(le rcx est toujours utilisé comme compteur). REPE/REPZ continue tant que le flag zéro est actif, tandis que REPNE/REPNZ poursuit tant qu’il est inactif.

memory_copy:
    ; Les paramètres suivent la convention System V AMD64 :
    ; rdi contient l'adresse de destination
    ; rsi contient l'adresse source
    ; rdx contient le nombre d'octets à copier
    
    movq %rdx, %rcx        ; Préparation du compteur
    cld                 ; Configuration pour copie vers l'avant
    rep movsb          ; Exécution de la copie
    ret

Pour résumer:

  1. rep (Repeat) — Répétition inconditionnelle :

    • Répète l’instruction RCX fois.

    • Décrémente RCX après chaque itération.

    • Continue jusqu’à RCX = 0.

    • Exemple : rep movsb effectue une copie mémoire de RCX octets depuis l’adresse dans RSI vers l’adresse dans RDI.

  2. repe/repz (Repeat while Equal/Zero) — Répétition conditionnelle sur égalité :

    • Continue tant que ZF = 1 (résultat égal/zéro) ET RCX > 0.

    • S’arrête dès que ZF = 0 (différence détectée) OU RCX = 0.

    • Exemple : repe cmpsb compare deux chaînes octet par octet et s’arrête à la première différence.

  3. repne/repnz (Repeat while Not Equal/Not Zero) — Répétition conditionnelle sur inégalité :

    • Continue tant que ZF = 0 (résultat différent/non-zéro) ET RCX > 0.

    • S’arrête dès que ZF = 1 (correspondance trouvée) OU RCX = 0.

    • Exemple : repne scasb recherche AL dans une chaîne pointée par RDI, s’arrête dès qu’il le trouve.

  • Le flag DF (Direction Flag) contrôle le sens de parcours : si DF = 0, les registres d’adresses (RDI, RSI) utilisés sont incrémentés ; si DF = 1, ils sont décrémentés. Dans le cas de scasb seulement RDI est mis à jour, vu que RSI n’est pas utilisé.

Pour des copies de grande taille, il peut être plus efficace d’utiliser movsd ou movsq qui copient respectivement 4 ou 8 octets par opération. Voici une version optimisée qui traite les données par blocs de 4 octets :

memory_copy_optimized:
    movq %rdx, %rcx
    shr $2, %rcx         ; Division par 4 pour utiliser movsd (4 octets)
    cld
    rep movsd          ; Copie principale par blocs de 4 octets
    
    movq %rdx, %rcx
    andq $3, %rcx         ; Récupération du reste (0,1,2 ou 3)
    rep movsb          ; Copie des octets restants
    ret

Note sur la performance

Bien que ces instructions soient optimisées au niveau du processeur, leur efficacité dépend du contexte. Pour de très petites copies (quelques octets), une simple séquence de mov peut s’avérer plus rapide. Pour de très grandes copies, les fonctions système comme memcpy, qui peuvent utiliser des instructions SIMD (Single Instruction Multiple Data) ou des optimisations spécifiques au processeur, sont souvent préférables.