Instructions Basiques#
Catégorie |
Opérations |
Opcodes |
Description |
|---|---|---|---|
Mouvement de données |
Copie de registre/mémoire |
Transfère des données entre des registres, dans la mémoire ou charge des valeurs immédiates |
|
Copie Conditionnelle |
Déplace les données uniquement si le code de condition (cc) est rempli (par exemple, |
||
Copie avec extension |
Étend le signe ( |
||
La Pile |
Push |
Décrémente RSP et stocke l’opérande dans la pile |
|
Pop |
Charge la valeur depuis la pile et incrémente RSP |
||
Enter/Leave |
Crée/supprime une stack frame |
||
Arithmetique |
Math Basique |
Addition et soustraction |
|
Multiplication |
Multiplication non signée ( |
||
Division |
Division non signée ( |
||
Math Rapide |
Incrémente ou décrémente de 1 |
||
Math Complexe |
Load Effective Address, calcule l’adresse pointée, et la charge dans le registre |
||
Bitwise |
Logique |
Opérations booléennes de base |
|
Shifts |
Décalage logique à gauche/à droite |
||
Arithmetic Shifts |
Décalage arithmétique à gauche/à droite |
||
Rotatation |
Rotation des bits |
||
Comparaison |
Compare |
Soustrait les opérandes et définit les indicateurs |
|
Test |
Fait un bitwise ANDs, met à jour les flags sans charger le résultat dans le registre destination |
||
Structure de contrôle |
Jump Unconditionnel |
Jump direct (unconditionnel) |
|
Jump Conditionnel |
Jump si (condition) |
||
Call/Return |
Appel et retour de fonction |
||
Contrôle des Flags |
Carry Flag |
Clear/Set CF |
|
Direction Flag |
Clear/Set DF |
||
Interrupt Flag |
Clear/Set IF |
||
Système |
Appel Système |
Appel système |
|
Interruption |
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, %raxest plus efficace quemov $0, %raxpour mettre à zéro un registre.test %rax, %raxest plus efficace quecmp $0, %raxpour 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
%raxva forcer les 32 bits de poids fort à zéro même si la valeur est négative.movslq/movsxdsont nécessaire pour l’extension de signe 32→64 bits.Vous pouvez écrire
movqpour charger une valeur immédiate de 8 octets (64 bits) dans un registre. Par contre, si vous dumpez le binaire obtenu viaobjdumpvous verez que l’instruction s’est changée enmovabs. C’est une particularité de la syntaxe AT&T,movabsest utilisée lors du chargement d’immédiats de 8 octets à la place demovq. C’est pour faire la différence entre lemovqui va charger des immédiats de 4 octets ou moins dans un register 8 octets en rajoutant des zéros, dumovqui 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 |
|---|---|---|---|
Store AL |
1Byte |
Charger AL dans (RDI) |
|
Store AX |
2Bytes |
Charger AX dans (RDI) |
|
Store EAX |
4Bytes |
Charger EAX dans (RDI) |
|
Store RAX |
8Bytes |
Charger RAX dans (RDI) |
|
Scan Byte |
1Byte |
Comparer le byte AL avec (RDI) |
|
Scan Word |
2Bytes |
Comparer le word AX avec (RDI) |
|
Scan Double Word |
4Bytes |
Comparer le dword EAX avec (RDI) |
|
Scan Quad Word |
8Bytes |
Comparer le qword RAX avec dans (RDI) |
|
Compare Byte |
1Byte |
Comparer (RSI) avec (RDI) |
|
Compare Word |
2Bytes |
Comparer (RSI) avec (RDI) |
|
Compare Double Word |
4Bytes |
Comparer (RSI) avec (RDI) |
|
Compare Quad Word |
8Bytes |
Comparer (RSI) avec (RDI) |
|
Move Byte |
1Byte |
Copier (RSI) dans (RDI) |
|
Move Word |
2Bytes |
Copier (RSI) dans (RDI) |
|
Move Double Word |
4Bytes |
Copier (RSI) dans (RDI) |
|
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:
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 movsbeffectue une copie mémoire de RCX octets depuis l’adresse dans RSI vers l’adresse dans RDI.
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 cmpsbcompare deux chaînes octet par octet et s’arrête à la première différence.
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 scasbrecherche 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
scasbseulement 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.