En profondeur avec l'assembleur

Mis à jour le jeudi 5 décembre 2013
Les bases

Un minimum de code

Oui, la théorie est bien finie !

Dans ce chapitre nous allons découvrir RadASM et écrire notre premier code.

Créer un nouveau projet

Nous allons maintenant apprendre à créer un Nouveau projet. Avant chaque nouveau programme que vous écrirez, il vous faudra faire de même. Suivez bien la marche à suivre...

Tout d'abord, ouvrez RadASM. Vous vous souvenez j'espère comment on fait : On ouvre le dossier nommé RadASM et on clique sur l'application du même nom. (Vous la reconnaîtrez aisément à son icône rouge formant un R et un A à l'envers.)

C'est fait ? Bien.

Cliquez ensuite sur l'onglet Fichier tout en haut à gauche, puis sur Nouveau projet, le premier du menu déroulant.
Vous aurez une fenêtre comme celle-ci qui apparaîtra :

Image utilisateur

Comme vous pouvez le voir, j'ai ajouté des numéros sur la capture d'écran.
En effet, vous aurez cinq choses à faire sur cette fenêtre. Ces numéros vous aideront à vous repérer :

1) Tout en haut, en dessous de "Assembleur utilisé", vous avez un menu déroulant.
Il vous permet de choisir l'Assembleur que vous désirez utiliser. Normalement vous n'aurez qu'une possibilité, vu que l'on n'a installé que masm. ;)
Choisissez donc masm.

2) Ensuite, juste en dessous, sous le titre "Type de projet", vous pouvez voir une liste de boutons à cocher. Comme l'indique ce titre, vous pouvez ici choisir le type de projet que vous voulez réaliser.
Choisissez Console App. Vous indiquez par cela à RadASM que vous allez créer un projet sur console. Nous verrons bientôt ce que cela veut dire.

3) Nom du projet : Ici, vous devrez écrire le nom de votre projet. Nous allons mettre "Premier prog", mais vous pouvez mettre ce que vous voulez.

4) Description du projet : Le titre est clair, je suppose. Vous pouvez écrire une courte description de votre projet. Contrairement à la case précédente, vous n'êtes pas obligés de remplir celle-ci.

5) En dessous, vous devrez choisir l'emplacement dans lequel vous voulez que votre projet soit enregistré.
Normalement, le chemin d’accès est automatiquement écrit comme il faut. Il doit se terminer par "RadASM\Masm\Projects". Si ce n'est pas déjà fait, indiquez-le en vous servant du bouton aux points de suspensions.

Au final, vous devez avoir ceci :

Image utilisateur

Voilà ! Vous pouvez maintenant cliquer sur le bouton "Next>", trois fois, sans vous préoccuper des autres fenêtres qui apparaîssent.
Enfin, cliquez sur "Finish" et c'est terminé ! :)

Présentation de l'environnement

Je vais maintenant vous présenter les principales fonctionnalités de RadASM.

Regardez cet écran :

Image utilisateur

Vous voyez les flèches rouges ? Vous devez cliquer sur les boutons qu'elles indiquent (clic simple sur le numéro 1 et double clic sur le numéro 2).

Normalement, après cela, RadASM devrait apparaître ainsi :

Image utilisateur

Si ça vous gêne ainsi, je vous la mets aussi en miniature ; ouvrez-la dans un autre onglet pour pouvoir suivre les explications en parallèle :

Image utilisateur

Comme vous pouvez le voir, RadASM est composé de plusieurs parties que j'ai numéroté sur la capture d'écran.
Voici une description pour chacune d'entre elles :

1. Tout en haut, vous avez deux barres d'outils, l'une au dessus de l'autre. La première vous permet d'accéder à toutes les fonctionnalités de RadASM. La seconde contient de petites icônes qui sont en fait des raccourcis vers les fonctionnalités les plus utilisées. Lorsque vous pointez votre curseur sur l'une d'entre elles, une bulle descriptive apparaît.

Voici celle que l'on utilisera le plus :

Image utilisateur

Cette icône sert à assembler et exécuter le programme. Vous pouvez aussi faire Ctrl+F5, c'est exactement pareil.

