Implémentation de Quicksort (Assembleur Y86)
Assembleur Y86
Algorithmes
Gestion mémoire
Programmation bas niveau
Ce projet est le seul projet scolaire sur ce site web. Il s'agit d'une implémentation complète de l'algorithme Quicksort en Assembleur Y86, une version simplifiée de x86.
L'objectif était de maîtriser la gestion mémoire bas niveau, les appels de fonction récursive et le respect des conventions d'appels (caller/callee save). L'algorithme utilise une méthode de partitionnement basée sur le pivot pour trier un tableau d'entiers 32 bits directement en mémoire.
Développer cela m'a appris comment les abstractions haut niveau (comme la récursion et les pointeurs) sont réellement gérées par le CPU et la pile. Réalisé le 28/02/2026, j'ai eu la note de 19/20 :)
.pos 0
init: irmovl stack,%esp # Initialisation du pointeur de la pile
# Définition de la taille du tableau
irmovl 9, %eax
# Empilement du second paramètre pour la fonction qsort (taille du tableau)
pushl %eax
# Récupération de l'adresse du tableau
irmovl tabdeb, %eax
# Empilement du premier paramètre pour la fonction qsort (adresse du tableau)
pushl %eax
# Appelle la fonction qsort
call qsort
# Nettoyage des paramètres
iaddl 8, %esp
halt # Fin du programme
# Pivot : met tout les éléments inférieurs ou égaux du pivot au début du tableau et ceux supérieurs a la fin
# ----------------- Fonction pivot-------------------------------
pivot:
# Sauvegarde des callee save
pushl %ebx # sauvegarde de ebx
pushl %esi # sauvegarde de esi
pushl %edi # sauvegarde de edi
# Récupération des paramètres
mrmovl 16(%esp), %esi # Récupération de l'adresse du début de l'intervalle à trier
mrmovl 20(%esp), %edi # Récupération de l'adresse de la fin de l'intervalle à trier
mrmovl 24(%esp), %ecx # Récupération de la valeur du pivot
boucle:
# Condition d'arret : les 2 pointeurs se croisent
rrmovl %esi, %ebx # on copie esi dans ebx (temp)
subl %edi, %ebx # comparaison indice debut - indice fin
jg fin # Si indice début >= indice fin -> ils se sont croisés : condition d'arret
mrmovl (%esi), %ebx # Récupération de la valeur à l'indice du départ
subl %ecx, %ebx # Comparaison de l'élément du départ avec le pivot
jg dgp # Si l'élément du départ est plus grand que le pivot
# valeur <= pivot
iaddl 4, %esi # On incrémente le début car on sait que la valeur qu'on vient d'ajouter est au bon endroit
jmp boucle # On continue la boucle
dgp:
mrmovl (%esi), %ebx # lecture de l'élément à déplacer vers la zone haute
mrmovl (%edi), %edx # lecture de l'élément à déplacer vers la zone basse
rmmovl %edx, (%esi) # Placement de la petite valeur à l'indice de gauche
rmmovl %ebx, (%edi) # Placement de la grande valeur à l'indice de droite
isubl 4, %edi # On décrémente la fin car on sait que la valeur qu'on vient d'ajouter est au bon endroit
jmp boucle # On continue la boucle sans avancer esi
fin: # arret le programme
# Placement de l'adresse du premier élément de la zone haute dans %eax
rrmovl %esi, %eax
# Une case avant %esi pour avoir le dernier élément de la zonne basse dans eax
isubl 4, %eax
# Restauration des callee_save
popl %edi # Restauration de %edi
popl %esi # Restauration de %esi
popl %ebx # Restauration de %ebx
ret
# ----------------- Fin Fonction pivot-------------------------------
# qsaux deb fin : prend l'élément à l'adresse deb comme pivot, appelle pivot sur deb+4, fin
puis échange deb avec la dernière valeur de la partie basse (nommé F).
S'appelle récursivement avec deb+4 F-4 et aussi récursivement avec F+4, fin.
# ----------------- Fonction Qsaux-------------------------------
qsaux:
# Sauvegarde tous les callee save
pushl %ebx # Sauvegarde de ebx
pushl %esi # Sauvegarde de esi
pushl %edi # Sauvegarde de edi
pushl %ebp # Sauvegarde de ebp
# ---- RECUPERATION DES PARAMETRE ----
# Récupération de l'adresse du début du tableau (PIVOT)
mrmovl 20(%esp), %ebp
# Récupération de la valeur du pivot
mrmovl (%ebp), %ecx
# Récupération de l'adresse de fin du tableau
mrmovl 24(%esp), %edi
# Copie de l'adresse du tableau
rrmovl %ebp, %esi
# Avance d'une case (car la première est le pivot)
iaddl 4, %esi
# ---- CONDITION D'ARRET : TABLEAU DE 1 CASE ----
# Copie du début du tableau dans ebx
rrmovl %ebp, %ebx
# soustraction des adresses du début et de la fin du tableau
subl %edi, %ebx
# Si les deux adresses sont égales, le tableau fait une case
jge arret_rec
# ---- APPEL DE PIVOT ----
# Passage de la valeur du pivot en paramètre
pushl %ecx
# Passage de la fin du tableau en paramètre
pushl %edi
# Passage du début du tableau en paramètre
pushl %esi
# Appel de la fonction pivot
call pivot
# Nettoyage la pile des paramètres
iaddl 12, %esp
# ---- ECHANGE DU PIVOT ET DE LA VALEUR ----
# L'adresse du dernier élément de la partie basse est dans eax
# On échange les éléments d'adresse %ebp et %eax
mrmovl (%eax), %ebx # Récupération du dernier élément de la partie basse
mrmovl (%ebp), %edx # Récupération de la valeur du pivot
rmmovl %ebx, (%ebp) # Déplacement de la valeur du dernier élément de la partie basse à la place du pivot
rmmovl %edx, (%eax) # Déplacement du pivot à sa bonne place dans le tableau
# Ici on a la valeur d'adresse eax au bon endroit.
# ---- APPEL RECUSRIF DE QSAUX SUR [debut, %eax-1] ----
# Récupération de l'adresse du dernier élement de la partie basse dans ebx
rrmovl %eax, %ebx
# retire 4 octets à %ebx pour avoir l'indice d'avant le pivot (au bon endroit)
isubl 4, %ebx
# Passage de la fin du tableau en paramètre
pushl %ebx
# Passage du début du tableau en paramètre
pushl %ebp
# Appel récursif de qsaux
call qsaux
# Nettoyage de la pile
iaddl 8, %esp
# ---- APPEL RECUSRIF DE QSAUX SUR [%eax+1, fin] ----
# Récupération de l'adresse du dernier élement de la partie basse dans ebx
rrmovl %eax, %ebx
# Ajout 4 octets à %ebx pour avoir l'indice d'après le pivot (au bon endroit)
iaddl 4, %ebx
# Passage de la fin du tableau en paramètre
pushl %edi
# Passage du début du tableau en paramètre
pushl %ebx
# Appel récursif de qsaux
call qsaux
# Nettoyage de la pile
iaddl 8, %esp
arret_rec:
# Restauration des callee_save
popl %ebp # Restauration de ebp
popl %edi # Restauration de edi
popl %esi # Restauration de esi
popl %ebx # Restauration de ebx
ret # On return
# qsort : prépare l'appel de qsaux
# ----------------- Fonction Qsort-------------------------------
qsort:
# Récupération du premier paramètre : l'adresse du tableau
mrmovl 4(%esp), %edx
# Récupération du deuxième paramètre : la taille du tableau
mrmovl 8(%esp), %ecx
# ecx * 4 pour calculer le nombre d'octets entre le début et la fin du tableau
isubl 1, %ecx # ecx - 1 pour ne pas compter la première
addl %ecx, %ecx # ecx * 2
addl %ecx, %ecx # ecx * 2
# Copie de l'adresse du début du tableau
rrmovl %edx, %eax
# Ajout de la taille * 4 pour otenir l'adrese de fin
addl %ecx, %eax
# Pousse l'adresse de fin du tableau sur la pile pour la passer en paramètre
pushl %eax
# Pousse l'adresse de début du tableau sur la pile pour la passer en paramètre
pushl %edx
# Appel de la fonction qsaux
call qsaux
# Nettoyage de la pile des paramètres qui ont été passés.
iaddl 8, %esp
.pos 800
.align 4
tabdeb: .long 9 # Création du tableau de test
.long 3
.long 7
.long 9
.long 4
.long 9
.long 9
.long 2
tabfin: .long 6
.pos 0x200
stack: