Base de connaissances CCM
Programmation - Langages - Assembleur - x86




Sujet 9831 - Exercice assembleur x86 inversion de chaîne

[ Voir ce sujet en ligne ] - [ Catégorie: Programmation - Langages - Assembleur - x86 ]




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


Énoncé


Le but est d'écrire une fonction en assembleur capable d'inverser une chaîne de caractères.
Cette fonction devra prendre en paramètre d'entrée un pointeur vers une chaîne de caractères et inverser cette chaîne sur le même pointeur.

Voici ce que donnerait cette fonction en C:
void inverse_chaine(char *str); //Le prototype de cette fonction
//Exemple d'utilisation:
char string[] = "Je suis une chaîne a inverser";
inverse_chaine(string);
printf(string); //Affichera "resrevni a eniahc enu sius eJ"


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

section .data
	chaine db 'Inverse moi! Je te dirais quel programmeur tu es!', 0x0

section .text
	global main, inverse_chaine

inverse_chaine:
		;Mettez votre code ici


main:
		mov eax, chaine ;Adresse de chaîne dans eax
		push eax
                ;Appel de inverse_chaine avec l'adresse de la chaîne à inverser
		call inverse_chaine 
                ;Les deux lignes suivantes sont optionnelles car l'adresse 
                de la chaîne (maintenant inversée) est toujours dans la pile. 
                mov eax, chaine ;Adresse de chaîne dans eax
		push eax
                ;Affichage de la chaîne avec printf
		call printf
		add esp, 4 ;On sort de la fonction main
		mov eax, 0

Essayez de résoudre cet exercice par vous-même dès maintenant sans regarder les sections suivantes. Plus on réfléchit par soi-même, plus on évolue. Si vous avez du mal, regardez la section qui suit (Indices) puis réessayez.
Bonne chance! C'est en forgeant que l'on devient forgeron ;-)

Rappel


Indices


Vous n'avez pas une idée? Allez, un petit indice pour vous faire démarrer : vous savez probablement que la pile est une mémoire dont l'accès est de type Last In First Out. Ce qui signifie que si vous poussez dans la pile trois lettres les unes après les autres comme a puis b puis c, vous les récupèrerez dans l'ordre inverse: c puis b puis a.

Corrigé


J'espère que vous avez réussi à faire quelque chose, même si vous pensez ne pas avoir utilisé la bonne manière, ce n'est pas grave, c'est comme ça qu'on apprend.

Voici une solution:
inverse_chaine:
                ;Prologue de la fonction
		push ebp
		mov ebp, esp
	
                ;On charge le pointeur passé en paramètre dans eax
		mov eax, [ebp+8]
                ;On push le caractère de fin de chaîne dans la pile
		push word 0

	chaine_dans_pile:
                ;On va empiler chaque caractère de la chaîne

                ;Récupération caractère courant
		mov bl, byte [eax]
                ;Est-ce la fin de chaîne? (bl = 0 ?)
		test bl, bl
                ;Si oui on passe à l'étape suivante
		jz fin_chaine_dans_pile
                ;Sinon on empile le caractère suivant
		push bx
                ;On incrémente le pointeur de 1 pour traiter le caractère suivant
		inc eax
                ;On passe au caractère suivant
		jmp chaine_dans_pile

	fin_chaine_dans_pile:
                ;On recharge le pointeur de la chaîne pour dépiler un à un chaque caractère
		mov eax, [ebp + 8]

	inversion:
                ;On dépile le caractère courant
		pop bx
                ;On le charge dans le pointeur de chaîne
		mov byte [eax], bl
                ;On incrémente l'adresse
		inc eax
                ;C'était la fin de la chaîne? (le 0 qu'on a empilé au début?)
		test bl, bl
                ;Non alors on continue
		jnz inversion
                ;C'est la fin de la chaîne, on marque la conclusion de la fonction
		leave
		ret

Explication


Comme suggéré dans la section "indices", l'idéal est d'utiliser la pile. On empile chaque caractère de la chaîne. Lorsqu'ils seront dépilés, on les récupèrera dans l'ordre inverse.
Voici donc ce qui se passe: on empile d'abord 0 qui sera donc dépilé plus tard, en dernier, pour marquer la fin de chaîne.
Ensuite, on empile un à un chaque caractère de la chaîne en passant par bl (les 8 caractères de poids faibles de ebx) qui est suffisant pour un caractère. Lorsqu'on empile, on prend bx (16 bits de poids faible de ebx) qui contient lui-même bl car on est obligé d'empiler au moins 2 octets.
Durant ces empilements successifs, on fera bien attention de ne pas empiler le caractère de fin.

