Page suivante - Page précédente - Table des matières

3. Assembleurs

3.1 Assembleur en-ligne de GCC

Le célèbre GNU C/C++ Compiler (GCC), est un compilateur 32 bits optimisant situé au coeur du projet GNU. Il gère assez bien les architectures x86 et permet d'insérer du code assembleur à l'intérieur de programmes C de telle manière que les registres puissent être soit spécifiés soit laissé aux bons soins de GCC. GCC fonctionne sur la plupart des plates-formes dont Linux, *BSD, VSTa, OS/2, *DOS, Win*, etc.

Où trouver GCC

Le site principal de GCC est le site FTP du projet GNU: ftp://prep.ai.mit.edu/pub/gnu/ On y trouve également toutes les applications provenant du projet GNU. Des versions configurées ou précompilées pour Linux sont disponibles sur ftp://sunsite.unc.edu/pub/Linux/GCC/. Il existe un grand nombre de miroirs FTP des deux sites partout de par le monde, aussi bien que des copies sur CD-ROM.

Le groupe de développement de GCC s'est récemment scindé en deux; pour plus d'informations sur la version expérimentale, egcs, voir http://www.cygnus.com/egcs/

Les sources adaptés à votre système d'exploitation préféré ainsi que les binaires précompilés peuvent être trouvés sur les sites FTP courants.

Le portage le plus célèbre de GCC pour DOS est DJGPP et il peut être trouvé dans le répertoire du même nom sur les sites ftp. Voir:

http://www.delorie.com/djgpp/

Il existe également un portage de GCC pour OS/2 appelé EMX qui fonctionne également sous DOS et inclut un grand nombre de routines d'émulation Unix. Voir les sites

http://www.leo.org/pub/comp/os/os2/gnu/emx+gcc/

http://warp.eecs.berkeley.edu/os2/software/shareware/emx.html

ftp://ftp-os2.cdrom.com/pub/os2/emx09c/

Où trouver de la documentation sur l'assembleur en ligne avec GCC?

La document de GCC inclus les fichiers de documentation au format texinfo. Vous pouvez les compiler avec TeX et les imprimer, ou les convertir au format .info et les parcourir interactivement avec emacs, ou encore les convertir au format HTML, ou en à peu près n'importe quel format (avec les outils adéquats). Les fichiers .info sont généralement installés en même temps que GCC.

La section à consulter est C Extensions::Extended Asm::

La section Invoking GCC::Submodel Options::i386 Options:: peut également vous aider. En particulier, elle donne les noms de contraintes pour les registres du i386: abcdSDB correspondent respectivement à %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp (aucune lettre pour %esp).

