Obligement - L'Amiga au maximum

Mardi 16 avril 2024 - 18:39  

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

 


Programmation : C - Insérer des routines assembleur
(Article écrit par Denis Jarril et extrait d'Amiga News Tech - juin 1991)


Lorsque l'on a en projet de développer un gros programme en C, il est souvent utile d'y ajouter quelques routines en assembleur, histoire de gagner du temps et/ou de la place, ou bien tout simplement parce qu'on ne peut pas faire autrement.

Ce cas est de loin le plus facile, l'interface avec l'assembleur étant tout naturel en langage C. A peine aura-t-on besoin de se souvenir de quelle manière les paramètres sont transmis (ce qui a d'ailleurs déjà été expliqué dans le précédent numéro de l'ANT, qui traitait alors de l'utilisation de l'amiga.lib en assembleur). Le cas inverse (à savoir : appeler des routines écrites en C ou accéder à des données définies dans ce langage) n'est pas beaucoup plus difficile, pour peu que l'on prenne la peine de s'y intéresser.

Bref rappel

A l'attention de ceux qui ne nous rejoindraient qu'à partir de ce numéro, un bref mais court rappel de ce qu'il faut faire pour appeler une routine assembleur depuis le C ne mangera pas de pain.

Par définition, le langage C passe tous les paramètres des fonctions par la pile, empilés en ordre inverse de leur déclaration. Pour un "long" ou un pointeur, un mot long (32 bits) est empilé, tandis que pour un "int" (16 bits, certains préfèrent dire "short" ou "word"), un "char" (8 bits), c'est un mot qui est empilé. Quant à la valeur de retour, s'il y a en une, elle est contenue dans le registre d0 au sortir de la fonction. Quand on sait ça, la suite n'est plus qu'un jeu d'enfant.

Voici tout de même un petit exemple, comme ça, pour la forme.

En C :

C

Et en assembleur :

C
C

Quelques remarques qui n'ont pas été faites précédemment. Côté C, la fonction à appeler doit être déclarée "extern" pour que l'éditeur de liens sache qu'il la trouvera ailleurs que dans le programme compilé. D'autre part, il est de bon ton de lui déclarer un prototype, histoire d'être sûr de ne pas se gourrer dans les paramètres...

Côté assembleur, plusieurs petites choses sont à prendre en compte. D'abord, le source doit évidemment être assemblé en objet et non en exécutable (n'importe quel macro-assembleur digne de ce nom fait cela très bien), ça tombe sous le sens.

De plus, le point d'entrée de la fonction doit être "exporté" grâce à la directive XDEF, sinon l'éditeur de liens se plaindra de ne pas trouver ce qu'il cherche. Ensuite, à cause d'une convention du C, son nom doit être précédé du caractère souligné "_". Enfin, c'est la fonction appelante qui a la charge de restaurer la pile, et non la fonction appelée, comme je l'ai encore vu récemment dans un magazine que je ne citerai pas mais qui parle beaucoup des 16/32 bits...

Permettez-moi d'ouvrir ici une parenthèse utile : il est tout à fait possible qu'une même routine assembleur soit appelée à la fois par le C et par une autre routine assembleur. Que faire dans ce cas ? Il serait en effet superflu - et en tout bien ennuyeux - de devoir empiler les paramètres et réajuster soi-même la pile alors que les registres du processeur sont tout de même faits pour ça ! La petite "astuce" (et encore !) suivante y remédie, en utilisant justement le coup du souligné :

C

Ainsi, cette routine pourra être appelé depuis le C par et depuis l'assembleur par :

C

Et depuis l'assembleur par :

C

Sympathique, non ?

Du C dans l'assembleur

Voyons maintenant le cas inverse. Il n'est pas rare qu'une routine assembleur appelée par une fonction C ait à son tour besoin d'appeler une autre fonction C et/ou d'accéder à des données globales du programme, elles-mêmes définies en C... Ce qui, encore une fois, n'est pas si terrible que ça en a l'air.

Il faut évidemment se rappeler la convention du passage des paramètres, mais également ne pas oublier que la pile doit être restaurée dans son état initial. Vite, vite, un exemple.

En C :

C
C

Et en assembleur :

C

Jusque-là, rien de vraiment compliqué : on s'est contenté d'utiliser la directive XREF pour indiquer à l'assembleur que le label "_RoutineC" (sans oublier le souligné) se trouve dans un autre module, extérieur à celui qu'il traite. Enfin, pour appeler la fonction, on a empilé le paramètre (32 bits), sauté avec JSR puis additionné à SP le nombre d'octets empilé, c'est-à-dire quatre. Enfantin.

Accéder aux données globales du programme C est tout aussi simple, bien qu'il faille différencier deux cas :
  • Le programme est compilé en modèle SMALL.
  • Le programme est compilé en modèle LARGE.
Dans le premier cas (SMALL), les données globales sont référencées par l'intermédiaire du registre A4 (et seulement par lui !). On aura par exemple :

C

Ceci limite les données à 32 ko - à cause de la manière dont le 68000 code ce mode d'adressage - mais produit un code plus compact et plus rapide.

Dans le second cas (LARGE), les données globales sont adressées directement par leur adresse effective :

C

Là, on n'est plus limité (?) qu'à 16 Mo de données, mais le code produit est plus gros et moins rapide. C'est une question de choix.

Vérifiez donc dans le manuel de votre compilateur quel type de code il produit (normalement, il doit savoir faire les deux !), mais si vous me permettez un conseil, utilisez toujours le modèle SMALL 32 ko de données, c'est déjà énorme ! Et si d'aventure vous en aviez besoin de plus, allouez-les dynamiquement avec AllocMem(), c'est beaucoup plus rentable !


[Retour en haut] / [Retour aux articles]