A l'étape suivante, on recharge le pointeur à l'adresse du début de la chaîne. Puis, on dépile successivement chaque caractère dans la chaîne en écrasant les anciennes valeurs. Lorsqu'on a dépilé le 0 de fin de chaîne, on l'insère également dans la chaîne puis on arrête. Et le tour est joué.

Lire la suite

Compiler un programme assembleur avec Nasm »
Publié par kilian - Dernière mise à jour le 17 octobre 2008 à 23:13 par fleursdespyrenees




Sujet 9836 - Compiler un programme assembleur avec Nasm

[ Voir ce sujet en ligne ] - [ Catégorie: Programmation - Langages - Assembleur - x86 ]





Nasm est un logiciel assembleur libre pour architecture x86. On peut le trouver pour plusieurs systèmes d'exploitation comme Linux ou Windows par exemple.
Un assembleur permet d'assembler du code assembleur. (sic)

Hélas, assembleur signifie deux choses

Cette astuce ne vous apprendra pas à programmer avec Nasm mais à créer un executable sous Linux et Windows à partir d'un code source destiné à Nasm.

Avec Linux


Etape 1. Créer un fichier source


Vous n'avez pas besoin d'un éditeur spécifique pour créer un fichier source destiné à Nasm. Vous pourriez éventuellement utiliser un éditeur qui supporte la coloration syntaxique de l'assembleur mais il n'y en a pas, à ma connaissance, qui supporte la syntaxe de nasm.
Vous pouvez donc choisir gedit, kwrite, xemacs etc...

Lorsque vous enregistrez votre fichier source, donnez lui l'extension .asm

Etape 2. Assembler le fichier source


Pour cette étape, vous aurez besoin du logiciel nasm installé sur votre machine. Si vous êtes sous Debian ou Ubuntu, il suffit de taper la commande
sudo apt-get install nasm


Si vous avez une autre distribution Linux, il vous faudra utiliser le gestionnaire de paquet de votre distribution (exemple urpmi, yum, emerge etc...) ou bien compiler nasm en téléchargeant l'archive depuis le site officiel.

Passons maintenant à l'assemblage de votre fichier source.
Rendez vous en ligne de commande dans le repertoire ou se situe votre fichier source que nous allons appeler test.asm pour l'exemple. Voici la ligne à taper:
nasm -f elf test.asm

Ceci créera un fichier nommé test.o dans le repertoire courant. Ce fichier n'est pas encore exécutable, ce n'est encore qu'un fichier objet, c'est à dire un fichier qu'il faut lier avec les bibliothèques dont il dépend comme par exemple la libraire standard libc.

Etape 3. Création de l'executable


Maintenant que nous avons notre fichier objet nommé test.o nous allons créer notre executable.
Deux cas se présentent ici:
ld test.o -o test

gcc test.o -o test


Voilà notre executable est créé, il s'appelle test et se situe dans le repertoire courant.

Etape 4. Execution du programme


Pour executer notre programme appellé "test", il suffit de taper cette commande:
./test

Vous pouvez également utiliser un déboggeur pour observer l'execution. Pour celà vous pouvez utiliser gdb qui s'utilise en ligne de commande. Si toutefois vous voulez un débogeur plus visuel, il existe des interfaces graphiques qui utilisent gdb en arrière plan comme par exemple Insight.

Avec windows


IMPORTANT: Sous windows la convention d'appel de paramètre n'est pas la même, la fonction appellée doit nettoyer elle-même la pile. De même, le main n'existe pas sous windows, il faut le remplacer par WinMain.
Si votre point d'entrée est _start ou main, il faudra changer celà en "_WinMain@16" et changer le "ret" à la fin de cette procédure d'entrée en "ret 16".
Exemple d'un fichier source correct sous Windows:
section .text
	global _WinMain@16

_WinMain@16:
	mov eax, 0
	ret 16	

