rss

Exercice assembleur x86 occurence d'un caractère

Publié par kilian, dernière mise à jour le jeudi 10 avril 2008 à 18:26:58 par kilian



Introduction


Ce petit exercice d'assembleur vise les architectures x86 (Processeurs Intel et Amd 32 bits) et utilise la syntaxe de Nasm, un assembleur libre, gratuit et utilisable sur différentes plateformes telles que Windows ou Linux.
De même les fonctions externes utilisées sont issues de la bibliothèque C standard.

Ainsi vous n'aurez pas de problèmes liés à votre machine pour faire cet exercice: il n'est pas dépendant du système d'exploitation utilisé. Il est uniquement dépendant de l'architecture x86.

NOTE: Pour utiliser nasm afin de tester cet exercice, vous trouverez un tutoriel d'utilisation/installation de nasm pour Windows et Linux en cliquant ici.

Notions abordées dans cet exercice

  • Ecriture d'une fonction avec gestion des paramètres d'entrée
  • Gestion des tableaux

Enoncé


Imaginons un tableau de caractères (qui ne se termine pas nécessairement par 0). On possède sa taille et on voudrait pouvoir tester la présence d'un caractère donné dans ce tableau. Le but va donc être d'écrire une fonction qui prend en entrée un tableau de caractères, sa taille et un caractère. Si ce caractère est présent dans le tableau, on retourne une valeur différente de zero, sinon on retourne zero.

Voici ce que donnerait cette fonction en C:
//Le prototype de cette fonction
int est_dans_tableau(char *tableau, int taille, char c); 
//Exemple d'utilisation:
char tab[] = {'n', 'e', 'u', 'e'};
est_dans_tableau(tab, sizeof(tab), 'u'); //Retournera autre chose que 0
est_dans_tableau(tab, sizeof(tab), 'a'); //Retournera 0


Il vous faudra insérer ce code là dedans:
extern printf

section .data
	tableau db 'dadedidadedavivoufufifamasibifisaz'
	oui db 'oui', 10, 0
	non db 'non', 10, 0

section .text
	global main

est_dans_tableau:
	;Insérez votre code ici!!


main:
	push ebp
	mov ebp, esp
	
       ;On va tester si m est présent dans le tableau
	push dword 'm'
	;La longueur du tableau (ici 34) 
	push dword 34 
	;Adresse de chaine dans eax
	push tableau

        ;Appel de est_dans_tableau avec l'adresse du tableau, 
        ;sa taille, et la valeur à chercher
	call est_dans_tableau
	test eax, eax
	jnz est_dedans ;Si eax != 0 alors on affiche oui
	push non ;Sinon on affichera non
	jmp affichage
        ;Affichage de la chaine avec printf
   est_dedans:
	push oui
   affichage:
	call printf

	mov eax, 0
	leave
	ret


C'est parti! Reflechissez un peu quelques dizaines de minutes s'il le faut. Faites une recherche sur les instructions en rapport avec les chaines. Pas d'indice pour cet exercice :-)

Corrigé


Voici une solution:
est_dans_tableau:
	;On récupère l'adresse du tableau (premier paramètre) dans edi
	mov edi, [esp + 4] 
	;On récupère la taille du tableau (second paramètre) dans ecx
	mov ecx, [esp + 8]
	;On récupère le caractère à trouver (troisième paramètre) dans eax
	mov eax, [esp + 12]

	;Recherche du caractère
	repne scasb
	;Si le flag ZERO (ZF) est à 1 c'est qu'on a trouvé le caractère
	;Sinon c'est qu'on ne l'a pas trouvé
	;Il nous suffit donc de mettre la valeur de ZF dans eax
	mov eax, 0
	;Si ZF = 1 alors al = 1 (al étant les 8 bits de poid faible d'eax)
	setz al 

	ret

Explication


Le but était de vous faire utiliser la combinaison des instructions de type "rep" et "scas". Ici nous utilisons "repne". Cette instruction répète l'instruction qui la suit en faisant décrémenter ecx à chaque itération. Cette boucle s'arrête lorsque ecx = 0 ou lorsque le Flag Zero (ZF) est à 1. L'instruction scasb, quant à elle, recherche la présence d'un caractère (logé dans al, partie basse de eax) dans l'emplacement mémoire pointé par edi. Si al est égal à la valeur pointée par edi, alors le Flag Zero est mis à 1. Ensuite, dans tous les cas, edi est incrémenté de 1.
Voici donc ce qui se passe, vu que ce qui vient d'être expliqué ne doit pas être très parlant, avouons le :-)
ZF = 0
ecx = longueur
eax = caractère
edi = tableau
//Boucle qui représente le "repne scasb"
Tant que ecx != 0 ET ZF = 0 Faire
    Si al == [edi] Alors
        ZF = 1
    FinSi
    ecx = ecx - 1
    edi = edi + 1
FinTantQue

eax = 0
//Condition qui représente le "setz"
Si ZF = 1 Alors
    eax = 1
FinSi


Et voilà :-)

Autres Astuces dans la catégorie x86