Obligement - L'Amiga au maximum

Vendredi 26 mai 2017 - 21:04  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Soutien

N'hésitez pas à soutenir le projet Obligement



Contact

David Brunet

Courriel

 


Programmation : C - interfacer le C et l'assembleur (2e partie)
(Article écrit par Cédric Beust et extrait d'A-News (Amiga News) - février 1990)


Suite de notre excursion dans les arcanes du compilateur C (le premier article est ici). Cette fois, on passe à des choses un peu plus complexes, accrochez vos ceintures !

Après vous avoir fait saliver avec le précédent article, il est temps de vous expliquer un peu comment nous allons procéder pour obtenir des routines "puts" et "sprinf" plus courtes. Nous allons écrire leur code en assembleur (rassurez-vous, c'est très court) et les assembler pour produire un code objet (puts.o et sprintf.o).

J'ai choisi de les appeler du même nom que celui de bibliothèque lc.lib car cela procure un avantage de taille. Lors de la compilation et de l'édition de liens, l'éditeur de liens prend les fonctions dans l'ordre de leur apparition dans les bibliothèques mentionnées. Si nous appelons notre bibliothèque mylib.lib, le simple fait de mettre ce nom avant lc.lib dans la ligne de commande de blink obligera celui-ci à prendre nos fonctions et pas celles de lc.lib. Pour puis, cela ne posera aucun problème, les paramètres étant identiques. Il faudra quelque peu modifier les appels de sprintf pour les adapter à notre version, mais c'est trois fois rien.

Autrement dit, il suffira de remplacer :

blink lib:c.o,a.o to a lib lib:lc.lib lib:amiga.lib

...par :

blink lib:c.o,a.o to a lib lib:mylib.lib lib:lc.lib lib:amiga.lib

...pour voir baisser votre code de façon significative. En fait, vous pourrez même omettre c.o. Mais j'y reviendrai.

Description de puts.o

Il n'y a pas plus simple : il s'agit tout bêtement d'utiliser la fonction Write() de la dos.library. Celle-ci est supposée ouverte et DosBase doit se trouver à un emplacement appelé _DOSBase. Cette fonction utilise _strlen de la bibliothèque lc.lib (cela oblige donc à lier également avec lc.lib). Rassurez-vous, _strlen est très petit (on ne peut pas faire plus petit) et si cela vous déplaît d'utiliser une autre bibliothèque, vous n'avez qu'à transférer son code dans mulib.lib.

Avant d'aller plus loin, parlons un peu de la création de bibliothèques avec Lattice. Il existe une fonction qui s'occupe de tout ça : oml (Object Module Librarian). Vous pouvez en avoir une description complète en faisant "oml <nombidon". Par exemple, pour avoir la liste de toutes les fonctions dans lc.lib, tapez :

oml l lib:lc.lib

Vous pouvez en extraire le ".o" que vous voulez en remplaçant le "1" par un "x" et en spécifiant son nom :

oml x lib:lc.lib strlen

Et pour désassembler le module ainsi extrait : "omd strlen".

Comme vous voyez, tout ceci est d'une extrême simplicité. La commande pour ajouter une fonction à une bibliothèque (et éventuellement créer cette bibliothèque) est :

oml lib.mylib.lib a puts.o

Une contrainte à ce propos : il faut nommer le module que vous ajoutez, ce qui est fait sous Devpac avec la directive IDNT (idem sous MetaComCo). Vous en savez maintenant suffisamment pour taper votre première fonction de bibliothèque. Voici donc le listing de puts.s :

C et assembleur

Une petite remarque avant d'aller plus loin : en toute rigueur, il faudrait adresser _DOSBase relativement au pointeur de base (registre a4 sur Lattice). J'ai rencontré quelques problèmes quand j'ai voulu le faire. Cela semble marcher comme ça mais méfiez-vous pour l'écriture d'autres fonctions de bibliothèque.

C'est bien beau tout ça, mais nous ne sommes pas affranchis pour autant de l'utilisation de printf pour faire des sorties formatées... Que nenni ! Passons à la fonction suivante.

Description de sprintf.o

La force de notre nouvelle fonction sprintf repose sur le fait qu'elle utilise une fonction en ROM qui fait le formatage : il s'agit de RawDoFmt. C'est une fonction très peu documentée et l'apprivoiser m'a causé bien des maux de tête causés par la visite fréquente de notre pote le Guru. Mais je l'ai dressée et elle m'obéit désormais au doigt et à l'oeil. Voyons sa syntaxe :

RawDoFmt(format, args, putchar, destination)
a0 a1 a2 a3

format : chaîne de formatage conforme au printf de C.

args : pointeur sur un tableau de longs représentant les arguments.

putchar : fonction de filtrage des caractères. En entrée, d0 contient le caractère à filtrer, et en sortie le caractère est mis dans (a3)+. Vous en faites ce que vous voulez entre-temps, le plus simple étant de le recopier tel quel.

destination : endroit où mettre la chaîne formatée.

L'analogie avec la syntaxe de sprintf est immédiate :

sprintf(destination,format,args)

Il suffit donc de réordonner les paramètres et d'ajouter la routine putchar(). Voici le listing de sprintf.s :

C et assembleur

Pour ceux qui s'obstineraient à ne pas utiliser d'includes en assembleur (ils sont dans l'erreur la plus totale. Ce n'est pas parce que Seka donne de mauvaises habitudes qu'il faut rester dans l'erreur. Utilisez les includes et vos listings seront beaucoup plus lisibles !), l'offset de RawDoFmt dans Exec est de -522.

Comme vous l'aurez peut-être remarqué, la nouvelle syntaxe est légèrement différente. Par exemple...

sprintf(var,"%d %d",a,b)

...devra devenir :

long arg[2];
...
arg[0]=a;
arg[1]=b;
sprintf(var,"%d %d",arg)

Le nouveau sprintf est légèrement plus restreint que l'ancien mais je suis incapable de dire jusqu'à quel point. Il faudrait pour le déterminer connaître exactement les limites de RawDoFmt. Jusqu'à maintenant, rien ne m'a jamais fait défaut dans cette nouvelle version.

Comment supprimer le startup c.o ?

C'est a priori une chose difficile car c.o, lc.lib et amiga.lib sont très liés et le fait d'utiliser une fonction de l'un d'eux oblige presque à coup sûr à recourir aux deux autres. Mais nous avons fait un grand pas dans ce sens et je vais vous montrer que c'est maintenant devenu possible. Il n'y a plus grand-chose à faire étant donné que nos puts et sprintf sont devenus très indépendants et à part strlen, ils ne font appel à aucune routine extérieure.

Nous pouvons donc dès à présent nous passer de c.o à une condition : il s'agit du fameux registre de base a4. Celui-ci n'est initialisé qu'au début de main. Or, nous n'avons plus de telle fonction (ou plus exactement, nous ne sommes plus obligés d'en avoir une). Il faut donc obliger le compilateur à initialiser a4 dès l'entrée, ce qui ce fait avec l'option "-y" sur lc. Ajoutons également l'option "-v" pour éviter de tester les dépassements de pile à chaque appel de fonction et nous pouvons affirmer que le code que nous obtenons commence à être compact...

Et pour finir...

Un exemple de programme C qui est tout tout tout petit...

C et assembleur
C et assembleur

Pour compiler ce programme, il suffit de le lancer par "execute a.c".

Remarquez l'utilisation de proto/exe,c.h afin de préciser comment trouver les registres utilisés lors de l'appel de fonctions en ROM (nous n'avons plus d'amiga.lib, rappelez-vous !) et l'absence de fonction main(). Le code obtenu fait 432 octets. Pas mal, non ? Combien aurait fait l'équivalent avec printf, puts et sprintf ?

Et voilà pour mylib.lib. Elle ne contient pour le moment que deux fonctions mais je suis sûr que vous ne manquerez pas d'idées pour l'étoffer.


[Retour en haut] / [Retour aux articles] [Article précédent]