home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / alde_c / misc / lib / dlibssrc / dstart.s < prev    next >
Encoding:
Text File  |  1987-07-06  |  10.1 KB  |  318 lines

  1. ******************************************************************************
  2. *
  3. * dstart.s -- startup code for the C runtime library
  4. *    
  5. *    IMPORTANT: SEE THE DESCRIPTION OF THE "STACK" VARIABLE, BELOW.
  6. *
  7. *    This is the startup code for any application running on the Atari ST
  8. *    with the public domain standard library routines by Dale Schumacher.
  9. *
  10. *    This must be the first object file in a LINK command. When the
  11. *    operating system gives it control, our process has ALL of memory
  12. *    allocated to it, and our stack pointer is at the top.
  13. *    This code (conditionally) gives some of that memory back
  14. *    to the operating system, places its stack pointer at the top
  15. *    of the memory it still owns, sets up some global variables.
  16. *    It then calls __main, the run-time library startup routine
  17. *    (which parses the command line into argc/argv, opens stdin and
  18. *    stdout, etc., before calling the programmer's _main).
  19. *
  20. *    This object file also includes __exit, which is the procedure the
  21. *    runtime library calls to exit back to the operating system.
  22. *
  23. ******************************************************************************
  24. *
  25. *    CONFIGUING THIS STARTUP FILE
  26. *
  27. *    The __STKSIZ variable (which is _STKSIZ in C source files) tells
  28. *    the startup routine how much space to set aside for stack/heap.
  29. *    The malloc(), lalloc(), realloc(), etc. memory management functions
  30. *    DO NOT allocate space from the heap (unlike the Alcyon C routines),
  31. *    so you typically don't need a huge stack unless you're doing lots
  32. *    of recursion.
  33. *
  34. *    If __STKSIZ is positive, it represents the number of bytes of
  35. *    stack/heap that you want to reserve.  If __STKSIZ is negative,
  36. *    it means "keep all BUT -(__STKSIZ) bytes" for stack/heap.  There
  37. *    is a minumum stack/heap size assembled into this module called
  38. *    MINSTACK.  Regardless of what __STKSIZ is, you will get at least
  39. *    MINSTACK byte, or the program will exit with "no enough memory".
  40. *    If the __STKSIZ variable is not defined by your program (the
  41. *    linker gives us a NULL pointer in that case), MINSTACK will be
  42. *    used instead.
  43. *
  44. *        An example using __STKSIZ this in C is:
  45. *
  46. *            /* outside all function blocks */
  47. *            unsigned long _STKSIZ = 32767;    /* 32K stack+heap */
  48. *        or
  49. *            unsigned long _STKSIZ = -8192;    /* keep all but 8K */
  50. *
  51. *        Note that in C, all variables get an underscore stuck on
  52. *        the front, so you just use one underscore in your program.
  53. *        Note also that it has to be all upper-case.
  54. *
  55. *    Note that if you give back less than 512 bytes, you still shouldn't
  56. *    use Pexec(), and if you give back less than (about) 4K, you shouldn't
  57. *    use the AES or VDI.
  58. *
  59.  
  60. MINSTACK=4096        * minimum stack+heap size. (also __STKSIZ if undefined)
  61. FUDGE=512        * minimum space to leave ABOVE our stack
  62.  
  63. * BASEPAGE ADDRESSES:
  64. p_lowtpa=$0        * Low TPA address (basepage address)
  65. p_hitpa=$4        * High TPA address (and initial stack pointer)
  66. p_tbase=$8        * ptr to Code segment start
  67. p_tlen=$c        * Code segment length
  68. p_dbase=$10        * ptr to Data segment start
  69. p_dlen=$14        * Data segment length
  70. p_bbase=$18        * ptr to Bss  segment start
  71. p_blen=$1c        * Bss  segment length
  72. p_dta=$20        * ptr to process's initial DTA
  73. p_parent=$24        * ptr to process's parent's basepage
  74. p_reserved=$28        * reserved pointer
  75. p_env=$2c        * ptr to environment string for process
  76. p_cmdlin=$80        * Command line image
  77.  
  78. * GEMDOS functions:
  79. cconws=$09        * Cconws(string): write to console
  80. mshrink=$4a        * Mshrink(newsize): shrink a block to a new size
  81. pterm=$4c        * Pterm(code): exit, return code to parent
  82.  
  83. .globl    __STKSIZ    * global variable holding stack size
  84. .globl    __main        * required external function... calls user's main()
  85.  
  86. .globl    __base
  87. .globl    __break
  88. .globl    __argc
  89. .globl    __argv
  90. .globl    __envp
  91. * ?    .globl    ___cpmrv
  92.  
  93. *
  94. *  Must be first object file in link statement
  95. *
  96.     .text
  97. .globl    __start
  98. __start:
  99.     move.l    sp,a1        * save our initial sp (used by ABORT)
  100.     move.l    4(sp),a0    * a0 = basepage address
  101.     move.l    a0,__base    * base = a0
  102.     move.l    p_bbase(a0),d0    * d0 = bss seg start
  103.     add.l    p_blen(a0),d0    * d0 += bss length  (d0 now = start of heap)
  104.     move.l    d0,__break    * __break = first byte of heap
  105.  
  106.     move.l    #__STKSIZ,a1    * load address of __STKSIZ.
  107.     move.l    a1,d1        * move it to data register for undefined check.
  108.     beq    keepmin        * if it's zero(undefined), keep minimum stack.
  109.     move.l    (a1),d1
  110.     bmi    giveback    *    if (__STKSIZ < 0) goto giveback;
  111.     add.l    d0,d1        *    d1 = __base+__STKSIZ; /* new sp */
  112.     bra    gotd1
  113.  
  114. keepmin:            * __STKSIZ was undefined; keep minimum.
  115.     move.l    #MINSTACK,d1
  116.     add.l    d0,d1        *    d1 = __base + MINSTACK;
  117.     bra    gotd1        *    goto gotd1;
  118.  
  119. giveback:
  120.     add.l    p_hitpa(a0),d1    *    d1 += hitpa;
  121.  
  122. gotd1:    move.l    d1,sp        * gotd1: sp = d1;
  123.  
  124. *
  125. * DOSHRINK: take SP as a requested stack pointer. Place it
  126. * between (__break+MINSTACK) and (p_hitpa(a0)-FUDGE).  If we can't,
  127. * abort. Otherwise, we return the remaining memory back to the o.s.
  128. * The reason we always shrink by at least FUDGE bytes is to work around
  129. * a bug in the XBIOS Malloc() routine: when there are fewer than 512
  130. * bytes in the largest free block, attempting a Pexec() breaks the
  131. * memory management system, thus, FUDGE must be at least 512.
  132. *
  133. * PSEUDOCODE:
  134. * doshrink(sp)
  135. * {
  136. *    /* if too low, bump it up */
  137. *    if (sp < (__break + MINSTACK))
  138. *        sp = (__break + MINSTACK);
  139. *
  140. *    /* if too high, bump it down */
  141. *    if (sp > (hitpa - FUDGE)) {
  142. *        sp = (hitpa - FUDGE);
  143. *
  144. *        /* if now too low, there's not enough memory */
  145. *        if (sp < (__break + MINSTACK))
  146. *            goto abort;
  147. *    }
  148. *    Mshrink(0,__base,(sp - __base));
  149. * }
  150. *
  151.     move.l    d0,d1        *   d1 = __break;
  152.     add.l    #MINSTACK,d1    *   d1 += MINSTACK;
  153.     cmp.l    d1,sp        *   if ((__break+MINSTACK) < sp)
  154.     bhi    minok        *     goto minok;
  155.     move.l    d1,sp        *   else sp = (__break+MINSTACK)
  156. minok:                * minok:
  157.     move.l    p_hitpa(a0),d2    *   d2 = hitpa;
  158.     sub.l    #FUDGE,d2    *   d2 -= FUDGE;
  159.     cmp.l    d2,sp        *   if ((hitpa - FUDGE) > sp)
  160.     bcs    maxok        *    goto maxok;
  161. *                *   else {
  162.     move.l    d2,sp        *    sp = (hitpa - FUDGE);
  163.     cmp.l    d1,d2        *     if ((__break+MINSTACK) > (hitpa-FUDGE))
  164.     bcs    abort        *        goto abort;    /* BAD NEWS */
  165. *                *   }
  166. maxok:
  167.  
  168. *
  169. * STACK LOCATION HAS BEEN DETERMINED. Return unused memory to the o.s.
  170. *
  171.     move.l    sp,d1        *   d1 = sp;
  172.     and.l    #-2,d1        *   /* ensure d1 is even */
  173.     move.l    d1,sp        *   sp = d1;
  174.     sub.l    a0,d1        *   d1 -= __base; /* d1 == size to keep */
  175.  
  176.     move.l    d1,-(sp)    * push the size to keep
  177.     move.l    a0,-(sp)    * and start of this block (our basepage)
  178.     clr.w    -(sp)        * and a junk word
  179.     move    #mshrink,-(sp)    * and the function code
  180.     trap    #1        * Mshrink(0,__base,(sp-base))
  181.     add.l    #12,sp        * clean the stack after ourselves
  182.  
  183. *
  184. * Finally, the stack is set up. Now call _main(cmdline, length)
  185. *
  186.     move.l    __base,a0    * set up _main(cmdline,length)
  187.     lea.l    p_cmdlin(a0),a2    * a2 now points to command line
  188.     move.b    (a2)+,d0    * d0 = length; a2++;
  189.     ext.w    d0        * extend byte count into d0.w
  190.     move.w    d0,-(a7)    * push length
  191.     move.l    a2,-(a7)    * Push commnd
  192.     clr.l    a6        * Clear frame pointer
  193.     jsr    __main        * call _main routine (it shouldn't return)
  194.     clr.w    -(a7)        * IF* it returns, we exit immediately
  195.     trap    #1        * with a zero status code
  196.  
  197. *
  198. * _exit(code)    Terminate process, return code to the parent.
  199. *
  200. .globl    __exit
  201. __exit:
  202.     tst.l    (a7)+        * drop return PC off the stack, leaving code
  203.     move.w    #pterm,-(a7)    * push function number
  204.     trap    #1        * and trap.
  205.  
  206. *
  207. * abort: used if the stack setup above fails. Restores the initial sp,
  208. * prints a message, and quits with the error ENSMEM.
  209. *
  210. abort:                * print an abortive message and quit
  211.     move.l    a1,sp        * restore initial sp
  212.     pea.l    abortmsg    * push string address
  213.     move.w    #cconws,-(a7)    * and function code
  214.     trap    #1        * and trap to print message
  215.     addq.l    #6,a7        * clean off stack
  216.     move.w    #-39,-(a7)    * push error number -39: ENSMEM
  217.     jsr    __exit        * and exit with it.
  218.  
  219. *
  220. * stack overflow error!
  221. *
  222. .globl    __sovf
  223. __sovf:
  224.     move.l    #ovf,-(sp)    * push message address
  225.     move.w    #cconws,-(sp)    * push fn code
  226.     trap    #1        * Issue message
  227.     move.w    #-1,-(a7)    * push return code (-1)
  228.     move.w    #pterm,-(a7)    * push function number
  229.     trap    #1        * and trap.
  230.  
  231. *
  232. *
  233. .globl    _brk
  234. _brk:        
  235.     cmp.l    __break,sp    * compare current break with current stack
  236.     bcs    __sovf        * actual stack overflow!
  237.     movea.l    4(sp),a0    * get new break
  238.     move.l    a0,d0        * compare with stack, including 256-byte
  239.     adda.l    #$100,a0    * chicken factor
  240.     cmpa.l    a0,sp        * if (sp < a0+256)
  241.     bcs    badbrk        *     bad break;
  242.     move.l    d0,__break    * OK break: save the break
  243.     clr.l    d0        * Set OK return
  244.     rts            * return
  245. badbrk:
  246.     move.l    #-1,d0        * Load return reg
  247.     rts            * Return
  248.  
  249. *
  250. *
  251. .globl    ___BDOS
  252. ___BDOS:
  253.     link    a6,#0        * link
  254.     move.w    8(sp),d0    * Load func code
  255.     move.l    10(sp),d1    * Load Paramter
  256.     trap    #2        * Enter BDOS
  257.     cmpa.l    __break,sp    * Check for stack ovf
  258.     bcs    __sovf        * overflow! print msg and abort
  259.     unlk    a6        * no error; return
  260.     rts            * Back to caller
  261.  
  262. *
  263. *    Hooks into the operating system through various traps
  264. *
  265. .globl    _gemdos
  266. _gemdos:
  267.     move.l    (sp)+,traddr    * pop return address
  268.     trap    #1        * do gemdos trap
  269.     move.l    traddr,-(sp)    * push return address
  270.     rts            * do normal return
  271.  
  272. .globl    _bios
  273. _bios:
  274.     move.l    (sp)+,traddr    * pop return address
  275.     trap    #13        * do gemdos trap
  276.     move.l    traddr,-(sp)    * push return address
  277.     rts            * do normal return
  278.  
  279. .globl    _xbios
  280. _xbios:
  281.     move.l    (sp)+,traddr    * pop return address
  282.     trap    #14        * do gemdos trap
  283.     move.l    traddr,-(sp)    * push return address
  284.     rts            * do normal return
  285.  
  286.  
  287. **********************************************************************
  288. *
  289. *    Data area
  290. *
  291.     .data
  292. ovf:        .dc.b    'Stack Overflow',$d,$a,0      * Overflow message
  293. abortmsg:    .dc.b    'Cannot initialize stack',$d,$a,0 * Abort message
  294. .globl    ___pname
  295. ___pname:    .dc.b    'runtime',0,0    * Program name
  296. .globl    ___tname
  297. ___tname:    .dc.b    'CON:',0    * Terminal device name
  298. .globl    ___lname
  299. ___lname:    .dc.b    'LST:',0    * List device name
  300. .globl    ___xeof
  301. ___xeof:    .dc.b    $1a        * Control-Z
  302.  
  303.  
  304. **********************************************************************
  305. *
  306. *    BSS AREA
  307. *
  308.     .bss
  309.     .even
  310. __base:        .ds.l    1    * -> Base Page
  311. __break:    .ds.l    1    * Break location
  312. __argc:        .ds.w    1    * number of command line args
  313. __argv:        .ds.l    1    * -> parsed command line args
  314. __envp:        .ds.l    1    * -> environment string
  315. * ?    ___cpmrv:    .ds.w    1    * Last CP/M return val
  316. traddr:        .ds.l    1    * system trap hook return address
  317.     .end
  318.