home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / gnu / libsrc87 / crt0.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-30  |  13.8 KB  |  477 lines

  1. /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2.  * NB: This file is used for both 16 and 32 bit code.
  3.  * USE NO "int"s IN HERE!!!!
  4.  *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  5.  *
  6.  *
  7.  * Crt0: C run-time initialization code.
  8.  * Written by Eric R. Smith, and placed in the public domain.
  9.  * Use at your own risk.
  10.  *
  11.  * _start(base): sets things up for the process whose basepage is
  12.  *    base. In particular, it sets up a valid environment, shrinks the
  13.  *    TPA to a reasonable value, and parses the command line.
  14.  *
  15.  * 01/03/89 ++jrb
  16.  *    The (new) meaning of _stksize: (thanks to allan pratt for the feedback)
  17.  *
  18.  * 11/27/91 ++jrb
  19.  *     More meanings for _stksize (thanks to eric and allan for the feedback)
  20.  *
  21.  *    _stksize            meaning
  22.  *      -4L        keep 3/4, free 1/4, malloc from own heap
  23.  *      -3L        keep 2/4 (1/2), free 1/2 malloc from own heap
  24.  *      -2L        keep 1/4 of memory, free 3/4, malloc from own heap
  25.  *
  26.  *    NOTE: all of the following will do malloc from Malloc() first,
  27.  *    when that fails, malloc() will do further mallocs from
  28.  *    our own heap. This lets us use the maximum amount of
  29.  *      memory in traditional ST's as well as newer split address
  30.  *    STs.
  31.  *
  32.  *      -1L        keep all of memory (except MINFREE at top) and do
  33.  *            mallocs from own heap, with heap grown upwards towards
  34.  *            stack, and the stack growing down towards heap,
  35.  *            with a minimum slush between them so that they
  36.  *            dont meet (only checked while malloc'ing). With
  37.  *            this model, further spawning is not possible, but it is
  38.  *            well suited for programs such as gcc-cc1 etc.
  39.  *            Thanks to Piet van Oostrum & Atze Dijkstra for this idea
  40.  *
  41.  *    0L        keep minimum amount of memory. this is also the
  42.  *            case when _stksize is undefined by the user.
  43.  *    1L        keep 1/4 of memory, free 3/4 ( as in Alcyon GEMSTART)
  44.  *    2L        keep 2/4 (1/2), free rest
  45.  *    3L        keep 3/4, free 1/4
  46.  *    other        keep that many bytes
  47.  *    -other        keep |other| bytes and malloc from own heap
  48.  *
  49.  * 02/14/90 ++jrb (thanks edgar)
  50.  *    auto acc detect
  51.  *    undump friendly
  52.  *   Note: some of the stuff here may seem extraneous: these are in
  53.  *     prep for upcoming plug'n play device interface
  54.  *     (the moment the ol'boss lets me do some "real" work).
  55.  *
  56.  *
  57.  * NOTE: dumping applications should use _initial_stack instead: if
  58.  *     !=0, then _stksize is initialized from _initial_stack, and
  59.  *     mallocs are always from internal heap. (TeX works much better now),
  60.  *     thanks edgar!
  61.  *
  62.  * Acc convention:
  63.  *    user sets _heapbase to bottom of stack + heap area
  64.  *         sets _stksize to the size of this area
  65.  *         at startup, sp will be set to top of this area
  66.  *         (_heapbase  + _stksize ) and malloc()'s will happen from heap.
  67.  *        (note malloc() and *not* Malloc())
  68.  *     OR
  69.  *    user sets only _stksize. then _heapbase is set to Malloc(_stksize)
  70.  *    sp to _heapbase + _stksize and mallocs all happen from this heap.
  71.  *
  72.  * 02/16/90 ++jrb
  73.  *  - bug fix: dont get screwed by desktop launch when fast bit is set
  74.  *             convert env string to format usable
  75.  *        (atari get your act together!!)
  76.  */
  77.  
  78. #include <basepage.h>
  79. #include <osbind.h>
  80. #ifndef _COMPILER_H
  81. #include <compiler.h>
  82. #endif
  83. #include <stddef.h>
  84.  
  85. #define isspace(c) ((c) == ' '||(c) == '\t')
  86. #define BUFSIZ    ((unsigned long)1024)    /* this must track the value */
  87.                     /* in stdio.h                */
  88. #define MINFREE    (8L * 1024L)        /* free atleast this much mem */
  89.                     /* on top */
  90. #define MINKEEP (8L * 1024L)        /* keep atleast this much mem */
  91.  
  92. /*
  93.  * this little goodie is for emacs
  94.  * edgar: note: it has grown two leading '_',
  95.  *              adjust in emacs/src/sysdep.c:start_of_data()
  96.  *
  97.  * __data_start removed, as that can be determined from the basepage.
  98.  */
  99.  
  100. BASEPAGE *_base;
  101. char **environ;
  102. static long argc;
  103. static char **argv;
  104.  
  105. /*
  106.  * initial stack is used primarily by dumping application,
  107.  * if it is, malloc is always from heap, and _stksize is init
  108.  * from initial_stack (to preserve the value in the undumped run)
  109.  */
  110. long _initial_stack;            /* .comm __initial_size, 4 */
  111. extern long _stksize;            /* picked up from user or stksiz.c */
  112. /* set to heap base addr when _stksize == -1L || _initial_stack || When DA */
  113. void *_heapbase;
  114.  
  115. /* default sizeof stdio buffers */
  116. size_t __DEFAULT_BUFSIZ__;    /* .comm             */
  117.  
  118. /* are we an app? */
  119. short _app;
  120.  
  121. /* are we on a split addr mem ST */
  122. short _split_mem = 0;
  123.  
  124. /* externs to pull in ident strings of all used libraries into the
  125.    executable. if a library is not used, then the extern is satisfied
  126.    by a dummy in the library
  127.  */
  128. asm("
  129.     .globl ___Ident_libg
  130.     .globl ___Ident_curses
  131.     .globl ___Ident_widget
  132.     .globl ___Ident_gem
  133.     .globl ___Ident_pml
  134.     .globl ___Ident_gnulib
  135.      ");
  136.  
  137. static void _acc_main __PROTO((void));
  138. static void _start1 __PROTO((BASEPAGE *bp));
  139. static long parseargs __PROTO((BASEPAGE *bp));
  140. static void setup_handlers __PROTO((void));
  141. static void _start0 __PROTO((BASEPAGE *));
  142. static void setup_handlers __PROTO((void));
  143. __EXTERN void _main __PROTO((long, char **, char **));
  144. __EXTERN void _init_signal __PROTO((void));
  145. __EXTERN void _start __PROTO((BASEPAGE *));
  146. #ifdef __GCRT0__
  147. __EXTERN void monstartup __PROTO((void *lowpc, void *highpc));
  148. __EXTERN void monitor __PROTO((void *lowpc, void *highpc, void *buffer, unsigned long bufsize, unsigned int nfunc));
  149. __EXTERN void moncontrol __PROTO((long flag));
  150. __EXTERN void _mcleanup __PROTO((void));
  151. __EXTERN int profil __PROTO((void *buff, unsigned long bufsiz, unsigned long offset, int shift));
  152. #endif
  153.  
  154. /*
  155.  * From: kbad@atari.UUCP (Ken Badertscher)
  156.  * Newsgroups: comp.sys.atari.st
  157.  * Subject: Am I a DA? (long)
  158.  *   .....
  159.  * I mentioned before that a DA's registers are garbage on startup, well,
  160.  * that's not entirely true.  When the DA gets control, register A0 always
  161.  * points to its basepage.  When a program is started by a GEMDOS Pexec(),
  162.  * register A0 is always cleared.  Using this fact, it is possible to
  163.  * implement startup code which gets the basepage address from register A0
  164.  * if the code is launched as a DA, or at 4(sp) if the code is launched by
  165.  * Pexec().  Since it knows how it was launched, it can also do the stack
  166.  * setup required of a DA, otherwise it can use the stack pointer it gets.
  167.  *
  168.  */
  169. /*
  170.  * revert back to testing A0 (instead of SP) after controversy on the net.
  171.  * packers will just have to fix themselves.
  172.  * in addition to testing A0 check long A0@(36) (parents basepage). for an
  173.  * acc this should be NULL.
  174.  */
  175. __asm__("
  176.      .text                
  177.      .even                
  178.      .globl __start            
  179. __start:
  180. "
  181. #ifdef __MBASE__
  182. "    movl    a0,a1            /* Find basepage, data seg */
  183.     cmpw    #0,a1
  184.     jne    1f
  185.     movl    sp@(4),a1
  186. 1:
  187.     movl    a1@(16)," __MBASESTR__ "    /* Set base to data seg + 32K */
  188.     subw    #32768," __MBASESTR__ "
  189.  
  190. "
  191. #define    Base    __MBASESTR__ "@(__base)"
  192. #define Heapbase __MBASESTR__ "@(__heapbase)"
  193. #define Stksize    __MBASESTR__ "@(__stksize)"
  194. #else
  195. #define Base    "__base"
  196. #define Heapbase "__heapbase"
  197. #define Stksize "__stksize"
  198. #endif
  199. "    cmpw    #0,a0             /* test acc or prog  */
  200.      jeq    __start0         /* br if prog          */
  201.     tstl    a0@(36)             /* tst parent basepage pointer */
  202.     jne     __start0         /* its a prog if != 0  */
  203.  
  204.  /* its an acc, set up a stck+heap */
  205.     movl    a0," Base "         /* sto basepage    */
  206.     tstl    " Heapbase "         /* setup _heapbase and sp */
  207.     jne    1f
  208.     movl    " Stksize ",d3         /* _heapbase not specified */
  209.     addql    #3, d3
  210.     andl    #0xfffffffc,d3
  211.     movl    d3,sp@-             /* _heapbase = Malloc(_stksize) */
  212.         movw    #0x48,sp@-
  213.     trap    #1
  214.     addqw    #6,sp
  215.     movl    d0," Heapbase "
  216.     addl    d3,d0
  217.     movl    d0, sp              /* sp = _heapbase + _stksize */
  218.     jra    __acc_main
  219. 1:                     /* heap base specified */
  220.      movl    " Heapbase ",sp         /* setup sp        */
  221.      addl    " Stksize ",sp        
  222.      jra    __acc_main");           /* acc main          */
  223.                        /* dont even think of */
  224.                        /* dropping through    */
  225.  
  226. static char    *acc_argv[] = {"", (char *) 0}; /* no name and no arguments */
  227.  
  228. static void _acc_main(void)
  229. {
  230.     _app = 0;                /* this is an accessory */
  231.     _main(1L, acc_argv, acc_argv);
  232.     /*NOTREACHED*/
  233. }
  234.  
  235. void _start0(bp) /* bp is passed at sp@(4) */
  236.     register BASEPAGE *bp;
  237. {
  238.     /* temporarily set sp at hitpa (rounded),then call the real
  239.        startup function. not doing this was blowing up the
  240.        stack provided by gemdos on a 1040, because _start1()
  241.        was pushing too many reggies on the stack
  242.        _start1() will finally set sp to its final value and
  243.        then do a mshrink().
  244.     */
  245.     asm volatile("movl %0,sp" ::"r"((long)bp->p_hitpa & ~3L));
  246.     _start1(bp);
  247. }
  248.  
  249. static void _start1(bp)
  250.     register BASEPAGE *bp __asm("a3");
  251. {
  252.     register long m __asm("d3");
  253.     register long freemem __asm("d4");
  254.     extern void etext();        /* fake-out if pcrel used */
  255.     
  256.     _app = 1;    /* its an application */
  257.     _base = bp;
  258.     if(!__DEFAULT_BUFSIZ__)
  259.         __DEFAULT_BUFSIZ__ = BUFSIZ;
  260.  
  261.     m = parseargs(bp);    /* m = # bytes used by environment + args */
  262. /* make m the total number of bytes required by program sans stack/heap */
  263.     m += (bp->p_tlen + bp->p_dlen + bp->p_blen + sizeof(BASEPAGE));
  264.     m = (m + 3L) & (~3L);
  265. /* freemem the amount of free mem accounting for MINFREE at top */
  266.     if((freemem = (long)bp->p_hitpa - (long)bp - MINFREE - m) <= 0L)
  267.         goto notenough;
  268.     
  269.     if(_initial_stack)
  270.     {
  271.         /* the primary use of _initial_stack will be in dumping */
  272.         /* applications where only a heap for malloc makes sense */
  273.         _heapbase = (void *) ((long)bp + m);
  274.         _stksize = _initial_stack;
  275.     }
  276.     
  277.     if((_stksize <  -1L))
  278.     {
  279.         _heapbase = (void *) ((long)bp + m);
  280.         _stksize = -_stksize - 1;
  281.         }
  282.         
  283.     if((!_initial_stack) && (_stksize >= -1L))
  284.         {   /* malloc from Malloc first, then from own heap */
  285.         _split_mem = 1;
  286.         }
  287.  
  288.     switch(_stksize)
  289.     {
  290.       case -1L:    /* keep all but MINFREE */
  291.         _stksize = freemem;
  292.         _heapbase = (void *) ((long)bp + m);
  293.         break;
  294.         
  295.       case 0L:    /* free all but MINKEEP */
  296.         _stksize = MINKEEP;
  297.         break;
  298.  
  299.       case 1L:    /* keep 1/4, free 3/4 */
  300.         _stksize = freemem >> 2;
  301.         break;
  302.  
  303.       case 2L:    /* keep 1/2, free 1/2 */
  304.         _stksize = freemem >> 1;
  305.         break;
  306.  
  307.       case 3L:    /* keep 3/4, free 1/4 */
  308.         _stksize = freemem - (freemem >> 2); 
  309.         break;
  310.  
  311.       default:
  312.         /* if _stksize > 0, keep that much */
  313.         break;
  314.     }
  315.     
  316. /* make m the total number of bytes including stack */
  317.     _stksize = _stksize & (~3L);
  318.     m += _stksize;
  319.  
  320. /* make sure there's enough room for the stack */
  321.     if (((long)bp + m) > ((long)bp->p_hitpa - MINFREE))
  322.         goto notenough;
  323.  
  324. /* set up the new stack to bp + m  */
  325.     asm volatile("\
  326.          movl    %0, sp  | move base to sp
  327.          addal    %1, sp    | add total bytes"
  328.              :            /* outputs */
  329.              : "g"(bp), "g"(m)    /* inputs  */
  330.              );     /* we dont tell gcc about clobbered reggies */
  331.     
  332. /* shrink the TPA - this is always correct, shared text or not -- hyc */
  333.     (void)Mshrink(bp, m);
  334.     asm volatile("subl a6,a6");    /* clear link reg for gdb */
  335.     
  336. /* establish handlers,  call the main routine */
  337.     setup_handlers();
  338. #ifdef __GCRT0__
  339.     monstartup((void *)(bp->p_tbase), (void *)etext-1);
  340. #endif
  341.     _main(argc, argv, environ);
  342.     /* not reached normally */
  343.  
  344. notenough:
  345.     Cconws("Fatal error: insufficient memory\r\n");
  346.         Pterm(-1);
  347. }
  348.  
  349.  
  350. /*
  351.  * parseargs(bp): parse the environment and arguments pointed to by the
  352.  * basepage. Return the number of bytes of environment and arguments
  353.  * that have been appended to the bss area (the environ and argv arrays
  354.  * are put here, as is a temporary buffer for the command line, if
  355.  * necessary).
  356.  *
  357.  * The MWC extended argument passing scheme is assumed.
  358.  *
  359.  */
  360.  
  361. static long parseargs(bp)
  362.     BASEPAGE *bp;
  363. {
  364.         long count = 4;        /* compensate for aligning */
  365.     long  i;
  366.     char *from, *cmdln, *to;
  367.     char **envp, **arg;
  368.     
  369. /* handle the environment first */
  370.  
  371.     environ = envp = (char **)(( (long)bp->p_bbase + bp->p_blen + 4) & (~3));
  372.     from = bp->p_env;
  373.     while (*from) {
  374.  
  375. /* if we find MWC arguments, tie off environment here */
  376.         if (*from == 'A' && *(from+1) == 'R' && *(from+2) == 'G' &&
  377.             *(from+3) == 'V' && *(from+4) == '=') {
  378.             *envp++ = (char *) 0; count += 4;
  379.             *from++ = 0;
  380. #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
  381.             if (bp->p_cmdlin[0] != 127)
  382.                 goto old_cmdlin;
  383. #endif
  384.             while (*from++) ; /* skip ARGV= string */
  385.             argv = arg = envp++;
  386.             *arg++ = from; count+= 4;
  387.             while (*from++) ; /* skip argv[0] */
  388.             goto do_argc;
  389.         }
  390.         *envp++ = from;
  391.         count += 4;
  392.         while (*from++);
  393.  
  394.         /* if launched from desktop -- fix up env
  395.                  * be careful while doing this, as the environment
  396.          * may have a variable whose value is the empty
  397.          * string. (make puts a MAKFLAGS=\0). The desktop
  398.          * typically has "PATH=\0C:\\0\0", so to distinguish
  399.          * the two cases, check for uppercase drive letter
  400.          * followed by ":\\"
  401.          */
  402. #define ISDRV(x) (('A' <= (x)) && ((x) <= 'Z'))
  403.          if ( (from[ -2 ] == '=') && (ISDRV(*from)) && 
  404.              (from[1] == ':') && (from[2] == '\\') )
  405.         {
  406.             char *p = &from[-1]; /* typically  "PATH=\0C:\\0\0" */
  407.             while(*from)
  408.             *p++ = *from++;
  409.             *p = '\0'; from++;
  410.         }
  411.     }
  412.     *envp++ = (char *)0;
  413.     count += 4;
  414.  
  415. /* Allocate some room for the command line to be parsed */
  416.     cmdln = bp->p_cmdlin;
  417.     i = *cmdln++;
  418.     from = to = (char *) envp;
  419.     if (i > 0) {
  420.         count += (i&(~3));
  421.         envp = (char **) ( ((long) envp)  + (i&(~3)) );
  422.     }
  423.     envp += 2; count += 8;
  424.  
  425. /* Now parse the command line and put argv after the environment */
  426.  
  427.     argv = arg = envp;
  428.     *arg++ = "";        /* argv[0] not available */
  429.     count += 4;
  430.     while(i > 0 && isspace(*cmdln) )
  431.         cmdln++,--i;
  432.  
  433.     while (i > 0) {
  434.         if (isspace(*cmdln)) {
  435.             --i; cmdln++;
  436.             while (i > 0 && isspace(*cmdln))
  437.                 --i,cmdln++;
  438.             *to++ = 0;
  439.         }
  440.         else {
  441.             if (!(*to++ = *cmdln++)) break;
  442.             --i;
  443.         }
  444.     }
  445.     *to++ = '\0';
  446.     *to = '\0'; /* bug fix example:cmdln == '\3' 'a' ' ' 'b' '\0' */
  447.     /* the loop below expects \0\0 at end to terminate! */
  448.     /* the byte @ cmdln[i+2] != 0 when fast bit is set */
  449. do_argc:
  450.     argc = 1;        /* at this point argv[0] is done */
  451.     while (*from) {
  452.         *arg++ = from;
  453.         argc++;
  454.         count += 4;
  455.         while(*from++) ;
  456.     }
  457.     *arg++ = (char *) 0;
  458.     return count+4;
  459. }
  460.  
  461. static void setup_handlers(void)
  462. {
  463.     /* more stuff to come */
  464.     _init_signal();
  465. }
  466.  
  467. void __exit(status)
  468.     long status;
  469. {
  470. #ifdef __GCRT0__
  471.     moncontrol(0L);
  472.     _mcleanup();
  473. #endif
  474.     Pterm(status);
  475.  
  476. }
  477.