[LANGUAGE english; PAGE 6]
[C;6;B]		Auto-Initialisation
		Auto-Exit
[J;1;N]
  lk actually supports two types of intialisation and \
exit code. Those are from:
[C;3; GOTO slink]		Slink
[1]			and
[3; GOTO dice]			DICE
[J]
[LABEL slink; 5]  . Slink's autos:
[1]
  This mode needs the use of the option SLINK.

  To have auto-initialisation, SAS/C creates functions \
named __STI<function name> or @_STI<function name> (The \
second one correspond to the same function called with \
registers not saved on the stack.) Those are called \
'CREATORS.'
  To have auto-exit, SAS/C creates functions named \
__STD<function name> or @_STD<function name>. Those \
are called 'DESTRUCTORS.'
  The code (or data) which needs those initialisation and \
exit functions is created into the same unit.
  The disaventage of this method is to create a relocation \
pointer for each function. This has a high time and space \
cost. The following initialisation method does not have \
that disaventage.
[5]
  The following example is an illustration of the \
functions of SAS/C. Note that's not a copy of it. \
Nothing oblige you to use those models.
[1]
  To call each of those functions, you need a function \
called '___construct'. lk will create two lists one \
after another both terminated with a null pointer and \
before the first one a pointer to the '___construct' \
function will be saved. In C, the declarations are:
[2]
    int (*)(void) __ctors[[];
    void (*)(void) __dtors[[];

  /* construct is called with ctors and dtors */
    extern int __construct(int (*)(void)[[]);

  with '__ctors[[-1] == __construct'
  and  '__ctors[[LASTFUNC + 1] == 0'
[1]
  Example of the functions which will call '___construct':
[2]
  int __init()
  {
    return (__construct(_ctors));
  }

  int __exit()
  {
    return (__construct(_dtors));
  }
[1]
  Of course you will have to call those two functions.

  Example of '___construct' function:
[2]
  int __construct(int (_tors*)(void))
  {
    int r = 0;

    while(*_tors) {
 /* This suppose destructors always returns 0 */
      if(!r) r = (*_tors)();
      _tors++;
    }

    return (r);
  }
[1]
  Note: SAS/C has a flag to know if the called functions \
are the creators or the destuctors.

  The object file looks like:
[2]
    hunk_unit  <unit name>
    hunk_name  <hunk name>
    hunk_code  <680x0 code>
               (it could be a hunk of data)
    hunk_ext   <ext_def: user function(s)>
               and other externals
    hunk_end
    hunk_name  <init hunk name>
    hunk_code  <680x0 code>
    hunk_ext   <ext_def: __STI<user function>
               and other externals
    hunk_end
    hunk_name  <exit hunk name>
    hunk_code  <680x0 code>
    hunk_ext   <ext_def: __STD<user function>
               and other externals
    hunk_end
[1]
  Note: there is no need to have STI/STD functions into \
another hunk of code, each function or hunk name can be \
different, some data or bss hunks can exist and any hunk \
can have the usual debug and symbols.

  To ensure that the order is respected, the creators and \
destructors names can include a level. The creator function \
with the lower level will be called first and the higher \
level will be called last. For the destructor functions the \
order is inverted; functions with the lower level will be \
called last and functions with the higher level will be \
called first. When no level is included the default is \
used, also 30000. The level is a long word value. \
Functions with the same level are called in the \
order they were defined (Now lk does not garantie \
it.)
  There is the generic syntax:
     __ST?[[_]<value><user function name>
  any number of underscore (_) may appear before the value.

  Example of names:
[2]    __STI3890_MyInit     (Called before defaults)
    @_STD__81956_MyExit  (Called after defaults)
[1]
  The initialisation function, in C, is declared as:
[2]     extern int _STImyinit(void);
[1]  when a creator returns TRUE (a value other than null) \
following creators will not be called.

  The exit function, in C, is declared as:
[2]     extern void _STDmyexit(void);
[1]  with the default SAS/C '___construct' function all \
descriptors are always called, even the corresponding \
initialisation has never took place.

  How to use it:

    For instance, if you define a function which needs \
the IntuitionBase, you will write:
[2]
  external void *Intuition;
  ...
    #asm
      MOVEA.L _Intuition(A6)
      JSR _LVOOpenWorkBench(A6)
    #endasm
  ...
[1]
    Then the corresponding initialisation and exit will be:
[2]
  void *Intuition;
  _STI_OpenIntuition()
  {
    Intuition = OldOpenLibrary
[R]			("intuition.library");
[L]    return (!Intuition);
  }

  void *Intuition;
  _STD_CloseIntuition()
  {
    if(Intuition) {
      CloseLibrary(Intuition);
      Intuition = (void *) 0;
    }
  }
[1]
[LABEL DICE; 5]  . DICE's autos:
[1]
  This mode needs the use of the option BLOCKUNIT \
(and eventually CC.) The use of DICE is needed only \
if you use DICE object files.

  dlink, to have auto-initialisation, uses the hunk names \
autoinit and autoexit. Those names might be modified as \
you want with lk, there is no restriction.
  Because all hunks with the same name are linked together, \
all autoinit and autoexit will be. Those hunks will be found \
in the same unit than the function/data which needs to be \
initialized. You need to have one hunk for the user function \
or data, one hunk for the initialisation and one hunk for the \
exit code. To produce several levels, several names are \
used (like autoinit0, autoinit1, ...) The header will call \
each of those groups of hunks one after another.

  Actually DICE uses autoinit0, autoinit1, autoexit0, \
autoexit1 and autoconfig. The only problem in DICE is \
the file 'c.o' which have some relocation pointing to \
empty hunks. This could be avoided by creating hunks \
with NOP's instructions. Anyway lk handled them, but \
it needs the use of the option DICE.
  The difference for DICE between the autoinits and \
autoconfig is that autoinits may fail.

  The functions of initialisation or of exit does not \
have the usual RTS at the end. This also enable, with \
a single call, to execute all functions of a given level. \
To create that kind of hunks you may use DICE which \
enables initialisation and exit functions or use \
your prefered assembler. You will have to verify that \
your assembler finish your hunks of code with a NOP \
when your code is not long word aligned.

  The last object file will also contains all \
init/exit hunks with that simple hunk of code \
which is the RTS. In DICE that file is the 'x.o' \
object. An RTS instruction will be used while initializing \
if you need to report a failure. DICE have a function \
named '__AutoFail' for this purpose.

  Note: all hunks having one of those names must be \
of type code.

  Example:

  file 'c.a'
[2]
    ...
    JSR     _autoinit0
    BEQ     .error      ;Exit now
    JSR     _autoinit1
    BEQ     .error
    JSR     __main
    JSR     _autoexit0  ;The order is user choice
    JSR     _autoexit1
    ...
[1]
  file 'myinit.a'
[2]
    LEA      _cnttable,A0
    MOVE.W  #$00FF,D0
.next
    MOVEQ   #$00,D1
    MOVEQ   #$07,D2
.cnt
    BTST.B  D2,D0
    BEQ.B   .iszero
    ADDQ.B  #$01,D1
.iszero
    DBF     D2,.cnt
    MOVE.B  D1,(A0)+
    DBF     D0,.next
                        ;<- NO RTS!
[1]
  file 'x.a'
[2]
    RTS
[1]
  See also:
[L;3][LINK block]		    BLOCKUNIT
[LINK block]			    BLOCKHUNK
[LINK cc]			    CC
[LINK dice]			    DICE
[LINK slink]			    SLINK
[5; LINK about; GOTO address]	    Become Registred
[LANGUAGE français]
[C;6;B]		Auto-Initialisation
		Auto-Exit
[J;1;N]
  Actuellement, lk supporte deux types de code d'initialisation \
et de sortie. Ceux-ci sont:
[C;3; GOTO slink]		Slink
[1]			et
[3; GOTO dice]			DICE
[J]
[LABEL slink; 5]  . Automatisation de Slink:
[1]
  Pour fonctionner avec lk vous avez besoin d'utiliser \
la commande SLINK.

  Pour avoir une initialisation automatique, SAS/C créé \
des fonctions nommées __STI<nom de fonction> et \
@_STI<nom de fonction> (La seconde correspond à la même \
fonction directement appelée avec les registres - sans \
qu'ils soient sauvés sur la pile.) Ces fonctions sont \
nommées 'CREATORS' (Créateur). 
  Pour avec un code automatique de sortie, SAS/C créé \
des fonctions nommées __STD<nom de fonction> et \
@_STD<nom de fonction>. Ces fonctions sont nommées \
'DESTRUCTORS' (Destructeurs).
  Le code (ou les données) qui nécessites ces initialisations \
et ce code de sortie sont tous présent dans la même unité.
  Le désaventage de cette méthode est de créer un pointeur de \
relocation pour chaque fonctions. Ceci prend un temps et de \
l'espace important. La méthode suivante ne possède pas ce \
désaventage.
[5]
  L'exemple suivant est une illustration des fonctions \
de SAS/C. Notez qu'il ne s'agit pas d'une copie des \
originaux. Rien ne vous oblige à utiliser ces \
modèles.
[1]
  Pour appeler chacune des ces fonctions, vous avez \
besoin d'une fonction nommée '___construct'. lk créra \
deux listes l'une derrière l'autre toutes deux terminées \
par un pointeur null, et devant la première table un \
pointeur à la fonction '___contruct' sera sauvé. En C, \
les déclarations sont:
[2]
    int (*)(void) __ctors[[];
    void (*)(void) __dtors[[];

  /* construct est appelé avec ctors et dtors */
    extern int __construct(int (*)(void)[[]);

  avec '__ctors[[-1] == __construct'
  et   '__ctors[[LASTFUNC + 1] == 0'
[1]
  Exemple de fonctions appelant '___construct':
[2]
  int __init()
  {
    return (__construct(_ctors));
  }

  int __exit()
  {
    return (__construct(_dtors));
  }
[1]
  Bien sûr, il vous faudra faire un appel à ces \
deux fonctions.

  Exemple de fonction '___construct':
[2]
  int __construct(int (_tors*)(void))
  {
    int r = 0;

    while(*_tors) {
 /*
  * Ceci suppose que les tous les destucteurs
  * retournent toujours FALSE.
  */
      if(!r) r = (*_tors)();
      _tors++;
    }

    return (r);
  }
[1]
  Note: SAS/C possède un drapeau lui permettant de savoir \
s'il appel les fonction de création ou de destruction.

  Le fichier objet resemble à:
[2]
    hunk_unit  <nom d'unité>
    hunk_name  <nom de hunk>
    hunk_code  <code 680x0>
         (il pourrait s'agir d'un hunk de données)
    hunk_ext   <ext_def: fonction(s) utilisateur>
               et autres externes
    hunk_end
    hunk_name  <nom du hunk d'initialisation>
    hunk_code  <code 680x0>
    hunk_ext   <ext_def: __STI<fonc. utilisateur>
               et autres externes
    hunk_end
    hunk_name  <nom du hunk de sortie>
    hunk_code  <code 680x0>
    hunk_ext   <ext_def: __STD<fonc. utilisateur>
               et autre externes
    hunk_end
[1]
  Note: il n'est absolument pas nécessaire d'avoir les \
fonctions STI/STD dans un hunk différent que le hunk \
utilisateur. Chacun des noms de hunk et de fonction \
peut être différent. Tous les autres hunks peuvent \
apparaître comme à l'habitude.

  Pour assurer que l'ordre voulu est respecté, les noms \
des créateurs et destructeurs peuvent inclure un niveau. \
La fonction créatrice avec le niveau le plus petit sera \
appelée la première et celle avec le niveau le plus \
élevé sera la dernière appelée. Pour les fonctions \
destructrices, l'ordre est inversé; les fonctions avec \
le niveau le plus petit seront appelée les dernières \
et les fonctions avec le niveau le plus grand seront \
appelées les premières. Lorsqu'aucun niveau n'est donné \
le niveau par défaut, qui est 30000, est utilisé. Le \
niveau est une valeur 32 bits. Pour les fonctions \
ayant le même niveau, elles sont appelées dans l'ordre \
quelles sont définie (néanmoins lk ne le garantie pas).
  En voici la syntaxe générique:
     __ST?[[_]<valeur><nom utilisateur>
  autant de caractère '_' peuvent apparaître \
avant la valeur proprement dite.

  Exemple de noms:
[2]    __STI3890_MyInit     (Called before defaults)
    @_STD__81956_MyExit  (Called after defaults)
[1]
  La fonction d'initialisation, en C, est déclarée comme \
suit:
[2]     extern int _STImoninit(void);
[1]  quand un créateur retourne vrai (une valeur autre \
que zéro) les créateurs suivant ne sont pas appelés.

  La fonction de sortie, en C, est déclaré comme suit:
[2]     extern void _STDmasortie(void);
[1]  avec la fonction par défaut de SAS/C, toutes les \
fonctions de destructions sont toujours appelées, même \
si l'initialisation correspondante n'a jamais eut lieu.

  Comment l'utiliser:

    Par exemple, si vous définisez une fonction qui \
à besoin de la base d'intuition, vous écririez:
[2]
  external void *Intuition;
  ...
    #asm
      MOVEA.L _Intuition(A6)
      JSR _LVOOpenWorkBench(A6)
    #endasm
  ...
[1]
    Les fonctions correspondantes d'initialisation et \
de sortie sont:
[2]
  void *Intuition;
  _STI_OpenIntuition()
  {
    Intuition = OldOpenLibrary
[R]			("intuition.library");
[L]    return (!Intuition);
  }

  void *Intuition;
  _STD_CloseIntuition()
  {
    if(Intuition) {
      CloseLibrary(Intuition);
      Intuition = (void *) 0;
    }
  }
[1]
[LABEL DICE; 5]  . Automatisation de DICE:
[1]
  Ce mode nécessite l'utilisation de l'option BLOCKUNIT \
(et éventuellement CC). L'utilisation de DICE n'est \
nécessaire que si les fichier objets de DICE sont \
utilisés.

  dlink, pour avoir une initialisation automatique, utilise \
les noms de hunks autoinit et autoexit. Ces noms pourront \
être modifiés à volonté avec lk, il n'y a aucun restriction.
  Du fait que tous les hunks portant le même nom sont liés \
ensemble, tous les hunks autoinit et autoexit le seront. \
Ces hunk seront rencontrés dans la même unité que la \
fonction ou les données qui nécessite ces automatisations. \
Vous avez besoin d'avoir un hunk distinct pour chaque \
élément: un hunk de code (ou donnée) utilisateur, un hunk \
pour le code d'initialisation, un hunk pour le code de \
sortie. Pour créer plusieurs niveaux, pluseurs noms \
sont utilisés (comme autoinit1, autoinit0, ...) L'entête \
appelera chacun de ces groupes hunks l'un après l'autre.

  Actuellement DICE utilise autoinit0, autoinit1, \
autoexit0, autoexit1 et autoconfig. Le seul petit \
problème ave DICE est le fichier 'c.o' qui contient \
quelques 'relocs' pointant à des hunks vides. Ceci aurait \
put être évité avec un instruction NOP dans ce hunk vide. \
Néanmoins lk sait comment les utilisés, mais il vous \
faut spécifier l'option DICE pour ceci.
  Avec DICE, la différence entre autoinit et autoconfig \
est dans le fait que autoinit peut returner une erreur.

  Les fonctions d'initialisation ou de sortie ne sont \
pas terminées par le RTS habituel. Ceci permet, avec \
un simple appel, d'exécuté toutes les fonctions d'un \
niveau donné. Pour créer ce type de hunk, vous pouvez \
utiliser DICE qui permet la création de fonctions \
d'initialisation et de sortie, sinon utilisez votre \
assembleur préféré. Il vous faudra néanmoins vérifier \
que votre assembleur termine bien votre hunk de code \
avec une instruction NOP lorsque votre code n'est \
pas aligné à un mot long.

  Le dernier fichier objet et celui qui contien \
l'instruction RTS pour chacun des hunks d'initialisation \
et de sortie. Le fichier de DICE pour faire ceci \
s'appel 'x.o'. Un RTS sera néanmoins utilisé s'il \
vous faut reporter une erreur durant l'initialisation. \
Avec DICE ceci est réalisé par la fonction '__AutoFail' \
que vous pouvez appeler a tout moment.

  Note: tous les hunks portant ces noms DOIVENT être \
de type code.

  Exemple:

  fichier 'c.a'
[2]
    ...
    JSR     _autoinit0
    BEQ     .error      ;Sort now
    JSR     _autoinit1
    BEQ     .error
    JSR     __main
    JSR     _autoexit0  ;L'order est aux choix
    JSR     _autoexit1  ; de l'utilisateur
    ...
[1]
  fichier 'myinit.a'
[2]
    LEA      _cnttable,A0
    MOVE.W  #$00FF,D0
.next
    MOVEQ   #$00,D1
    MOVEQ   #$07,D2
.cnt
    BTST.B  D2,D0
    BEQ.B   .iszero
    ADDQ.B  #$01,D1
.iszero
    DBF     D2,.cnt
    MOVE.B  D1,(A0)+
    DBF     D0,.next
                        ;<- NO RTS!
[1]
  fichier 'x.a'
[2]
    MoveQ   #$00,D0     ;No error!
    RTS
[1]
  Voir:
[L;3][LINK block]		    BLOCKUNIT
[LINK block]			    BLOCKHUNK
[LINK cc]			    CC
[LINK dice]			    DICE
[LINK slink]			    SLINK
[5; LINK about; GOTO address]	    Être Enregistré
