l'assembleur  [livre #4602]

par  pierre maurette




MASM - MASM32

Pour programmer en pur assembleur, nous avons décidé de nous appuyer sur MASM, officiellement Microsoft Macro-Assembleur , dans ses versions ml.exe  6.15.8803 et 7.00.9254. Pour les tests, la première a parfois été renommée ml615.exe , la seconde ml7.exe . c'est sous ce nom qu'ils peuvent apparaître de temps en temps dans divers fichiers du CD-Rom.

Pourquoi MASM, plutôt que TASM, NASM, Paradigm ? Parce que ses règles de langage et de syntaxe sont une référence de fait, et les syntaxes des autres produits s'en inspirent parfois. Nous avons déjà abordé ce point.

MASM32 est un kit bâti autour de MASM, en version 6.14 au moment de la rédaction de ces lignes.

Les défauts de MASM, sur lesquels nous ne revenons pas, n'empêchent en rien une programmation efficace. Il s'agit essentiellement d'un certain laxisme de l'assembleur quand il doit interpréter les constructions d'un code source. C'est la raison pour laquelle nous insisterons sur l'utilisation qui devrait au début être systématique des fichiers listing  .lst .

Dans  le cadre de cet ouvrage, nous nous contenterons d'installer et de prendre en main MASM (ou MASM32). L'objectif est de placer le lecteur en situation d'expérimenter confortablement. Pour une description complète de la syntaxe et des nombreuses notions souvent complexes de ce macro-assembleur, le lecteur se reportera à l'édition de la collection "Référence".

5.1 Installer une distribution MASM

MASM désigne non pas un programme, mais un ensemble d'outils, bâti autour essentiellement du ou des assembleurs ml.exe et du ou des lieurs link.exe . Depuis, semble-t-il, une version 6.1x, MASM n'est plus disponible à la vente en tant que produit complet, accompagné de sa documentation. Cet assembleur n'est plus considéré comme un produit de développement commercial, mais plus comme un outil nécessaire, entretenu de façon minimale mais suffisante.

Cet état de fait présente l'avantage de rendre le produit librement accessible, mais complique notre tâche, puisqu'il faut partir à la chasse aux éléments et ensuite les installer, c’est-à-dire le plus souvent les recopier dans des dossiers correctement choisis.

Bien que non distribué, il n'est pas impossible, le produit ayant été relativement répandu à une certaine époque, que vous ayez la chance d'en posséder encore une copie complète. Les bennes à ordures de certains organismes de formation sont un bon territoire de chasse, histoire vécue ! Seul problème dans ce cas, trouver une des dernières versions 6.1x, contenant 5 disquettes 3"1/2 1.44MB encore lisibles. Si vous avez la chance d'être dans cette situation, faites immédiatement une copie des cinq disquettes de distribution sur disque dur.

La principale source d'approvisionnement était jusqu'à récemment les divers DDK (Drivers Development Kit), en accès libre sur le site de Microsoft. La politique de l'éditeur concernant ces kits a changé et nombre de liens fournis sur Internet sont devenus obsolètes. Signalons à ce sujet que les auteurs de ces pages de liens préfèrent souvent conserver ces liens morts en toute connaissance de cause. Les divers SDK/DDK existent toujours, mais les modalités pour se les procurer ont changé.

Des liens précis ou des liens vers des pages de liens sont disponibles sur le CD-Rom. De plus, un moteur de recherche comme Google fournit également de bons renseignements.

Si vous hésitez sur une version à installer, il est vivement conseillé d'installer l'ensemble MASM32. Vous aurez ainsi tout ce qu'il faut pour travailler immédiatement, y compris de la documentation et les fichiers  .lib et .inc nécessaires.

Dans MASM32 version 8, la version de l'assembleur ml.exe est la 6.14.8444, celle du lieur link.exe la 5.12.8078. Il existe deux versions plus récentes de l'assembleur, très proches de cette 6.14 : une 6.15.8803, incluse dans le Visual Studio Processor Pack, toujours intéressant à télécharger, ne serait-ce que pour la documentation et la 7.0 de Visual Studio .NET. Mais, répétons-le, MASM32 v. 8 est tout à fait suffisant. Ces deux versions sont également plus récentes que celles fournies avec MASM d'origine Microsoft.

Il existe deux situations pour lesquelles vous pouvez avoir besoin d'autres programmes que ceux fournis avec le kit MASM32, situations qu'il ne faut pas confondre :

  Pour générer un exécutable DOS 16 bits, il faut utiliser le lieur segmenté link.exe (dernière version 5.60.339) ou éventuellement tout autre lieur DOS compatible.

  Le problème est différent pour l'assembleur ml.exe  : à partir de la version 6.12, il s'agit d'une application console 32 bits. Attention, ceci n'a rien à voir avec le code objet généré. La dernière version tournant en environnement DOS 16 bits est la 6.11d. Les situations débouchant aujourd'hui sur ce besoin sont certainement rares.

Nous verrons comment intégrer les outils nécessaires pour assembler du code 16 bits à partir d'une installation MASM32.

Dans les versions antérieures à 6.x de MASM, l’assembleur portait le nom de masm.exe . Dans le seul but de pouvoir réutiliser les makefiles des anciens projets, les versions 6.x de MASM sont fournies avec un exécutable masm.exe , qui n’est qu’un simple traducteur (MASM Compatibility Driver Version 6.11), qui appelle ml.exe en adaptant les paramètres de la ligne de commandes.

Reste le problème de la documentation exhaustive. Les dernières versions vendues officiellement étaient accompagnées d'un ensemble de quatre ouvrages, dont il circule des versions .doc ou .pdf . Depuis, peu de choses ont évolué, au plan de la syntaxe et de la philosophie du produit. Il suffit de vérifier les points de détail qui peuvent avoir changé.

La première chose à faire est de consulter l’aide en ligne de commandes, en saisissant par exemple ml /? ou ml /? >h.txt pour récupérer la sortie dans un fichier texte. Nous obtenons ainsi un résultat strictement identique pour les versions 6.15 et 7.0.

Ensuite, tout dépend de la façon dont la nouvelle version a été approvisionnée. Pour la 7.0 de Visual Studio .NET, l’aide en ligne contient une rubrique Microsoft Macro Assembler Reference . Pour la 6.15, le Visual Studio Processor Pack inclut un ficher MasmRef.doc . Les deux décrivent, de la même façon brute mais exhaustive, options en ligne de commandes, messages d’erreur, directives, opérateurs et symboles, pour ml.exe et éventuellement pour tel ou tel utilitaire. Les principales différences visibles sur la version 7.0 concernent les directives de type de processeur, ce qui n’a rien d’étonnant.

