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 : Assembleur - les variables locales
(Article écrit par Thomas Pimmel et extrait d'ANews - septembre 1999)
|
|
L'homo-assembleur n'utilise généralement la pile que pour y ranger sa massue et éventuellement ses adresses de retour.
Je vous propose dans cette rubrique une méthode simple pour créer des variables locales, histoire de ne pas gâcher tout cet
espace et de rendre vos programmes réentrants.
Nous allons nous servir de l'instruction "link", inventée par un fumeur de LIFO (last in, first out) et des macros. Link est un
animal assez évolué, mais relativement facile à domestiquer. Pour ceux qui ne le connaissent pas, voici ses habitudes. Tout
d'abord, il faut savoir que link ne se reproduit pas en captivité et que sa femelle s'appelle "unlk". L'exemple suivant...
...sauve le contenu de a5 dans la pile, copie le SP (stack pointer) dans a5, puis recule le SP de 16 octets. C'est l'équivalent
de la routine suivante :
move.la5,-(sp)
move.lsp,a5
sub.l #16,sp
|
On constate que a5 pointe sur la fin de la zone allouée. Pour effacer la zone, il faut utiliser les décalages suivants :
clr.l -4(a5)
clr.l -8(a5)
clr.l -12(a5)
clr.l -16(a5)
|
L'instruction "unlk a5" fait le contraire et rétablit la pile :
move.l a5,sp
move.l (sp)+,a5
|
On voit tout de suite qu'utiliser des décalages négatifs, ce n'est pas très propre pour un homo-erectus qui va de l'avant. Il
faudrait pouvoir définir des noms de variables pour ces décalages, par le moyen d'une structure.
Pour déclarer une structure, on utilise la macro STRUCTURE définie dans exec/types.i, et pour déclarer des décalages on a le choix
entre LONG, WORD, APTR, etc.
Je propose donc de créer les macros _LONG, _WORD, etc. qui reculeront le décalage au lieu de l'avancer. Voici la définition de
LONG :
_LONG MACRO ;long (32 bits)
\1 EQU SOFFSET
SOFFSET SET SOFFSET+4
ENDM
|
Elle peut être complétée par celle-ci :
LONGMACRO
SOFFSET SET SOFFSET-4
\1 SET SOFFSET
ENDM
|
Et voici à quoi peut ressembler une structure destinée aux variables locales :
STRUCTURE variable_locale,0
__LONG motlong ; -4
__LONG petitkiki ; -8
__LONG varloc_sizeof ; -8
|
On l'utilise très simplement :
link a5,#varloc_sizeof
move.l#$BABA,motlong(a5)
unlk a5
|
C'est tout de même plus joli.
On va donc reprendre exec/types.i et recréer toutes les macros. Jetez un oeil sur le nouvel include suivant (varloc.i).
J'ai repris toutes les définitions de macros en les adaptant aux décalages négatifs :
*********************************************
* Macros pour variables locales
*********************************************
_APTR MACRO
SOFFSET SET SOFFSET-4
\1 SET SOFFSET
ENDM
_LONG MACRO
SOFFSET SET SOFFSET-4
\1 SET SOFFSET
ENDM
_SHORT MACRO
SOFFSET SET SOFFSET-2
\1 SET SOFFSET
ENDM
_BYTE MACRO
SOFFSET SET SOFFSET-1
\1 SET SOFFSET
ENDM
_STRUCT MACRO ; name, size
SOFFSET SET SOFFSET-\2
\1 EQU SOFFSET
ENDM
_LINK MACRO
link \1,#(\2&$fffffffc)
ENDM
|
Une petite macro bien pratique, en passant :
STRUCT MACRO ; name, size
SOFFSET SET SOFFSET-\2
\1 EQU SOFFSET
ENDM
|
Avec _STRUCT il est possible de loger une structure entière dans la pile (ici une structure de dos.i) :
STRUCTURE utile,0
_STRUCT ma_structure,ds_
SIZEOF
LABEL utile_sizeof
|
Pour utiliser cette structure, on peut imaginer un code comme celui-ci :
lea ma_structure(a5),a()
clr.l ds_Days(a0)
clr.l ds_Minute(a0)
clr,l ds_Tick(a0)
|
Avant de vous laisser graver ces quelques lignes de code sur les murs de la grotte, une dernière macro :
_LINK MACRO
link \1,#(\2&$fffffffc
ENDM
|
Ceux qui n'ont pas abusé de l'alcool de palme ont compris... Cette macro assure l'alignement de la pile et vous évitera
des accidents de chasse. De plus, elle vous évite de devoir écrire la caractère "#", et j'ai horreur d'écrire les "#".
STRUCTURE exemple,0
__STRUCT date,dat_SIZEOF
__BYTE pipo
LABEL exemple_sizeof
MaFonction
_LINK a3,exemple_sizeof
clr.b pipo(a3)
unlk a3
rts
|
Voici un petit exemple. C'est une routine qui ouvre une bibliothèque et affiche un petit message d'erreur :
include exec/types.i
include exec/memory.i
include dos/dos.i
include varloc.i
include exec_lib.i
include dos_lib.i
Début
; ouverture de la doslib version 75, ça devrait
; en toute logique foirer complètement
moveq #75,d0
lea dosname(pc),a0
bsr OpenLibrary
tst.l d0
beq .error
nop ; sisi!
.error
moveq #0,d0
rts
;=============================
; Base=OpenLibrary(libname/version)
; a0 d0
;=============================
STRUCTURE openlibrary,0
_LONG ol_version ; version
_APTR ol_name ; nom de la lib à ouvrir
_APTR ol_dosbase ; dos.library
_APTR ol_output ; sortie donnée par _LVOOutput
_APTR ol_closeoutput ; sortie donnée par _LVOOpen
_APTR ol_return ; valeur de retour
LABEL ol_sizeof
OpenLibrary
_LINK a5,ol_sizeof
movem.l d2-7/a2-4,-(sp)
; init de la structure
move.l a0,ol_name(a5)
move.l d0,ol_version(a5)
clr.l ol_closeoutput(a5)
clr.l ol_dosbase(a5)
clr.l ol_return(a5)
; ouverture
bsr OL_Open
; fermetures éventuelles
bsr OL_Close
move.l ol_return(a5),d0
movem.l (sp)+,d2-7/a2-4
unlk a5
rts
;----------------
; ouvrir lib
;----------------
OL_Open
; on ouvre
move.l ol_name(a5),a1
move.l ol_version(a5),d0
move.l 4.w,a6
jsr _LVOOpenLibrary(a6)
move.l d0,ol_return(a5)
bne.s .rts
bsr OL_Error
.rts
rts
;----------------
; fermer dosbase et con:
;----------------
OL_Close
; fermer con:
move.l ol_closeoutput(a5),d1
beq.s .noclose
move.l ol_dosbase(a5),a6
jsr _LVOClose(a6)
.noclose
; fermer doslib
move.l ol_dosbase(a5),a1
tst.l a1
beq.s .nolib
move.l 4.w,a6
jsr _LVOCloseLibrary(a6)
.nolib
rts
;----------------
; Afficher erreur
;----------------
OL_Error
; ouvrir dos en version 0
moveq #0,d0
lea dosname(pc),a1
move.l 4.w,a6
jsr _LVOOpenLibrary(a6)
move.l d0,ol_dosbase(a5)
beq.s .nomsg
; chercher une sortie
move.l ol_dosbase(a5),a6
jsr _LVOOutput(a6)
move.l d0,ol_output(a5)
bne.s .displaymsg
; ouvrir con:
move.l #ol_con,d1
move.l #MODE_NEWFILE,d2
jsr _LVOOpen(a6)
move.l d0,ol_output(a5)
move.l d0,ol_closeoutput(a5)
beq.s .nomsg
.displaymsg
bsr OL_DspMsg
.nomsg
rts
;----------------
; "Write" Erreur
;----------------
STRUCTURE dspmsg,0
_APTR dm_buffer
_LONG dm_size
LABEL dm_sizeof
OL_DspMsg
_LINK a4,dm_sizeof
clr.l dm_size(a4)
clr.l dm_buffer(a4)
; compter la place utile pour le message
lea ol_msg(pc),a0
lea ol_name(a5),a1
lea RDFMT_Cpt(pc),a2
lea dm_size(a4),a3
move.l 4.w,a6
jsr _LVORawDoFmt(a6)
; allouer mémoire
move.l dm_size(a4),d0
move.l #MEMF_PUBLIC,d1
move.l 4.w,a6
jsr _LVOAllocVec(a6)
move.l d0,dm_buffer(a4)
beq.s .rts
; copier
lea ol_msg(pc),a0
lea ol_name(a5),a1
lea RDFMT_Copy(pc),a2
move.l dm_buffer(a4),a3
move.l 4.w,a6
jsr _LVORawDoFmt(a6)
; écrire message dans sortie
move.l ol_output(a5),d1
move.l dm_buffer(a4),d2
move.l dm_size(a4),d3
subq.l #1,d3 ; le zéro de la fin n'a pas à être imprimé
move.l ol_dosbase(a5),a6
jsr _LVOWrite(a6)
; libérer mémoire
move.l dm_buffer(a4),a1
move.l 4.w,a6
jsr _LVOFreeVec(a6)
.rts
unlk a4
rts
RDFMT_Cpt
addq.l #1,(a3)
rts
RDFMT_Copy
move.b d0,(a3)+
rts
;========================
; Constantes
;========================
dosname dc.b 'dos.library',0
ol_con dc.b 'con:////"Test"/CLOSE/WAIT',0
ol_msg dc.b 'Erreur lors de l''ouverture de',$a
dc.b '"%s" version %lu',$a,0
|
Pour le mois prochain, ne perdez pas cet article. Nous verrons comment lancer des sous-programmes en multitâche.
Il y aura de l'aventure, du sexe, de la violence, et bien sûr des caraïbles locales.
|