Obligement - L'Amiga au maximum

Vendredi 19 avril 2024 - 22:10  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

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

Articles in english


Réseaux sociaux

Suivez-nous sur X




Liste des 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,
ALL


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


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Dossier : Les bibliothèques sur AmigaOS
(Article écrit par Gilles Soulet et extrait d'Amiga News - novembre 1992)


Cet article est le premier d'une série consacrée aux bibliothèques de l'Amiga. Au cours de cette longue saga, je vous parlerai des bibliothèques les plus utilisées de l'Amiga, comme Exec ou Intuition, ainsi que de certaines bibliothèques "étrangères" comme ARP ou Req, en vous expliquant à quoi elles servent et comment les utiliser.

Introduction

Si vous avez déjà programmé sur Amiga, vous avez pu vous rendre compte que toute la ROM est organisée en "librairies" (bibliothèques). Dans une bibliothèque sont regroupées toutes les fonctions associées à un certain domaine du système d'exploitation. Ainsi, la bibliothèque graphique "graphics.library" contient les fonctions permettant de dessiner avec l'Amiga, tandis que la "dos.library" contient les fonctions d'entrées-sorties et de gestion des disquettes.

Une bibliothèque est véritablement une bibliothèque de fonctions. Ce principe n'est pas révolutionnaire : tous les ordinateurs modernes l'ont adopté, car ceci permet de mettre de l'ordre dans une ROM qui peut parfois contenir des centaines de fonctions accessibles au programmeur. Là où les choses deviennent très intéressantes, c'est que notre ordinateur préféré, lui, est multitâche.

La "pureté" des bibliothèques

Le fait que l'Amiga soit multitâche, représente une souplesse d'utilisation inégalable pour l'utilisateur... et une petite prouesse de conception du système d'exploitation ! En effet, la moindre fonction de la plus insignifiante des bibliothèques doit être "pure", ou "réentrante", c'est-à-dire conçue de telle manière que plusieurs programmes puissent l'appeler en même temps.

Par exemple, il peut arriver que deux programmes tournant dans le système ouvrent chacun une fenêtre "en même temps". Pour ouvrir une fenêtre, on utilise la fonction OpenWindow() de la bibliothèque Intuition. Cette fonction n'existe bien sûr qu'en un seul exemplaire dans la ROM de l'Amiga. C'est donc bien le même code machine qui va être utilisé et exécuté "simultanément" par deux programmes différents. En fait, il n'y a pas réellement simultanéité car le système fonctionne en temps partagé, c'est-à-dire que des quantums de temps sont attribués à toutes les tâches actives (task-scheduling, je vous en reparlerai très bientôt...). Or, ceci pose de nombreux problèmes au niveau du code, et c'est pourquoi celui-ci doit être pur.

Si vous avez déjà un tant soit peu programmé (ce que j'espère, sinon mieux vaut tard que jamais...), vous avez sans doute pris l'habitude d'utiliser des variables. Les variables sont des cases mémoires de votre programme, qui contiennent non pas du code exécutable, mais des données. Imaginez que votre programme soit exécuté deux fois en même temps... Il y aurait de très gros problèmes, car les variables seraient sans cesse modifiées par les deux exécutions occasionnant des boucles infinies, des erreurs de calcul et autres gros plantus !

C'est pourtant ce qui arrive quand deux programmes utilisent "en même temps" la même fonction de la ROM ! Donc, un programme pur ne doit absolument pas se modifier lui-même au cours de son exécution, sinon il ne pourrait pas être exécuté par deux processus différents. Or, chaque fois que vous modifiez une variable d'un programme, vous modifiez en fait une partie (des données) de ce programme.

Conséquence : un programme pur ne peut pas utiliser de variables ! Comme vous pouvez l'imaginer, écrire un code pur n'est pas toujours très facile. Comment s'arranger en effet pour ne pas utiliser des variables et autres tableaux. Et pourtant, pratiquement toute la ROM de l'Amiga est pure, à l'exception de quelques fonctions spéciales utilisées uniquement par le système lors d'une initialisation ! C'est pourquoi je vous parlais de prouesse : imaginez écrire 256 ko de code pur...

Sans entrer dans les détails, il faut savoir qu'il existe quand même un moyen de stocker des données temporaires dans un code pur : c'est d'utiliser la pile. Comme chaque programme possède sa propre pile, une fonction de la ROM peut empiler et dépiler des données locales sans perturber le fonctionnement d'un autre programme qui exécuterait le même code. Si l'on doit absolument avoir recours à des zones de travail (pour les tableaux, les tampons mémoire, etc.) on utilise alors l'allocation mémoire dynamique.

"Run-Time-library"

C'est cette spécificité d'ordinateur multitâche, et son corollaire, c'est-à-dire l'obligation d'écrire des routines "pures" qui sont à l'origine de l'apparition des bibliothèques de l'Amiga. Les bibliothèques sont destinées à fournir au programmeur des fonctions pures, utilisables "en temps réel" par plusieurs tâches à la fois.

C'est pourquoi on les appelle des "Run-Time libraries", ou "shared libraries", car leur code peut être "partagé" par plusieurs programmes, à la différence des bibliothèques des compilateurs (amiga.lib, c.lib...) dans lesquelles l'éditeur de lien "pioche" des fonctions particulières, non pures (printf(), scanf()... pour un compilateur C) et les ajoute à votre exécutable, augmentant sa taille. Ainsi, si vous créez deux programmes avec votre compilateur C, et que dans chaque programme il y ait la fonction "printf()", le code correspondant existera dans chaque exécutable.

Si ces deux programmes sont lancés dans le système, le même code existera donc en deux exemplaires à des emplacements mémoire différents. Cette perte de place a d'ailleurs inspiré Robert W. Albrecht, qui a écrit une bibliothèque run-time contenant toutes les fonctions C standard : la cclib.library).

Pour éviter de confondre les bibliothèques C et les bibliothèques run-time, les premières portent l'extension "lib" (lcsr.lib, amiga.lib...) alors que les secondes portent l'extension "library" (exec.library, dos.library...).

Retour aux sources

A l'origine, les concepteurs de la ROM de l'Amiga ont créé plusieurs bibliothèques d'usage général. Certaines sont en ROM, tandis que les autres doivent être chargées en mémoire à partir du tiroir "Libs:". C'est d'ailleurs dans ce tiroir que le système va chercher les bibliothèques qui ne se trouvent pas en ROM. Voici la liste des bibliothèques du système 1.3 ainsi que leur localisation et leur but :
  • [Nom] [Type] [Contenu]
  • clist, ROM, gestion des Clistes.
  • console, ROM, gestion du console handler.
  • diskfont, disque, gestion des polices sur disques.
  • dos, ROM, gestion des entrées-sorties et des disques.
  • expansion, ROM, gestion du port d'extension de l'Amiga.
  • exec, ROM, noyau du système.
  • graphics, ROM, graphismes, animations, bitmap, Blitter...
  • icon, disque, gestion des icônes.
  • intuition, ROM, interface graphique (fenêtres, écrans...).
  • layers, ROM, plans graphiques (masquages, défilement...).
  • mathffp, ROM, Fast Floating Point (bibliothèque mathématique).
  • mathieeedoubbas, disque, gestion des doubles flottants (standard IEEE).
  • mathtrans, disque, fonctions sin, cos, log... et inverse.
  • ramlib, ROM, gestion du disque virtuel RAM.
  • timer, ROM, gestion des "timers" (chronomètres).
  • translator, disque, traduction anglais -> phonèmes (pour le narrator).
  • version, disque, accès aux versions du système.
Avec l'apparition du système 2.0, et l'augmentation de la taille de la ROM (512 ko), de nouvelles bibliothèques ont été créées tandis que d'autres ont migré en ROM. Le but de cette série d'articles n'est pas de passer en détail toutes les bibliothèques standard de l'Amiga (pour cela, je vous renvoie au Rom Kernel Manual, ou à La Bible De L'Amiga) mais plutôt d'expliquer comment utiliser une bibliothèque (en général) et de détailler les bibliothèques "étrangères" les plus utilisées (arp.library, req.library, reqtools.library...) sur lesquelles tout le monde n'a pas toujours une documentation bien précise.

Structure et utilisation

Nous commençons donc par la base, c'est-à-dire comment est faite une bibliothèque ! L'implantation en mémoire d'une bibliothèque est toujours la même : on trouve d'abord une table de sauts (jmp) vers les fonctions (ou entrées) de la bibliothèque, puis juste après le dernier saut, la structure de la bibliothèque elle-même :

bibliothèques

J'espère que vous êtes habitués à jongler entre C et assembleur ! Il y a peu de commentaires à faire sur cette structure. Le champs "lib_PosSize" est présent car des champs supplémentaires peuvent être rajoutés à la fin de la structure. Néanmoins, le début reste toujours le même. La table des sauts, suivie de la structure, se trouve toujours en RAM, y compris pour les bibliothèques de la ROM (Exec, Intuition...). Par contre, le code des fonctions proprement dit peut se trouver en ROM ou en RAM. Dans ce dernier cas, il est placé généralement peu après la fin de la structure. Ce code correspond bien entendu aux entrées de la table des sauts.

Les règles de bonne conduite

Pour utiliser une bibliothèque sur Amiga, vous devez vous plier à un petit nombre de règles très simples. Ce sont des règles de bonne conduite, que tout programmeur civilisé se doit de respecter afin que tous les programmes cohabitent en bonne intelligence. Que vous travailliez en C ou en assembleur, je vous engage à respecter ces règles. Il y a encore trop de vandales qui continuent à faire des jumps sauvages dans la ROM !

Avant d'utiliser une bibliothèque, il faut l'ouvrir, au moyen de la fonction OpenLibrary(), qui vous renvoie un pointeur sur la bibliothèque que vous désirez utiliser (ou un pointeur NULL si elle n'existe pas). Ceci permet de s'assurer que la bibliothèque en question est bien présente dans le système sur lequel on se trouve. Ceci indique également à l'Amiga que vous êtes désormais un "client" de cette bibliothèque. Vous n'êtes peut-être pas le seul. Aussi, à chaque ouverture, le champs lib_OpenCnt est incrémenté.

Quand vous ne vous servez plus d'une bibliothèque, vous devez la fermer au moyen de la fonction CloseLibrary(). Le champs lib_OpenCnt est alors décrémenté, et s'il passe à zéro, ceci signifie que plus personne n'utilise la bibliothèque, et que le système pourra l'éliminer de la mémoire si le besoin s'en fait sentir. Pas mal, non ?

Une fois que la bibliothèque est ouverte, on peut utiliser toutes ses fonctions. Le protocole d'appel en assembleur est très simple : dans le registre a6 on met le pointeur sur la bibliothèque, on passe les paramètres de la fonction dans les registres adéquats, et on fait un magnifique "jsr offset(a6)" où "offset" représente le décalage (négatif) vers le saut correspondant dans la table des sauts.

J'insiste lourdement sur deux points : premièrement, interdiction formelle de faire un saut directement dans le code de la bibliothèque, car certains programmes peuvent "détourner" des fonctions au niveau de la table des sauts, grâce à la fonction SetFunction() (ceci est tout à fait légal).

Deuxièmement, il faut absolument mettre la base de la bibliothèque dans le registre a6. En effet, la plupart des fonctions d'une bibliothèque appellent à leur tour d'autres fonctions de cette bibliothèque en se servant du registre a6 comme base. Le non-respect de ce dernier point est à l'origine de nombreux problèmes d'incompatibilité entre les systèmes 1.3 et 2.0.

Le protocole d'entrées/sorties des fonctions est très simple. Tous les paramètres sont passés par registres. Les pointeurs sont passés dans les registres d'adresses, alors que les nombres, les masques et les "flags" (drapeaux) sont passés dans les registres de données. Les fonctions renvoient toujours leur résultat dans d0. Le contenu des registres d0, d1, d2, a0, a1, a2 peut être détruit alors que tous les autres registres (y compris a6) sont toujours restaurés après l'appel. En C, c'est encore plus simple car c'est le compilateur qui se charge de tout : il suffit d'ouvrir la bibliothèque et d'appeler ses fonctions.

N'oubliez jamais (en C comme en assembleur) de vérifier que la bibliothèque s'est bien ouverte correctement. La fonction OpenLibrary() prend deux paramètres en entrée : un pointeur sur le nom de la bibliothèque (chaîne de caractères terminée par 0) et un nombre entier correspondant au numéro de version. La fonction recherche (d'abord parmi les bibliothèques déjà installées dans le système, puis dans la ROM, puis enfin dans le tiroir "Libs:") une bibliothèque dont le nom est le même que celui spécifié, et dont le numéro de version est supérieur ou égal à celui spécifié. Si une telle bibliothèque est déjà présente en mémoire, un pointeur sur la structure est retourné. Si elle existe uniquement sous forme de fichier dans "Libs:", le fichier est chargé grâce à LoadSeg(), la nouvelle bibliothèque est rajoutée dans la liste des bibliothèques résidentes, et le pointeur est également retourné. Si la bibliothèque requise n'existe nulle part, OpenLibrary() renvoie 0 (pointeur NULL).

Exec

Comme nous l'avons vu, l'ouverture d'une bibliothèque se fait au moyen de la fonction OpenLibrary(). Or, cette fonction se trouve elle-même dans une bibliothèque (Exec). Comment faire pour utiliser cette fonction alors qu'il faut d'abord ouvrir Exec pour pouvoir l'utiliser ? C'est le gag du serpent qui se mord la queue !

En fait, comme la bibliothèque Exec est le coeur d'AmigaOS, le noyau du système d'exploitation, elle est toujours ouverte et l'adresse de base de sa structure est stockée à l'adresse 4 de la mémoire. Cette adresse 4 est appelée "ExecBase", et c'est l'adresse fondamentale du système. Son contenu (c'est-à-dire l'adresse de la structure Exec) peut varier d'une machine à l'autre (en fonction de la mémoire présente) mais il reste toujours le même après une réinitialisation. Exec est la seule bibliothèque qu'il ne soit pas nécessaire d'ouvrir : on récupère directement le pointeur sur cette bibliothèque en consultant l'adresse 4. Typiquement, une ouverture en assembleur de la bibliothèque graphique ressemble à ceci :

bibliothèques

A présent, on peut utiliser les fonctions de la graphics.library :

bibliothèques

A la fin, n'oublions pas de fermer la graphics.library :

bibliothèques

Voilà, c'est tout pour aujourd'hui. Le mois prochain, nous nous pencherons plus en détail sur le fonctionnement de deux bibliothèques internes : Exec et Intuition, avant de s'embarquer pour un grand voyage au pays des bibliothèques étrangères.


[Retour en haut] / [Retour aux articles]