home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / gcc / ixemulsrc.lha / ixemul / libsrc / crt0.c next >
C/C++ Source or Header  |  1996-12-11  |  13KB  |  475 lines

  1. /* revamped version by Loren J. Rittle. Thanks Loren !! */
  2.  
  3. /* I guess I should start to put my sources into RCS........ */
  4.  
  5. #include <exec/types.h>
  6. #include <exec/libraries.h>
  7. #include <exec/execbase.h>
  8.  
  9. #include <inline/exec.h>
  10. #include <libraries/dosextens.h>
  11. #include <proto/intuition.h>
  12. #include <limits.h>
  13. #include "kprintf.h"
  14. #include <stdlib.h>
  15. #include <stdarg.h>
  16. #include <string.h>
  17. #include <sys/wait.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20. #include <arpa/nameser.h>
  21. #include <resolv.h>
  22.  
  23. #include <sys/syscall.h>
  24. #ifdef BASECRT0
  25. #include <sys/exec.h>
  26. #endif /* BASECRT0 */
  27.  
  28. /* get the current revision number. Version control is automatically done by
  29.  * OpenLibrary(), I just have to check the revision number 
  30.  */
  31. #undef IX_VERSION
  32. #include "version.h"
  33.  
  34. #define MSTRING(x) STRING(x)
  35. #define STRING(x) #x
  36.  
  37. struct Library *ixemulbase;
  38.  
  39. static int start_stdio(int, char **, char **);
  40. static int exec_entry (struct Library *ixembase, int argc, char *argv[], char *env[]);
  41. static int ENTRY();
  42.  
  43. int  extend_stack_ix_exec_entry(int argc, char **argv, char **environ, int *real_errno, 
  44.                int (*main)(int, char **, char **));
  45. int  extend_stack_ix_startup(char *aline, int alen, int expand,
  46.         char *wb_default_window, unsigned main, int *real_errno);
  47. void ix_get_vars2 ();
  48. void monstartup(char *lowpc, char *highpc);
  49. void __init_stk_limit(void **limit, unsigned long argbytes);
  50.  
  51. /*
  52.  * Have to take care.. I may not use any library functions in this file,
  53.  * since they are exactly then used, when the library itself couldn't be
  54.  * opened...
  55.  */
  56.  
  57. extern int main();
  58.  
  59. /*
  60.  * This is the first code executed.  Note that a_magic has to be at
  61.  * a known offset from the start of the code section in order for
  62.  * execve() to know that the program that it is starting uses the
  63.  * ixemul library.
  64.  *
  65.  * The first instruction used to be a "jmp pc@(_ENTRY)", which when
  66.  * assembled by gas 2.5.2 produces an 8 byte 68020 PC relative jump
  67.  * rather than the desired 68000 short PC relative jump.  Changing
  68.  * it to "jmp pc@(_ENTRY:W)" generated the right instruction but
  69.  * a bad jmp offset.  So we use "jra _ENTRY" which seems to work
  70.  * fine on all m68k.  However, since programs are now in use
  71.  * linked with crt0 files with the 8 byte instruction, we need to
  72.  * maintain the hack in execve() that allows either jmp, and now
  73.  * the jra, and we need to ensure that a 16 bit displacement is
  74.  * required to reach ENTRY() or else we will have to add yet
  75.  * another pattern to match in execve().
  76.  *
  77.  */
  78.  
  79.  
  80. asm("
  81.     .text
  82.  
  83.     jra    _ENTRY        | by default jump to normal AmigaOS startup
  84.     .align    2        | ensure exec starts at byte offset 4
  85.  
  86.     | this is a struct exec, for now only OMAGIC is supported
  87.     .globl    exec
  88. exec:
  89.     .word    ___machtype    | a_mid
  90.     .word    0407        | a_magic = OMAGIC
  91.     .long    ___text_size    | a_text
  92.     .long    ___data_size    | a_data
  93.     .long    ___bss_size    | a_bss
  94.     .long    0        | a_syms
  95.     .long    _exec_entry    | a_entry
  96.     .long    0        | a_trsize
  97.     .long    0        | a_drsize
  98.  
  99.     | word alignment is guaranteed
  100. ");
  101.  
  102. extern  int expand_cmd_line;    /* expand wildcards ? */
  103. int     h_errno = 0;        /* networking error code */
  104. struct  __res_state _res = {    /* Resolver state default settings */
  105.     RES_TIMEOUT,            /* retransmition time interval */
  106.     4,                      /* number of times to retransmit */
  107.     RES_DEFAULT,        /* options flags */
  108.     1                       /* number of name servers */
  109. };
  110. int     _res_socket = -1;    /* resolv socket used for communications */
  111. char    *default_wb_window = 0;    /* Default Workbench output window name. */
  112. int     errno = 0;        /* error results from the library come in here.. */
  113. char    *_ctype_;        /* we use a pointer into the library, this is static anyway */
  114. int     sys_nerr;        /* number of system error codes */
  115. struct  ExecBase *SysBase;
  116. struct  Library *DOSBase;
  117. struct  __sFILE **__sF;
  118. static  char *dummy_environ = 0;
  119. char    **environ = { &dummy_environ };    /* this is a default for programs not started via exec_entry */
  120. char    *__progname = "";
  121.  
  122. extern  void *__stk_limit;
  123. extern  unsigned long __stk_argbytes;
  124.  
  125. #ifdef DEBUG_VERSION
  126. static inline u_int __geta4(void)
  127. {
  128.   u_int res;
  129.  
  130.   asm volatile ("movel a4,%0" : "=g" (res));
  131.   return res;
  132. }
  133. #endif
  134.  
  135. static void ix_panic(const char *msg, ...)
  136. {
  137.   struct IntuitionBase *IntuitionBase;
  138.   va_list ap;
  139.         
  140. /* Use address 4 instead of the SysBase global as globals may not yet be
  141.    available (a4-handling) */
  142. #undef EXEC_BASE_NAME
  143. #define EXEC_BASE_NAME *(void **)4
  144.  
  145.   va_start(ap, msg);
  146.   if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0)))
  147.     {
  148.       struct EasyStruct panic = {
  149.         sizeof(struct EasyStruct),
  150.         0,
  151.         "",
  152.         (char *)msg,
  153.         "Abort"
  154.       };
  155.         
  156.       EasyRequestArgs(NULL, &panic, NULL, ap);
  157.  
  158.       CloseLibrary ((struct Library *) IntuitionBase);
  159.    }
  160.   va_end(ap);
  161.  
  162. #undef EXEC_BASE_NAME
  163. #define EXEC_BASE_NAME SysBase
  164. }
  165.  
  166.  
  167. #ifdef BASECRT0
  168. extern int __datadata_relocs();
  169. extern int __data_size, __bss_size;
  170.  
  171. #ifdef RCRT0
  172. /* have to do this this way, or it is done base-relative.. */
  173. static inline int dbsize() 
  174. {
  175.   int res;
  176.   KPRINTF (("enter dbsize()\n"));
  177.   asm ("movel #___data_size,%0; addl #___bss_size,%0" : "=r" (res));
  178.   return res;
  179. }
  180.  
  181. static void inline
  182. ix_resident (void *base, int num, int a4, int size, void *relocs)
  183. {
  184.   typedef void (*func)(int, int, int, void *);
  185.  
  186.   KPRINTF (("enter ix_resident()\n"));
  187.   ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4, size, relocs);
  188. }
  189.  
  190. #else
  191. static void inline
  192. ix_resident (void *base, int num, int a4)
  193. {
  194.   typedef void (*func)(int, int);
  195.  
  196.   KPRINTF (("enter ix_resident()\n"));
  197.   ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4);
  198. }
  199. #endif
  200. #endif /* BASECRT0 */
  201.  
  202. static int
  203. exec_entry (struct Library *ixembase, int argc, char *argv[], char *env[])
  204. {
  205. #ifdef BASECRT0
  206.   register int a4;
  207.   /* needed, so that data can be accessed. ix_resident might change this
  208.      again afterwards */
  209.   asm volatile ("lea    ___a4_init,a4" : "=r" (a4) : "0" (a4));
  210.   asm volatile ("movel    a4,%0" : "=r" (a4) : "0" (a4));
  211.  
  212.   KPRINTF (("enter exec_entry()\n"));
  213. #ifdef RCRT0
  214.   ix_resident (ixembase, 4, a4, dbsize(), __datadata_relocs);
  215. #else
  216.   ix_resident (ixembase, 2, a4);
  217. #endif
  218. #endif /* BASECRT0 */
  219.   ixemulbase = ixembase;
  220.   if (ixemulbase->lib_Version < IX_VERSION)
  221.   {
  222.     ix_panic("Need at least version " MSTRING (IX_VERSION) " of " IX_NAME ".");
  223.     return W_EXITCODE(20, 0);
  224.   }
  225.  
  226. /*
  227.  * Set the limit variable to finish the initialization of the stackextend code.
  228.  */
  229.   __init_stk_limit(&__stk_limit,__stk_argbytes);
  230.  
  231.   return extend_stack_ix_exec_entry (argc, argv, env, &errno, start_stdio);
  232. }
  233.  
  234. /* this thing is best done with sprintf else, but it has to work without the
  235.  * library as well ;-(
  236.  */
  237. __inline static char *
  238. itoa (int num)
  239. {
  240.   short snum = num;
  241.  
  242.   /* how large can a long get...?? */
  243.   /* Answer (by ljr): best method to use (in terms of portability)
  244.      involves number theory.  The exact number of decimal digits
  245.      needed to store a given number of binary digits is
  246.  
  247.     ceiling ( number_of_binary_digits * log(2) / log(10) )
  248.      or
  249.     ceiling ( number_of_binary_digits * 0.301029996 )
  250.  
  251.      Since sizeof evaluates to the number of bytes a given type takes 
  252.      instead of the number of bits, we need to multiply sizeof (type) by
  253.      CHAR_BIT to obtain the number of bits.  Since an array size specifier
  254.      needs to be integer type, we multiply by 302 and divide by 1000 instead
  255.      of multiplying by 0.301029996.  Finally, we add 1 for the null terminator
  256.      and 1 because we want the ceiling of the function instead of the floor.
  257.      Funny thing about this whole affair is that you really wanted to know
  258.      the size a short could expand to be and not a long...  :-) I know
  259.      comments get out of date, etc.  The nice thing about this method is
  260.      that the size of the array is picked at compile time based upon the
  261.      number of bytes really needed by the local C implementation. */
  262.   static char buf[sizeof snum * CHAR_BIT * 302 / 1000 + 1 + 1];
  263.   char *cp;
  264.   
  265.   KPRINTF (("enter itoa()\n"));
  266.   buf[sizeof buf - 1] = 0;
  267.   cp = &buf[sizeof buf - 1];
  268.   do
  269.   {
  270.     *--cp = (snum % 10) + '0';
  271.     snum /= 10;
  272.   } while (snum);
  273.  
  274.   return cp;
  275. }
  276.  
  277. __inline static char *
  278. pstrcpy (char *start, char *arg)
  279. {
  280.   KPRINTF (("enter pstrcpy()\n"));
  281.   while ((*start++ = *arg++)) ;
  282.   return start - 1;
  283. }
  284.  
  285. /* Note: This routine must be far enough away from the start of code
  286.    so that the PC relative offset won't fit in a byte and the assembler
  287.    will generate the right instruction pattern that execve() is looking
  288.    for to know that this is a program that uses the ixemul.library. */
  289.  
  290. static int
  291. ENTRY (void)
  292. {
  293.   register unsigned char *rega0  asm("a0");
  294.   register unsigned long  regd0  asm("d0");
  295. #ifdef BASECRT0
  296.   register int a4;
  297. #endif /* BASECRT0 */
  298.   struct Library *ibase;
  299.   UBYTE *aline = rega0;
  300.   ULONG alen = regd0;
  301.   int res;
  302.  
  303. #ifdef BASECRT0
  304.   /* needed, so that data can be accessed. ix_resident() might change this
  305.      again afterwards */
  306.   asm volatile ("lea    ___a4_init,a4" : "=r" (a4) : "0" (a4));
  307.   asm volatile ("movel a4,%0" : "=r" (a4) : "0" (a4));
  308. #endif /* BASECRT0 */
  309.  
  310.   KPRINTF (("enter ENTRY()\n"));
  311.   KPRINTF (("alen = %ld; aline = '%s'\n", alen, aline));
  312.  
  313. /* Use address 4 instead of the SysBase global as globals may not yet be
  314.    available (a4-handling) */
  315. #undef EXEC_BASE_NAME
  316. #define EXEC_BASE_NAME *(void **)4
  317.  
  318.   ibase = OpenLibrary (IX_NAME, IX_VERSION);
  319.   KPRINTF (("ibase = %lx\n", ibase));
  320.   if (ibase)
  321.     {
  322. #ifdef BASECRT0
  323. #ifdef RCRT0
  324.       ix_resident (ibase, 4, a4, dbsize(), __datadata_relocs);
  325. #else
  326.       ix_resident (ibase, 2, a4);
  327. #endif
  328.       KPRINTF (("ix_resident: a4 = $%lx\n", __geta4()));
  329. #endif /* BASECRT0 */
  330.  
  331.       ixemulbase = ibase;
  332.  
  333. /*
  334.  * Set the limit variable to finish the initialization of the stackextend code.
  335.  */
  336.       __init_stk_limit(&__stk_limit,__stk_argbytes);
  337.  
  338.       KPRINTF (("calling ix_startup()\n"));
  339.       res = extend_stack_ix_startup (aline, alen, 
  340.                 expand_cmd_line, default_wb_window, (int)start_stdio, &errno);
  341.  
  342.       CloseLibrary (ixemulbase);
  343.     }
  344.   else
  345.     {
  346.       struct Process *me = (struct Process *)((*(struct ExecBase **)4)->ThisTask);
  347.  
  348.       ix_panic("Need at least version " MSTRING (IX_VERSION) " of " IX_NAME ".");
  349.       
  350.       /* quickly deal with the WB startup message, as the library couldn't do
  351.        * this for us. Nothing at all is done that isn't necessary to just shutup
  352.        * workbench..*/
  353.       if (! me->pr_CLI)
  354.         {
  355.       Forbid (); 
  356.       ReplyMsg ((WaitPort (& me->pr_MsgPort), GetMsg (& me->pr_MsgPort)));
  357.     }
  358.       
  359.     res = 20;
  360.     }
  361.   return (res);
  362. #undef EXEC_BASE_NAME
  363. #define EXEC_BASE_NAME SysBase
  364. }
  365.  
  366. void ix_get_variables(int from_vfork_setup_child)
  367. {
  368.   /* more to follow ;-) */
  369.   ix_get_vars2 (11, &_ctype_, &sys_nerr, &SysBase, &DOSBase, &__sF,
  370.                 &environ, (from_vfork_setup_child ? &environ : NULL),
  371.                 (from_vfork_setup_child ? &errno : NULL), &h_errno,
  372.                 &_res, &_res_socket);
  373. }
  374.  
  375. int
  376. start_stdio (int argc, char **argv, char **env)
  377. {
  378.   int res;
  379. #ifndef BASECRT0
  380.   extern void etext ();
  381.   extern void _mcleanup (void);
  382. #else /* BASECRT0 */
  383.  
  384.   KPRINTF (("start_stdio1: a4 = $%lx\n", __geta4()));
  385. #endif /* BASECRT0 */
  386.  
  387. #ifdef DEBUG_VERSION
  388.   KPRINTF (("enter start_stdio()\n"));
  389.   KPRINTF (("argc = %ld (args follow)\n", argc));
  390.   {
  391.     int i;
  392.     for (i = 0; i < argc; i++)
  393.       {
  394.     KPRINTF (("argv[%ld] = '%s'\n", i, argv[i]));
  395.       }
  396.   }
  397. #endif
  398.   
  399.   ix_get_variables(0);
  400.   environ = env;
  401.  
  402. #ifndef BASECRT0
  403. #ifdef MCRT0
  404.   atexit(_mcleanup);
  405.   monstartup((char *)start_stdio, (char *)etext);
  406. #endif
  407. #endif /* not BASECRT0 */
  408.  
  409.  
  410.   if (argv[0])
  411.     if ((__progname = strrchr(argv[0], '/')) == NULL)
  412.       __progname = argv[0];
  413.     else
  414.       ++__progname;
  415.   res = main (argc, argv, env);
  416.   return res;
  417. }
  418.  
  419. asm("
  420.     .text
  421.  
  422. _extend_stack_ix_startup:
  423. "
  424. #ifdef BASECRT0
  425.   #ifdef LBASE
  426. "    movel    a4@(___stack:L),d0"
  427.   #else
  428. "    movel    a4@(___stack:W),d0"
  429.   #endif
  430. #else
  431. "    movel    ___stack,d0"
  432. #endif
  433. "
  434.     beq    no_stkext1
  435.     jbsr    ___stkext_startup
  436. no_stkext1:
  437.     jmp    _ix_startup
  438.  
  439. _extend_stack_ix_exec_entry:
  440. "
  441. #ifdef BASECRT0
  442.   #ifdef LBASE
  443. "    movel    a4@(___stack:L),d0"
  444.   #else
  445. "    movel    a4@(___stack:W),d0"
  446.   #endif
  447. #else
  448. "    movel    ___stack,d0"
  449. #endif
  450. "
  451.     beq    no_stkext2
  452.     jbsr    ___stkext_startup
  453. no_stkext2:
  454.     jmp    _ix_exec_entry
  455. ");
  456.  
  457. #ifndef BASECRT0
  458. #ifdef CRT0
  459. /*
  460.  * null mcount and moncontrol,
  461.  * just in case some routine is compiled for profiling
  462.  */
  463. asm(".globl mcount");
  464. asm(".globl _moncontrol");
  465. asm("_moncontrol:");
  466. asm("mcount: rts");
  467. #endif /* CRT0 */
  468. #endif /* not BASECRT0 */
  469.  
  470. #ifndef BASECRT0
  471. #ifdef MCRT0
  472. #include "gmon.c"
  473. #endif
  474. #endif /* not BASECRT0 */
  475.