2. Au centre, la fenêtre principale. C'est là que nous écrirons notre programme.
Oui, je sais c'est tout noir, mais vous pourrez changer ça, si ça vous gène. On s'en occupera très bientôt, juste après notre premier programme, (vous comprendrez alors pourquoi je ne l'ai pas fait tout de suite).

3. Ceci est une zone de votre écran que vous allez sans doute haïr durant les prochains jours. C'est là que le debuggeur vous indiquera les erreurs de votre programme. D'autant plus qu'il le fera en anglais, et pas dans le plus clair... Mais ne vous inquiétez pas, même si vous ne lisez pas l'anglais, je vous expliquerai tout ce qu'il y a comprendre.
(Il n'empêche que connaître l'anglais est un atout crucial en programmation, qui plus est en assembleur. :-° )

4. C'est ici que vous apercevrez les fichiers contenus dans votre projet. Nous allons travailler pour l'instant uniquement dans celui qui se termine par ".asm". (Celui que je vous ai demandé d'ouvrir tout à l'heure.)

5. Ceci est un outil très utile qu'on apprendra à utiliser plus tard.

Avant de commencer notre premier programme, il faut que vous sachiez une chose. Pour l'instant, nous n'allons pas écrire de programme avec fenêtres mais seulement sur console. Si vous ne connaissez pas la différence, je vous invite à lire ce qu'a écrit M@téo21 à ce sujet dans son tuto sur le langage C.

Les mots-clés

Nous avons enfin créé un nouveau projet. Super. Nous sommes maintenant face à un écran noir comme la mort, et je vous entends d'ici penser : Mais qu'est-ce qu'on va bien pouvoir y écrire...?
Rassurez-vous, je me suis posé la même question lorsque je me suis retrouvé dans cette situation pour la première fois...
Pour vous simplifier les choses, je vais vous faire un petit rappel-introduction qui vous sera d'une grande aide par la suite. Même si vous avez une mémoire d'éléphant, lisez tout, je vais y ajouter de nouvelles informations importantes. ;)

Tout d'abord, un petit rappel :

Un programme est composé d'une suite d'instructions. L'ordinateur lit les instructions et les applique dans l'ordre.
Il existe un nombre fixe d'instructions existantes. Elles constituent ce qu'on appelle le jeu d'instructions.
Le nombre d'instructions disponibles peut varier d'une architecture à l'autre. Dans notre architecture, la 80x86, le jeu d'instructions contient environ une centaine d'instructions.

Tous les programmes ne sont donc en réalité que des combinaisons de ces instructions. Uniquement de ces instructions. Rien d'autre.

A quoi ressemblent ces instructions ? A des trucs comme ça : 0110 1000 1110 1001. Oui, les instructions sont écrites en binaire.

A la base, le programme est enregistré sur le disque dur. Puis, lorsque vous le lancez, toutes ses instructions sont copiées du disque dur vers la mémoire vive. Ensuite, le processeur va chercher la première instruction et l'appliquer, il va ensuite chercher la seconde et faire de même... Ainsi de suite jusqu'à qu'il ait tout terminé.