Si vous ne passez pas par une procédure d'installation, vous pourrez vous inspirer de ce qui suit, ainsi que de ce qui a été écrit sur le sujet au chapitre précédent, pour procéder manuellement. Il n'est pas nécessaire de chercher à tout prix à innover et la structure de dossiers habituelle conviendra : créez un dossier nommé MASM par exemple, ou DEV si vous centralisez les outils de plusieurs langages pour partager ceux, nombreux, qui sont communs. Ensuite, créez une série de sous-dossiers, qui peuvent être BIN (les exécutables de base), INCLUDE (pour les .inc , mais aussi les .h s'il y a lieu), LIB , et tous ceux qui vous semblent utiles pour structurer la chose, DOC , TOOLS ou OUTILS , SOURCES (pour les sources des .lib ), etc.

Il est tout à fait pertinent de partir d'une installation existante (Visual Studio, C++Builder, C++ 5.50) et d’ajouter simplement les fichiers nécessaires dans les dossiers adéquats. Le dernier nommé, C++ 5.50, un compilateur C++ en lignes de commande gratuit et présent sur le CD-Rom, serait une bonne solution, plutôt dans le cas d'assembleurs de la famille TASM.

Commençons par le commencement, nous allons donc décrire deux installations, celle de MASM 6.11 et celle de MASM32.

5.1.1 Installation de MASM 6.11

Nous allons installer ensemble MASM à partir d'une copie sur disque dur d'une distribution version 6.11, puis appliquer un patch de mise à jour vers la version 6.13. Celui-ci a été chargé sur Internet, il s’appelle ml613 . Quoi qu’il en soit, c’est dans cette arborescence d’installation que nous copierons les divers composants de MASM, au fur et à mesure de l’apparition de nouvelles versions. Pour cette raison, nous allons nommer notre dossier d’installation tout simplement MASM .

Si vous ne possédez pas cette distribution telle quelle, vous pouvez vous inspirer de ce qui suit pour créer une arborescence analogue et y copier les fichiers utiles.

L’installation sera décrite sous XP, qui est aujourd'hui l’environnement le plus éloigné de l’environnement cible de ce package. Qui peut le plus peut le moins, tout devrait fonctionner de la même façon sous d’autres versions de Windows. L'installation a d'ailleurs été faite dans une partition partagée entre plusieurs OS sélectionnables au boot, MASM sera utilisé à partir de Windows 2000 et Windows 98 sans problème.

Ce fait est logique, puisqu'en fait d’installation, il s’agit pour l'essentiel d’une copie après décompression, et c’est bien ce que nous recherchons.

Le dossier MASM occupera aux alentours de 8 Mo. Il est bien clair que, au moment de faire des choix, la place occupée sur le disque ne sera pas un critère déterminant, alors que la volonté de ne pas perturber son système d’exploitation en sera un.

Considérons le contenu de la première disquette d’installation dans …\\masm6\disque1 et lançons par un double-clic setup.exe .

Astuce

Simuler des disquettes

Il est très conseillé, comme signalé plus haut, de sauvegarder ses logiciels sur disquettes sur une série de répertoires, par exemple ..\D1 , .., ..\Dn , sur disque dur ou CDRW. La première idée qui vient est d'en faire ensuite autant de copies sur disquettes neuves pour procéder à l'installation.

Il est généralement possible de procéder autrement : copier le contenu de la première disquette dans un répertoire (parfois, la racine d'une partition), et lancer l'install. Ensuite, il suffit de profiter de l'invitation à changer de disquette et du multitâche de Windows pour modifier le contenu du répertoire, en y copiant successivement le contenu des sauvegardes de chaque disquette.

Parfois, si les disquettes ne contiennent pas de nom de fichier en commun, il est possible de tout copier dans un seul répertoire d'installation.

Laissons passer l’écran de bienvenue et nous arrivons sur l’écran figurant sur l’illustration.

Début d’installation
figure 5.01 Début d’installation

Nous allons bien entendu appuyer sur  Entrée  pour continuer l’installation avec choix, non sans avoir remarqué, à l’avant-dernière ligne et à la précédente, la possibilité de consulter la liste des fichiers du package et celle d’extraire chacun d’eux individuellement, ce qui pourra être utile ultérieurement.

Nous passons par une série de choix ; nous avons opté pour les suivants.

Étapes de l’installation
figure 5.02 Étapes de l’installation

Ce qui est ici appelé Windows est la version 3. Les choix que nous avons faits installent un maximum de fichiers.

PWB est l’atelier intégré, qui permet d’accéder à l’aide tout en éditant, compilant et testant les programmes. L'espace disque n'est pas cher, il est préférable de l’installer même sans envisager de l’utiliser.

N’installez pas de driver de souris, car XP ou 98 s’occupe de ce point. masm.exe étant proposé pour des raisons de compatibilité, le copier ne peut pas nuire. Enfin, nous installons les fichiers d’aide et les exemples.

Nous choisissons d’installer sur  C: , ensuite nous éditons le dossier de masm611 en masm , pour le premier dossier proposé, bin . Cette modification n’est à faire que pour ce dossier, les autres suivront. L’installation se poursuit ; il suffit de confirmer tous les choix puis de quitter.

Il reste à installer éventuellement le patch vers 6.11d ou 6.13. Un patch contient généralement une nouvelle version de ml.exe , plus éventuellement de nouveaux fichiers textes et utilitaires. Si vous récupérez ml.exe d’une autre façon, il faut copier au minimum ce fichier, ainsi que celui de messages d’erreurs ml.err . MasmRef.doc est également utile.

Pour des raisons de gestion de la mémoire étendue, la version 6.13 nécessite au minimum Windows NT ou 95 pour fonctionner, ce qui ne devrait pas poser de problème, sauf si vous tenez à booter en DOS vrai pour développer. Mais, dans ce cas, il aurait été préférable de faire l’installation sous DOS. Précisons que cette limitation n’empêche pas 6.13 de générer des applications DOS. Pour être exact, la 6.13 va s’exécuter dans une fenêtre DOS de Windows à partir de 95.

Le fichier ml613.exe n’est qu’un fichier compressé auto-décompactable. Décompactons-le donc dans un dossier ml613 par exemple et commençons la mise à jour. Nous menons cette opération sous Windows, et non en ligne de commandes.

Il est conseillé dans le readme.txt de sauvegarder quelques fichiers ( ml.exe , ml.err , h2inc.exe , h2inc.err et win.inc ). Cela est facultatif, puisque nous savons les récupérer à partir de la 6.11.

Copions patch.exe , patch.rtd et patch.rtp dans c:\masm\ , puis lançons patch.exe , en fenêtre DOS si nous souhaitons pouvoir lire les résultats. Nous pouvons effacer les trois fichiers patch copiés. Il reste à copier h2inc.exe et h2inc.err dans le dossier bin et win.inc dans le dossier include .

Vous pouvez renommer readme.txt en readme613.txt , puis le copier dans la racine du dossier d’installation ( c:\masm\ dans notre cas). Copiez également les autres fichiers textes, en remplacement de ceux existant.

Avant de faire le ménage, pensez à recopier la documentation dont vous disposez dans le dossier d’installation ou à tout autre endroit où vous avez pour excellente habitude de la centraliser. Dans ce dernier cas, renommez-le de façon explicite, Docs_masm_6 par exemple.

Vous pouvez maintenant effacer les dossiers \\masm6 et ml613 . Cette installation n’a modifié aucun fichier système, ni la base de registre bien entendu. Vous pouvez éventuellement zipper et archiver le dossier c:\masm complet, à une étape où tout fonctionne correctement. Un peu plus tard serait le mieux.

Si le programme d’installation n’a pas modifié le système, c’est parce qu’il utilise une autre très bonne méthode pour arriver au même résultat. Il a fabriqué un certain nombre de fichiers ; libre à nous de les utiliser. Ces fichiers se trouvent dans le dossier binr , à l’exception de tools.pre , qui est dans init .

Le fichier new-vars.bat , prévu pour modifier autoexec.bat , contient :

SET PATH=C:\MASM\BIN;C:\MASM\BINR;%PATH%
SET LIB=C:\MASM\LIB
SET INCLUDE=C:\MASM\INCLUDE
SET INIT=C:\MASM\INIT
SET HELPFILES=C:\MASM\HELP\*.HLP
SET ASMEX=C:\MASM\SAMPLES
SET TMP=D:\WINDOWS\TEMP

Nous allons l’utiliser pour modifier non pas notre autoexec.bat (nous sommes sous XP, et de plus nous n’aimons pas ça), mais un fichier masmxp.bat , comme suit :

PATH = %SystemRoot%\system32
 
SET PATH=C:\MASM\BIN;C:\MASM\BINR;%PATH%
SET LIB=C:\MASM\LIB
SET INCLUDE=C:\MASM\INCLUDE
SET INIT=C:\MASM\INIT
SET HELPFILES=C:\MASM\HELP\*.HLP
SET ASMEX=C:\MASM\SAMPLES
SET TMP=D:\WINDOWS\TEMP
 
%SystemRoot%\system32\cmd.exe

Élaborez dès maintenant le fichier masm.bat , adapté à vos dossiers et à votre version de Windows.

Il sera ensuite possible de créer des raccourcis vers ce fichier, pour par exemple lancer la session en mode Plein écran et de le modifier légèrement pour lancer directement l’atelier : il suffit de remplacer la dernière ligne par pwb ou par qh , pour lancer l’aide, une fois celle-ci configurée.

new-conf.sys comporte des lignes à ajouter éventuellement à un fichier config.sys . Il ne nous intéresse pas dans notre configuration.

new-sys.ini sert éventuellement à modifier le fichier system.ini . Gardons-le au frais pour l’instant. Il est utile si nous souhaitons exploiter cvw , une version Windows de CodeView, mais qui semble ne pas vouloir fonctionner sur les versions actuelles.

Le fichier tools.pre , dans le dossier init , sera simplement renommé tools.ini . Cela va permettre aux utilitaires d’environnement de retrouver les fichiers nécessaires à leur fonctionnement. Après avoir ouvert une fenêtre par le batch fabriqué au paragraphe précédent, testez qh , avant et après le renommage de tools.pre .

Vous pouvez maintenant découvrir qh et pwb . avant d’aborder la première application, essayez par exemple la séquence suivante :

Lancez masm.bat , puis qh . Cliquez sur <Contents> , puis sur <Assembly> dans le rectangle Languages . Repérez le rectangle System Resources pour un usage ultérieur, puis cliquez sur <BIOS Calls> , <13h-Direct Disk Services> et enfin 02h Read Sectors .

La fonction Read Sector dans Quick Help
figure 5.03 La fonction Read Sector dans Quick Help

Une fois les fonctions BIOS repérées, vous pouvez revenir quelques étapes en arrière, pour explorer les fonctions  <MS‑DOS Calls> , à la recherche des fonctions de gestions de fichiers.

Si vous disposez de cette aide, elle sera utile. En revanche, il est certain que l’utilisation de pwb risque de nous apporter des déboires, à cause de sa vétusté, si nous utilisons une version de Windows à partir de la 95. Il est préférable d'utiliser, pour un plus grand confort, un éditeur indépendant et surtout exploiter les possibilités de multitâche de Windows.

5.1.2 Présentation et installation de MASM32

Rappelons que l'ensemble MASM32 ne permet pas tel quelle la programmation DOS 16 bits. C'est d'ailleurs pratiquement son seul inconvénient majeur. Nous proposerons un bricolage fonctionnel à la fin de cette rapide prise en main.

C'est par contre une solution extrêmement confortable, parce que complète en une seule installation, pour aborder la programmation Windows. Sans être exhaustif et sans affirmer non plus qu'il n'existe pas de solution concurrente, voyons quelques goodies de MASM32 :

  Ensemble complet et cohérent pour faire du développement 32 bits, jusqu'à l'éditeur de code.

  Intégration des bibliothèques et fichiers d'en-tête nécessaires pour du développement Windows immédiat.

  L'environnement permet de fonctionner en syntaxe MASM pure.

  Installation efficace, peu contraignante et évolutive, nous allons y revenir.

  Bibliothèques propres à la distribution fort utiles, fournies avec code source.

  Une grande quantité de documentation et tutoriaux inclus en un seul téléchargement.

  Produit suffisamment populaire pour générer une bonne activité sur internet.

  Embryon d'activité et de documentation en langue française.

L'auteur a découvert le projet MASM32 sur Internet, n'y est absolument pas impliqué et donc n'a aucune possibilité d'en garantir la pérennité.

Les liens pour télécharger MASM32 sont fournis sur le CD-Rom. Une recherche Google sur ce mot clé tout simplement les fournit parmi les quelques premières réponses. Au moment de la rédaction de ces lignes, il est possible de télécharger les packages compressés : masm32v7.zip (environ 5,2 Mo) et masm32v8.exe (environ 3,1 Mo).

L'installation ne pose pas de problème particulier. Pour la version 7, install.exe peut très bien être lancé directement à partir du désarchiveur (WinRar ou WinZip). Pour la version 8, il suffit de lancer masm32v8.exe . En revanche, bien qu'il soit possible d'accéder au contenu masm32v8.exe à l'aide d'un désarchiveur, il ne faut pas tenter une installation personnalisée par ce moyen, un grand nombre d'éléments comme les librairies étant construits lors de l'installation.

Le seul choix proposé est la partition d'installation.

Installation de MASM32
figure 5.04 Installation de MASM32

Bien que le processus semble bloqué aux premiers instants, l'installation est assez rapide sur une machine récente. Le facteur global de décompression est assez impressionnant.

Donc, tout s'installe dans un dossier masm32 , à la racine de la partition choisie. Le nom du répertoire est imposé. Nous allons comprendre pourquoi. En cas d'installation simultanée de deux versions, 7 et 8 par exemple, il faudra donc choisir de le faire sur deux partitions différentes.

Rien ne s'installe en dehors de ce dossier, pas de raccourcis, la base de registre n'est pas modifiée, ni les variables d'environnement. Donc, MASM32 qui vient d'être installé ne doit pas interférer avec des installations antérieures d'autres environnements de développement dont certains programmes peuvent porter le même nom.

Il en découle qu'il n'existe pas de processus spécifique de désinstallation, il suffit d'effacer le dossier masm32 , après bien entendu avoir sauvegardé son travail personnel.

Autre conséquence, dans le cas où vous auriez plusieurs systèmes d'exploitation installés sur votre machine et le désir légitime de tester vos programmes sous ces divers OS, une seule installation suffira. Vous devriez même pouvoir le faire sur une partition qui ne porterait pas la même lettre dans tous les systèmes. Mais ce dernier point n'a pas été testé, les partitions aux noms incertains apportant souvent d'autres ennuis. Il reste une possibilité (improbable) que le processus d'installation code en dur le nom de la partition d'installation dans certains fichiers.

Enfin, sous réserve de ce dernier point, il serait possible de faire une archive du dossier masm32 juste après l'installation. Mais pour quel gain ?

Nous voilà face à une foule d'outils, d'exemples et de documentations diverses. Nous n'utilisons pas de façon habituelle l'éditeur fourni avec cet environnement, et il vous appartiendra de le découvrir par vous-même si vous souhaitez l'adopter. Néanmoins, pour ceux qui sont fâchés avec la langue anglaise, nous allons ensemble effectuer une prise en main de niveau zéro. Ceci va également nous permettre de découvrir quelques fichiers qui nous seront utiles et qui semblent en première approche sous-documentés.

Nous considérons que MASM32 a été installé dans la partition C: . Avec l'Explorateur, allez dans C:\MASM32\EXAMPLE1\LISTBOX . Vous pouvez par curiosité double-cliquer sur listbox.exe . Ensuite, effacez les fichiers listbox.exe et listbox.obj .

Maintenant, dans C:\MASM32\ , vous pouvez lancer qeditor.exe . Vous aurez avantage, si vous pensez utiliser ce programme de façon habituelle, à créer un raccourci vers lui et le déposer par exemple sur le Bureau.

Par le menu File / Open , ouvrez le fichier C:\MASM32\EXAMPLE1\LISTBOX\listbox.asm .

QEditor
figure 5.05 QEditor

Vous pouvez constater que cet éditeur est de type SDI (Single Document Interface), c’est-à-dire qu'il ne peut ouvrir qu'un seul document. Pour travailler sur plusieurs documents simultanément, il faut ouvrir plusieurs instances de QEditor, ce qui peut être obtenu par File / New Instance ou tout simplement en le lançant plusieurs fois.

Étudiez le menu Project .

Le menu Project
figure 5.06 Le menu Project

Run Program ne fait rien, pas même de message d'erreur ou d'avertissement. Essayez Assemble & Link . Une fenêtre de type DOS apparaît.

Construction de LISTBOX.exe
figure 5.07 Construction de LISTBOX.exe

Les fichiers listbox.obj et listbox.exe ont été créés dans le dossier C:\MASM32\EXAMPLE1\LISTBOX . Nous pouvons maintenant relancer la commande Project / Run Program . Et le programme tourne effectivement.

Le programme LISTBOX
figure 5.08 Le programme LISTBOX

Voilà, vous pouvez maintenant vous lancer, si vous le souhaitez, à la découverte des menus Tools , Templates , Script et Help , ce dernier étant dans un premier temps le plus enrichissant. Réservé aux anglophones, rappelons-le encore.

Ce qui nous intéresse d'urgence, c'est la façon dont fonctionne le menu Project . Bizarrement, dans Help / Quick Editor Help , même en utilisant la fonction Rechercher , l'aide semble muette sur le sujet. Aide-toi, le ciel t'aidera. Une étude des fichiers  .ini ou une recherche des fichiers contenant par exemple Assemble ASM file , nous amène rapidement, dans le même dossier que qeditor.exe , à menus.ini , dont voici un extrait :

[&Project]
Compile &Resource File,\MASM32\BIN\Bres.bat {b}
&Assemble ASM file,\MASM32\BIN\Assmbl.bat {b}
-
&Link OBJ File,\MASM32\BIN\Lnk.bat {b}
Assemble && Link,\MASM32\BIN\Build.bat {b}
&Build All,\MASM32\BIN\Bldall.bat {b}
Run &Makeit.bat,makeit.bat
-
Console Link &OBJ File,\MASM32\BIN\Lnkc.bat {b}
&Console Assemble && Link,\MASM32\BIN\Buildc.bat {b}
Console Build &All,\MASM32\BIN\Bldallc.bat {b}
-
&Run Program,{b}.exe

L'interprétation en est immédiate. Le caractère  & précède la lettre de raccourci de l'élément de menu, exactement comme dans les fichiers de scripts de ressources. Le caractère  - seul sur une ligne de menu devient un séparateur. Enfin, {b}  est remplacé par le nom du fichier en cours d'édition, sans extension.

Il est ainsi facile d’ajouter ou de modifier un élément du menu Project , ainsi que Tools , Templates , Script et Help .

À l’inverse, et notre but était bien là, nous savons maintenant où trouver une série de fichiers batch, que nous allons modifier pour réutilisation dans l'environnement de notre choix. C’est une dizaine de fichiers .bat du dossier C:\MASM32\BIN .

Ces fichiers sont très simples à interpréter. Le principe de la modification sera de changer les références du type \masm32\bin\ml /c /coff "%1.asm" en ?:\masm32\bin\ml /c /coff "%1.asm" , où ?  est la lettre de votre partition d'installation. Il en est de même pour les fichiers batch particuliers de certains exemples. De la même façon, selon l'utilisation que vous ferez de MASM32 et de ces nombreux et excellents exemples, vous pourrez être amenés à modifier certaines lignes dans le code source :

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
 
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

en (par exemple) :

include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
 
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib

Vous trouverez un grand nombre d'utilitaires, parfois avec code source en assembleur. Sans code source, mais tout à fait utile : dumppe.exe , utilisé par les fonctions Tools / Dis‑assemble EXE file et Tools / Dis‑assemble DLL de QEditor.

Les lignes qui suivent et terminent cette rapide découverte de MASM32 s'adressent à ceux parmi les lecteurs qui, séduits par MASM32, chercheraient toutefois à tester quelques programmes DOS, pour un effort minimal, en termes de téléchargement et d'installation.

Nous avons vu, en introduisant MASM, que l'outil nécessaire et souvent manquant pour obtenir des exécutables DOS 16 bits est le lieur segmenté. Chez Microsoft, nous avons cité la version 5.60.339 de link.exe , téléchargeable sous forme d'une archive lnk563.exe (voir CD-Rom). Nous avons extrait link.exe de cette archive et l'avons copié sous le nom link560.exe , dans le dossier C:\MASM32\BIN .

Ensuite, nous avons ajouté trois lignes au fichier menus.ini  :

...
Console Build &All,\MASM32\BIN\Bldallc.bat {b}
-
&DOS Construit,\MASM32\BIN\builallD.bat {b}
DOS Assemble,\MASM32\BIN\assmblD.bat {b}
DOS Lien,\MASM32\BIN\lnkD.bat {b}
-
&Run Program,{b}.exe
...

Ceci modifie le menu Project .

Menus supplémentaires
figure 5.09 Menus supplémentaires

Il nous reste à fabriquer et à sauver les fichiers batch dans le dossier C:\MASM32\BIN . Ceci nous donne :

@echo off
 
if exist "%1.obj" del "%1.obj"
if exist "%1.exe" del "%1.exe"
if exist "%1.lst" del "%1.lst"
if exist "%1.map" del "%1.map"
 
\masm32\bin\ml /Fl /Sa /Fm /Bl"\masm32\bin\link560.exe" %1.asm > \masm32\bin\asmbl.txt
 
\masm32\thegun.exe \masm32\bin\asmbl.txt
LEGENDE=Le fichier builallD.bat

Remarquez ici l'option /Bl NomFichier , qui permet de modifier le nom du lieur.

 

@echo off
 
if exist "%1.obj" del "%1.obj"
if exist "%1.exe" del "%1.exe"
if exist "%1.lst" del "%1.lst"
if exist "%1.map" del "%1.map"
 
\masm32\bin\ml /Fl /Sa /Fm /c %1.asm > \masm32\bin\asmbl.txt
 
\masm32\thegun.exe \masm32\bin\asmbl.txt
LEGENDE=Le fichier ASSMBLD.bat

 

 

@echo off
 
if exist "%1.exe" del "%1.exe"
 
\masm32\bin\link560.exe %1.obj;> \masm32\bin\lnk.txt
 
\masm32\thegun.exe \masm32\bin\lnk.txt
LEGENDE=Le fichier LNKD.bat

 

Pour un usage plus soutenu, ces trois fichiers demandent certainement à être améliorés ou personnalisés. Sous cette forme, ils fonctionnent et permettent de construire un petit programme d'essai, dans le dossier Test_DOS .

L'étude complète de MASM n'est pas dans les objectifs de ce livre. Elle pourrait d'ailleurs faire l'objet d'un ouvrage à elle seule. Nous allons simplement présenter un aperçu général de la syntaxe au travers de l'étude d'un code source.

Il est tout à fait possible, à partir de là,  de progresser à l'aide de documentation (voir CD-Rom, puis Internet) et d'expérimentations. Dans cette optique, nous traiterons en fin de chapitre la génération et l'interprétation de fichiers listings, indispensables à la compréhension du fonctionnement de certaines directives.

5.2 Le code source, généralités

À l'exception des symboles prédéfinis et de ceux définis par l'utilisateur, MASM n'est pas sensible à la casse, c’est-à-dire qu'il ne fait pas la différence entre majuscules et minuscules. Il n'est pas bon de trop profiter de ce faux avantage et bien préférable de se fixer des contraintes. Nommez les mnémoniques et registres toujours de la même façon dans un projet donné ou sur l'ensemble de votre œuvre, donnez un nom à chaque variable ou étiquette selon une règle de nommage qui peut être personnelle mais qui inclut la casse et référencez ces éléments toujours de la même façon. Pas de code de ce genre :

label1: mov eax, 4
        MOV EBX, EAX
        anD ebx, 4
        JZ LABEL1
        jmp Label1

Ceci est particulièrement important si vous programmez plusieurs langages.

À l’inverse, mais pour les mêmes raisons, lors de l'utilisation d'un compilateur sensible à la casse, évitez d'utiliser cette caractéristique pour faire la différence entre deux identificateurs.

Regardons le listing simpliste suivant :

 1 ;--------------------------------------------------;
 2 ;Programme hello "squelet"
 3 ;Pierre Maurette pour Assembleur / Micro Application
 4 ;Sète, le 3/03/2003
 5 ;--------------------------------------------------;
 6 lowbyte EQU     low
 7 ;--------------------------------------------------;
 8         .286
 9         .MODEL SMALL
10 ;--------------------------------------------------;
11         .STACK 500
12 ;--------------------------------------------------;
13 const1  EQU     513+6
14 ;--------------------------------------------------;
15         .DATA
16 bijor   DB      "Bonjour, e-monde !",0Dh, 0Ah, "$"
17 IFDEF DEBUG
18 testdb  DB      "Mode DEBUG",0Dh, 0Ah, "$"
19 ENDIF
20 str1    DB      " ",0Dh,0Ah, "$"
21 var1    SBYTE   7
22 var2    WORD    2
23 ;--------------------------------------------------;
24         .CODE
25 debut:   mov ax, @data  ;initialisation data segment
26          mov ds, ax
27 ;--------------------------------------------------;
28          ; Message de bienvenue
29          mov ah, 09h
30          mov dx, offset bijor
31          int 21h
32 ;--------------------------------------------------;
33          ;Code d'essai
34          IFDEF DEBUG
35            ;.ERRDEF DEBUG
36            mov ah, 09h
37            mov dx, offset testdb
38            int 21h
39          ENDIF
40          mov al, var1
41          mov al, byte ptr var2
42          mov al, lowbyte const1
43          .IF SBYTE PTR al > 9
44          mov al, 3 * 3
45          .ENDIF
46          cmp al, 0
47          jnl suite
48          mov al, 0
49 suite:   add al, '0'
50          mov str1, al
51          mov ah, 09h
52          mov dx, offset str1
53          int 21h
54 ;--------------------------------------------------;
55          ; attente touche
56          mov ah, 00h
57          int 16h
58 
59          ;et fin du programme
60          mov AH, 4Ch             ;fin du programme
61          int 21h                 ;et retour au DOS
62 
63          END debut
64 ;--------------------------------------------------;

Ce petit programme exécutable sous DOS sera assemblé et lié par une suite de commandes regroupées dans un ficher batch :

echo off
PATH = %SystemRoot%\system32
SET PATH=C:\MASM\BIN;C:\MASM\BINR;%PATH%
SET LIB=C:\MASM\LIB
SET INCLUDE=C:\MASM\INCLUDE
 
del *.obj
del *.exe
del *.lst
del *.map
del listing.txt
 
REM ml7 /? >ml7.txt
REM ml615 /? >ml615.txt
 
REM ml7 /Zi /Fl"listing.txt" /Sf /Sg /Fm /omf %1.asm
ml615 /Zi /Fl"%1.txt" /Fm /Sg /Sf /omf %2 %1.asm
REM ml615 /Zi /Fl /Sa /Fm /omf %1.asm
REM ml615 /Zi /Fl /Sa /Fm %1.asm
REM dir
pause

Les lignes débutant par SET  servent à positionner temporairement, c’est-à-dire pour la session ouverte par le fichier batch, des variables d'environnement. Pour le reste, nous pouvons retrouver les commutateurs de la ligne de commandes utilisés en faisant ml /? ou ml /? >h.txt .

À partir de ces listings, nous allons prendre un premier contact avec le vocabulaire MASM. Il est difficile d'être totalement précis dans la catégorisation des éléments du langage, la notion de directive par exemple s'applique à des éléments fonctionnellement très variés. Il faut faire avec, et ce n'est pas un vrai problème. Sauf éventuellement pour rédiger un texte à visée pédagogique. Cette syntaxe est basée sur cinq grandes catégories d'éléments :

Les instructions , que nous reconnaissons facilement à partir de la ligne 25. Elles nous intéresseront dans cette partie de l'ouvrage quand, comme à la ligne 30, elles mettent en œuvre pour l'écriture de l'opérande des spécificités de MASM. Pour le reste, elles sont explorées particulièrement dans le chapitre Le jeu d'instructions .

Des directives , éléments propres à MASM, qui permettent de passer des ordres à l'assembleur. En réalité, les directives peuvent être définies comme ce qui n'est pas classé dans les autres catégories. Certaines produisent du code, comme à la ligne 43 le .IF . D'autres se contentent de transmettre une information à l'assembleur, comme le .286 de la ligne 8 ou le IFDEF de la ligne 34.

Les attributs sont également de types relativement variés. Globalement, ce sont les paramètres des directives. Nous trouvons des directives avec attribut aux lignes 9, 11, 13 et bien d'autres.

Les opérateurs , qui sont utilisés dans les expressions, qui peuvent par exemple calculer un attribut. Nous en voyons aux lignes 13 (+) et 43 (>) par exemple.

Des symboles prédéfinis , par lesquels MASM permet au programme d'accéder à certaines valeurs : à la ligne 25, @data est un symbole qui remplace la valeur du sélecteur de segment des données.

Il est habituel, depuis l'origine de la littérature sur l'assembleur, de présenter la ligne d'instructions standard de la façon suivante :

[[Label:]] [[Mnémonique]] [[Opérandes]] [[;Commentaires]]

C'est bien joli, mais dans le listing proposé, seule la ligne 25 correspond à ce schéma. Il est préférable d'aborder les éléments syntaxiques par familles et ensuite par thèmes.

Quelques remarques fondamentales pour mieux situer les éléments de ce code source dans le processus de fabrication de l'exécutable. Nous avons dit qu'il est difficile d'avoir une attaque rigoureuse de la syntaxe de MASM. Il est vrai qu'un label, ou étiquette, et un nom de variable, c'est pareil et ce n'est pas non plus la même chose. Il y a par contre deux points sur lesquels il est possible de catégoriser :

  Différencier ce qui est connu dès l'assemblage et ce qui ne le sera qu'à l'exécution. Ce point est fondamental.

  Dans le code source, différencier les lignes qui génèrent de l'octet en mémoire de celles qui n'en produisent pas. L'étude du fichier listing est très utile pour la compréhension de ce point.

Quelles lignes produisent de l'occupation mémoire ? 16, 18, 20 à 22, 25, 26, 29 à 31, 36 à 38, 41 à 53 (y compris 43 et 45), 56, 57,60 et 61.

Les lignes 18, et 36 à 38 produisent bien des données et du code, si l'assembleur les traite. Nous y reviendrons un peu plus loin. Quand à la ligne 11, elle crée une pile, donc de la mémoire, c'est un cas un peu particulier.

Aux lignes 15 et 24, nous trouvons les directives .DATA  et .CODE . Elles correspondent au début de deux zones de mémoire, des segments logiques. Attention, ces segments ne sont pas ceux du 8086, même s'il peut y avoir correspondance parfois. Un compteur démarre à cet endroit, un compteur de position, un pour chaque segment. Il est incrémenté d'un nombre variable d'unités à chaque ligne qui génère de la mémoire. La valeur dans ce compteur est très proche d'un offset.

Qu'est-ce qu'un label ou étiquette en bon français ? Un objet, une constante nommée, qui prend la valeur du compteur de position de l'endroit où il est placé dans le code source. C'est en première approche très peu différent d'un nom de variable. Ces constantes, noms de variables, de labels, mais également de segments sont utilisables par les instructions du programme pour accéder à la mémoire. C'est ainsi qu'il est possible d'écrire à la ligne 40 mov al, var1 , ou à la ligne 47 jnl suite . Que fait l'assembleur à l'arrivée sur la ligne 40 ? quand il était passé par la ligne 21, il avait noté dans une table qu'il existait dorénavant un symbole var1 , qui correspondait à un offset donné dans le segment débuté par .DATA , disons le segment pointé par DS pour simplifier. Il va donc utiliser sa documentation Intel pour fabriquer les trois octets de l'instruction, A0 pour l'opcode, plus les deux octets de l'offset. C'est en réalité un peu plus sioux que ça, mais nous pouvons en rester à cette image. Il génère vraiment trois octets. En fait, il connaît ces adresses à un décalage près.

Puisque nous en sommes au travail de l'assembleur, détaillons une séance complète d'assemblage, en sachant que beaucoup de notions nous sont peut-être encore inconnues :

Dans un premier tour de piste, il évalue les conditions d'assemblage conditionnel et nettoie le source de l'inutile.

Il développe ce qui doit l'être (macros, equates). Ici, il remplace par exemple à la ligne 42 lowbyte par low , comme il lui a été demandé à la ligne 6. Fin de la passe 1.

Dans le même ordre d'idée, il calcule ce qu'il doit, par exemple à la ligne 44 : 3 x 3 = 9 (bravo).

Il code les instructions qu'il sait coder : la ligne 46, par exemple.

Il remplace les offsets qu'il ne connaît pas entièrement par l'offset interne, celui correspondant plus ou moins au compteur de position.

Il copie dans le fichier objet les segments et leurs attributs.

Il copie dans le fichier objet des marqueurs pour repérer ce qui est à corriger en fonction des adresses réelles des segments (c'est bien cela qui manquait).

Il fabrique le fichier listing si demandé.

Il fabrique une ligne de commandes pour le lieur, en particulier il lui indique les librairies à lier et l'appelle.

10 Il se recouche, parce qu'il a bien travaillé et qu'il est très fatigué.

Les deux ou trois premières phases sont le fait d'une couche particulière, correspondant parfois dans d'autres langages à un programme indépendant : le préprocesseur. Nous n'avons pas parlé ici des possibles inclusions de fichiers, .inc en général : ces inclusions ne changent rien, les inclusions créent un fichier source développé, c'est tout.

 

Ensuite le lieur :

Arrange les segments au mieux, en fonction des instructions de l'assembleur, il résout donc toutes les adresses à une seule inconnue près : l'adresse réelle du début de ce bloc.

Il corrige les offsets marqués.

Il copie les informations sur les adresses à modifier (remplir par une valeur correcte) dans l'en-tête du fichier .exe sous forme d'une table de relogement (ou relocation).

Il fabrique et sauve ce fichier exécutable.

 

Et enfin le chargeur (loader) du système d'exploitation :

Il fabrique dans la mémoire un en-tête (PSP), qui par exemple contient les paramètres de la ligne de commandes, des informations pour le retour en fin d'exécution, etc.

Il alloue de la mémoire au programme, et là, il connaît enfin toutes les adresses.

Il charge le programme en mémoire.

Il corrige les adresses qui doivent l'être (celles figurant dans la table créée par le lieur).

Il initialise les registres de segment et lance le programme.

 

5.3 Génération et lecture des listings

Placer physiquement un article sur les listings au tout début d’un parcours d’apprentissage peut sembler anachronique. Il est pourtant clair que, lors de la découverte de notions nouvelles comme les données ou les macros, la consultation d’un listing est souvent plus enrichissante que le test du programme, même au sein d’un débogueur.

En réalité, la compilation d’un source avec génération de listing, sans édition de lien, est tout à fait suffisante dans beaucoup de cas pour accompagner la lecture de la documentation. Nous aurons donc besoin de produire et de lire un fichier listing dès le début de l'apprentissage.

À l’inverse, l’interprétation des listings aborde des notions qui devront être admises en première lecture.

Pour désigner un listing, nous utiliserons le mot listing, issu de l’anglais ... listing. Plus sérieusement, dans un dictionnaire déjà un peu ancien, nous avons relevé la définition du mot listing (ou listage) : document produit par l’imprimante d’un ordinateur. Effectivement, le listing est historiquement orienté imprimante. Il s’agissait d’un document important dans la gestion de projet, voire contractuellement d’un élément de la livraison finale. MASM est bien plus efficace que bien des compilateurs C ou C++ sur le plan de la génération des listings.

Pour cette présentation, nous nous baserons sur ml.exe version 7.0 avec tests sur 6.15 en cas de doute.

Vous trouverez quelques fichiers évoqués dans les lignes qui suivent dans un répertoire du CD-Rom.

5.3.1 Génération d’un listing

Deux familles d’actions influent sur la génération d’un fichier listing :

  Les paramètres de la ligne de commandes à l’appel de ml.exe .

  Une série de directives au sein du code source.

Les paramètres de la ligne de commandes qui intéressent la génération d’un fichier de listing sont /Fl ainsi que tous les  /S? . Ajoutons /EP qui envoie un listing passe 1 à l’écran. Tous sont décrits dans le tableau récapitulatif des commutateurs de la ligne de commandes. Par défaut, c’est-à-dire quelles que soient les directives dans le source et si le commutateur /Fl n’est pas envoyé à ml.exe , aucun fichier listing ne sera généré.

Pour lire le tableau, il faut bien voir que certaines de ces directives vont par couples, comme par exemple  .LIST/.NOLIST . Ces couples fonctionnent en flip-flop, pour déterminer des zones de listing dans laquelle le comportement sera déterminé.

Directives de gestion des listings

Directive

Effet

.LISTALL

Équivalent à .LIST + .LISTIF + .LISTMACROALL .

.LIST

Positionnée par défaut. Démarre le listing des instructions.

.NOLIST

Interdit le listing des instructions.

.XLIST

Autre forme de .NOLIST

.LISTIF

Force le listing des instructions non assemblées en cas d’assemblage conditionnel.

.TFCOND

Autre forme de .LISTIF

.NOLISTIF

Stoppe l’effet de .LISTIF . Les instructions non assemblées ne sont plus listées.

.SFCOND

Autre forme de .NOLISTIF

.NOCREF  [nom[,nom..]]

Interdit le listing des noms de symboles dans la table. Possibilité de limiter cette interdiction à certains symboles dont les noms sont donnés.

.XCREF

Autre forme de .NOCREF

.CREF

Stoppe l’effet de .NOCREF (ou .XCREF ).

.LISTMACROALL

Force le listing complet de macros développées.

.LALL

Autre forme de .LISTMACROALL .

.LISTMACRO

Positionnée par défaut. Liste les instructions des macros développées qui génèrent code ou données.

.XALL

Autre forme de .LISTMACRO

.NOLISTMACRO

Interdit le listing des macros développées.

.SALL

Autre forme de .NOLISTMACRO

PAGE

Génère un saut de page.

PAGE [[nl][nc]]

Positionne les dimensions de la page à nl lignes de nc caractères.

PAGE +

Changement de section. Le N° de page repasse à 1.

TITLE  texte

Fixe le titre du listing.

SUBTITLE  texte

Fixe le sous-titre du listing.

SUBTTL  texte

Autre forme de .SUBTITLE texte.

 

Il est visible que certains comportements sont commandés à la fois par un commutateur de la ligne de commandes et par une directive. Il est donc possible que surviennent des ordres contradictoires. Voici quelques règles de priorité applicables :

  Sans commutateur /Fl , aucun listing ne sera généré.

  Le commutateur /Sa (avec /Fl , répétons-le) rend inopérantes les directives du code source visant à interdire ou limiter le listing.

  Dans le code source, .NOLIST masque les autres directives, comme .LISTMACROALL .

  Les commutateurs /Sx , /Ss , /Sp , /Sl positionnent les comportements à une valeur différente de celle par défaut. Ensuite, les directives correspondantes reprennent au besoin la main.

Bien qu’il ne s’agisse pas à proprement parler de listing, citons ici la directive ECHO (ou %OUT , c’est équivalent). Elle permet d’envoyer du texte sur STDOUT , donc à priori l’écran. Ce peut être utilisé par exemple pour signaler qu’un processus d’assemblage risque d’être long, et à signaler au fur et à mesure différentes étapes de l’assemblage. Un exemple, avec une macro texte prédéfinie :

%ECHO Programme &@FileName
 ECHO par l'excellent Julius Caius Caesar
 ECHO Début de l'assemblage ...

 

Manipulons maintenant pour mettre un peu en pratique. Avec un fichier test.asm ne contenant pour l’instant aucune directive listing, ajoutez /Fl dans la ligne de commandes, par exemple en modifiant un fichier build.bat . Vérifiez que le commutateur de ligne de commandes /Sa n’est pas actif, ni aucun commutateur de type  /S? . Un fichier listing portant le nom test.lst est créé. Remplaçons le commutateur par /Fllisting.txt ou /Fl"listing.txt" (attention, pas d’espace devant le nom du fichier). Le fichier listing créé porte maintenant le nom listing.txt .

Nous analyserons les fichiers listing un peu plus loin. Si vous y jetez un coup d’œil et si vous avez un include test.inc dans votre source, vous constatez que ce fichier est logiquement listé au moment de son inclusion.

Dans le fichier source, rajoutez la ligne include win.inc , où un autre gros fichier d’en-tête selon votre installation. Le fichier listing prend de l’embonpoint et perd par la même occasion de la lisibilité. La raison est claire, mais le phénomène deviendra gênant dans les applications Windows. Modifions :

.NOLIST
include win.inc
.LIST

Le début du listing devient plus lisible, mais la taille demeure importante, à cause de la taille des symboles. Les symboles issus de notre code sont de plus noyés dans ceux issus de win.inc . Modifions à nouveau :

.NOCREF
.NOLIST
include win.inc
.LIST
.CREF

Maintenant, tous nos symboles sont listés, mais plus ceux en provenance de win.inc .

Une dernière manipulation, avant de passer aux listes de commutateurs et de directives. Nous avons dans notre code d’essai une zone assemblée sous condition :

;UTILE EQU UTILE
…
IFDEF UTILE                  
         ; Partie "utile" (!!)
;        mov ax, 69
         mov ax, 60 + (3 * 3)
         cmp ax, bx
         jne @F
         
         mov ah, 09h
         mov dx, offset egal
         int 21h                 
ENDIF

En jouant sur la mise ou non en commentaire de la première ligne, nous constatons que n’est listé dans listing.txt que ce qui est effectivement assemblé. Or, dans le cadre d’un projet ou deux parties du code ne sont jamais assemblées ensemble, il sera parfois gênant de ne pouvoir produire un listing plus complet. Nous pouvons utiliser les directives .LISTIF (ou . LISTALL ) et .NOLISTIF pour modifier cet état de fait dans tout le source ou sur certaines zones. Nous verrons alors le code source des parties non assemblées, mais évidemment pas le code objet généré. Le commutateur /Sx (et /Sa ) produit un effet similaire sur l ‘ensemble du source.

 

5.3.2 Contenu du fichier listing

Vous pouvez utiliser pour cette découverte du fichier listing à la fois celui généré par nos manipulations précédentes ( test.lst ou listing.txt ) et le fichier sk_win.lst issu d’une application Windows et présent sur le CD-Rom. Vous aurez ainsi à disposition une application DOS 16 bits et une autre en 32 bits, sous Windows.

En cas d’erreur à l’assemblage, le fichier listing est généré autant que faire se peut. Vous trouverez un message d’erreur au-dessous de l’instruction fautive :

                     mov var1, var2
test.asm(59) : error A2070: invalid instruction operands

 

Supposons que tout s’est bien passé. Si nous avons positionné les options adéquates, nous avons trois grandes zones dans le fichier listing généré :

La sortie du préprocesseur, ou passe 1. C’est le travail de première lecture de l’assembleur, sans génération de code. Les fichiers inclus sont parcourus, les macros développées. Cette partie alourdit inutilement le listing. Il est généralement inutile de la demander par le commutateur /Sf .

La passe 2 (et finale) du travail du compilateur. C’est la génération du code proprement dite, listée encore de façon chronologique.

Une partie synthétique : les diverses tables regroupant les macros, les diverses structures définies, segments, groupes et symboles.

La section génération du code

Attention, le fichier listing est généré avec des tabulations. Il est préférable de configurer la taille de la tabulation à 8 voire plus dans votre éditeur. Nous n’avons pas ici respecté cette valeur pour des raisons de mise en page. Cette valeur de 8 est par contre trop importante pour la saisie de code profondément indenté, une valeur de 2 à 4 étant préférable.

Dans le listing vous retrouvez bien entendu tout votre code source, commentaires compris, au fur et à mesure qu’il est parcouru par l’assembleur, et en fonction des options et directives de listing. Ce source occupe la droite de la ligne d’écran. Les quatre premières colonnes, à gauche, sont réservées au code généré. Entre les deux groupes de colonnes peuvent se trouver certains symboles. Par exemple  C indique des lignes, quel que soit leur contenu, hors du fichier principal, donc dans un fichier inclus :

            include resrc1.inc
               C 
               C option expr32
               C option casemap:none
               C 
               C ; Begin of file resrc1.h
 = 00000001          C IDI_ICON     EQU      1t
 = 00000001          C IDOK         EQU      1t
 = 00000002          C IDM_MENU     EQU      2t

 

Voyons le contenu des colonnes de gauche, code généré. Tout d’abord, le cas particulier : pour les equates, ou plus généralement les constantes symboliques manifestes, nous trouvons à gauche la valeur affectée, pour laquelle il n’y a bien entendu pas d’affectation mémoire, précédée du signe  =  :

= blibli            VALT1     TEXTEQU <blibli>
= 45                VALT2     TEXTEQU %(3*15)
= @FileName         VALT3     EQU     @FileName
= 0000              NULL      EQU     0
= 004E              VALEUR    =       78
= TEST              VALT31    TEXTEQU @FileName
= blibli            VALT4     CATSTR  VALT1 VALT2 VALT3
= MaClasse->Taille  VALT5     TEXTEQU <MaClasse-!>Taille>
= "Bonjour"         VALT6     EQU     "Bonjour"
= "Aurevoir"        VALT6     EQU     "Aurevoir"

 

Dans le cas général d’une ligne générant de la mémoire, code ou données, la première colonne est toujours une adresse, plus précisément un offset. Il est noté en hexadécimal, donc sur 4 signes dans un modèle 16 bits et 8 dans un modèle 32 bits. Par exemple, la première occurrence d’une directive de segment indique toujours 0000. Ensuite, l’assembleur gère cet offset :

0000                    .DATA
                        ORG 10h
0010 00000000           VARX    dword ?
...
; Code
…
0014                    .DATA
0014 000C               var1    dw   12

 

Nous voyons dans cet exemple que, dans le cas d’une déclaration, la mémoire réservée et initialisée est indiquée à la suite de l’offset. Il en est de même pour les chaînes de caractères. Les réservations mémoire par la directive DUP  font appel à une présentation particulière :

0040   0020 [     Table1 byte  32 dup (0FFh)
        FF
       ]
0060   0040 [     Table2 dword 64 dup (?)
        00000000
       ]

Il faut bien lire dans les colonnes, par exemple 0040 0020[FF] , pour 32 octets initialisés à 255 à l’offset 64.

Pour une ligne de code ordinaire, contenant une instruction, après l’offset, nous trouvons optionnellement (commutateur /Sc ) une indication du nombre de cycles nécessaires à l’instruction. Bien entendu cette donnée n’est pas mesurée, mais prise dans une table et dépend du processeur déclaré. Donc, cette indication est sur un processeur moderne peu utile. Ensuite, c’est le code généré pour l’instruction, s’il est connu à l’assemblage :

0023   4   B8 0045      mov ax, 60 + (3 * 3)

Cette instruction est complètement définie : offset 0023h , 4 cycles sur un 8086, B8h opcode du MOV immédiat, 0045h soit 69, l’assembleur ayant calculé 60 + (3* 3) . Il n’y a pas d’espace entre 00 et 45, ce n’est pas innocent. C’est un WORD, si c’est une image de la mémoire que nous voulons représenter, c’est B8 45 00 qu’il faut écrire (little endian).

Si le code n’est entièrement déterminé à l’assemblage, mais sera résolu par le lieur, la lettre  R indique ce caractère relogeable :

002C   4   BA 002A R    mov dx, offset egal

Dans ce cas, BA est l’opcode correct. 002A n’est pas l’offset de la variable egal . C’est l’offset de la variable dans la zone de données à laquelle elle appartient. Cette valeur sera calculée, avec l’ensemble des valeurs relogeables, par le lieur. Le mot segment est normalement utilisé ici pour désigner les zones de données, il entraîne de graves ambiguïtés.

De la même façon, la lettre  E indique une donnée externe, ici une adresse, qui sera également résolue par le lieur :

000001F7   7m  E8 00000000 E  *  call InitCommonControls

L’astérisque  * qui apparaît dans cette ligne indique du code généré par MASM. Comme ici par la directive conditionnelle .IF  :

                     .IF(ax == bx)
 0026  3B C3         *      cmp    ax, bx
 0028  75 07         *      jne    @C0001
 002A  B4 09                  mov ah, 09h
 002C  BA 0016 R              mov dx, offset egal
 002 F  CD 21                  int 21h    
                     .ENDIF
 0031          *@C0001:

La directive INVOKE génère beaucoup de code de ce type.

Enfin, un entier de 1 à 9 ou un signe  + dans la colonne centrale indique un niveau d’imbrication dans les développements de macros. Voici un exemple, extrait de la partie passe 1 du listing (le rôle de la macro MINMAXLIST est décrit par ailleurs) :

                 C MINMAXLIST    MACRO param1, param2, args
                 C    p1 = 0
                 C    FOR p2, <args>
                 C           IF p2 GT p1
                 C               p1 = p2
                 C           ENDIF
                 C    ENDM
                 C    param1 EQU p1
                 C 
                 C    p1 = 7FFFFFFFh
                 C    FOR p2, <args>
                 C           IF p2 LT p1
                 C               p1 = p2
                 C           ENDIF
                 C    ENDM
                 C    param2 EQU p1           
                 C       
                 C    ENDM
                 C        
                 C MINMAXLIST   WM_MAXI, WM_MINI, <1,2,3>
                1C      ??0000 = 0
                2C                      ??0000 = 1
                2C                      ??0000 = 2
                2C                      ??0000 = 3
                1C      ??0000 = 7FFFFFFFh
                2C                      ??0000 = 1

 

La section des tables

Cette section comporte au maximum sept tables :

Macros ;

Structures et unions ;

Structures de champs de bits (records) ;

Types ;

Segments et groupes ;

Procédures et fonctions ;

Symboles.

Seules les 5 et 7 sont de tous les projets, les trois dernières si nous considérons qu’un main() ne fait pas de mal. Les éléments de ces tables, à l’exception de la table des segments et groupes, sont listés par ordre alphabétique.

La table des macros se contente de les lister, en précisant toutefois s’il s’agit d’une procédure, qui ne renvoie rien, ou d’une fonction, qui donc renvoie quelque chose :

Macros:
 
                N a m e                 Type
 
ArgCount . . . . . . . . . . . . . . .  Func
MINMAXLIST . . . . . . . . . . . . . .  Proc
MMOV . . . . . . . . . . . . . . . . .  Proc

 

La table des structures et unions indique pour chacune d’entre elles son nom et sa taille en octets, suivi de la liste des éléments avec indication pour chacun de leur offset par rapport au début de la structure et du type. Cette table peut être très utile à imprimer, pour du travail à partir de fichiers .inc mal connus :

Structures and Unions:
 
                N a m e                  Size
                                         Offset      Type
 
ABCFLOAT . . . . . . . . . . . . . . .   0000000C
  abcfA  . . . . . . . . . . . . . . .   00000000    DWord
  abcfB  . . . . . . . . . . . . . . .   00000004    DWord
  abcfC  . . . . . . . . . . . . . . .   00000008    DWord
CPINFOEXA  . . . . . . . . . . . . . .   0000011C
  MaxCharSize  . . . . . . . . . . . .   00000000    DWord
  DefaultChar  . . . . . . . . . . . .   00000004    Byte
  LeadByte . . . . . . . . . . . . . .   00000006    Byte
  UnicodeDefaultChar . . . . . . . . .   00000012    Word
  CodePage . . . . . . . . . . . . . .   00000014    DWord
  CodePageName . . . . . . . . . . . .   00000018    Byte

 

Pour chaque structure de champs de bits ou record, Width donne la taille en bits de la structure complète, # fields le nombre de champs dans le record.

Pour chaque champ, Shift donne l’offset en bits du LSB (bit de poids faible) du champ par rapport au LSB du record. Width est le nombre de bits du champ, Mask donne la valeur maximale du champ, Initial est la valeur initiale du champ s’il est initialisé :

Records:
 
        N a m e           Width         # fields
                          Shift         Width         Mask   Initial
 
FPOProlog  . . . . . . .  00000010      00000006
  cbFrame  . . . . . .    0000000E      00000002      C000     ?
  reserved . . . . . .    0000000D      00000001      2000     ?
  fUseBP . . . . . . .    0000000C      00000001      1000     ?
  fHasSEH  . . . . . .    0000000B      00000001      0800     ?
  cbRegs . . . . . . .    00000008      00000003      0700     ?
  cbProlog . . . . . .    00000000      00000008      00FF     ?
ImportRec  . . . . . .    00000010      00000003
  Reserved . . . . . .    00000005      0000000B      FFE0     ?
  NameType . . . . . .    00000002      00000003      001C     ?
  Type2  . . . . . . .    00000000      00000002      0003     ?

 

La table des types liste les types définis par TYPEDEF . Size est la taille en octets du type, Attr le type de base de la définition :

Types:
 
       N a m e             Size         Attr
 
HWINSTA  . . . . . . .     00000004     DWord 
HWND . . . . . . . . .     00000004     DWord 
INT64  . . . . . . . .     00000008     QWord  

 

La liste des groupes et segments n’appelle pas de commentaire particulier. Voici un exemple pour un programme Windows :

Segments and Groups:
 
          N a m e         Size    Length   Align  Combine Class
 
CONST  . . . . . . . . . .32 Bit  0000008B DWord  Public  'CONST'  ReadOnly
FLAT . . . . . . . . . . .GROUP
_BSS . . . . . . . . . . .32 Bit  000001C0 DWord  Public  'BSS'  
_DATA  . . . . . . . . . .32 Bit  00000289 DWord  Public  'DATA'  
_TEXT  . . . . . . . . . .32 Bit  0000078A DWord  Public  'CODE'  

 

Et pour un programme DOS :

Segments and Groups:
 
          N a m e         Size   Length  Align   Combine  Class
 
DGROUP . . . . . . . . . .GROUP
_DATA  . . . . . . . . . .16 Bit  0177   Word     Public  'DATA'  
STACK  . . . . . . . . . .16 Bit  0100   Para     Stack   'STACK'    
_TEXT  . . . . . . . . . .16 Bit  0035   Word     Public  'CODE'

 

La table des procédures et fonctions liste toutes les fonctions et procédures référencées par le programme, donc y compris les externes.

Procedures,  parameters and locals:
 
                N a m e                 Type     Value    Attr
 
Main . . . . . . . . . . . . . . . . .    P Near     0000      _TEXT    Length= 0035 Public
 
 
 
 
Procedures,  parameters and locals:
 
                N a m e                 Type     Value    Attr
 
AProposProc  . . . . . . . . . . . . .    P Near     00000528 _TEXT    Length= 0000004E Public STDCALL
  hDlg . . . . . . . . . . . . . . . .    DWord     bp + 00000008
  uMsg . . . . . . . . . . . . . . . .    DWord     bp + 0000000C
  wParam . . . . . . . . . . . . . . .    DWord     bp + 00000010
  lParam . . . . . . . . . . . . . . .    DWord     bp + 00000014
AbortDoc . . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
AbortPath  . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
ActivateKeyboardLayout . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
AddAtomA . . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
AddAtomW . . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL

 

La table des symboles regroupe ce qui reste. Donc en particulier mélange les variables, les labels (étiquettes) et les constantes symboliques, définies généralement par les equates ou par l’assembleur lui-même. Ces dernières sont de type Number ou Text , qui justement ne sont pas réellement des types. Pour les variables, c’est un vrai nom de type qui apparaît dans cette colonne Type .

La colonne Value représente pour les constantes symboliques vraiment la valeur du symbole. Pour les variables et les labels, cette valeur est en réalité l’offset du symbole par rapport au début du segment qui le contient.

Symbols:
 
          N a m e          Type      Value    Attr
 
??0000 . . . . . . . . . . Number    0001h
@CodeSize  . . . . . . . . Number    0000h
@DataSize  . . . . . . . . Number    0000h
@Interface . . . . . . . . Number    0000h
@Model . . . . . . . . . . Number    0002h
@code  . . . . . . . . . . Text      _TEXT
@data  . . . . . . .  . .  Text      DGROUP
@fardata?  . . . . . . . . Text      FAR_BSS
@fardata . . . . . .  . .  Text      FAR_DATA
@stack . . . . . . .  . .  Text      DGROUP
NULL . . . . . . . . . . . Number    0000h
SC . . . . . . . . . . . . Byte      0160     _DATA
Table1 . . . . . . .  . .  Byte      0040     _DATA
Table2 . . . . . . . . . . DWord     0060     _DATA
UTILE  . . . . . . .  . .  Text      UTILE
VARX . . . . . . . . . .   DWord     0010     _DATA
WM_MAXI  . . . . . . . . . Number    0003h
WM_MINI  . . . . . .  . .  Number    0001h
bijor2 . . . . . . . . . . Byte      0161     _DATA
bijor  . . . . . . .  . .  Byte      0014     _DATA
debut  . . . . . . .  . .  L Near    0000     _TEXT
egal . . . . . . . .  . .  Byte      002A     _DATA
nomfichier . . . . .  . .  Byte      0031     _DATA
var1 . . . . . . . .  . .  Word      003C     _DATA
var2 . . . . . . . . . . . Word      003E     _DATA

 

Envoyer un message à l'auteur

se connecter pour pouvoir écrire

Ce site est créé et maintenu (laborieusement) par Pierre Maurette
hébergé par 1 & 1