Suivez-nous sur X
|
|
|
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
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : C - Appel de l'assembleur depuis le C et inversement
(Article écrit par Roméo Rapido et extrait d'A-News (Amiga News) - mars 1989)
|
|
Appel de l'assembleur depuis le C
Revenons à l'article sur la compilation séparée. Je tiens ici à préciser que les
utilisateurs de K-Seka ne peuvent pas lier leur fichier en assembleur avec des fichiers C compilés. De même, les fichiers
générés par le Lattice et l'Aztec sont incompatibles. Utilisez donc l'assembleur qui est vendu avec votre compilateur.
Seule exception, Assem, l'assembleur du kit développeur qui utilise Blink et est donc compatible Lattice.
Ce qu'il faut absolument savoir sur les appels de fonctions en C et en assembleur : le compilateur passe les arguments
par la pile et ceci de droite à gauche. Exemple : si on écrit "Kill(Atari,vite);" le compilateur empilera "vite" puis "Atari"
et enfin fera un "jsr _Kill".
Bon et maintenant comment récupérer les arguments en ASM. Il suffit d'utiliser un adressage indirect avec déplacement,
en sachant que lors de l'exécution d'un "jsr", le PC est incrémenté de 6 pour pointer sur l'instruction suivante à executer
(2=1 mot pour l'instruction et 4 pour l'opérande qui est une adresse) puis est sauvegardé sur la pile (c'est l'adresse de
retour utilisée par "rts" qui la dépilera et fera un "jmp" à cette adresse).
Quand on sauvegarde sur la pile, il faut prédécrémenter le pointeur de pile qui pointe toujours sur la dernière valeur empilée.
Pour sauvegarder sur la pile, on utilise un adressage indirect prédécrémenté de la forme :
De même, pour dépiler, il faut postincrémenter le pointeur de pile (qui est en fait le registre a7, on peut donc écrire
indifféremment a7 ou sp).
Pour avoir accès au premier argument, il suffit d'écrire :
Le déplacement est de 4, ce qui correspond à l'adresse de retour qui a été empilée par le "jsr".
Bon, pour le deuxième, c'est pareil sauf que si le premier argument est un entier court on écrira :
Et si c'est un pointeur ou un entier long :
Déplacement de 4 ou 4+2 suivant la taille du premier paramètre.
Appels du C depuis l'assembleur
Bon, maintenant, voyons le mécanisme inverse : appel du C depuis l'assembleur.
Exemple : appel de la fonction déclarée comme suit :
void triche(arnaque,vol)
short int arnaque;
long vol;
|
Le code sera de la forme :
move.l d0,-(sp)
move.w d1,-(sp)
jsr _triche
addq.w #6,sp
|
Que vient faire ce "addq" ? C'est très simple, incrémenter le pointeur de pile est la méthode la plus rapide pour "dépiler"
donc on additionne le nombre d'octets que l'on a empilé au SP.
On aurait pu écrire :
move.w (sp)+,d1
move.l (sp)+,d0
|
Ce qui aurait eu le même effet à part que l'on récupère dans les registres les valeurs passées en paramètre et que l'exécution
est plus lente. De plus, il n'y a pas de réel intérêt car les fonctions en C mettent en place une zone de pile dans laquelle
elles sauvegardent le contexte, donc pas besoin de dépiler pour récupérer le contexte (quoi que quelques fois ?).
Une dernière remarque : si vous appelez une fonction en ASM qui sauvegarde des registres (ce qui est plus prudent).
Exemple : movem.l d0-d3/a1,-(sp)
Il faut modifier vos déplacements pour accéder aux paramètres ; ces déplacements deviennent [4 + nombre_de_reg_sauvegardés x 4],
soit ici [4 + 5 x 4] = 24, donc l'accès au premier paramètre se fait via :
Nota : n'oubliez pas de restituer le contexte par :
Enfin, un dernier mot si vous utilisez l'Aztec C : pas de problèmes, vous avez SDB pour suivre l'exécution en ASM
mais si vous utilisez le Lattice C, compilez avec l'option -d (lc1 -d ...) puis liez avec le drapeau ADDSYM au lieu
de NODEBUG, cela vous permettra d'utiliser Metascope qui est un débogueur compatible Lattice. Il permet de
visualiser la table des symboles, l'exécution en mode trace pas à pas, de modifier les registres, de voir la mémoire
en hexa ou désassemblée, modifier la mémoire, placer des points d'arrêt, enfin tout quoi qui faut pour travailler
correctement en assembleur.
Pour l'utiliser : ouvrez la table des symboles, cherchez "_main", cliquez sur son adresse et pressez les touches [Amiga+b].
Vous avez installé un "break point", faites [Amiga+g] et l'exécution s'arrêtera au début de votre programme. Metascope
permet même de modifier directement le code en mémoire (comme K-Seka mais en cliquant sur une instruction,
il demande par quelle autre instruction on veut la remplacer). Il ne lui manque qu'une option Save, dommage.
|