(Bien entendu ceci est le déroulement d'un programme vu en gros. Plus tard, nous en apprendrons les détails.)

A l'époque de l'invention des ordinateurs, les programmeurs écrivaient les instructions en binaire. Mais cela provoquait beaucoup d'erreurs, car quoi que l'on dise, le binaire n'est pas fait pour les humains : Vous vous trompez d'un bit, et c'est une toute autre instruction que l'ordinateur reçoit...

On a donc inventé le langage assembleur. Son principe est très simple : On représente chaque instruction par un petit mot écrit en lettres humaines. On peut donc écrire le programme avec ces mots là. Puis, on met en marche un logiciel qui va remplacer chacun de ces mots par l'instruction binaire équivalente : L'ordinateur peut maintenant lire notre programme.

Ce logiciel "traducteur" se nomme l'Assembleur (avec un 'A' majuscule). L'Assembleur que nous allons utiliser dans ce tuto se nomme MASM.

On appelle ces mots de remplacement des mnémoniques, car en plus d'être écrits en lettres humaines, chacun a été inventé de façon à faire penser automatiquement à l'instruction qu'il représente.
Par exemple, add est le symbole mnémonique de l'instruction qui sert à additioner.

(Et là on peut dire merci aux inventeurs de l'Assembleur, qui, j'en suis sûr, n'auraient pas été dérangés outre mesure par des symboles comme GfRd, UUtE et autres joyeusetés. Ils ont pensé à nous en se servant de mnémoniques, c'est sympa de leur part, non ? :-° )

Nous pouvons donc maintenant répondre en partie à notre question : "Que va-t-on écrire dans l'écran noir ?"

Vous connaissez maintenant la réponse : Des instructions. (Sous forme de mnémoniques, bien entendu.)
Nous allons donc apprendre à utiliser ces instructions, puis, nous apprendrons à les associer afin de créer des programmes.

Vous avez peut-être remarqué que j'ai précisé au dessus "en partie".

Car les instructions ne seront pas les seules composantes de notre code.

Quoi ! Mais tu nous as dit au moins dix fois qu'un programme était composé uniquement d'instructions !!

Oui, c'est vrai. Mais soyons plus précis : Le programme que l'ordinateur lira à la fin sera composé uniquement d'instructions.

Il n'empêche que, dans notre code, nous utiliserons parfois d'autres types de mots-clés que les instructions. Car il existe d'autres types de mots-clés que les instructions.

En voici deux nouveaux (en plus des instructions) :

  1. Les directives

  2. Les macros

Je vais les expliquer un à un. Commençons d'abord par les directives :

Les directives sont des ordres que l'on donne à l'Assembleur lui-même, autrement dit, MASM. Elles concernent seulement et uniquement MASM.
On les utilise pour demander certaines choses à MASM, notamment comment on veut qu'il assemble le programme. Ces directives seront donc lues par MASM avant l'assemblage. Puis, en fonction de ce qu'elles lui demandent, MASM assemblera le programme en langage machine.

Au final, les directives ne feront donc pas partie du programme en langage machine, puisqu'elles ne sont destinées qu'à l'Assembleur et non au processeur.

Nous apprendrons un certain nombre de directives au cours de ce tuto. L'important est de toujours garder en tête que l'ordinateur ne les verra pas dans le programme final, puisqu'elles ne servent qu'à MASM.

En résumé :

  • Les instructions sont lues par le processeur durant l'exécution du programme, et sont donc assemblées.

  • Les directives sont lues par MASM avant l'assemblage du programme. Elles ne sont donc pas assemblées.

Nous verrons très bientôt nos premières directives (avant la fin du chapitre).

Passons maintenant aux macros :

Vous savez peut-être qu'écrire un programme en assembleur est en général assez long.
Rien que pour demander à l'ordinateur d'afficher du texte à l'écran, il faut un très grand nombre d'instructions.

A l'époque de l'invention de l'assembleur, c'était comme ça, il fallait écrire des centaines de lignes pour faire des programmes très simples. o_O

Le plus frustrant était que la plupart des tâches sont répétées très souvent. Par exemple : afficher du texte à l'écran, enregistrer ce qui est tapé au clavier, etc. A chaque fois que l'on voulait ordonner à l'ordinateur d'accomplir l'une de ces tâches, il fallait réécrire à nouveau tout le code nécessaire à son déroulement. Et comme ces tâches étaient très courantes, c'était vraiment du temps perdu pour rien...

Jusqu'à ce que les programmeurs aient une idée géniale pour raccourcir considérablement l'écriture des programmes : Les macros.

Voici en quoi cela consiste : Ils écrivirent à l'avance le code de toutes les tâches les plus couramment utilisées, et les enregistrèrent dans des fichiers. Par ailleurs, ils associèrent à chacune de ces tâches un nom. Bien entendu, chaque nom est en général évocateur quant à la tâche qu'il représente. Grâce à cela, écrire un programme est beaucoup plus facile : Quand on arrive à une tâche déjà écrite par les programmeurs, il suffit d'écrire le nom qui correspond à cette tâche. Ensuite, lorsqu'on lance l'Assembleur, ce dernier remplace chaque nom par le code correspondant (celui que les programmeurs avaient écrit à l'avance). Puis, il passe à l'assemblage du programme.

Ces raccourcis sont très, très utilisés. Ce sont les macros. Il en existe un grand nombre.

Nous aussi, nous allons utiliser les macros. Cela nous facilitera grandement les choses. Mais il ne faut surtout pas oublier que derrière chacun de ces petits noms d'apparence anodine se cache un long code complexe.

