*--------------------------------------------------------------------* * Startup code to create reentrant program files using the * Manx Aztec 'C' compiler (any version). * * Created by: Olaf Barthel, MXM * Brabeckstrasse 35 * D-3000 Hannover 71 * * Federal Republic of Germany * * * Z-Net: O.BARTHEL@A-Link-H * Fido: Olaf Barthel@2:247/200 * Sub: olsen@veeble.uucp * UUCP: olsen%veeble@horga.as.sub.org * * Copyright (C) 1990 by MXM, all rights reserved. * *--------------------------------------------------------------------* * * This startup code permits to create 100% reentrant programs. * Neither is arp.library required, nor is the program to be * terminated via exit() (such as with Lattice/SAS 'C'). * * The following conditions must be met for the program to * work properly: * * 1) The program MUST not use the large code/large data model. * * 2) The program MUST not use scatter loading or overlays. * * Since the entire data segment, containing initialized * and uninitialized data (bss), is cloned both data types * will reside in the same type of memory (chip/public). * This may not be a problem since it already is the default * with the small memory/small data model. * * Important! Your program MUST not perform a segment split * using the detach.o?? module or its segment list * will be deallocated. Should this happen the next * call to your resident program will crash your * Amiga! * * Should you discover any 'undocumented features' or errors * in this program, please DO inform me ASAP! * *--------------------------------------------------------------------* * * To create a resident program, use the following sequence: * * AS Resident.asm * CC * * LN Resident.o -Lc * *--------------------------------------------------------------------* include "exec/types.i" include "exec/tasks.i" include "exec/alerts.i" include "exec/memory.i" include "exec/execbase.i" include "libraries/dosextens.i" *--------------------------------------------------------------------* * * Global macro definitions (doesn't use asmsupp.i). * *--------------------------------------------------------------------* CALL macro xref _LVO\1 jsr _LVO\1(a6) endm AbsExecBase equ (4).w *--------------------------------------------------------------------* * * Global static and shared data. * *--------------------------------------------------------------------* dseg DosName: dc.b 'dos.library',0 ; Name of dos.library. MemName: dc.b 'MXM',0 ; Identification of the ; cloned data segment. public __H1_org,__H1_end,__H2_org,__H2_end public __savsp,_SysBase,_DOSBase *--------------------------------------------------------------------* cseg entry .begin public .begin,_geta4,__main mc68881 *--------------------------------------------------------------------* * * Global entry point of the program to follow. * *--------------------------------------------------------------------* .begin move.l sp,a3 ; Remember stackpointer. far data lea __H1_org+32766,a4 ; Get the data base register. near data lea __H1_end,a1 lea __H2_org,a2 cmp.l a1,a2 ; Small code/small data? bne Error1 ; Obviously not! movem.l d0/a0,-(sp) ; Remember command line. lea __H1_org,a1 ; Where's the data segment? move.l AbsExecBase,a6 ; SysBase. CALL TypeOfMem ; Check memory type bset #MEMB_CLEAR,d0 ; We want clear memory. bclr #MEMB_FAST,d0 ; Not necessarily fast mem! *--------------------------------------------------------------------* * * We will create a MemEntry structure right on the stack and * will copy the contents of the data segment to the allocated * block of memory. * *--------------------------------------------------------------------* pea (__H2_end-__H1_org).w ; Length of data segment. move.l d0,-(sp) ; Type of memory. pea (1).w ; Number of entries (1). clr.l -(sp) ; Node... clr.l -(sp) ; Still node... clr.l -(sp) ; Ever still node... lea (sp),a0 ; Start of MemEntry. CALL AllocEntry ; Allocate! add.w #24,sp ; Fix the stack. move.l d0,a1 ; Did we get an entry? beq Error2 ; Fix the stack and quit! pea (a1) ; Put it on the stack. *--------------------------------------------------------------------* * * To help geta4() to identify the MemEntry we will give it * a unique name. * *--------------------------------------------------------------------* lea MemName,a0 ; Get the node name. move.l a0,LN_NAME(a1) ; Put it in the MemEntry. move.l ThisTask(a6),a0 ; Get current task. lea TC_MEMENTRY(a0),a0 ; Look for MemList. CALL AddTail ; Add the MemEntry. move.l (sp)+,a1 ; Get the MemEntry. move.l ML_SIZE+ME_ADDR(a1),a1 ; Remember memory block. lea __H1_org,a0 ; Get start of data segment. move.l #((__H1_end-__H1_org)/4)-1,d0 ; Remember its length. *--------------------------------------------------------------------* * * This loop will copy the contents of the data segment to * our 'fake' segment. * *--------------------------------------------------------------------* 1$ move.l (a0)+,(a1)+ ; Copy data. dbra d0,1$ *--------------------------------------------------------------------* * * Do the last setups for the main program. * *--------------------------------------------------------------------* start bsr _geta4 ; Load the base register. move.l a3,__savsp ; Set the original stack ; pointer. lea DosName,a1 ; Name of dos.library. moveq #0,d0 ; No special version. CALL OpenLibrary ; Open the tin... move.l d0,_DOSBase ; Successful? bne 2$ ; Start the main program. move.l #AG_OpenLib!AO_DOSLib,d7 ; Blast! lea ThisTask(a6),a5 ; Current task. CALL Alert ; Call Mr.Guru. bra Error2 ; Finish it. 2$ move.l a6,_SysBase ; Set SysBase. andi.w #AFF_68881,AttnFlags(a6) ; FPU present? beq 3$ lea Restore,a5 CALL Supervisor ; Reset FPU. 3$ jsr __main ; Call main routine. addq.l #8,sp ; Fix the stack. *--------------------------------------------------------------------* * * If __main simply 'drops through' dos.library won't have been * closed. To keep the counts even, we will test if DOS is still * open and close it if necessary. * *--------------------------------------------------------------------* move.l _DOSBase,a1 move.l a1,d0 ; dos.library still open? beq 4$ ; Don't think so. move.l AbsExecBase,a6 ; SysBase. CALL CloseLibrary ; Close the library. 4$ rts ; Back to shell. *--------------------------------------------------------------------* Error2: addq.l #8,sp ; Fix the stack. move.l AbsExecBase,a6 ; SysBase. *--------------------------------------------------------------------* * * This part handles early startup failure. If this program was * started from Workbench the startup message will probably * be roaming around. We will intercept it and send it back * to the caller. * *--------------------------------------------------------------------* move.l ThisTask(a6),a0 ; Get current task. tst.l pr_CLI(a0) ; Started from Workbench? bne Error1 lea pr_MsgPort(a0),a0 ; Remember our MsgPort. move.l a0,a3 CALL WaitPort ; Wait for WBenchStartup. move.l a3,a0 ; Return MsgPort. CALL GetMsg ; Pick up WBenchMsg. move.l d0,a3 ; Remember Message. CALL Forbid ; Turn off multitasking. move.l a3,a1 ; Return the message. CALL ReplyMsg ; And reply it. Error1: moveq #-1,d0 ; Failed! rts *--------------------------------------------------------------------* * * This subroutine will reset the FPU (if any)! * *--------------------------------------------------------------------* Restore: clr.l -(sp) frestore (sp)+ ; Reset the FPU. rte *--------------------------------------------------------------------* * * One of the most important routines of this file. Sets * the global data segment pointer to a defined value. * *--------------------------------------------------------------------* _geta4: movem.l d0-d1/a0-a1/a6,-(sp) ; Save some registers. move.l AbsExecBase,a6 ; SysBase. move.l ThisTask(a6),a0 ; Get current task. lea TC_MEMENTRY(a0),a0 ; Remember MemList. lea MemName,a1 ; Get name of MemEntry. CALL FindName ; Scan the list... move.l d0,a1 move.l ML_SIZE+ME_ADDR(a1),a4 ; Start of data segment. lea 32766(a4),a4 ; Add the offset. movem.l (sp)+,d0-d1/a0-a1/a6 ; Restore all registers. rts *--------------------------------------------------------------------* end