Voici une série d’exercices corrigés sur la programmation en assembleur (Assembly), une des plus anciennes et des plus proches du matériel des langages de programmation. Ces exercices couvriront des aspects de base comme les opérations arithmétiques, les branchements conditionnels, la gestion de boucles, et la manipulation de registres. Les exemples utiliseront une architecture courante telle que x86.
Écrire un programme en assembleur qui additionne deux nombres, les charge dans les registres AX et BX, puis place le résultat dans CX.
section .data
num1 dw 5 ; Premier nombre
num2 dw 7 ; Deuxième nombre
section .text
global _start
_start:
mov ax, [num1] ; Charger num1 dans AX
mov bx, [num2] ; Charger num2 dans BX
add ax, bx ; Ajouter AX et BX
mov cx, ax ; Placer le résultat dans CX
; Sortie du programme (pour un système Unix)
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui multiplie deux nombres. Les valeurs sont chargées dans les registres AX et BX, et le résultat est stocké dans DX:AX.
section .data
num1 dw 8 ; Premier nombre
num2 dw 3 ; Deuxième nombre
section .text
global _start
_start:
mov ax, [num1] ; Charger num1 dans AX
mov bx, [num2] ; Charger num2 dans BX
imul bx ; Multiplie AX par BX, résultat dans DX:AX
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui additionne les nombres de 1 à 5 en utilisant une boucle, et place le résultat final dans AX.
section .data
sum dw 0 ; Variable pour stocker la somme
counter dw 1 ; Compteur initialisé à 1
section .text
global _start
_start:
mov cx, 5 ; Répéter 5 fois
mov ax, 0 ; Initialiser la somme dans AX
loop_start:
add ax, [counter] ; Ajouter la valeur du compteur à AX
inc word [counter]; Incrémenter le compteur
loop loop_start ; Décrémenter CX et répéter la boucle si CX > 0
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui compare deux nombres et détermine si le premier est supérieur, inférieur ou égal au second. Affichez le résultat en utilisant des étiquettes conditionnelles.
section .data
num1 dw 6 ; Premier nombre
num2 dw 6 ; Deuxième nombre
section .text
global _start
_start:
mov ax, [num1] ; Charger num1 dans AX
mov bx, [num2] ; Charger num2 dans BX
cmp ax, bx ; Comparer AX et BX
je equal ; Si égal, sauter à "equal"
jg greater ; Si supérieur, sauter à "greater"
jl less ; Si inférieur, sauter à "less"
equal:
; Les nombres sont égaux
mov eax, 1 ; Simule une sortie avec code 1
jmp end_program
greater:
; num1 est supérieur à num2
mov eax, 2 ; Simule une sortie avec code 2
jmp end_program
less:
; num1 est inférieur à num2
mov eax, 3 ; Simule une sortie avec code 3
end_program:
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui appelle une fonction pour additionner deux nombres. Le programme principal charge les valeurs, et la fonction additionne les nombres avant de retourner le résultat.
section .data
num1 dw 12
num2 dw 8
section .text
global _start
_start:
mov ax, [num1] ; Charger num1 dans AX
mov bx, [num2] ; Charger num2 dans BX
call add_numbers ; Appel de la fonction
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall
add_numbers:
add ax, bx ; Additionner AX et BX
ret ; Retourner à l’appelant avec le résultat dans AX Écrire un programme en assembleur qui inverse un tableau de 5 éléments en place.
Voici la suite et fin de l’Exercice 6 sur l’inversion d’un tableau en assembleur :
Écrire un programme en assembleur qui calcule la factorielle d’un nombre stocké en mémoire. Le résultat sera retourné dans AX.
section .data
num dw 5 ; Nombre dont on veut calculer la factorielle
result dw 1 ; Résultat (initialisé à 1)
section .text
global _start
_start:
mov ax, [num] ; Charger le nombre dans AX
mov bx, ax ; Sauvegarder le nombre dans BX
mov cx, ax ; Utiliser CX comme compteur
; Boucle pour calculer la factorielle
factorial_loop:
cmp cx, 1 ; Si CX est égal à 1, fin de la boucle
jle end_factorial ; Sauter si CX <= 1
imul bx, cx ; Multiplier BX (résultat partiel) par CX
loop factorial_loop ; Décrémenter CX et répéter
end_factorial:
mov [result], bx ; Sauvegarder le résultat final dans la mémoire
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui utilise une interruption système pour afficher une chaîne de caractères à l’écran.
section .data
message db 'Bonjour Assembleur!', 0xA, 0xD, '$' ; Message avec nouvelle ligne et fin de chaîne
section .text
global _start
_start:
mov ah, 0x09 ; Fonction d'affichage de chaîne (DOS)
mov dx, message ; Charger l'adresse du message dans DX
int 0x21 ; Appel de l'interruption pour afficher le texte
; Sortie du programme
mov ax, 0x4C00 ; Terminer le programme (DOS)
int 0x21 ; Appel de l'interruption pour quitter Écrire un programme en assembleur qui additionne deux tableaux de 5 éléments et stocke le résultat dans un troisième tableau.
section .data
array1 dw 1, 2, 3, 4, 5 ; Premier tableau
array2 dw 5, 4, 3, 2, 1 ; Deuxième tableau
result dw 5 dup(0) ; Tableau pour stocker le résultat (initialisé à 0)
n dw 5 ; Taille des tableaux
section .text
global _start
_start:
mov esi, array1 ; Pointeur sur array1
mov edi, array2 ; Pointeur sur array2
mov edx, result ; Pointeur sur result
mov cx, [n] ; Nombre d'éléments dans les tableaux
sum_loop:
mov ax, [esi] ; Charger l'élément de array1
add ax, [edi] ; Ajouter l'élément correspondant de array2
mov [edx], ax ; Stocker le résultat dans result
; Incrémenter les pointeurs
add esi, 2
add edi, 2
add edx, 2
loop sum_loop ; Décrémenter CX et répéter la boucle
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui incrémente un compteur jusqu’à une valeur donnée et arrête lorsque la valeur 10 est atteinte.
section .data
counter dw 0 ; Compteur initialisé à 0
limit dw 10 ; Limite fixée à 10
section .text
global _start
_start:
mov cx, [counter] ; Charger la valeur du compteur
mov ax, [limit] ; Charger la limite
increment_loop:
inc cx ; Incrémenter le compteur
cmp cx, ax ; Comparer le compteur à la limite
je end_loop ; Si le compteur atteint la limite, sauter à end_loop
jmp increment_loop ; Répéter la boucle
end_loop:
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Ces exercices couvrent les bases de la programmation assembleur, en passant par les opérations arithmétiques, la gestion de boucles, les comparaisons et l’utilisation d’interruptions. Ils vous aident à comprendre comment interagir avec les registres, gérer la mémoire et exécuter des opérations conditionnelles dans le contexte d’un processeur.
Voici une série d’exercices en assembleur couvrant des cas particuliers qui sont moins courants ou plus complexes, touchant des aspects spécifiques comme la gestion de débordements, l’optimisation mémoire, la gestion de nombres signés, ou encore des manipulations plus avancées de registres et d’interruptions.
Écrire un programme en assembleur qui effectue l’addition de deux grands nombres. Si un débordement se produit (c’est-à-dire que le résultat dépasse la capacité des registres), le programme devra signaler l’erreur.
section .data
num1 dw 40000 ; Premier nombre (grand pour provoquer un débordement)
num2 dw 30000 ; Deuxième nombre
section .text
global _start
_start:
mov ax, [num1] ; Charger num1 dans AX
add ax, [num2] ; Ajouter num2 à AX
jo overflow_error ; Si un débordement se produit, sauter à "overflow_error"
; Si pas de débordement, continuer normalement
jmp end_program ; Sauter à la fin du programme
overflow_error:
; Gestion de l'erreur de débordement (simuler un code d'erreur, par exemple)
mov eax, 1 ; Code d'erreur
end_program:
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui multiplie deux nombres signés (positifs ou négatifs) et place le résultat dans un registre. Le programme doit également gérer le signe du résultat correctement.
section .data
num1 dw -7 ; Premier nombre signé (négatif)
num2 dw 5 ; Deuxième nombre signé (positif)
section .text
global _start
_start:
mov ax, [num1] ; Charger num1 dans AX
imul word [num2] ; Multiplier num1 par num2 (signé)
; Le résultat est dans DX:AX, mais ici, DX ne sera pas utilisé pour des petits nombres
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui calcule la somme des carrés des entiers de 1 à N, où N est une valeur stockée en mémoire. Le résultat final doit être placé dans un registre.
section .data
N dw 5 ; Calculer la somme des carrés de 1 à N (ici N = 5)
sum dw 0 ; Stocker la somme
section .text
global _start
_start:
mov cx, [N] ; Charger N dans CX (compteur de boucle)
mov ax, 0 ; Initialiser AX à 0 (stockage temporaire de la somme)
sum_loop:
mov bx, cx ; Charger la valeur actuelle de CX
imul bx, bx ; Calculer le carré (BX = CX * CX)
add ax, bx ; Ajouter le carré à la somme (AX = AX + BX)
loop sum_loop ; Décrémenter CX et répéter jusqu'à CX = 0
; Placer la somme dans [sum]
mov [sum], ax ; Stocker le résultat dans sum
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui prend une chaîne de caractères représentant des chiffres hexadécimaux (ex: « 1A3F ») et la convertit en un nombre binaire. Le résultat sera stocké dans un registre.
section .data
hex_string db '1A3F', 0 ; Chaîne représentant un nombre hexadécimal
result dw 0 ; Résultat
section .text
global _start
_start:
mov esi, hex_string ; Pointeur sur la chaîne
mov ax, 0 ; Initialiser AX pour stocker le résultat
convert_loop:
mov al, [esi] ; Charger le caractère suivant dans AL
test al, al ; Vérifier si fin de chaîne (0)
jz end_conversion ; Si 0, la conversion est terminée
; Convertir le caractère hexadécimal en sa valeur numérique
sub al, '0' ; Convertir les chiffres '0' à '9'
cmp al, 9
jle valid_digit ; Si <= 9, c'est un chiffre valide
sub al, 7 ; Convertir les lettres 'A' à 'F'
valid_digit:
shl ax, 4 ; Décaler le résultat actuel à gauche de 4 bits (multiplication par 16)
or ax, al ; Ajouter la nouvelle valeur hexadécimale
inc esi ; Passer au caractère suivant
jmp convert_loop ; Répéter pour le caractère suivant
end_conversion:
; Placer le résultat final dans [result]
mov [result], ax
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui prend un entier et inverse tous ses bits. Par exemple, si l’entrée est 0b1010 (10 en décimal), le programme doit produire 0b0101.
section .data
number dw 0xA ; Nombre à inverser (0b1010)
section .text
global _start
_start:
mov ax, [number] ; Charger le nombre dans AX
not ax ; Inverser tous les bits de AX
; Le résultat est maintenant dans AX
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Voici la suite et fin de l’Exercice 6 pour la génération de la séquence de Fibonacci en assembleur :
mov ax, 1 ; Deuxième terme (fibo[1] = 1)
mov [esi], ax ; Stocker dans fibo[1]
add esi, 2 ; Avancer dans le tableau
dec cx ; Décrémenter CX car nous avons déjà stocké deux termes
dec cx
fib_loop:
mov ax, [esi-2] ; Charger le terme précédent (fibo[n-1])
mov bx, [esi-4] ; Charger le terme avant-dernier (fibo[n-2])
add ax, bx ; Calculer fibo[n] = fibo[n-1] + fibo[n-2]
mov [esi], ax ; Stocker le nouveau terme dans le tableau
add esi, 2 ; Avancer dans le tableau pour le prochain terme
loop fib_loop ; Répéter jusqu'à CX = 0 (tous les termes générés)
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui parcourt un tableau d’entiers et trouve le maximum. Le résultat doit être stocké dans un registre.
section .data
array dw 5, 12, 7, 25, 9 ; Tableau de 5 éléments
n dw 5 ; Nombre d'éléments dans le tableau
max dw 0 ; Stocker le maximum
section .text
global _start
_start:
mov cx, [n] ; Charger le nombre d'éléments dans CX
mov esi, array ; Pointeur sur le début du tableau
mov ax, [esi] ; Charger le premier élément du tableau dans AX
mov [max], ax ; Initialiser le maximum avec le premier élément
add esi, 2 ; Avancer dans le tableau
find_max_loop:
cmp cx, 1 ; Si CX = 1, il n'y a plus d'éléments à comparer
je end_max ; Fin de la boucle si plus d'éléments
mov bx, [esi] ; Charger l'élément suivant du tableau
cmp [max], bx ; Comparer avec le maximum actuel
jge no_update ; Si le maximum est plus grand ou égal, pas besoin de mettre à jour
mov [max], bx ; Sinon, mettre à jour le maximum
no_update:
add esi, 2 ; Avancer au prochain élément du tableau
loop find_max_loop ; Décrémenter CX et continuer la boucle
end_max:
; Le maximum est maintenant stocké dans [max]
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui divise deux nombres et stocke le quotient et le reste dans des registres séparés.
section .data
dividend dw 25 ; Dividende
divisor dw 4 ; Diviseur
quotient dw 0 ; Quotient
remainder dw 0 ; Reste
section .text
global _start
_start:
mov ax, [dividend] ; Charger le dividende dans AX
mov dx, 0 ; Initialiser DX à 0 (nécessaire pour la division)
mov bx, [divisor] ; Charger le diviseur dans BX
div bx ; Diviser DX:AX par BX (quotient dans AX, reste dans DX)
mov [quotient], ax ; Stocker le quotient dans "quotient"
mov [remainder], dx ; Stocker le reste dans "remainder"
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui échange deux éléments dans un tableau. Les indices des éléments à échanger sont stockés en mémoire.
section .data
array dw 10, 20, 30, 40, 50 ; Tableau de 5 éléments
index1 dw 1 ; Premier index (élément à la position 1)
index2 dw 3 ; Deuxième index (élément à la position 3)
section .text
global _start
_start:
mov si, [index1] ; Charger le premier index dans SI
shl si, 1 ; Multiplier l'index par 2 (car chaque élément est un mot)
mov di, [index2] ; Charger le deuxième index dans DI
shl di, 1 ; Multiplier l'index par 2
mov ax, [array + si] ; Charger l'élément à l'index 1 dans AX
mov bx, [array + di] ; Charger l'élément à l'index 3 dans BX
; Échanger les valeurs
mov [array + si], bx ; Mettre l'élément 3 à la place de l'élément 1
mov [array + di], ax ; Mettre l'élément 1 à la place de l'élément 3
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall Écrire un programme en assembleur qui copie une chaîne de caractères d’un emplacement mémoire à un autre jusqu’à atteindre la fin de la chaîne (0x00).
Voici la suite et fin de l’Exercice 10 : Copie d’une chaîne de caractères en assembleur :
inc edi ; Passer au caractère suivant dans la destination
jmp copy_loop ; Répéter la boucle pour copier le caractère suivant
end_copy:
; Sortie du programme
mov eax, 60 ; Code système pour exit
xor edi, edi ; Retourner 0
syscall 0x00), qui marque la fin de la chaîne.Ces exercices illustrent divers cas particuliers dans la programmation en assembleur, notamment :
not.Ces exercices visent à renforcer la compréhension de la manipulation des registres, des pointeurs, des boucles, des conditions, et de la gestion de la mémoire en assembleur, tout en traitant des situations pratiques et courantes dans l’optimisation de bas niveau.
Une série progressive d’exercices pour comprendre les registres, les opérations arithmétiques, les conditions, les boucles, la mémoire et la pile en assembleur x86.
Une série progressive d’exercices pour comprendre les registres, les opérations arithmétiques, les conditions, les boucles, la mémoire et la pile en assembleur x86. Chaque activité associe un objectif, un exemple de code, une illustration du fonctionnement du processeur et une correction commentée.
Un registre représente une petite zone de stockage directement intégrée au processeur. L’assembleur x86 manipule ces registres pour effectuer des calculs, déplacer des données, comparer des valeurs ou gérer les appels de fonctions.
MOV EAX, 5MOV copie une donnée vers une destination. Elle ne déplace pas physiquement la valeur hors de la source.
Écrire un programme assembleur x86 qui place la valeur 12 dans le
registre EAX, la valeur 8 dans le registre
EBX, puis additionne les deux nombres. Le résultat doit rester dans
EAX.
EAX = indéfiniEBX = indéfini EAX = 20EBX = 8 section .text
global _start
_start:
mov eax, 12
mov ebx, 8
add eax, ebx
Les deux instructions MOV initialisent les registres. L’instruction
ADD EAX, EBX additionne ensuite le contenu de EBX à celui
de EAX. La destination étant EAX, le résultat final est
enregistré dans ce registre.
Placer la valeur 15 dans EAX, puis soustraire
21. Déterminer la valeur finale de EAX.
mov eax, 15
sub eax, 21 EAX = -6
L’instruction SUB EAX, 21 retire 21 du contenu de
EAX. Dans une représentation signée sur 32 bits, le résultat correspond
à −6. En représentation hexadécimale complément à deux, cette valeur
peut apparaître sous la forme FFFFFFFA.
Comparer les valeurs 18 et 12. Placer
1 dans ECX lorsque la première valeur est supérieure,
sinon placer 0.
mov eax, 18
mov ebx, 12
cmp eax, ebx
jg valeur_superieure
mov ecx, 0
jmp fin
valeur_superieure:
mov ecx, 1
fin:
CMP effectue une soustraction logique sans conserver le résultat.
Cette instruction modifie les indicateurs du registre d’état. L’instruction
JG teste ensuite ces indicateurs et déclenche le saut lorsque la première
valeur signée est strictement supérieure à la seconde.
Utiliser une boucle pour additionner successivement les nombres de
1 à 5. Le résultat final doit être stocké dans EAX.
mov eax, 0
mov ebx, 1
mov ecx, 5
boucle:
add eax, ebx
inc ebx
loop boucle | Tour | Valeur ajoutée | EAX après addition | ECX restant |
|---|---|---|---|
| 1 | 1 | 1 | 4 |
| 2 | 2 | 3 | 3 |
| 3 | 3 | 6 | 2 |
| 4 | 4 | 10 | 1 |
| 5 | 5 | 15 | 0 |
Le registre EAX contient finalement 15.
L’instruction LOOP décrémente automatiquement ECX, puis
retourne à l’étiquette indiquée tant que ECX reste différent de zéro.
Calculer la somme des quatre valeurs du tableau
3, 5, 7, 9. Utiliser ESI comme pointeur vers les données.
section .data
tableau dd 3, 5, 7, 9
section .text
mov esi, tableau
mov ecx, 4
mov eax, 0
addition:
add eax, [esi]
add esi, 4
loop addition dd occupe quatre octets. Le pointeur ESI doit donc avancer de 4 octets à chaque tour.
La notation [ESI] signifie que le programme lit la valeur stockée à
l’adresse contenue dans ESI. Après quatre passages, la somme obtenue
est 24.
Placer successivement les valeurs 10 et 25 dans la
pile, puis les récupérer dans EAX et EBX.
push 10
push 25
pop eax
pop ebx
La pile applique le principe LIFO : la dernière valeur empilée est
la première retirée. Le registre EAX reçoit donc 25 et
EBX reçoit 10.
Comparer trois nombres et conserver le plus grand dans EAX.
Tester si un entier est pair en utilisant une opération logique avec
AND.
Calculer la factorielle de 5 à l’aide d’une boucle et de l’instruction
IMUL.
| Compétence | Instructions à mobiliser | Résultat attendu |
|---|---|---|
| Recherche du maximum | CMP, JG, MOV | La valeur maximale dans EAX |
| Test pair ou impair | AND, CMP, JE | 1 si pair, 0 si impair |
| Calcul d’une factorielle | IMUL, DEC, JNZ | 120 pour 5! |
| Instruction | Fonction | Exemple |
|---|---|---|
MOV | Copier une valeur | MOV EAX, 10 |
ADD | Additionner | ADD EAX, EBX |
SUB | Soustraire | SUB EAX, 5 |
IMUL | Multiplier des valeurs signées | IMUL EAX, EBX |
CMP | Comparer deux valeurs | CMP EAX, EBX |
JMP | Effectuer un saut inconditionnel | JMP fin |
JE | Sauter si les valeurs sont égales | JE egal |
JG | Sauter si la première valeur est supérieure | JG maximum |
PUSH | Empiler une valeur | PUSH EAX |
POP | Retirer une valeur de la pile | POP EBX |
Une série progressive d’exercices corrigés pour comprendre les registres ARM, les opérations arithmétiques, les branchements conditionnels, l’accès à la mémoire, les tableaux et les sous-programmes. Les exemples peuvent servir d’introduction à ARM Cortex, Raspberry Pi, STM32 et aux systèmes embarqués.
L’architecture ARM repose largement sur l’utilisation des registres. Les données sont généralement chargées depuis la mémoire dans un registre avant d’être traitées, puis enregistrées à nouveau en mémoire lorsque cela devient nécessaire.
MOV R0, #5# indique généralement une valeur immédiate. L’instruction MOV R0, #5 place donc directement la valeur 5 dans le registre R0.
Placer la valeur 14 dans R0, la valeur
6 dans R1, puis enregistrer leur somme dans
R2.
R0 = 14R1 = 6 R2 = 20 MOV R0, #14
MOV R1, #6
ADD R2, R0, R1
L’instruction ADD R2, R0, R1 additionne le contenu de
R0 et de R1. Le résultat est placé dans
R2, tandis que les valeurs de départ restent disponibles.
Charger la valeur 25 dans R0, puis retirer
9. Le résultat doit être enregistré dans R1.
MOV R0, #25
SUB R1, R0, #9 R1 = 16
L’instruction SUB utilise ici trois opérandes. Le premier correspond
au registre de destination, le deuxième à la valeur de départ et le troisième
à la valeur soustraite.
Comparer les valeurs stockées dans R0 et R1.
Placer 1 dans R2 lorsque R0
est supérieur à R1, sinon placer 0.
MOV R0, #18
MOV R1, #12
CMP R0, R1
BGT superieur
MOV R2, #0
B fin
superieur:
MOV R2, #1
fin:
CMP compare les deux registres en mettant à jour les indicateurs
du processeur. L’instruction BGT déclenche ensuite un branchement
lorsque la première valeur signée est strictement supérieure à la seconde.
Calculer la somme des nombres de 1 à 5. Utiliser
R0 comme accumulateur et R1 comme compteur.
MOV R0, #0
MOV R1, #1
boucle:
ADD R0, R0, R1
ADD R1, R1, #1
CMP R1, #6
BNE boucle | Tour | Valeur ajoutée | Valeur de R0 | Valeur suivante de R1 |
|---|---|---|---|
| 1 | 1 | 1 | 2 |
| 2 | 2 | 3 | 3 |
| 3 | 3 | 6 | 4 |
| 4 | 4 | 10 | 5 |
| 5 | 5 | 15 | 6 |
Le registre R0 contient finalement 15.
La boucle continue tant que R1 reste différent de 6.
Charger une valeur déclarée en mémoire dans le registre R1,
puis lui ajouter 5.
.data
nombre:
.word 12
.text
LDR R0, =nombre
LDR R1, [R0]
ADD R1, R1, #5 LDR R0, =nombre charge l’adresse de la donnée, tandis que LDR R1, [R0] lit la valeur située à cette adresse.
Le premier LDR prépare l’accès à la mémoire. Le deuxième récupère
la valeur 12. L’instruction ADD produit ensuite le résultat final :
R1 = 17.
Calculer la somme des quatre valeurs du tableau
4, 7, 2, 9. Utiliser un registre comme pointeur et un autre
comme compteur.
.data
tableau:
.word 4, 7, 2, 9
.text
LDR R0, =tableau
MOV R1, #4
MOV R2, #0
boucle_tableau:
LDR R3, [R0], #4
ADD R2, R2, R3
SUBS R1, R1, #1
BNE boucle_tableau
L’instruction LDR R3, [R0], #4 lit la valeur pointée par
R0, puis avance automatiquement le pointeur de quatre octets.
La somme finale stockée dans R2 vaut 22.
Créer un sous-programme qui additionne les valeurs contenues dans
R0 et R1, puis renvoie le résultat dans
R0.
MOV R0, #8
MOV R1, #11
BL addition
B fin
addition:
ADD R0, R0, R1
BX LR
fin:
L’instruction BL appelle le sous-programme et enregistre l’adresse
de retour dans LR. L’instruction BX LR permet ensuite
de reprendre l’exécution après l’appel. Le résultat final vaut
19.
Tester si une valeur est paire en utilisant l’instruction
AND.
Comparer trois nombres et conserver la valeur maximale dans
R0.
Calculer la factorielle de 5 avec une boucle et l’instruction
MUL.
| Instruction | Fonction | Exemple |
|---|---|---|
MOV | Charger ou copier une valeur | MOV R0, #10 |
ADD | Additionner deux valeurs | ADD R2, R0, R1 |
SUB | Soustraire une valeur | SUB R1, R0, #4 |
MUL | Multiplier | MUL R2, R0, R1 |
CMP | Comparer deux valeurs | CMP R0, R1 |
B | Effectuer un branchement | B fin |
BEQ | Brancher si les valeurs sont égales | BEQ egal |
BNE | Brancher si elles sont différentes | BNE boucle |
LDR | Charger une donnée depuis la mémoire | LDR R1, [R0] |
STR | Enregistrer une donnée en mémoire | STR R1, [R0] |
BL | Appeler un sous-programme | BL addition |
BX LR | Revenir après un appel | BX LR |
Une série progressive d’exercices corrigés pour maîtriser les registres MIPS, les opérations arithmétiques, les branchements conditionnels, les boucles, les tableaux, la mémoire et les appels système. Les exemples sont compatibles avec les environnements pédagogiques MARS et QtSPIM.
Le processeur MIPS utilise plusieurs catégories de registres. Certains servent à conserver des valeurs temporaires, d’autres à transmettre des paramètres, stocker des résultats ou gérer les appels de fonctions.
li $t0, 5li charge une valeur immédiate dans un registre. L’instruction la charge quant à elle une adresse mémoire.
Charger la valeur 12 dans le registre $t0,
la valeur 8 dans $t1, puis enregistrer leur
somme dans $t2.
$t0 = 12$t1 = 8 $t2 = 20 li $t0, 12
li $t1, 8
add $t2, $t0, $t1
L’instruction add $t2, $t0, $t1 additionne les contenus
de $t0 et $t1. Le résultat est stocké dans
$t2, sans modifier les deux registres de départ.
Charger la valeur 25 dans $t0 et la valeur
9 dans $t1. Enregistrer la différence dans
$t2.
li $t0, 25
li $t1, 9
sub $t2, $t0, $t1 $t2 = 16
Le premier registre après l’instruction sub correspond à
la destination. Le calcul effectué est donc
$t2 = $t0 - $t1.
Comparer les valeurs contenues dans $t0 et $t1.
Placer 1 dans $t2 lorsque
$t0 est supérieur à $t1, sinon placer
0.
li $t0, 18
li $t1, 12
bgt $t0, $t1, superieur
li $t2, 0
j fin
superieur:
li $t2, 1
fin:
L’instruction pseudo-MIPS bgt effectue un branchement lorsque
le premier opérande est strictement supérieur au second. Ici, la condition
est vraie, donc le programme rejoint l’étiquette superieur.
Calculer la somme des entiers de 1 à 5. Utiliser
$t0 comme accumulateur et $t1 comme compteur.
li $t0, 0
li $t1, 1
li $t2, 6
boucle:
add $t0, $t0, $t1
addi $t1, $t1, 1
bne $t1, $t2, boucle | Tour | Valeur ajoutée | Valeur de $t0 | Valeur suivante de $t1 |
|---|---|---|---|
| 1 | 1 | 1 | 2 |
| 2 | 2 | 3 | 3 |
| 3 | 3 | 6 | 4 |
| 4 | 4 | 10 | 5 |
| 5 | 5 | 15 | 6 |
Le registre $t0 contient finalement 15.
La boucle continue tant que $t1 reste différent de 6.
Charger la valeur déclarée sous l’étiquette nombre dans
le registre $t0, puis lui ajouter 5.
.data
nombre: .word 12
.text
la $t1, nombre
lw $t0, 0($t1)
addi $t0, $t0, 5 la charge une adresse dans un registre. L’instruction lw lit ensuite un mot de 32 bits à cette adresse.
Le registre $t1 pointe vers la donnée. La commande
lw $t0, 0($t1) récupère la valeur 12, puis
addi produit le résultat final 17.
Calculer la somme des quatre valeurs du tableau
4, 7, 2, 9. Utiliser un registre comme pointeur et un autre
comme compteur.
.data
tableau: .word 4, 7, 2, 9
.text
la $t0, tableau
li $t1, 4
li $t2, 0
boucle_tableau:
lw $t3, 0($t0)
add $t2, $t2, $t3
addi $t0, $t0, 4
addi $t1, $t1, -1
bne $t1, $zero, boucle_tableau
Chaque mot déclaré avec .word occupe quatre octets.
Le pointeur $t0 avance donc de quatre octets à chaque tour.
La somme finale conservée dans $t2 vaut 22.
Afficher le nombre 42 dans la console avec un appel système MIPS.
li $v0, 1
li $a0, 42
syscall
Dans MARS et QtSPIM, le registre $v0 contient le numéro
du service demandé. Le registre $a0 transporte ici
l’entier transmis au service d’affichage.
Demander au programme de lire un entier dans la console, puis transférer
la valeur saisie dans le registre $t0.
li $v0, 5
syscall
move $t0, $v0
Le service numéro 5 lit un entier. Après l’appel système, la valeur saisie
est disponible dans $v0. L’instruction move
la copie dans $t0.
Créer une fonction qui additionne les valeurs transmises dans
$a0 et $a1. Le résultat doit être renvoyé
dans $v0.
li $a0, 8
li $a1, 11
jal addition
j fin
addition:
add $v0, $a0, $a1
jr $ra
fin:
L’instruction jal appelle la fonction et conserve
l’adresse de retour dans $ra. L’instruction
jr $ra permet ensuite de reprendre le programme principal.
Le résultat renvoyé dans $v0 vaut 19.
Tester si un entier est pair avec une opération logique
andi.
Comparer trois nombres et conserver le plus grand dans
$t0.
Calculer la factorielle de 5 à l’aide d’une boucle et de
l’instruction mul.
| Compétence | Instructions conseillées | Résultat attendu |
|---|---|---|
| Tester un nombre pair | andi, beq | 1 si pair, 0 sinon |
| Rechercher un maximum | bgt, move | Valeur maximale dans $t0 |
| Calculer une factorielle | mul, addi, bne | 120 pour 5! |
| Instruction | Fonction | Exemple |
|---|---|---|
li | Charger une valeur immédiate | li $t0, 10 |
la | Charger une adresse mémoire | la $t0, tableau |
add | Additionner deux registres | add $t2, $t0, $t1 |
addi | Additionner une valeur immédiate | addi $t0, $t0, 1 |
sub | Soustraire deux registres | sub $t2, $t0, $t1 |
mul | Multiplier deux valeurs | mul $t2, $t0, $t1 |
lw | Charger un mot depuis la mémoire | lw $t0, 0($t1) |
sw | Enregistrer un mot en mémoire | sw $t0, 0($t1) |
beq | Brancher si deux valeurs sont égales | beq $t0, $t1, egal |
bne | Brancher si deux valeurs diffèrent | bne $t0, $zero, boucle |
j | Effectuer un saut direct | j fin |
jal | Appeler une fonction | jal calcul |
jr $ra | Revenir après un appel | jr $ra |
syscall | Appeler un service système | syscall |
Les travaux pratiques en assembleur permettent de passer rapidement de la théorie à l’exécution réelle des instructions. Registres, opérations arithmétiques, comparaisons, boucles, pile et mémoire deviennent plus faciles à comprendre lorsqu’ils sont manipulés étape par étape. Cette série de TP corrigés s’accompagne de simulateurs interactifs pour tester des valeurs, observer le comportement du processeur et vérifier immédiatement les résultats obtenus. Elle convient aux étudiants, aux débutants en programmation bas niveau et à toute personne souhaitant progresser sur les architectures x86, ARM ou MIPS.
Des travaux pratiques progressifs pour manipuler les registres, exécuter des opérations, comprendre les comparaisons, simuler des boucles et suivre l’évolution de la mémoire. Chaque TP associe un énoncé, un code d’exemple, une correction et un mini-simulateur.
Choisissez deux valeurs, sélectionnez une instruction puis observez le résultat stocké dans le registre de destination.
Charger deux nombres dans des registres, effectuer une addition et conserver le résultat dans un troisième registre.
; Exemple x86
mov eax, 14
mov ebx, 6
add eax, ebx
; EAX contient maintenant 20
Les instructions MOV initialisent les registres. L’instruction
ADD EAX, EBX ajoute ensuite le contenu de EBX
à celui de EAX. Le résultat final reste dans EAX.
Ce simulateur reproduit le raisonnement d’une instruction CMP,
suivie d’un branchement conditionnel.
Comparer les valeurs 25 et 17. Conserver la plus grande dans
le registre EAX.
mov eax, 25
mov ebx, 17
cmp eax, ebx
jge fin
mov eax, ebx
fin:
L’instruction CMP EAX, EBX compare les deux valeurs.
Si EAX est supérieur ou égal, le programme rejoint directement
l’étiquette fin. Dans le cas contraire, la valeur de
EBX est copiée dans EAX.
Entrez une limite afin de calculer la somme des entiers de 1 jusqu’à cette valeur. Le simulateur affiche l’état du compteur et de l’accumulateur à chaque tour.
Utiliser un compteur et un accumulateur pour calculer la somme des nombres de 1 à 5.
mov eax, 0
mov ebx, 1
mov ecx, 5
boucle:
add eax, ebx
inc ebx
loop boucle
Après cinq itérations, le registre EAX contient 15.
L’instruction LOOP décrémente automatiquement
ECX avant de vérifier si la boucle doit continuer.
Entrez plusieurs entiers séparés par des virgules. Le simulateur reproduit la lecture successive des cases mémoire et l’avancement du pointeur.
Calculer la somme des quatre valeurs du tableau
4, 7, 2, 9.
section .data
tableau dd 4, 7, 2, 9
section .text
mov esi, tableau
mov ecx, 4
mov eax, 0
boucle_tableau:
add eax, [esi]
add esi, 4
loop boucle_tableau dd occupe quatre octets. Le registre pointeur doit donc avancer de quatre octets après chaque lecture.
Le registre ESI contient l’adresse de l’élément courant.
La notation [ESI] lit la valeur stockée à cette adresse.
La somme finale conservée dans EAX vaut 22.
Le générateur propose un nouvel exercice basé sur une opération, une comparaison, une boucle ou un tableau.
Quelle instruction permet de comparer deux valeurs sans conserver directement le résultat de la soustraction ?
Le métier de marchand de biens immobiliers consiste à acquérir des biens dans une logique…
Le succès d'un événement se prépare bien avant l'ouverture des portes. Une communication structurée permet…
La chromatographie liquide haute performance (HPLC) est aujourd'hui l'une des techniques analytiques les plus utilisées…
La HPLC (Chromatographie Liquide Haute Performance) est aujourd'hui l'une des techniques analytiques les plus utilisées…
Créer une SCI répond souvent à un projet de long terme. Certains souhaitent acquérir un…
Organiser un mariage est une aventure aussi enthousiasmante qu'exigeante. Derrière chaque cérémonie réussie se cachent…
This website uses cookies.