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 */