Etape 1. Installer les logiciels nécessaires


Nous allons d'abord installer nasm. Allez sur la section de téléchargement de CCM où bien sur le site officiel dans la section download (choisissez la version Win32 binaries). Gardez l'archive dans un coin, on s'en servira plus tard.

L'étape la plus délicate va être d'installer MingW qui est un environnement de développement libre pour windows.
A cette adresse, choisissez la dernière version de MinGW. Aujourd'hui c'est la version 5.0.0.
Executez cet installeur. S'il vous propose de mettre à jour votre installeur dés le début, dites non. Laissez toutes les options selectionnées par défaut puis attendez la fin de l'installation.

A présent, nous allons insérer nasm dans l'environnement de développement MingW, comme des sauvages mais avec de la délicatesse.
Décompressez l'archive de nasm, vous devriez obtenir un dossier contenant, entre autres, un fichier nommé nasm.exe
Copiez ce fichier dans le repertoire C:\MinGW\bin

Etape 2. Créer un fichier source


Tout comme pour Linux, il n'y a pas besoin d'utiliser un éditeur spécifique pour créer un fichier source destiné à Nasm.
Vous pouvez utiliser par exemple le Bloc Note mais faites attention, le bloc note de windows a tendance à rajouter l'extension .txt au fichiers qu'il crée. Pour lever toute ambiguité, je vous recommande chaudement d'afficher les extensions de vos fichiers.
Evitez en tout cas des traitements de textes comme Word ou WordPad qui risquent d'enregistrer votre fichier dans un format indésirable.

Si vous le souhaitez, vous pouvez également utiliser un éditeur qui utilise la coloration syntaxique pour la syntaxe de nasm comme par exemple NasmEdit IDE (gratuit).

Dans tous les cas, je vous conseille de donner l'extension .asm à votre fichier source.

Etape 3. Assembler le fichier source


Ouvrez l'interpréteur de commande de windows (tapez cmd.exe dans "Executer" du menu démarrer ou directement "cmd" dans la barre "recherche" du logo windows sous Windows Vista.
Avec cet interpréteur de commande, vous devrez vous rendre dans le dossier qui contient votre fichier source avec la commande "cd".
Une fois que vous êtes dans ce repertoire, assemblez votre fichier source (appellons le test.asm) avec cette commande:
nasm -f win32 test.asm -o test.o

Vous avez à présent un fichier objet qui n'est pas encore executable, mais il le sera bientôt, passons à la dernière étape.

Etape 4. Création et execution du programme


Toujours depuis votre fenêtre de commande, une dernière commande à taper pour créer l'executable:
ld test.o -o test.exe

Si vous avez un problème avec cette commande, c'est que vous avez peut être oublié le lire le point important que j'ai noté plus haut au début de la section "Pour Windows".
Pour tester votre executable, tapez simplement "test" dans la fenêtre de commande. Si vous voulez un debugger pour visualiser de plus près ce qui se passe, utilisez OllyDbg, c'est un excellent debuggeur.

Lire la suite

Exercice assembleur x86 nombre premier »
Publié par kilian - Dernière mise à jour le 16 novembre 2009 à 16:20 par marlalapocket




Sujet 9863 - Exercice assembleur x86 nombre premier

[ Voir ce sujet en ligne ] - [ Catégorie: Programmation - Langages - Assembleur - x86 ]



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


Enoncé


Le but est d'écrire une fonction en assembleur capable de determiner si un entier non signé est un nombre premier ou pas. On donnera un seul paramètre d'entrée de type entier non signé qui représentera
le nombre à tester. La valeur de retour doit être 1 si le nombre est premier et 0 si le nombre n'est pas premier.