Mais bien entendu, il ne sera pas question d'utiliser bêtement des codes écrits par d'autres toute notre vie, du moins, pas sans comprendre parfaitement leur fonctionnement.
C'est pour cette raison que, plus tard, lorsque nous en serons capables, je vous montrerai où trouver ces codes, et nous les lirons ensemble. Vous comprendrez alors de quoi sont faites les macros que l'on aura si souvent utilisé. Vous pourrez alors, si vous le désirez, écrire ces tâches sans l'aide des macros. (Par ailleurs, nous apprendrons aussi à créer nous-mêmes nos propres macros... Mais patience, le chemin est long jusque là !)

En attendant, nous allons "bêtement" utiliser les macros sans savoir comment elles sont codées, mais il n'y a pas de honte à avoir, tout le monde est passé par là !

Vous comprenez maintenant que je ne vous ai pas menti. Finalement, un programme est bien constitué uniquement d'instructions :

  • Les directives ne sont pas integrées au programme.

  • Les macros sont en réalité eux-même composées d'instructions. Lorsque vous utilisez une macro, elle est remplacée par la suite d'instructions préalablement préparée par les programmeurs.

En résumé, nous connaissons maintenant trois types de mots-clés :

  • Les instructions

  • Les directives

  • Les macros

Non, ce ne sont pas les seuls... Nous en découvrirons d'autres plus tard. Mais pour l'instant, ceux-là seront suffisants...

Tout cela peut vous paraître flou et confus. C'est tout à fait normal : uniquement de la théorie, sans jamais pratiquer, n'est pas facile à digérer. C'est pour cela que je vous propose de commencer à coder tout de suite notre premier programme. :)

Vous allez peu à peu faire connaissance avec les instructions, les macros et les directives. Ils vous paraissent pour l'instant étranges sans doute, mais vous ne tarderez pas à les apprivoiser.

Code minimal

Ca y est ! On va enfin commencer à coder pour de bon. :)

Ouvrez bien vos yeux, vous allez découvrir ce qu'on appelle le code minimal, c'est à dire le code que tout programme contient obligatoirement :

.386
.model flat, stdcall
option casemap : none

include \masm32\include\masm32rt.inc


.code


salut :

exit  
 
end salut

Euh, là on pige rien...

Ne vous inquiétez pas, c'est tout à fait normal : vous êtes sensé ne rien comprendre.

Tout sera expliqué comme il faut, en temps et en heure. Je dis "en temps et en heure", car en effet, vous n'avez pas encore le niveau nécessaire pour comprendre entièrement ce code.

Je vais donc expliquer ce qui est maintenant compréhensible. Par la suite, j'ajouterai des explications au fur et à mesure de votre progression.
Mais pas d'inquiétude ! Vous pourrez parfaitement apprendre à programmer sans comprendre toutes ces lignes.

Copiez simplement ce code dans RadASM, et lisez les explications que je peux vous offrir pour l'instant.

Commençons par la première ligne :

.386 : Voilà. Vous avez devant vous votre première directive ! Alors, ça fait quel effet ? :D

Oui, .386 est une directive. Elle indique à MASM pour quel processeur nous allons programmer. Le 80386.

Nous indiquons par cela à MASM que nous allons utiliser dans notre code uniquement les fonctionnalités présentes dans le 80386, mais pas celles qui ont été ajoutées plus tard dans les processeurs ultérieurs tel que le 80486 ou le Pentium. Si on transgresse cette règle et que l'on utilise de nouvelles fonctionnalités, le debuggeur ne manquera pas cette occasion de nous tomber dessus...

Le programme créé sera donc compatible avec le 80386 ainsi qu'avec tous les processeurs qui l'ont suivis, (puisque ceux-ci contiennent aussi les fonctionnalités du 80386). Mais il ne marchera pas sur les processeurs précédents (comme le 80286), car il utilisera des fonctionnalités inconnues pour eux.

Pour chaque processeur, il existe une directive qui lui fait référence :

  • .8086 pour le 8086

  • .186 pour le 80186

  • .286 pour le 80286

  • .386 pour le 80386

  • .486 pour le 80486

  • .586 pour le Pentium

Il vous suffit donc d'écrire la directive que vous voulez tout au début de votre code.

Si vous ne mettez rien, MASM fera comme si vous avez mis ".8086", et va donc assembler uniquement si le code est compatible avec le premier des processeurs, et donc automatiquement avec tous les processeurs (puisque tous ont aussi les capacités du premier).

.model flat, stdcall : Encore une directive. Mais vous n'avez pas encore le niveau requis pour comprendre ce qu'elle fait. Je l'expliquerai plus tard.

