*
* AmigaDOS RESIDENTABLE C PROGRAMS (initial startup)
* for SAS/C® Development System V6.0 and higher
*
* "shellcres2.a" is loosely based on the original startup module "c.a"
*
* "c.a" startup module Copyright © SAS Institute
* "shellcres2.a" startup module by Gabriele Falcioni
*
* - Minimal version.
* - Shell Only. Workbench StartupMsg not handled.
* - Opens exec.library and dos.library V37+
* - Requires SAS/C V6.0 or higher.
*
* - Module interface:
*
* void __stdargs early_main(void);	/* user entry point */
* void late_exit(long code);			/* exit code entry point */
*
* Use the following command line to make shellcres2.o
* asm -u -iINCLUDE: shellcres2
*

	INCLUDE "exec/types.i"
	INCLUDE "exec/memory.i"
	INCLUDE "exec/funcdef.i"
	INCLUDE "exec/execbase.i"
	INCLUDE "exec/exec_lib.i"

	INCLUDE "dos/dos.i"
	INCLUDE "dos/dosextens.i"

*****************************************************************************

callsys MACRO
	JSR	_LVO\1(A6)
	ENDM

*****************************************************************************

	XREF	LinkerDB			; linker defined base value
	XREF	_BSSBAS			; linker defined base of BSS
	XREF	_BSSLEN			; linker defined length of BSS

	XREF	RESLEN
	XREF	RESBASE
	XREF	NEWDATAL

STDMEM			EQU	(MEMF_CLEAR!MEMF_PUBLIC)
AbsExecBase		EQU	4

*****************************************************************************
* The very first line of code...
*****************************************************************************

	SECTION text,code

	XREF	early_main		; C entry point: void early_main(void)
	XDEF	late_exit		; C exit point:  void late_exit(long code)
	XDEF	@late_exit		; like above but registerized parameters

beginprog:
		movem.l	d2-d6/a2-a6,-(a7)		; backup registers...

		lea		LinkerDB,a4
		move.l	AbsExecBase.W,a6

		;
		; allocate a new data section
		;

		move.l	#RESLEN,d0
		move.l	#STDMEM,d1
		callsys	AllocMem
		tst.l		d0
		bne.b		1$

		;
		; ERROR!
		; can't allocate new DATA block
		;

		move.l	ThisTask(a6),a0		; myself
		moveq		#ERROR_NO_FREE_STORE,d0
		move.l	d0,pr_Result2(a0)

		moveq		#RETURN_FAIL,d0
		bra		endprog

1$:	move.l	d0,a2						; a2: ptr to new data block

		;
		; SANITY CHECK:
		; if a4 is NULL then we have only a BSS section!
		; In this case, skip copy and relocation steps
		;

		move.l	a4,d0
		beq.b		nreloc

		;
		; copy data section
		;

		move.l	a2,a0
		sub.l		#RESBASE,a4
		move.l	#NEWDATAL,d0
		subq.l	#1,d0

2$:	move.l	(a4)+,(a0)+
		dbf		d0,2$

		;
		; relocate (if required) new data section
		;

		move.l	(a4)+,d0
		beq.b		nreloc					; check if relocation required

3$:	move.l	a2,a0
		add.l		(a4)+,a0					; a0 now has addr of reloc
		move.l	a2,a1
		add.l		(a0),a1					; sum block addr to reloc offset
		move.l	a1,(a0)
		subq.l	#1,d0
		bne.b		3$

nreloc:
		move.l	a2,a4						; set up new base register
		add.l		#RESBASE,a4

		;
		; open dos.library V37+
		;

		lea		doslib_name(PC),a1
		moveq		#37,d0					; request Release 2
		callsys	OpenLibrary

		move.l	d0,DOSBase(a4)			; set DOSBase and QUIT (with error) if NULL
		bne.b		go_main

		;
		; ERROR!
		; can't open dos.library V37+
		;

		move.l	ThisTask(a6),a0		; myself
		moveq		#ERROR_INVALID_RESIDENT_LIBRARY,d0
		move.l	d0,pr_Result2(a0)

		moveq		#RETURN_FAIL,d2
		bra.b		freeres

		;
		; call main program
		;

go_main:
		move.l	a7,stackptr(a4)		; save stack ptr
		move.l	a6,SysBase(a4)			; "open" exec.library

		jsr		early_main(PC)			; The Game Begins...

		moveq		#0,d0
		bra.b		@late_exit

late_exit:
		move.l	4(a7),d0					; extract return code

@late_exit:
		move.l	d0,d2						; save return code

		move.l	stackptr(a4),a7		; restore stack ptr
		move.l	SysBase(a4),a6			; restore SysBase

freedos:
		move.l	DOSBase(a4),a1
		callsys	CloseLibrary			; close dos.library

freeres:
		move.l	#RESLEN,d0
		move.l	a4,a1
		sub.l		#RESBASE,a1
		callsys	FreeMem

		move.l	d2,d0						; restore return code

endprog:
		movem.l	(a7)+,d2-d6/a2-a6		; restore registers...
		rts									; ...and QUIT!

doslib_name:
		dc.b 'dos.library',0

*****************************************************************************

	SECTION __MERGED,BSS

	XDEF SysBase
	XDEF DOSBase

stackptr:	ds.l	1
SysBase:		ds.l	1
DOSBase:		ds.l	1

	END