Voici ce que donnerait cette fonction en C:
int est_premier(unsigned int n); //Le prototype de cette fonction
//Exemple d'utilisation:
unsigned int nb = 3;
if (est_premier(nb) == 1){
    printf("Le nombre %d est premier!, nb);
}


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

section .data
		entrer db 'Entrez un nombre!', 0xa, 0x0
		oui    db 'C est un nombre premier', 0xa, 0x0
		non    db 'Ce n est pas un nombre premier', 0xa, 0x0
		format_d db '%d', 0x0

section .text
		global main

est_premier:
		;Insérez votre code ici!

	
main:
		push ebp
		mov ebp, esp

		;On prévoit de la place pour un entier dans la pile
		;Celui que l'on entrera avec scanf
		sub esp, 4

		;Petite phrase de bienvenue
		push entrer
		call printf
		add esp, 4

		;On demande à l'utilisateur d'entrer un nombre
		push esp ;Adresse de l'entier
		push format_d ; %d
		call scanf
		add esp, 8

		;On appelle notre fonction avec l'entier entré
		push dword [esp]
		call est_premier
		;On teste le retour (eax == 0 ?)
		test eax, eax
		;Si égal à zero => pas premier
		jz pasPremier
		;Sinon
		push oui
		call printf
		;On va vers la conclusion de la fonction pour ne pas
		;entrer dans la section pasPremier
		jmp quit

	pasPremier:
		push non
		call printf

	quit:
		leave
		ret


C'est parti! Pas d'indice pour cet exercice!

Rappel


Corrigé


Voici une solution:
est_premier:
		;Prologue de la fonction
		push ebp
		mov ebp, esp

		;On charge notre nombre n dans ecx
		;ecx sera ensuite décrémenté pour tester tous les nombres
		;qui pourraient diviser n en allant de n à 2
		mov ecx, [ebp + 8]
		;On part du principe qu'il est premier (ebx = 1)
		mov ebx, 1
	divisions:
		;Deux cas se présentent ici
		;Soit on vient d'entrer dans la fonction et ecx est notre nombre
		;s'il est plus petit ou égal à 2, il est premier
		;Soit on vient de tester une division par 2 et donc inutile d'aller plus loin
		;car il est premier
		cmp ecx, 2
		;ecx <= 2, notre nombre est premier
		jbe finDivisions
		;On décrémente le diviseur
		dec ecx
		;On met dans eax notre nombre à diviser (l'argument n)
		mov eax, [ebp + 8]
		;edx doit être égal à zero car il est partie haute du nombre divisé
		xor edx, edx
		;La division (eax / ecx)
		div ecx
		;Le reste de la division est égal à zero?
		test edx, edx
		;Si non c'est que notre diviseur n'a pas été capable de diviser
		;notre nombre n. On continue à penser qu'il est premier et on le divisera
		;par ecx - 1
		jnz divisions
		;Si le reste est nul c'est que notre nombre n'est pas premier
		mov ebx, 0

	finDivisions:
		;On charge le retour de la fonction avec ebx
		;qui contient notre réponse 
		;(1: nombre premier 0: pas premier)
		mov eax, ebx
		leave
		ret

Explication


L'algorithme utilisé dans cette solution est assez simple même s'il ne parait pas l'être une fois traduit en assembleur (un peu comme tous les algorithme en assembleur finalement).

Voici ce qu'on fait ici. On part du principe que notre nombre n est premier. On prend notre nombre n et on le divise successivement par tous les nombres qu'il lui sont inférieurs jusqu'au nombre 2 inclus.
Si l'un de ces nombres est capable de le diviser (c'est à dire que le reste de la division est égal à zero), alors on arrête les tests et on déclare que notre nombre n'est pas premier.
De même si notre nombre est dés le départ inférieur ou égal à 2, on ne fait pas de test et on dit qu'il est premier.
Schématiquement voici notre idée:
Fonction est_premier (n: entier non signé) : entier
    diviseur = n
    premier = 1
    Tant que n <= 2
    Faire
        diviseur = diviseur - 1
        reste = n mod diviseur
        Si reste == 0
        Alors
            premier = 0
            sortir de la boucle
        FinSi
     FinTantQue
Fin
retourner premier

Pour celà on utilise l'instruction div qui divise eax par un registre donné en paramètre, en l'occurence ici c'est ecx qui est notre diviseur et qui est décrémenté à chaque test. C'est une division pour nombres non-signés (sinon utiliser idiv). Le quotient est placé dans eax (notre nombre n, rechargé à chaque passage dans la boucle) et le reste est placé dans edx.
On a juste à tester le reste. Cette boucle de divisions est située sous le label "divisions".
Voilà c'est un algorithme qui pourrait être optimisé, mais ce n'est pas le but...le but d'une solution étant de rester simple. Après tout ce ne sont pas les nombres premiers qui nous interessent mais l'assembleur (euh...n'est ce pas?).

Petite note: dans notre solution, lorsque l'on fait
div ecx

ce qui provoque eax = eax / ecx et edx = eax % ecx
on a pris soin de mettre edx à zero. C'est une précaution à prendre car en fait edx représente la partie de poids fort du nombre divisé.
Voici ce qui se passe en réalité:
eax = edx:eax / ecx et edx = edx:eax / ecx
En mettant edx à zero, on est sûr que edx ne viendra pas ajouter des bits de poids fort innatendus dans notre division.

Lire la suite

Liens utiles assembleur x86 »
Publié par kilian - Dernière mise à jour le 19 novembre 2009 à 14:14 par marlalapocket




Sujet 9899 - Liens utiles assembleur x86

[ Voir ce sujet en ligne ] - [ Catégorie: Programmation - Langages - Assembleur - x86 ]

Voici quelques liens utiles pour l'assembleur x86. Le but étant de compiler des documents pertinents autant pour ceux qui débutent que pour ceux qui sont à l'aise dans ce domaine.


Tutoriels


Références complètes


Assembleur sous windows


* La page d'Iczelion (en) . C'est un site qui a déjà un peu d'âge mais sa documentation est loin d'être périmée. On y apprend comment invoquer les fonctions de l'API windows en assembleur par exemple. Il y a de nombreux exemples, de la simple MessageBox jusqu'a la gestion des processus.

Assembleur sous Linux


* Linux Assembly (en). Ce site n'est pas spécifique à l'architecture x86 mais couvre le thème plus général d'assembleur sous Linux . On y trouve de nombreuses explications sur l'assembleur inline, l'utilisation de nasm, de gas etc...

Logiciels


Assembleurs


Les assembleurs sont les logiciels qui transforment le code assembleur en code machine pour finalement produire du code exécutable.

Emulateurs

Lire la suite

Exercice assembleur x86 occurence d'un caractère »
Publié par kilian - Dernière mise à jour le 13 novembre 2009 à 13:07 par marlalapocket




Sujet 10330 - Exercice assembleur x86 occurence d'un caractère

[ Voir ce sujet en ligne ] - [ Catégorie: Programmation - Langages - Assembleur - x86 ]




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


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à :-)

Lire la suite

Assembleur - Multiplication par une constante »
Publié par kilian - Dernière mise à jour le 16 novembre 2009 à 13:14 par marlalapocket




Sujet 12520 - Assembleur - Multiplication par une constante

[ Voir ce sujet en ligne ] - [ Catégorie: Programmation - Langages - Assembleur - x86 ]

En assembleur vous pouvez effectuer une multiplication en utilisant les instructions mul (nombres non signés) et imul.
On l'utilise ainsi:
mul nom_registre

Ensuite en interne, le processeur multiplie le contenu de eax ou ax ou al (selon la taille du registre donné en paramètre) puis stocke le résultat dans eax ou ax pour la partie "poids faible" du résultat et dans edx ou dx pour la partie "poids fort" du résultat, si le registre passé en paramètre de mul est supérieur à un octet.

Utiliser mul est un peu lourd car il faut déplacer la valeur multipliée dans eax, la valeur à multiplier dans un autre registre et le registre de résultat sera obligatoirement eax, ce qui écrase la valeur qu'il possédait.

Toutefois, si vous désirez juste multiplier un registre par une constante et mettre le résultat dans le registre de votre choix, vous pouvez utiliser un raccourci avec l'instruction "lea" (load effective address). Cette instruction sert à récupérer l'adresse d'une donnée en mémoire.
lea registre_destination, [adresse_mémoire] ; place adresse_memoire dans registre_destination

Le gros avantage est que, en lieu et place de l'adresse mémoire, vous pouvez mettre une multiplication ou une addition d'un registre par une constante.

Imaginons donc que vous vouliez multiplier ecx par 7 et mettre le résultat dans ebx, la commande serait la suivante:
lea ebx, [ecx * 7]


Voilà donc pour le raccourci bien pratique. Malheureusement vous ne pouvez pas multiplier deux registres ensemble par ce raccourci.
Publié par kilian - Dernière mise à jour le 13 novembre 2009 à 13:27 par marlalapocket





© Tous droits réservés 2010 Jean-François Pillou