option casemap : none : Cette ligne est aussi une directive. Elle indique à MASM que nous voulons faire une difference entre les majuscules et les minuscules. Nous verrons bientôt des exemples qui vous permettront de comprendre cela.

include \masm32\include\masm32rt.inc : Cette directive est aussi pour plus tard.

.code : Cette directive indique à MASM qu'à partir d'ici nous commençons à écrire notre programme proprement dit.

salut : et end salut : Tout le code du programme doit être écrit entre "salut :" et "end salut" (ligne 11 et 15). En réalité, libre à vous de choisir le mot que vous voulez, du moment que vous mettez le même les deux fois : Avant les deux points et après le "end", à la fin.
Nous decouvrons ici un nouveau type de mot. Ce n'est ni une instruction, ni une directive, ni une macro. C'est un label. Je ne vous en ai pas parlé plus tôt pour ne pas vous surcharger. D'autant plus que nous ne verrons que plus tard à quoi cela sert exactement.

Pour l'instant ne retenez qu'une seule chose : Vous devez écrire tout votre code entre ces deux mots : "salut :" et "end salut".

exit : Ceci n'est ni une instruction, ni une directive. Oui ! Vous avez deviné, c'est une macro.

Normalement, pour quitter convenablement un programme, il faut écrire quelques lignes de code à la fin. Au lieu de cela, nous allons utiliser cette macro qui va faire le travail à notre place.

Exit est une macro qui sert à quitter le programme.

Il va sans dire que exit devra être le dernier mot de votre code (à part end label), puisque l'ordinateur quitte le programme dès qu'il le lit. Toutes les instructions qui suivront ce mot ne seront donc pas exécutées.

Voilà, c'est terminé. Au risque de me répéter, je dirai que tous vos programmes devront au moins contenir ce code. C'est le minimum vital.

Bon, eh bien maintenant vous pouvez lancer la sauce. Appuyez sur le bouton "Construire et exécuter" ou faites Ctrl+F5. MASM assemblera votre code et l'exécutable sera lancé. (Vous aurez sûrement une boîte de dialogue vous demandant "Accept the command etc...". Faites OK.)

Alors ? C'est comment ?

Ben c'est nul ! Ca a rien fait ! Juste une console qui apparaît et disparaît plus vite que son ombre ! C'est normal ou j'ai raté un truc ? :(

Oui, c'est tout à fait normal. Le contraire aurait été inquiétant. D'ailleurs, ceux qui ont eu un super jeu vidéo qui s'est lancé...euh...c'est pas vraiment normal. (Profitez du jeu quand même, hein ! :-° )

La raison de cette apparition/disparition est simple : Nous n'avons pas mis le programme en pause.

Voici ce qui se passe : L'ordinateur lit le code et la première chose qu'il voit est le "exit", qui lui demande de quitter le programme, alors il obéit et quitte le programme. C'est pour cela que la console apparaît et disparaît aussitôt.

Pour remédier à ce problème, il faut mettre le programme en pause, pour cela nous devons encore utiliser une macro.
La voici :

inkey

Ajoutez cette macro juste avant exit et appuyez sur 'Construire et exécuter'.

Voilà ! La consôle reste avec nous jusqu'à ce que vous appuyez sur une touche. C'est ce que le message en anglais veut dire : "Appuyez sur une touche pour continuer...".
Lorsque vous appuyez sur une touche du clavier, le programme se termine.

Vous pouvez aussi remplacer le message en anglais avec celui que vous voulez. Comme ceci :

inkey "Appuyez sur une touche pour continuer..."

Je vous met maintenant le code en entier, en surlignant la nouvelle ligne en jaune (qui c'est qui a dit que le zCode c'était pourri ? :soleil: ) :

.386
.model flat, stdcall
option casemap : none

include \masm32\include\masm32rt.inc


.code


salut :

inkey "Appuyez sur une touche pour continuer..."
exit  
 
end salut

Perfecto ! :D

Voilà, la console est prête, il ne nous reste plus qu'à apprendre à programmer, pour y afficher quelque chose... :p

Nous allons donc découvrir de ce pas notre première instruction, afin que vous puissiez enfin donner des ordres à l'ordinateur.

Rendez-vous au chapitre 8 !

L'auteur

Exemple de certificat de réussite
Exemple de certificat de réussite