4. Méta-programmation/macro-traitement

Contenu de cette section

La programmation en assembleur est particulièrement pénible si ce n'est pour certaines parties critiques des programmes.

Pour travail donné, il faut l'outil approprié; ne choisissez donc pas l'assembleur lorsqu'il ne correspond pas au problème à résoudre: C, OCAML, perl, Scheme peuvent être un meilleur choix dans la plupart des cas.

Toutefois, il y a certains cas où ces outils n'ont pas un contrôle suffisamment fin sur la machine, et où l'assembleur est utile ou nécessaire. Dans ces cas, vous apprécierez un système de programmation par macros, ou un système de méta-programmation, qui permet aux motifs répétitifs d'être factorisés chacun en une seule définition indéfiniment réutilisable. Cela permet une programmation plus sûre, une propagation automatique des modifications desdits motifs, etc. Un assembleur de base souvent ne suffit pas, même pour n'écrire que de petites routines à lier à du code C.

4.1 Description

Oui, je sais que cette partie peut manquer d'informations utiles à jour. Vous êtes libres de me faire part des découvertes que vous auriez dû faire à la dure...

GCC

GCC vous permet (et vous oblige) de spécifier les contraintes entre registres assembleurs et objets C, pour que le compilateur puisse interfacer le code assembleur avec le code produit par l'optimiseur. Le code assembleur en ligne est donc constitué de motifs, et pas forcément de code exact.

Et puis, vous pouvez mettre du code assembleur dans des macro-définitions de CPP ou des fonctions "en-ligne" (inline), de telle manière que tout le monde puisse les utiliser comme n'importe quelle fonction ou macro C. Les fonctions en ligne ressemblent énormément aux macros mais sont parfois plus propres à utiliser. Méfiez-vous car dans tous ces cas, le code sera dupliqué, et donc seules les étiquettes locales (comme 1:) devraient être définies dans ce code assembleur. Toutefois, une macro devrait permettre de passer en paramètre le nom éventuellement nécessaire d'une étiquette définie non localement (ou sinon, utilisez des méthodes supplémentaires de méta-programmation). Notez également que propager du code assembleur en-ligne répandra les bogues potentiels qu'il contiendrait, aussi, faites doublement attention à donner à GCC des contraintes correctes.

Enfin, le langage C lui-même peut être considéré comme étant une bonne abstraction de la programmation assembleur, qui devrait vous éviter la plupart des difficultés de la programmation assembleur.

Méfiez-vous des optimisations consistant à passer les arguments en utilisant les registres: cela interdit aux fonctions concernées d'être appelées par des routines exterieurs (en particulier celles écrites à la main en assembleur) d'une manière standard; l'attribut asmlinkage devrait empêcher des routines données d'être concernées par de telles options d'optimisation. Voir les sources du noyau Linux pour avoir des exemples.

GAS

GAS a quelques menues fonctionnalité pour les macro, détaillées dans la documentation TeXinfo. De plus

J'ai entendu dire que les versions récentes en seront dotées... voir les fichiers TeXinfo). De plus, tandis que GCC reconnaît les fichiers en .s comme de l'assembleur à envoyer dans GAS, il reconnaît aussi les fichiers en .S comme devant être filtrer à travers CPP avant d'être envoyer à GAS. Au risque de me répéter, je vous convie à consulter les sources du noyau Linux.

GASP

Il ajoute toutes les fonctionnalités habituelles de macro à GAS. Voir sa documentation sous forme texinfo.

NASM

NASM possède aussi son système de macros. Consultez sa documentation. Si vous avez quelqu'idée lumineuse, contactez les auteurs, étant donné qu'ils sont en train de développer NASM activement. Pendant ce même temps, lisez la partie sur les filtres externes un peu plus loin.

AS86

Il possède un système simple de macros, mais je n'ai pas pu trouver de documentation. Cependant, les sources sont d'une approche particulièrement aisée, donc si vous êtes intéressé pour en savoir plus, vous devriez pouvoir les comprendre sans problème. Si vous avez besoin d'un peu plus que des bases, vous devriez utiliser un filtre externe (voir un peu plus loin).

