        ;
        ;   EXIT.A  (Alfred Faust , 2001)
        ;   adapted from  C.A
        ;
        ;   to compile Tools&Accessories for Bars&Pipes
        ;   Mainly for use the __exit and __MemList functions while linking
        ;   without to have the _main (Tools&Accessories are not
        ;   selfstarting programs).
        ;
        ;   Use it in conjunction of x.o at the last position in the link
        ;   chain.
        ;
        ;   Example:
        ;
        ;   dlink mmc.o exit.o cs.lib amiga3.1s.lib x.o -o MMC.paccess
        ;
        ;   (C)Copyright 1990-1992, Matthew Dillon, All Rights Reserved
        ;
        ;   Amiga startup code for resident and non-resident DCC programs.
        ;
        ;   DLINK supplied variables:
        ;
        ;   * __BSS_LEN   : # long words of BSS (occurs after DATA)
        ;   * __DATA_LEN  : # long words of initialized data to copy
        ;                   (if resident)
        ;   * __DATA_BAS  : Base of data (read only if resident)
        ;   * __RESIDENT  : Is this code residentable?  If this variable
        ;                   is set then there are no absolute data/bss
        ;                   references except __DATA_BAS and there is
        ;                   NO BSS MEMORY ALLOCATED AFTER THE DATA
        ;                   SECTION.
        ;
        ;                   If this variable is not set then absolute
        ;                   references refer to the same storage as
        ;                   A4 relative accesses and uninitialized
        ;                   BSS space exists just after the data section.
        ;
        ;                   Note that in the large-data model + fragmented
        ;                   sections, there are usually real BSS hunks
        ;                   floating about that have been zerod by
        ;                   LoadSeg() (in this case __BSS_LEN could be 0)
        ;
        ;   COMPILER:
        ;
        ;   * If -r option specified when compiling then the compiler
        ;     will generate autoinit code to handle data initialization
        ;     that would otherwise require a reloc32 hunk.
        ;
        ;   * If -r or -md specified compiler references all data items
        ;     using A4-Relative addressing.
        ;
        ;   C LIB CODE:
        ;
        ;   * Resident:         Allocate (__DATA_LEN+__BSS_LEN)*4
        ;     Not Resident:     Zero out preallocated BSS.
        ;
        ;   * Generate A4 ref ptr to bss base + 32766 (uses Aztec's
        ;     conventions).
        ;
        ;   * All library code uses the SMALL-DATA with alternate
        ;     BSS and DATA section names (based in this source
        ;     file) so the linker puts library related data/bss
        ;     first.  BUT, BSS always comes after DATA unless
        ;     you -frag the link (can't resident a frag'd link),
        ;     so if there is more than 64KBytes of *initialized*
        ;     data you must -frag the link.
        ;
                section text,code

                xref    __RESIDENT      ; (dlink), executable is residentable
                xref    __BSS_LEN       ; (dlink), length of BSS
                xref    __DATA_BAS      ; (dlink), base of initialized data
                xref    __DATA_LEN      ; (dlink), length of data


                xref    _LVOSetSignal
                xref    _LVOAllocMem
                xref    _LVOFreeMem
                xref    _LVOForbid
                xref    _LVOReplyMsg

                xdef    __exit          ; we are _exit()

start:
;;;;;;;;;;;;;;;;movem.l D2-D7/A2-A6,-(sp)       ;Not needed!

                move.l  4.W,A6              ; Exec base

                move.l  sp,A2
                move.l  A0,-(sp)            ; save arg for _main() call
                move.l  D0,-(sp)            ; save arglen for _main() call

                ;   If we are flagged resident then there is NO BSS ALLOCATED
                ;   If we are not flagged resident then BSS IS ALLOCATED AFTER
                ;       DATA, BUT NOT CLEARED.

                move.w  #__RESIDENT,D0
                beq     snotres

                ;   Allocate BSS+DATA space and then copy static data.

                move.l  #__BSS_LEN,D0
                add.l   #__DATA_LEN,D0
                asl.l   #2,D0               ; x4
                addq.l  #8,D0               ; MemList header extra
                move.l  D0,D5               ; D5 = #bytes
                moveq.l #0,D1               ; Any memory ok
                jsr     _LVOAllocMem(A6)
                tst.l   D0
                bne     alok
                move.l  A2,sp
                moveq.l #-1,D0
                bra     exfail

alok            move.l  D0,A0
                clr.l   (A0)+               ; MemList entry next ptr
                move.l  D5,(A0)+            ; MemList entry #bytes
                lea     32766(A0),A4        ; SET A4
                lea     -8(A0),A3           ; A3 = MemList entry base
                                            ; can't copy to MemList(A4) yet


                ;   Copy data to allocated copy

                                            ; A0 = dst
                lea     __DATA_BAS,A1       ; A1 = src
                move.l  #__DATA_LEN,D0      ; D0 = long words
                bra     bssent