Le site "DJGPP Games resource" (qui n'est pas réservé aux seuls développeurs de jeux) possède une page particulière sur l'assembleur:

http://www.rt66.com/~brennan/djgpp/djgpp_asm.html

Enfin, il existe une page de la Toile appelée "DJGPP Quick ASM Programming Guide", contenant des URL sur des FAQ, la syntaxe assembleur AT&T x86, des informations sur l'assembleur en ligne, et la conversion des fichiers .obj/.lib:

http://remus.rutgers.edu/~avly/djasm.html

GCC soutraite l'assemblage proprement dit à GAS et suit donc sa syntaxe (voir plus bas), cela implique que l'assembleur en ligne doit utiliser des caractères pourcents entre apostrophes pour qu'ils soient passés à GAS. Voir la section dédiée à GAS.

Vous trouverez un grand nombre d'exemples instructifs dans le répertoire linux/include/asm-i386/ des sources de Linux.

Appeller GCC pour obtenir du code assembleur en ligne correcte?

Assurez-vous d'appeller gcc avec l'option -O (ou -O2, -O3, etc) pour activer les optimisations et l'assembleur en ligne. Si vous ne le faîtes pas, votre code pourra compiler mais ne pas s'exécuter correctement!! En fait (merci à Tim Potter, timbo@moshpit.air.net.au), il suffit d'utiliser l'option -fasm, faisant partie de toutes les fonctionnalités activées par l'option -O. Donc si vous avez des problèmes en raison d'optimisations boguées dans votre implémentation de gcc, vous pouvez toujours utiliser l'assembleur en ligne. De même, utilisez l'option -fno-asm pour désactiver l'assembleur en ligne (on peut se demander pourquoi?).

Plus généralement, les bonnes options de compilation à utiliser avec gcc sur les plates-formes x86 sont


 gcc -O2 -fomit-frame-pointer -m386 -Wall

-O2 est le bon niveau d'optimisation. Les optimisations supérieures génèrent un code un peu plus important, mais très légèrement plus rapide. De telles sur-optimisations peuvent être utiles que dans le cas d'optimisations de boucles que vous pouvez toujours réaliser en assembleur. Si vous avez besoin de faire ce genre de choses, ne le faîtes que pour les routines qui en ont besoin.

-fomit-frame-pointer permet au code généré de se passer de la gestion inutile des pointeurs de fenêtre, ce qui rend le code plus petit plus rapide et libère un registre pour de plus amples optimisations. Cette option exclue l'utilisation des outils de déboggage (gdb), mais lorsque vous les utilisez, la taille et la vitesse importent peu.

-m386 génère un code plus compacte sans ralentissement notable, (moins de code signifie également mois d'entrées/sorties sur disque et donc une exécution plus rapide). Vous pouvez également utiliser l'option -mpentium sur la version GCC gérant l'optimisation pour ce processeur.

-Wall active toutes les mises-en-garde (warning) et vous évite de nombreuses erreurs stupides et évidentes.

Pour optimiser encore plus, vous pouvez utiliser l'option -mregparm=2 et/ou les attributs de fonctions qui peuvent être utilisés mais ils peuvent dans certains cas poser de nombreux problèmes lors de l'édition de liens avec du code externe (notamment les bibliothèques partagées)...

Notez que vous pouvez ajoutez ces options aux options utilisées par défaut sur votre système en éditant le fichier /usr/lib/gcc-lib/i486-linux/2.7.2.3/specs (cependant, ne rajoutez pas -Wall à ces options).

3.2 GAS

GAS est l'assembleur GNU, utilisé par gcc.

Où le trouver?

Au même endroit où vous avez trouvé gcc, dans le paquetage binutils.

Qu'est-ce que la syntaxe AT&T

Comme GAS a été inventé pour supporter un compilateur 32 bits sous unix, il utilise la syntaxe standard "AT&T", qui ressemblent assez à l'assembleur m68k. La syntaxe n'est ni pire, ni meilleur que la syntaxe "Intel". Elle est juste différente. Lorsque vous aurez l'habitude de vous en servir, vous la trouverez plus régulière que la syntaxe Intel, quoique que légèrement plus ennuyeuse aussi.

Voici les points les plus importants à propos de la syntaxe de GAS:

  • Les noms de registres sont préfixés avec %, de façon que les registres sont %eax, %dl et consorts au lieu de juste eax, dl, etc. Ceci rend possible l'inclusion directe de noms de symboles externes C sans risque de confusion, ou de nécessité de préfixes _.
  • L'ordre des opérandes est source(s) d'abord, destination en dernier, à l'opposé de la convention d'intel consistant à mettre la destination en premier, les source(s) ensuite. Ainsi, ce qui en syntaxe intel s'écrit mov ax,dx (affecter au registre ax le contentu du registre dx) s'écrira en syntaxe att mov %dx, %ax.
  • La longueur des opérandes est spécifiée comme suffixe du nom d'instruction. Le suffixe est b pour un octet (8 bit), w pour un mot (16 bit), et l pour un mot long (32 bit). Par exemple, la syntaxe correcte pour l'instruction ci-dessus aurait dû être movw %dx,%ax. Toutefois, gas n'est pas trop aussi strict que la syntaxe att l'exige, et le suffixe est optionel quand la longueur peut être devinée grâce aux opérandes qui sont des registres, la taille par défaut étant 32 bit (avec une mise en garde quand on y fait appel).
  • Les opérandes immediates sont marqués d'un préfixe $, comme dans addl $5,%eax (ajouter la valeur longue immédiate 5 au registre %eax).
  • L'absence de préfixe à une opérande indique une adresse mémoire; ainsi movl $foo,%eax met l'adresse de la variable foo dans le registre %eax, tandis que movl foo,%eax met le contenu de la variable foo dans le registre %eax.
  • L'indexation ou l'indirection se fait en mettant entre parenthèses le registre d'index ou la case mémoire contenant l'indirection, comme dans testb $0x80,17(%ebp) (tester le bit de poids fort de l'octet au déplacement 17 après la case pointée par %ebp).

Un programme existe pour vous aider à convertir des programmes écrits avec la syntaxe TASM en syntaxe AT&T. Voir

ftp://x2ftp.oulu.fi/pub/msdos/programming/convert/ta2asv08.zip

GAS possède une documentation complète au format TeXinfo, qui est distribuée entre autre avec les sources. Vous pouvez parcourir les pages .info qui en sont extraites avec Emacs. Il y avait aussi un fichier nommé gas.doc ou as.doc disponible autour des sources de GAS, mais il a été fusionné avec la documentation TeXinfo. Bien sûr, en cas de doute, l'ultime documentation est constituée par les sources eux-mêmes! Une section qui vous intéressera particulièrement est Machine Dependencies::i386-Dependent::

Les sources de Linux dont un bon exemple: regardez dans le répertoire linux/arch/i386 les fichiers suivants: kernel/*.S, boot/compressed/*.S, mathemu/*.S

Si vous codez ce genre de chose, un paquetage de thread, etc vous devriez regarder d'autres langages (OCaml, gforth, etc), ou des paquetages sur les thread (QuickThreads, pthreads MIT, LinuxThreads, etc).

Enfin générer à partir d'un programme C du code assembleur peut vous montrer le genre d'instructions que vous voulez. Consultez la section Avez-vous besoin de l'assembleur? au début de ce document.

mode 16 bits limité

GAS est un assembleur 32 bits, conçu pour assembler le code produit par un compilateur 32 bits. Il ne reconnaît que d'une manière limité le mode 16 bits du i386, en ajoutant des préfixes 32 bits aux instructions; vous écrivez donc en réalité du code 32 bits, qui s'exécute en mode 16 bits sur un processeur 32 bits. Dans les deux modes, il gère les registres 16 bits, mais pas l'adressage 16 bits. Utilisez les instructions .code16 et .code32 pour basculer d'un mode à l'autre. Notez que l'instruction assembleur en ligne asm(".code16\n") autorisera gcc à générer du code 32 bits qui fonctionnera en mode réél!

Le code nécessaire pour que GAS gère le mode 16 bits aurait été ajouté par Bryan Ford (à confirmer?). Toutefois, ce code n'est présent dans aucune distribution de GAS que j'ai essayée (jusqu'à binutils-2.8.1.x) ... plus d'informations à ce sujet seraient les bienvenues dans ce HowTo.

Une solution bon marché pour insérer quelques instructions 16-bit non reconnues pas GAS consiste à définir des macros (voir plus bas) qui produisent directement du code binaire (avec .byte), et ce uniquement pour les rares instructions 16 bits dont vous avez besoin (quasiment aucunes, si vous utilisez le .code16 précédement décrit, et pouvez vous permettre de supposer que le code fonctionnera sur un processeur 32 bits). Pour obtenir le système de codage correct, vous pouvez vous inspirer des assembleurs 16 bits.

3.3 GASP

GASP est un préprocesseur pour GAS. Il ajoute des macros et une syntaxe plus souple à GAS.

Où trouver gasp?

gasp est livré avec gas dans le paquetage binutils GNU.

Comment il fonctionne?

Cela fonctionne comme un filtre, tout comme cpp et ses variantes. Je ne connais pas les détails, mais il est livré avec sa propre documentation texinfo, donc consultez-la, imprimez-la, assimilez-la. La combinaison GAS/GASP me semble être un macro-assembleur standard.

3.4 NASM

Du projet Netwide Assembler est issu encore un autre assembleur, écrit en C, qui devrait être assez modulaire pour supporter toutes les syntaxes connues et tous les formats objets existants.

Où trouver NASM?

http://www.cryogen.com/Nasm

Les versions binaires se trouvent sur votre miroir sunsite habituel dans le répertoire devel/lang/asm/. Il devrait également être disponible sous forme d'archive .rpm ou .deb parmi les contributions à votre distribution préférée RedHat ou Debian.

Son rôle

Au moment de l'écriture de ce HOWTO, NASM en est à la version 0.96.

La syntaxe est à la Intel. Une gestion de macros est intégrée.

Les formats objets reconnus sont bin, aout, coff, elf, as86, (DOS) obj, win32, et rdf (leur propre format).

NASM peut être utilisée comme assembleur pour le compilateur libre LCC.

Comme NASM évolue rapidement, ce HowTo peut ne pas être à jour à son sujet. A moins que vous n'utilisiez BCC comme compilateur 16 bit (ce qui dépasse le cadre de ce document), vous devriez utiliser NASM plutôt que AS86 ou MASM, car c'est un logiciel libre avec un excellent service après-don, qui tourne sur toutes plateformes logicielles et matérielles.

Note: NASM est également livré avec un désassembleur, NDISASM.

Son analyseur "grammatical", écrit à la main, le rend beaucoup plus rapide que GAS; en contrepartie, il ne reconnaît qu'une architecture, en comparaison de la pléthore d'architectures reconnues par GAS. Pour les plates-formes x86, NASM semble être un choix judicieux.

3.5 AS86

AS86 est un assembleur 80x86, à la fois 16 et 32 bits, faisant partie du compilateur C de Bruce Evans (BCC). Il possède une syntaxe à la Intel.

Where to get AS86

Une version complètement dépassée de AS86 est diffusée par HJLu juste pour compiler le noyau Linux, dans un paquetage du nom de bin86 (actuellement version 0.4) disponible dans le répertoire GCC des sites FTP Linux. Je déconseille son utilisation pour toute autre chose que compiler Linux. Cette version ne reconnaît qu'un format de fichiers minix modifié, que ne reconnaissent ni les binutils GNU ni aucun autre produit. Il possède de plus certains bogues en mode 32 bits. Ne vous en servez donc vraiment que pour compiler Linux.

Les versions les plus récentes de Bruce Evans (bde@zeta.org.au) est diffusée avec la distribution FreeBSD. Enfin, elles l'étaient! Je n'ai pas pu trouver les sources dans la distribution 2.1. Toutefois, vous pouvez trouver les sources dans

http:///www.eleves.ens.fr:8080/home/rideau/files/bcc-95.3.12.src.tgz

Le projet Linux/8086 (également appelé ELKS) s'est d'une certaine manière chargée de maintenir bcc (mais je ne crois pas qu'ils aient inclus les patches 32 bits). Voir les sites http://www.linux.org.uk/Linux8086.html et ftp://linux.mit.edu/.

Entre autres choses, ces versions plus récentes, à la différence de celle de HJLu, gèrent le format a.out de Linux; vous pouvez donc effectuer des éditions de liens avec des programmes Linux, et/ou utiliser les outils habituels provenant du paquetage binutils pour manipuler vos données. Cette version peut co-exister sans problème avec les versions précédentes (voir la question à ce sujet un peu plus loin).

La version du 12 mars 1995 de BCC ainsi que les précédentes a un problème qui provoque la génération de toutes les opérations d'empilement/dépilement de segments en 16 bits, ce qui est particulièrement ennuyant lorsque vous développez en mode 32 bits. Un patch est diffusé par le projet Tunes

http://www.eleves.ens.fr:8080/home/rideau/Tunes/

à partir du lien suivant: files/tgz/tunes.0.0.0.25.src.tgz ou dans le répertoire LLL/i386/.

Le patch peut également être directement récupéré sur

http://www.eleves.ens.fr:8080/home/rideau/files/as86.bcc.patch.gz

Bruce Evans a accepté ce patch, donc si une version plus récente de BCC existe, le patch devrait avoir été intégré...

Comme appeller l'assembleur?

Voici l'entrée d'un Makefile GNU pour utiliser bcc pour transformer un fichier assembleur .s à la fois en un objet a.out GNU .o et un listing .l:


%.o %.l:        %.s
 bcc -3 -G -c -A-d -A-l -A$*.l -o $*.o $<

Supprimez %.l, -A-l, et -A$*.l, si vous ne voulez pas avoir de listing. Si vous souhaitez obtenir autre chose que du a.out GNU, consultez la documentation de bcc concernant les autres formats reconnus et/ou utilisez le programme objcopy du paquetage binutils.

Où trouver de la documentation

Les documentations se trouvent dans le paquetage bcc. Des pages de manuel sont également disponibles quelque part sur le site de FreeBSD. Dans le doute, les sources sont assez souvent une bonne documentation: ce n'est pas très commenté mais le style de programmation est très simple. Vous pouvez essayer de voir comment as86 est utilisé dans Tunes 0.0.0.25...

Que faire si je ne peux plus compiler Linux avec cette nouvelleversion

Linus est submergé par le courrier électronique et mon patch pour compiler Linux avec un as86 a.out n'a pas dû lui parvenir (!). Peu importe: conservez le as86 provenant du paquetage bin86 dans le répertoire /usr/bin, et laissez bcc installer le bon as86 en tant que /usr/local/libexec/i386/bcc/as comme que de droit. Vous n'aurez jamais besoin d'appeler explicitement ce dernier, car bcc se charge très bien de tout, y compris la conversion en a.out Linux, lorsqu'il est appelé avec les bonnes options. Assemblez les fichiers uniquement en passant par bcc, et non pas en appelant as86 directement.

3.6 Autres assembleurs

Il s'agit d'autres possibilités, qui sortent de la voie ordinaire, pour le cas où les solutions précédentes ne vous conviennent pas (mais je voudrais bien savoir pourquoi?), que je ne recommande pas dans les cas habituels, mais qui peuvent se montrer fort utiles si l'assembleur doit faire partie intégrante du logiciel que vous concevez (par exemple un système d'exploitation ou un environnement de développement).

L'assembleur de Win32Forth

Win32Forth est un système ANS FORTH 32 bit libre qui fonctionne sous Win32s, Win95, Win/NT. Il comprend un assembleur 32 bit libre (sous forme préfixe ou postfixe) intégrée au langage FORTH. Le traitement des macro est effectué en utilisant toute la puissance du langage réflexif FORTH. Toutefois, le seul contexte d'entrée et sortie reconnu actuellement est Win32For lui-même (aucune possibilité d'obtenir un fichier objet, mais vous pouvez toujours l'ajouter par vous-même, bien sûr). Vous pouvez trouver Win32For à l'adresse suivante: ftp://ftp.forth.org/pub/Forth/win32for/

Terse

Terse est un outil de programmation qui fournit LA syntaxe assembleur la plus compacte pour la famille des processeur x86! Voir le site http://www.terse.com. Ce n'est cependant pas un logiciel libre. Il y aurait eu un clone libre quelque part, abandonné à la suite de mensongères allégations de droits sur la syntaxe, que je vous invite à ressusciter si la syntaxe vous intéresse.

Assembleurs non libres et/ou non 32 bits

Vous trouverez un peu plus d'informations sur eux, ainsi que sur les bases de la programmation assembleur sur x86, dans la FAQ de Raymond Moon pour le forum comp.lang.asm.x86. Voir http://www2.dgsys.com/~raymoon/faq/asmfaq.zip

Remarquez que tous les assembleurs DOS devraient fonctionner avec l'émulateur DOS de Linux ainsi qu'avec d'autres émulateurs du même genre. Aussi, si vous en possédez un, vous pouvez toujours l'utiliser à l'intérieur d'un vrai système d'exploitation. Les assembleurs sous DOS assez récents gèrent également les formats de fichiers objets COFF et/ou des formats gérés par la bibliothèque GNU BFD de telle manière que vous pouvez les utiliser en conjonction avec les outils 32 bits libres, en utilisant le programme GNU objcopy (du paquetage binutils) comme un filtre de conversion.


Page suivante - Page précédente - Table des matières