home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / rom / dos / loadseg_aout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-27  |  11.7 KB  |  365 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: loadseg_aout.c,v 1.2 1997/01/27 00:36:24 ldp Exp $
  4.     $Log: loadseg_aout.c,v $
  5.     Revision 1.2  1997/01/27 00:36:24  ldp
  6.     Polish
  7.  
  8.     Revision 1.1  1996/12/22 11:42:46  iaint
  9.     Finally, support for loading binaries in a.out format.
  10.  
  11.  
  12.     Desc: Load an a.out format image into memory.
  13.     Lang: English.
  14. */
  15. #include <exec/memory.h>
  16. #include <proto/exec.h>
  17. #include <dos/dosasl.h>
  18. #include <proto/dos.h>
  19. #include <proto/aros.h>
  20. #include "dos_intern.h"
  21. #include <aros/debug.h>
  22. #include <aros/machine.h>
  23.  
  24. extern struct DosLibrary * DOSBase;
  25.  
  26. /*
  27.     a.out files are much simpler than ELF format files or AmigaOS files.
  28.     This is probably due to the age of the format (AT&T V7 I think).
  29.  
  30.     We load the text and combined data/bss segments randomly into memory
  31.     in two huge chunks. This is because it would be rather tricky to split
  32.     them up, as they are designed really for virtual memory based-machines
  33.     (so they can be loaded at the same address).
  34.  
  35.     This has the unfortunate side effect of that for large programs, if
  36.     your memory is quite fragmented, you will not have enough memory to
  37.     load the program into memory.
  38.  
  39.     THINGS TO DO:
  40.         -   Adapt this to use InternalLoadSeg() calling information.
  41.             Can't do this until InternalLoadSeg() exists though :)
  42.         -   Make it work properly.
  43.  
  44. */
  45.  
  46. /* The structure defining the file */
  47. struct aout_hdr
  48. {
  49.     UWORD   a_magic;            /* Magic number                         */
  50.     UWORD   a_mid;              /* Machine ID and flags (flags not used */
  51.     ULONG   a_text;             /* Length of text segment               */
  52.     ULONG   a_data;             /* Length of data segment               */
  53.     ULONG   a_bss;              /* Length of BSS space required         */
  54.     ULONG   a_syms;             /* Symbol table length (bytes)          */
  55.     ULONG   a_entry;            /* Program start point                  */
  56.     ULONG   a_trsize;           /* Size of text relocations (bytes)     */
  57.     ULONG   a_drsize;           /* Size of data relocations (bytes)     */
  58. };
  59.  
  60. /* A relocation record */
  61. struct reloc
  62. {
  63.     LONG    r_address;          /* Offset in the section to the reloc   */
  64.     ULONG   r_symbolnum : 24,   /* Actually the segment number          */
  65.             r_pcrel : 1,        /* PC relative (do nothing)             */
  66.             r_length : 2,       /* Length of relocation - should be 2   */
  67.             r_extern : 1,       /* External relocation - not supported  */
  68.             r_pad   : 4;
  69. };
  70.  
  71. #define OMAGIC      0407        /* Not used */
  72. #define NMAGIC      0410        /* The format we use. */
  73. #define ZMAGIC      0413        /* Not used */
  74.  
  75. #define MID_i386    134         /* i386 binary (386BSD) */
  76.  
  77. #define N_EXT       0x01        /* External flag - symbol can be accessed
  78.                                    externally */
  79. #define N_ABS       0x02        /* Absolute Symbol - Not used */
  80. #define N_TEXT      0x04        /* Text symbol */
  81. #define N_DATA      0x06        /* Data symbol */
  82. #define N_BSS       0x08        /* BSS symbol */
  83.  
  84. /*  This is used so that we can jump over any constant stuff at the
  85.     beginning of the text hunk.
  86.  
  87.     GCC tends to put string constants for a function before the function
  88.     in the text segment, so the very first byte of the text segment is
  89.     not actually code, but a string. This jumps over that.
  90. */
  91. struct JumpHunk
  92. {
  93.     BPTR    next;
  94.     struct JumpVec vec;
  95. };
  96.  
  97. /* relocate(exec, reloc, current, refer):
  98.     exec    -   The files exec header.
  99.     reloc   -   The relocation data.
  100.     current -   The base of the hunk we are currently relocating in.
  101.     refer   -   The base of the hunk that the data references.
  102.  
  103.     The hunk bases point to the "next hunk pointer", so we have to
  104.     add the size of a BPTR to the hunk to get the real address.
  105.  
  106.     PC relative relocations are do-nothings because, no matter what the
  107.     load address of the code is, the data at that location is still the
  108.     same.
  109. */
  110.  
  111. static LONG relocate(   struct aout_hdr *head,
  112.                         struct reloc *reloc,
  113.                         UBYTE  *currentHunk,
  114.                         UBYTE  *referHunk
  115.                     )
  116. {
  117.     /*  I don't test whether the currentHunk is valid, since if it isn't
  118.         we should never have got here.
  119.  
  120.         It could however be possible to say get a reference into a
  121.         data or bss hunk that doesn't exist.
  122.     */
  123.     if(referHunk == NULL)
  124.     {
  125.         D(bug("LoadSeg_AOUT: Trying to refer to a non-existant hunk.\n"));
  126.         return ERROR_BAD_HUNK;
  127.     }
  128.  
  129.     /*
  130.         References are relative to the file offset, so if this is a data
  131.         or BSS hunk, then we have to subtract the text segment size from
  132.         the address. It is effectively added back on by the stored value.
  133.  
  134.         If BSS hunks were not contiguous with the data hunk then we would
  135.         have to do a similar thing there.
  136.     */
  137.     if(reloc->r_symbolnum != N_TEXT)
  138.     {
  139.         /* We should check whether we are doing a non-text PC rel here. */
  140.         referHunk -= head->a_text;
  141.     }
  142.  
  143.     if(reloc->r_length != 2)
  144.     {
  145.         D(bug("LoadSeg_AOUT: Cannot relocate, bad reloc length at offset %ld\n",
  146.  reloc->r_address));
  147.         return ERROR_BAD_HUNK;
  148.     }
  149.  
  150.     /* If we try this on a PC relative reloc, nothing will work */
  151.     if(!reloc->r_pcrel)
  152.         *(ULONG *)¤tHunk[reloc->r_address] += (ULONG)referHunk;
  153.  
  154.     return 0;
  155. }
  156.  
  157. BPTR LoadSeg_AOUT(BPTR file)
  158. {
  159.     struct reloc     rel;
  160.     UBYTE           *texthunk = NULL;
  161.     UBYTE           *datahunk = NULL;
  162.     struct JumpHunk *jumphunk = NULL;
  163.     struct aout_hdr  header;
  164.     LONG             rel_remain;
  165.     LONG             err;
  166.     LONG            *error = &(((struct Process *)FindTask(NULL))->pr_Result2);
  167.  
  168. #define ERROR(a)    { *error = a; goto end; }
  169.  
  170.     /* In case we have already had something attempt to load the file. */
  171.     Seek(file, 0, OFFSET_BEGINNING);
  172.  
  173.     if(Read(file, &header, sizeof(struct aout_hdr)) != sizeof(struct aout_hdr))
  174.     {
  175.         D(bug("LoadSeg_AOUT: Can't read all of header\n"));
  176.         ERROR(ERROR_FILE_NOT_OBJECT);
  177.     }
  178.  
  179.     /*
  180.         The format that we use is an NMAGIC format with relocation
  181.         information. The important things about this is that the
  182.         text/data/bss segments are not page aligned (although that
  183.         doesn't really matter at this point in time). And most
  184.         importantly, the file thinks its being loaded at address
  185.         0x00000000 (rather than 0x00001000 for ZMAGIC files).
  186.     */
  187.     if( ((header.a_mid) != MID_i386) || (header.a_magic != NMAGIC))
  188.     {
  189.         D(bug("LoadSeg_AOUT: Bad magic number 0x%4x 0x%4x\n", header.a_magic, header.a_mid));
  190.         ERROR(ERROR_OBJECT_WRONG_TYPE);
  191.     }
  192.  
  193.     /* It appears that GCC is putting some constant strings in the text
  194.        segment before the entry point. So what we have to do is jump
  195.        over those strings to the actual entry. To do this I will use
  196.        a struct JumpVec (yes the same as in the the library bases).
  197.     */
  198.     jumphunk = AllocVec(sizeof(struct JumpHunk), MEMF_CLEAR|MEMF_ANY);
  199.     if(jumphunk == NULL)
  200.         ERROR(ERROR_NO_FREE_STORE);
  201.  
  202.     /* Text segment is required. */
  203.     texthunk = AllocVec(header.a_text + sizeof(BPTR), MEMF_CLEAR|MEMF_ANY);
  204.     if(texthunk == NULL)
  205.         ERROR(ERROR_NO_FREE_STORE);
  206.  
  207.     /* Link and Bump the text hunk past the next hunk pointer. */
  208.     jumphunk->next = MKBADDR(texthunk);
  209.     texthunk += sizeof(BPTR);
  210.  
  211.     jumphunk->vec.jmp = __AROS_ASMJMP;
  212.     __AROS_SET_VEC(&jumphunk->vec, texthunk + header.a_entry);
  213.  
  214.     if(Read(file, texthunk, header.a_text) != header.a_text)
  215.     {
  216.         D(bug("LoadSeg_AOUT: Can't read all of text segment\n"));
  217.         ERROR(ERROR_BAD_HUNK);
  218.     }
  219.  
  220.     /*
  221.        Data hunk is not required, but probably exists.
  222.        It doesn't for a number of disk based libs and devs that I looked at
  223.     */
  224.     if(header.a_data)
  225.     {
  226.         /* Include BSS with the data hunk. */
  227.         datahunk = AllocVec(header.a_data + header.a_bss + sizeof(BPTR), MEMF_CLEAR|MEMF_ANY);
  228.         if(datahunk == NULL)
  229.             ERROR(ERROR_NO_FREE_STORE);
  230.  
  231.         datahunk += sizeof(BPTR);
  232.  
  233.         if(Read(file, datahunk, header.a_data) != header.a_data)
  234.         {
  235.             D(bug("LoadSeg_AOUT: Can't read all of data segment\n"));
  236.             ERROR(ERROR_BAD_HUNK);
  237.         }
  238.     }
  239.     else if(header.a_bss)
  240.     {
  241.         datahunk = AllocVec(header.a_bss + sizeof(BPTR), MEMF_CLEAR|MEMF_ANY);
  242.         if(datahunk == NULL)
  243.             ERROR(ERROR_NO_FREE_STORE);
  244.  
  245.         datahunk += sizeof(BPTR);
  246.     }
  247.  
  248.     /* Link hunks together. If no data or bss, datahunk == NULL */
  249.     ((BPTR *)texthunk)[-1] = MKBADDR( (BPTR *)datahunk -1);
  250.     if(datahunk)    ((BPTR *)datahunk)[-1] = (BPTR)NULL;
  251.  
  252.     /* First of all, text relocations. */
  253.     rel_remain = header.a_trsize / sizeof(struct reloc);
  254.     for(; rel_remain > 0; rel_remain-- )
  255.     {
  256.         if(Read(file, &rel, sizeof(struct reloc)) != sizeof(struct reloc))
  257.         {
  258.             D(bug("LoadSeg_AOUT: Can't load a text relocation.\n"));
  259.             ERROR(ERROR_BAD_HUNK);
  260.         }
  261.  
  262.         if(rel.r_extern)
  263.         {
  264.             D(bug("LoadSeg_AOUT: Can't relocate external symbols.\n"));
  265.             ERROR(ERROR_BAD_HUNK);
  266.         }
  267.  
  268.         switch(rel.r_symbolnum)
  269.         {
  270.             case    N_TEXT | N_EXT:
  271.             case    N_TEXT:
  272.                 err = relocate(&header, &rel, texthunk, texthunk);
  273.                 break;
  274.  
  275.             case    N_DATA | N_EXT:
  276.             case    N_DATA:
  277.             case    N_BSS | N_EXT: /* this is a bit silly */
  278.             case    N_BSS:
  279.                 err = relocate(&header, &rel, texthunk, datahunk);
  280.                 break;
  281.  
  282.             default:
  283.                 D(bug("LoadSeg_AOUT: Can't relocate! Invalid Text SymNum\n"));
  284.                 ERROR(ERROR_FILE_NOT_OBJECT);
  285.         }
  286.         if(err)
  287.         {
  288.             ERROR(err);
  289.         }
  290.     } /* for(relocation entry) */
  291.  
  292.     /* Next of all, data relocations. */
  293.     rel_remain = header.a_drsize / sizeof(struct reloc);
  294.     for(; rel_remain > 0; rel_remain-- )
  295.     {
  296.         if(Read(file, &rel, sizeof(struct reloc)) != sizeof(struct reloc))
  297.         {
  298.             D(bug("LoadSeg_AOUT: Can't load a text relocation.\n"));
  299.             ERROR(ERROR_BAD_HUNK);
  300.         }
  301.  
  302.         if(rel.r_extern)
  303.         {
  304.             D(bug("LoadSeg_AOUT: Can't relocate external symbols.\n"));
  305.             ERROR(ERROR_FILE_NOT_OBJECT);
  306.         }
  307.         switch(rel.r_symbolnum)
  308.         {
  309.             case    N_TEXT|N_EXT:
  310.             case    N_TEXT:
  311.                 err = relocate(&header, &rel, datahunk, texthunk);
  312.                 break;
  313.  
  314.             case    N_DATA|N_EXT:
  315.             case    N_DATA:
  316.             case    N_BSS|N_EXT:
  317.             case    N_BSS:
  318.                 err = relocate(&header, &rel, datahunk, datahunk);
  319.                 break;
  320.  
  321.             default:
  322.                 D(bug("LoadSeg_AOUT: Can't relocate! Invalid Data SymNum\n"));
  323.                 ERROR(ERROR_FILE_NOT_OBJECT);
  324.         }
  325.         if(err)
  326.         {
  327.             ERROR(err);
  328.         }
  329.     }
  330.  
  331.     /* Flush the caches */
  332.     CacheClearE(texthunk, header.a_text, CACRF_ClearI|CACRF_ClearD);
  333.     if(datahunk)
  334.         CacheClearE(datahunk, header.a_data + header.a_bss, CACRF_ClearI|CACRF_ClearD);
  335.  
  336.     /* Ok, it is relocated, and ready to run. Remember to subtract
  337.        next hunk pointer from the text hunk.
  338.      */
  339.  
  340.     if(header.a_entry != 0)
  341.     {
  342.         /* jumphunk is the address of the next hunk pointer. */
  343.         return MKBADDR(jumphunk);
  344.     }
  345.     else
  346.     {
  347.         /* We don't need it */
  348.         FreeVec(jumphunk);
  349.         return MKBADDR((BPTR *)texthunk - 1);
  350.     }
  351.  
  352.   end:
  353.     /* If we allocated a text or data hunk, then we should free them */
  354.     if(datahunk)
  355.         FreeVec(datahunk - sizeof(BPTR));
  356.  
  357.     if(texthunk)
  358.         FreeVec(texthunk - sizeof(BPTR));
  359.  
  360.     if(jumphunk)
  361.         FreeVec(jumphunk);
  362.  
  363.     return (BPTR)NULL;
  364. }
  365.