bsslop          move.l  (A1)+,(A0)+
bssent          dbf     D0,bsslop
                sub.l   #$10000,D0
                bcc     bsslop
                bra     clrbss


                ;   Not resident, BSS space has been allocated for us
                ;   beyond the specified data, just load the base ptr

snotres         lea     __DATA_BAS,A4
                lea     32766(A4),A4
                sub.l   A3,A3

clrbss
                ;   CLEAR BSS   &-32766(A4) + __DATA_LEN*4

                lea     -32766(A4),A0
                move.l  #__DATA_LEN,D0
                asl.l   #2,D0
                add.l   D0,A0

                move.l  #__BSS_LEN,D0       ; longwords of bss
                moveq.l #0,D1
                bra     clrent
clrlop          move.l  D1,(A0)+
clrent          dbf     D0,clrlop
                sub.l   #$10000,D0
                bcc     clrlop

                move.l  A3,___MemList(A4)   ; memlist entry (if resident)
                move.l  A2,__ExitSP(A4)     ; sp to restore

                moveq.l #0,D0               ; new signals
                move.l  #$1000,D1           ; signal mask
                jsr     _LVOSetSignal(A6)   ; clear ^C


                ;   Return value of 0 indicates succcess.  Flags
                ;   have been set.
                ;
                ;   Note that if the standard _main entry point is used,
                ;   the very first autoinit0 code will check for and
                ;   retrieve the workbench message.

                jsr     __AutoInit0         ; A6 has SYSBase
                bne     xfail
                pea     1.W                 ; autoconfig loader
                jsr     __AutoConfig        ; note, rt pulls stack
                addq.l  #4,sp
                jsr     __AutoInit1         ; A6 has SYSBase
                bne     xfail

                ;   fall through to low level exit... this avoids referencing
                ;   exit() if the user overides _main().

xfail
                clr.l   -(sp)
                clr.l   -(sp)

                ;   _EXIT()
                ;
                ;   since entry uses malloc we must free any incidental memory
                ;   at __exit instead of _exit.
                ;
                ;   ReplyMsg(_WBMsg) just before returning

__exit:
                pea     -1.W
                jsr     __AutoConfig        ; note, rt pulls stack
                addq.l  #4,sp
                move.l  _SysBase(A4),A6
                jsr     __AutoExit1         ; A6 has SysBase
                jsr     __AutoExit0         ; A6 has SysBase

                move.l  4(sp),D0
                move.l  __ExitSP(A4),A7     ; get sp... because we might free
                                            ; the space taken by the variable!
                move.l  D0,-(sp)            ; save exit code on original stack

                move.l  ___MemList(A4),D0   ; free memory
                beq     ex20

ex10            move.l  D0,A2
                move.l  (A2),A3             ; next...
                move.l  4(A2),D0            ; bytes
                move.l  A2,A1               ; ptr
                jsr     _LVOFreeMem(A6)
                move.l  A3,D0               ; next...
                bne     ex10

ex20
                move.l  (sp)+,D0            ; get exit code
                ;move.l  4(sp),D0            ; get exit code
                ;move.l  A5,sp               ; restore sp

                tst.l   D6                  ; reply to workbench msg if it
                beq     ex30                ; exists
                jsr     _LVOForbid(A6)      ; forbid through exit
                move.l  D6,A1
                jsr     _LVOReplyMsg(A6)

ex30
                ;   FINIS, poof.

exfail
;;;;;;;;;;;;;;;;movem.l (sp)+,D2-D7/A2-A6
                rts


                ;   Base of autoinit section

                section autoinit0,code
__AutoInit0:
                section autoinit1,code
__AutoInit1:
                section autoexit0,code
__AutoExit0:
                section autoexit1,code
__AutoExit1:
                section autoconfig,code
__AutoConfig:


                ;   All library C code is compiled with the -S option
                ;   which uses 'libdata' and 'libbss' section names,
                ;   forcing library data to come before program data
                ;   and library bss to come before program bss (because
                ;   library data/bss sections are declared here first
                ;   and sections of like name are coagulated).
                ;
                ;   All items are declared as data instead of bss, even
                ;   through they could be bss, to support a >64K of
                ;   initialized data with the small-data libraries.

                section libdata,data

                xdef    ___MemList      ; Used by malloc/free
                xdef    __ExitSP

_SysBase        ds.l    1               ; Pointer to exec.library
__ExitSP        ds.l    1               ; Stack pointer for use in exit
__WBMsg         ds.l    1               ; Workbench startup message
___MemList      ds.l    1               ; List of allocated memory

                section libbss,bss
_Reserved       ds.l    0               ; Force section to exist (dummy)

                END