Autres assembleurs

4.2 Filtres externes

Quelque soit la gestion des macros de votre assembleur, ou quelque soit le langage que vous utilisez (même le C), si le langage n'est pas assez expressif pour vous, vous pouvez faire passer vos fichier à travers un filtre externe grâce à une règle comme suit dans votre Makefile:


%.s:    %.S autres_dépendances
        $(FILTER) $(FILTER_OPTIONS) < $< > $@

CPP

CPP n'est vraiment pas très expressif, mais il suffit pour les choses faciles, et il est appelé d'une manière transparente par GCC.

Comme exemple de limitation, vous ne pouvez pas déclarer d'objet de façon à ce qu'un destructeur soit automatiquement appelé à la fin du bloc ayant déclaré l'objet. Vous n'avez pas de diversions ou de gestion de portée des variables, etc.

CPP est livré avec tout compilateur C. Si vous pouvez faire sans, n'allez pas chercher CPP (bien que je me demande comment vous pouvez faire).

M4

M4 vous donne la pleine puissance du macro-traitement, avec un langage Turing-équivalent, récursivité, expressions régulières, etc. Vous pouvez faire avec tout ce que cpp ne peut faire.

Voir macro4th/This4th que l'on trouve sur ftp://ftp.forth.org/pub/Forth/ dans Reviewed/ ANS/ (?), ou les sources de Tunes 0.0.0.25 comme exemple de programmation avancée en utilisant m4.

Toutefois, le système de citation est très pénible à utiliser et vous oblige à utiliser un style de programmation par fonctions récursives avec passage explicite de continuation (CPS) pour toute programmation avancée (ce qui n'est pas sans rappeler à TeX -- au fait quelqu'un a-t-il déjà essayé d'utiliser TeX comme macro-processeur pour autre chose que de la mise-en-page?). Toutefois, ce n'est pas pire que cpp qui ne permet ni citation ni récursivité.

La bonne version de m4 à récupérer est GNU m4 1.4 (ou ultérieure si elle existe). C'est celle qui contient le plus de fonctionnalité et le moins de bogues ou de limitations. m4 est conçu pour être intrinsèquement lent pour toute utilisation sauf la plus simple; cela suffit sans aucun doute pour la plupart des programmes en assembleur (vous n'allez quand même pas écrire des millions de lignes en assembleur, si?).

Macro-traitement avec votre propre filtre

Vous pouvez écrire votre propre programme d'expansion de macro avec les outils courants comme perl, awk, sed, etc. C'est assez rapide à faire et vous pouvez tout contrôler. Mais bien toute puissance dans le macro-traitement doit se gagner à la dure.

Méta-programmation

Plutôt que d'utiliser un filtre externe qui effectue l'expansion des macros, une manière de réaliser cela est d'écrire des programmes qui écrivent d'autres programmes, en partie ou en totalité.

Par exemple, vous pourriez utiliser un programme générant du code source

Pensez-y!

Backends provenant de compilateur existants

Des compilateurs comme SML/NJ, Objective CAML, MIT-Scheme, etc, ont leur propre générateur de code assembleur, que vous pouvez ou non utiliser, si vous souhaitez générer du code semi-automatiquement depuis les langages correspondants.

Le New-Jersey Machine-Code Toolkit

Il s'agit projet utilisant le langage de programmation Icon pour bâtir une base de code de manipulation d'assembleur. Voir http://www.cs.virginia.edu/~nr/toolkit/

Tunes

Le projet de système d'exploitation OS développe son propre assembleur comme étant une extension du langage Scheme. Il ne fonctionne pas encore totalement, de l'aide est bienvenue.

L'assembleur manipule des arbres de syntaxes symboliques, de telle manière qu'il puisse servir comme base d'un traducteur de syntaxe assembleur, un désassembleur, l'assembleur d'un compilateur, etc. Le fait qu'il utile un vrai langage de programmation puissant comme Scheme le rend imbatable pour le macro-traitement et pour la méta-programmation.

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


Chapitre suivant, Chapitre Précédent

Table des matières de ce chapitre, Table des matières générale

Début du document, Début de ce chapitre