[comp.sys.atari.st] GEMDOS memory managment with Megamax

braner@batcomputer.tn.cornell.edu (braner) (01/19/87)

[]

Here is an elegant solution to the problem of controlling GEMDOS allocation
of program memory for a C program compiled with Megamax.  In addition, this
solution allows easy choice of stack size from the C source code of a program.

Below is a modified version of the Megamax 'init.c'.  Compile it ONCE (ignore
the compiler warnings) and then replace the 'init.o' module in syslib with it:

	mmcc init.c
	mmlib R syslib init.o

Save syslib.  In your programs from now on, somewhere in the C source (but
NOT inside a function, i.e. NOT as an automatic variable!), add the line:

	long _stacklen = 123456;

(or whatever length you want the stack to be) and then compile and link
as usual - no fuss.  But note that you HAVE to have that line in the source,
or else the linker will complain about not finding '_stacklen' (which is used
in the new 'init').

Note that '_stacklen' is 'long': you can make it any size you want, so EACH
function in your code can have up to 32K of automatic variables, and you can
use code that's recursive to any depth - provided that you set _stacklen big
enough (and that you have enough RAM in the hardware).

If you want to do Ptermres(lots), use "long _stacklen = lots+some;"

Finally, the addresses of the top and bottom of the stack are in the global
variables _stacktop and _stackbot (defined in init.c as integer pointers).
You can set up a big stack and then use some of it for data storage (as a
static array) via the _stackbot pointer.  Make sure that there is enough space
left between the top of that data block and _stacktop for the actual stack
requirements.  While malloc() is limited to 64K, this data-storage method lets
you have arrays of ANY size.  But the MAXIMUM space has to be allotted when
the program is invoked, and cannot be returned to the system while the program
is running.  If that is a problem use Malloc() (capital M).  And remember:
this method (and calling Malloc(), too!) is NOT portable C.

- Moshe Braner

~~~~~~~~~~~~~~~~~~~ cut here ~~~~~~~~~~~~~~~~~~~~~~~
/*
 *	This is the very first stuff that executes when a program is run.
 *	It sets up the global variables, strings, stack etc.
 *
 *	Modified for variable stack length by Moshe Braner, 870119.
 */

/* Base page definitions */

#define ltpa 0		/* Low TPA address	*/
#define htpa 4		/* High TPA address	*/
#define lcode 8		/* Code segment start	*/
#define codelen 12	/* Code segment length	*/
#define ldata 16	/* Data segment start	*/
#define datalen 20	/* Data segment length	*/
#define lbss 24		/* Bss  segment start	*/
#define bsslen 28	/* Bss  segment length	*/
#define freelen 32	/* free segment length	*/
#define resvd 36	/* Reserved		*/
#define fcb2 56		/* 2nd parsed fcb	*/
#define fcb1 92		/* 1st parsed fcb	*/
#define command 128	/* Command tail		*/

extern _init(), _main(), main(), _initargcv(), exit();

char *_base;		/* points to base page of program	*/

extern long _stacklen;	/* NEEDS TO BE DEFINED AS AN INITIALIZED
			   NON-AUTO VARIABLE IN C SOURCE!	*/

int  *_stackbot;	/* POINTER TO BOTTOM OF USER STACK	*/
int  *_stacktop;	/* POINTER TO TOP OF USER STACK		*/

overlay "init!"
asm {
	_init:		/* initialization entry point;
			   RTS plugged in by linker		*/
}

int _argc;		/* initialized by _initargcv		*/
char **_argv;

overlay "main"
asm {
_main:
	move.l	A7,A5		; save A7 so we can get the base page address
	move.l	4(A5),A5	; A5=basepage address
	move.l	lbss(A5),D0
	move.l	D0,A0		; for later
	add.l	bsslen(A5),D0	; D0 points at end of bss segment
	move.l	D0,A1		; for later
	add.l	#256,D0		; add size of temporary user stack
	and.l	#-2,D0		; ensure even byte boundary
	move.l	D0,A7		; set up temporary user stack	
	move.l	datalen(A5),D0	; swap data and bss segments
	subq.l	#1,D0		; dbf loop is stupid
	ble.s	swapcont	; might not have any data
swap:
	move.b	-(A0),-(A1)
	dbf	D0,swap
swapcont:
	move.l	ldata(A5),A0	; clear bss segment
	move.l	bsslen(A5),D0
	subq.l	#1,D0
	ble.s	clrcont		; might not have any bss?
clear:	
	clr.b	(A0)+
	dbf	D0, clear
clrcont:
	move.l	ldata(A5),A4	; A4 points between bss and data
	adda.l	bsslen(A5),A4
	move.l	A5,_base(A4);
	move.l	lcode(A5),A5	; A5 points to jump table
	jsr	_init		; initialize globals and statics now
	move.l	_base(A4),A0	; retrieve base page pointer
	move.l	#256,D0		; base page length
	add.l	codelen(A0),D0
	add.l	datalen(A0),D0
	add.l	bsslen(A0),D0	; D0 = total length (less stack)
	move.l	D0,D1
	add.l	A0,D1		; compute stack bottom
	btst	#0,D1		; ensure even byte boundary
	beq.s	botev
	addq.l	#1,D1
botev:	move.l	D1,_stackbot(A4)
	add.l	_stacklen(A4),D0   ; HERE WE GET USER'S CHOICE!
	move.l	D0,D1
	add.l	A0,D1		; compute stack top
	and.l	#-2,D1		; ensure even byte boundary
	move.l	D1,_stacktop(A4)
	move.l	D0,-(A7)	; (still using temporary stack)
	move.l	A0,-(A7)
	clr.w	-(A7)		; junk word
	move.w	#0x4a,-(A7)	; return storage above stack to system
	trap	#1
	lea	12(A7),A7
	tst.l	D0		; CHECK FOR ERRORS!
	beq.s	ok
	move.w	#-39,-(A7)	; "not enough memory"
	jsr	exit
ok:	move.l	_stacktop(A4),A7   ; SETUP USER STACK!
	move.l	_base(A4),A0
	pea	command(A0)
	jsr	_initargcv	; parse command line into argc and argv
	addq.l	#4,A7
	move.l	_argv(A4),-(A7)
	move.w	_argc(A4),-(A7)
	jsr	main		; call application's entry point
	addq.l	#6,A7
	clr.w	-(A7)
	jsr	exit
}

/* end of init.c */