home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / rom / dos / loadseg_elf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-04  |  10.7 KB  |  497 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: loadseg_elf.c,v 1.17 1997/02/04 14:13:02 digulla Exp $
  4.  
  5.     Desc: Code to dynamically load ELF executables
  6.     Lang: english
  7. */
  8. #include <exec/memory.h>
  9. #include <proto/exec.h>
  10. #include <dos/dosasl.h>
  11. #include <proto/dos.h>
  12. #include <proto/aros.h>
  13. #include "dos_intern.h"
  14. #include <aros/debug.h>
  15.  
  16. extern struct DosLibrary * DOSBase;
  17.  
  18. #define SHT_PROGBITS    1
  19. #define SHT_SYMTAB    2
  20. #define SHT_STRTAB    3
  21. #define SHT_RELA    4
  22. #define SHT_NOBITS    8
  23. #define SHT_REL     9
  24.  
  25. #define ET_REL        1
  26.  
  27. #define EM_386        3
  28. #define EM_68K        4
  29.  
  30. #define R_386_32    1
  31. #define R_386_PC32    2
  32. #define R_68K_32    1
  33. #define R_68K_PC32    4
  34.  
  35. #define STT_OBJECT    1
  36. #define STT_FUNC    2
  37.  
  38. #define ELF32_ST_TYPE(i)    ((i) & 0x0F)
  39.  
  40. struct elfheader
  41. {
  42.     UBYTE ident[16];
  43.     UWORD type;
  44.     UWORD machine;
  45.     ULONG version;
  46.     APTR  entry;
  47.     ULONG phoff;
  48.     ULONG shoff;
  49.     ULONG flags;
  50.     UWORD ehsize;
  51.     UWORD phentsize;
  52.     UWORD phnum;
  53.     UWORD shentsize;
  54.     UWORD shnum;
  55.     UWORD shstrndx;
  56. };
  57.  
  58. struct sheader
  59. {
  60.     ULONG name;
  61.     ULONG type;
  62.     ULONG flags;
  63.     APTR  addr;
  64.     ULONG offset;
  65.     ULONG size;
  66.     ULONG link;
  67.     ULONG info;
  68.     ULONG addralign;
  69.     ULONG entsize;
  70. };
  71.  
  72. struct symbol
  73. {
  74.     ULONG name;     /* Offset of the name string in the string table */
  75.     ULONG value;    /* Varies; eg. the offset of the symbol in its hunk */
  76.     ULONG size;     /* How much memory does the symbol occupy */
  77.     UBYTE info;     /* What kind of symbol is this ? (global, variable, etc) */
  78.     UBYTE other;    /* undefined */
  79.     WORD  shindex;  /* In which section is the symbol defined ? */
  80. };
  81.  
  82. struct relo
  83. {
  84.     ULONG addr;     /* Address of the relocation (relative to the last loaded hunk) */
  85.     ULONG info;     /* Type of the relocation */
  86. #ifdef __mc68000__
  87.     LONG  addend;   /* Constant addend used to compute value */
  88. #endif
  89. };
  90.  
  91. struct hunk
  92. {
  93.     ULONG   size;   /* Size of the hunk */
  94.     UBYTE * memory; /* First byte */
  95. };
  96.  
  97. int read_block (BPTR file, ULONG offset, APTR buffer, ULONG size)
  98. {
  99.     LONG    subsize;
  100.     UBYTE * buf     = (UBYTE *)buffer;
  101.  
  102.     if (Seek (file, offset, OFFSET_BEGINNING) < 0)
  103.     return 1;
  104.  
  105.     while (size)
  106.     {
  107.     subsize = Read (file, buf, size);
  108.  
  109.     if (subsize == 0)
  110.     {
  111.         ((struct Process *)FindTask (NULL))->pr_Result2 = ERROR_BAD_HUNK;
  112.         return 1;
  113.     }
  114.  
  115.     if (subsize < 0)
  116.         return 1;
  117.  
  118.     buf  += subsize;
  119.     size -= subsize;
  120.     }
  121.  
  122.     return 0;
  123. } /* read_block */
  124.  
  125. BPTR LoadSeg_ELF (BPTR file)
  126. {
  127.     struct elfheader eh;
  128.     UBYTE       * shtab    = NULL;
  129.     UBYTE       * shstrtab = NULL;
  130.     UBYTE       * strtab   = NULL;
  131.     struct symbol  * symtab   = NULL;
  132.     struct hunk    * hunks    = NULL;
  133.     struct relo    * reltab   = NULL;
  134.     struct symbol  * symbol;
  135.     struct sheader * sh;
  136.  
  137.     ULONG   numsym,
  138.         numrel,
  139.         i;
  140.     WORD    t,
  141.         mint   = 0,
  142.         maxt   = 0;
  143.     UBYTE * loaded;
  144.     BPTR    last   = 0;
  145.     LONG  * error  = &((struct Process *)FindTask (NULL))->pr_Result2;
  146.  
  147. #define ERROR(a)    { *error = a; goto end; }
  148.  
  149.     /* Load the header */
  150.     if (read_block (file, 0, &eh, sizeof (eh)))
  151.     goto end;
  152.  
  153.     /* Check the header of the file */
  154.     if
  155.     (
  156.     eh.ident[0] != 0x7f
  157.     || eh.ident[1] != 'E'
  158.     || eh.ident[2] != 'L'
  159.     || eh.ident[3] != 'F'
  160.     )
  161.     ERROR (ERROR_NOT_EXECUTABLE);
  162.  
  163.     /* Check file type and the CPU the file is for */
  164.     if (eh.type != ET_REL || (eh.machine != EM_386 && eh.machine != EM_68K))
  165.     ERROR (ERROR_OBJECT_WRONG_TYPE);
  166.  
  167.     /* Get memory for section headers */
  168.     shtab = AllocVec (eh.shentsize * eh.shnum, MEMF_ANY);
  169.  
  170.     if (shtab == NULL)
  171.     ERROR (ERROR_NO_FREE_STORE);
  172.  
  173.     /* Read section table */
  174.     if (read_block(file, eh.shoff, shtab, eh.shentsize * eh.shnum))
  175.     goto end;
  176.  
  177.     /* Look up the symbol table */
  178.     for (t=1; t<eh.shnum; t++)
  179.     {
  180.     sh = (struct sheader *)(shtab + t*eh.shentsize);
  181.  
  182.     if (sh->type == SHT_SYMTAB)
  183.         break;
  184.     }
  185.  
  186.     if (t == eh.shnum)
  187.     ERROR (ERROR_OBJECT_WRONG_TYPE);
  188.  
  189.     /* Allocate memory for the symbol table */
  190.     symtab = AllocVec (sh->size, MEMF_ANY);
  191.  
  192.     if (symtab == NULL)
  193.     ERROR (ERROR_NO_FREE_STORE);
  194.  
  195.     /* Read the symbol table */
  196.     if (read_block (file, sh->offset, symtab, sh->size))
  197.     goto end;
  198.  
  199.     numsym = sh->size / sizeof (struct symbol);
  200.  
  201.     mint = maxt = symtab[0].shindex;
  202.  
  203. /* kprintf ("Symbol %d: index=%d\n", 0, symtab[0].shindex); */
  204.  
  205.     /* Find the minimal number of hunks which are neccessary to satisfy
  206.        all symbol references (ie. all hunks in which a symbol resides) */
  207.     for (i=1; i<numsym; i++)
  208.     {
  209. /* kprintf ("Symbol %d: index=%d\n", i, symtab[i].shindex); */
  210.  
  211.     if (symtab[i].shindex < mint)
  212.         mint = symtab[i].shindex;
  213.  
  214.     if (symtab[i].shindex > maxt)
  215.         maxt = symtab[i].shindex;
  216.     }
  217.  
  218.     /* Allocate memory for information about every hunk */
  219.     hunks = AllocVec (sizeof (struct hunk) * (maxt - mint + 1), MEMF_CLEAR);
  220.  
  221.     if (hunks == NULL)
  222.     ERROR (ERROR_NO_FREE_STORE);
  223.  
  224.     /* Offset the base. Now I can simply access the first hunk as
  225.     hunks[t] instead of hunks[t-mint] */
  226.     hunks -= mint;
  227.  
  228.     /* Find the basic size for each hunk */
  229.     for (t=1; t<eh.shnum; t++)
  230.     {
  231.     sh = (struct sheader *)(shtab + t*eh.shentsize);
  232.  
  233.     if (sh->type == SHT_PROGBITS || sh->type == SHT_NOBITS)
  234.         hunks[t].size = sh->size;
  235.     }
  236.  
  237.     /* Load names of sections */
  238.     if (eh.shstrndx)
  239.     {
  240.     sh = (struct sheader *)(shtab + eh.shstrndx*eh.shentsize);
  241.  
  242.     shstrtab = AllocVec (sh->size, MEMF_ANY);
  243.  
  244.     if (shstrtab == NULL)
  245.         ERROR (ERROR_NO_FREE_STORE);
  246.  
  247.     if (read_block (file, sh->offset, shstrtab, sh->size))
  248.         goto end;
  249.  
  250.     /* {
  251.         int n, t;
  252.  
  253.         for (n=t=0; t<sh->size; n++)
  254.         {
  255.         kprintf ("String %d@%d: \"%s\"\n", n, t, &shstrtab[t]);
  256.         t += strlen (&shstrtab[t]) + 1;
  257.         }
  258.     } */
  259.     }
  260.  
  261.     /* Look for names of symbols */
  262.     for (t=eh.shnum; t>0; t--)
  263.     {
  264.     sh = (struct sheader *)(shtab + t*eh.shentsize);
  265.  
  266.     if (sh->type == SHT_STRTAB)
  267.         break;
  268.     }
  269.  
  270.     /* Found the section with the names ? Load the symbols' names */
  271.     if (t)
  272.     {
  273.     strtab = AllocVec (sh->size, MEMF_ANY);
  274.  
  275.     if (strtab == NULL)
  276.         ERROR (ERROR_NO_FREE_STORE);
  277.  
  278.     /* kprintf ("Reading StrTab at %d (offset=%ld, size=%ld)\n", eh.shstrndx, sh->offset, sh->size); */
  279.  
  280.     if (read_block (file, sh->offset, strtab, sh->size))
  281.         goto end;
  282.  
  283.     /*{
  284.         int n, t;
  285.  
  286.         for (n=t=0; t<sh->size; n++)
  287.         {
  288.         kprintf ("String %d@%d: \"%s\"\n", n, t, &strtab[t]);
  289.         t += strlen (&strtab[t]) + 1;
  290.         }
  291.     } */
  292.     }
  293.  
  294.     /* kprintf ("    File has %d sections.\n", eh.shnum); */
  295.  
  296.     /* Reserve memory for each global symbol in its hunk */
  297.     for (i=0; i<numsym; i++)
  298.     {
  299.     if (symtab[i].shindex < 0)
  300.     {
  301.         symtab[i].value = hunks[symtab[i].shindex].size;
  302.  
  303.         hunks[symtab[i].shindex].size += symtab[i].size;
  304.     }
  305.     }
  306.  
  307.     /* Allocate memory for each segment */
  308.     for (t=mint; t<=maxt; t++)
  309.     {
  310.     /* Don't allocate memory for hunks which don't need any */
  311.     if (hunks[t].size)
  312.     {
  313.         hunks[t].memory = AllocVec (hunks[t].size + sizeof (BPTR), MEMF_CLEAR);
  314.  
  315.         if (hunks[t].memory == NULL)
  316.         ERROR (ERROR_NO_FREE_STORE);
  317.  
  318.         hunks[t].memory += sizeof(BPTR);
  319.  
  320. D(bug("   Hunk %3d: 0x%p - 0x%p\n", t, hunks[t].memory, hunks[t].memory+hunks[t].size));
  321.     }
  322.     }
  323.  
  324.     /* Show the final addresses of global symbols */
  325.     if (strtab)
  326.     {
  327.     for (i=0; i<numsym; i++)
  328.     {
  329.         /* Print the symbol if it has a name and if it's a variable
  330.         or function */
  331.         if (strtab[symtab[i].name]
  332.         && (
  333.             ELF32_ST_TYPE(symtab[i].info) == STT_OBJECT
  334.             || ELF32_ST_TYPE(symtab[i].info) == STT_FUNC
  335.         )
  336.         )
  337.         {
  338.         kprintf ("    Symbol at 0x%p: %s\n"
  339.             , hunks[symtab[i].shindex].memory + symtab[i].value
  340.             , &strtab[symtab[i].name]
  341.         );
  342.         }
  343.     }
  344.     }
  345.  
  346.     loaded = NULL;
  347.  
  348.     /* Now load the pieces into memory */
  349.     for (t=1; t<eh.shnum; t++)
  350.     {
  351.     sh = (struct sheader *)(shtab + t*eh.shentsize);
  352.  
  353.     switch(sh->type)
  354.     {
  355.     case SHT_PROGBITS: /* Code */
  356.         if (read_block (file, sh->offset, hunks[t].memory, sh->size))
  357.         goto end;
  358.  
  359.         loaded = hunks[t].memory;
  360.  
  361.         if (strtab)
  362.         {
  363.         kprintf ("    Section at 0x%p ... 0x%p: %s\n"
  364.             , loaded
  365.             , loaded + sh->size - 1
  366.             , &shstrtab[sh->name]
  367.         );
  368.         }
  369.  
  370.         break;
  371.  
  372.     case SHT_RELA:
  373.     case SHT_REL: /* Relocation table */
  374.         if (loaded == NULL)
  375.         ERROR (ERROR_OBJECT_WRONG_TYPE);
  376.  
  377.         /* Get memory for the relocation table */
  378.         reltab = AllocVec (sh->size, MEMF_ANY);
  379.  
  380.         if (reltab == NULL)
  381.         ERROR (ERROR_NO_FREE_STORE);
  382.  
  383.         /* Load it */
  384.         if (read_block (file, sh->offset, reltab, sh->size))
  385.         goto end;
  386.  
  387.         numrel = sh->size / sizeof (struct relo);
  388.  
  389.         /* For each relocation ... */
  390.         for (i=0; i<numrel; i++)
  391.         {
  392.         symbol = &symtab[reltab[i].info >> 8];
  393.  
  394.         switch (reltab[i].info & 0xFF)
  395.         {
  396. #ifdef __i386__
  397.         case R_386_32: /* 32bit absolute */
  398.             /* The address of a symbol is the base address of the
  399.             hunk in which the symbol is plus the offset of the
  400.             symbol to the beginning of this hunk. */
  401.             *(ULONG *)&loaded[reltab[i].addr] +=
  402.             (ULONG)hunks[symbol->shindex].memory + symbol->value;
  403.             break;
  404.  
  405.         case R_386_PC32: /* 32bit PC relative */
  406.             /* Similar to R_386_32 but relative to the address where
  407.             the relocation is in memory. */
  408.             *(ULONG *)&loaded[reltab[i].addr] +=
  409.             (ULONG)hunks[symbol->shindex].memory +
  410.             symbol->value - (ULONG)&loaded[reltab[i].addr];
  411.             break;
  412. #endif
  413. #ifdef __mc68000__
  414.         case R_68K_32:
  415.             *(ULONG *)&loaded[reltab[i].addr] =
  416.             (ULONG)hunks[symbol->shindex].memory + symbol->value +
  417.             reltab[i].addend;
  418.             break;
  419.         case R_68K_PC32:
  420.             *(ULONG *)&loaded[reltab[i].addr] =
  421.             ((ULONG)hunks[symbol->shindex].memory+ symbol->value +
  422.             reltab[i].addend - (ULONG)&loaded[reltab[i].addr]);
  423.             break;
  424. #endif
  425.  
  426.         default:
  427.             ERROR (ERROR_BAD_HUNK);
  428.         } /* switch */
  429.         } /* for */
  430.  
  431.         /* Release memory */
  432.         FreeVec (reltab);
  433.         reltab = NULL;
  434.         loaded = NULL;
  435.  
  436.         break;
  437.     } /* switch */
  438.     }
  439.  
  440.     /* Link hunks (and flush caches) */
  441.     for (t=mint; t<0; t++)
  442.     {
  443.     if (hunks[t].size)
  444.     {
  445.         CacheClearE(hunks[t].memory, hunks[t].size,
  446.         CACRF_ClearI|CACRF_ClearD);
  447.         ((BPTR *)hunks[t].memory)[-1] = last;
  448.         last = MKBADDR((BPTR *)hunks[t].memory - 1);
  449.     }
  450.     }
  451.  
  452.     for (t=maxt; t>=0; t--)
  453.     {
  454.     if (hunks[t].size)
  455.     {
  456.         CacheClearE(hunks[t].memory, hunks[t].size,
  457.         CACRF_ClearI|CACRF_ClearD);
  458.         ((BPTR *)hunks[t].memory)[-1] = last;
  459.         last = MKBADDR((BPTR *)hunks[t].memory-1);
  460.     }
  461.     }
  462.  
  463.     /* Free hunk information table */
  464.     FreeVec (hunks+mint);
  465.  
  466.     hunks = NULL;
  467.  
  468. end:
  469.     FreeVec (reltab);
  470.  
  471.     /* Free all hunks, too ? */
  472.     if (hunks != NULL)
  473.     {
  474.     for (t=mint; t<=maxt; t++)
  475.     {
  476.         if (hunks[t].memory != NULL)
  477.         FreeVec (hunks[t].memory - sizeof(BPTR));
  478.     }
  479.  
  480.     FreeVec (hunks + mint);
  481.  
  482.     /* Fail */
  483.     last = NULL;
  484.     }
  485.  
  486.     if (shstrtab)
  487.     FreeVec (shstrtab);
  488.  
  489.     if (strtab)
  490.     FreeVec (strtab);
  491.  
  492.     FreeVec (symtab);
  493.     FreeVec (shtab);
  494.  
  495.     return last;
  496. } /* LoadSeg_ELF */
  497.