| 1 | /* Load and run a MIPS position independent ECOFF file.
|
|---|
| 2 | Written by Ian Lance Taylor <ian@cygnus.com>
|
|---|
| 3 | Public domain. */
|
|---|
| 4 |
|
|---|
| 5 | /* This program will load an ECOFF file into memory and execute it.
|
|---|
| 6 | The file must have been compiled using the GNU -membedded-pic
|
|---|
| 7 | switch to produce position independent code. This will only work
|
|---|
| 8 | if this program is run on a MIPS system with the same endianness as
|
|---|
| 9 | the ECOFF file. The ECOFF file must be complete. System calls may
|
|---|
| 10 | not work correctly.
|
|---|
| 11 |
|
|---|
| 12 | There are further restrictions on the file (they could be removed
|
|---|
| 13 | by doing some additional programming). The file must be aligned
|
|---|
| 14 | such that it does not require any gaps introduced in the data
|
|---|
| 15 | segment; the GNU linker produces such files by default. However,
|
|---|
| 16 | the file must not assume that the text or data segment is aligned
|
|---|
| 17 | on a page boundary. The start address must be at the start of the
|
|---|
| 18 | text segment.
|
|---|
| 19 |
|
|---|
| 20 | The ECOFF file is run by calling it as though it were a function.
|
|---|
| 21 | The address of the data segment is passed as the only argument.
|
|---|
| 22 | The file is expected to return an integer value, which will be
|
|---|
| 23 | printed. */
|
|---|
| 24 |
|
|---|
| 25 | #include <stdio.h>
|
|---|
| 26 | #include <sys/types.h>
|
|---|
| 27 | #include <sys/stat.h>
|
|---|
| 28 |
|
|---|
| 29 | /* Structures used in ECOFF files. We assume that a short is two
|
|---|
| 30 | bytes and an int is four bytes. This is not much of an assumption,
|
|---|
| 31 | since we already assume that we are running on a MIPS host with the
|
|---|
| 32 | same endianness as the file we are examining. */
|
|---|
| 33 |
|
|---|
| 34 | struct ecoff_filehdr {
|
|---|
| 35 | unsigned short f_magic; /* magic number */
|
|---|
| 36 | unsigned short f_nscns; /* number of sections */
|
|---|
| 37 | unsigned int f_timdat; /* time & date stamp */
|
|---|
| 38 | unsigned int f_symptr; /* file pointer to symtab */
|
|---|
| 39 | unsigned int f_nsyms; /* number of symtab entries */
|
|---|
| 40 | unsigned short f_opthdr; /* sizeof(optional hdr) */
|
|---|
| 41 | unsigned short f_flags; /* flags */
|
|---|
| 42 | };
|
|---|
| 43 |
|
|---|
| 44 | struct ecoff_aouthdr
|
|---|
| 45 | {
|
|---|
| 46 | unsigned short magic; /* type of file */
|
|---|
| 47 | unsigned short vstamp; /* version stamp */
|
|---|
| 48 | unsigned int tsize; /* text size in bytes, padded to FW bdry*/
|
|---|
| 49 | unsigned int dsize; /* initialized data " " */
|
|---|
| 50 | unsigned int bsize; /* uninitialized data " " */
|
|---|
| 51 | unsigned int entry; /* entry pt. */
|
|---|
| 52 | unsigned int text_start; /* base of text used for this file */
|
|---|
| 53 | unsigned int data_start; /* base of data used for this file */
|
|---|
| 54 | unsigned int bss_start; /* base of bss used for this file */
|
|---|
| 55 | unsigned int gprmask; /* ?? */
|
|---|
| 56 | unsigned int cprmask[4]; /* ?? */
|
|---|
| 57 | unsigned int gp_value; /* value for gp register */
|
|---|
| 58 | };
|
|---|
| 59 |
|
|---|
| 60 | #define ECOFF_SCNHDR_SIZE (40)
|
|---|
| 61 |
|
|---|
| 62 | static void
|
|---|
| 63 | die (s)
|
|---|
| 64 | char *s;
|
|---|
| 65 | {
|
|---|
| 66 | perror (s);
|
|---|
| 67 | exit (1);
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | int
|
|---|
| 71 | main (argc, argv)
|
|---|
| 72 | int argc;
|
|---|
| 73 | char **argv;
|
|---|
| 74 | {
|
|---|
| 75 | FILE *f;
|
|---|
| 76 | struct stat s;
|
|---|
| 77 | char *z;
|
|---|
| 78 | struct ecoff_filehdr *fh;
|
|---|
| 79 | struct ecoff_aouthdr *ah;
|
|---|
| 80 | unsigned int toff;
|
|---|
| 81 | char *t, *d;
|
|---|
| 82 | int (*pfn) ();
|
|---|
| 83 | int ret;
|
|---|
| 84 |
|
|---|
| 85 | if (argc != 2)
|
|---|
| 86 | {
|
|---|
| 87 | fprintf (stderr, "Usage: %s file\n", argv[0]);
|
|---|
| 88 | exit (1);
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | f = fopen (argv[1], "r");
|
|---|
| 92 | if (f == NULL)
|
|---|
| 93 | die (argv[1]);
|
|---|
| 94 |
|
|---|
| 95 | if (stat (argv[1], &s) < 0)
|
|---|
| 96 | die ("stat");
|
|---|
| 97 |
|
|---|
| 98 | z = (char *) malloc (s.st_size);
|
|---|
| 99 | if (z == NULL)
|
|---|
| 100 | die ("malloc");
|
|---|
| 101 |
|
|---|
| 102 | if (fread (z, 1, s.st_size, f) != s.st_size)
|
|---|
| 103 | die ("fread");
|
|---|
| 104 |
|
|---|
| 105 | /* We need to figure out the start of the text segment, which is the
|
|---|
| 106 | location we are going to call, and the start of the data segment,
|
|---|
| 107 | which we are going to pass as an argument. We also need the size
|
|---|
| 108 | and start address of the bss segment. This information is all in
|
|---|
| 109 | the ECOFF a.out header. */
|
|---|
| 110 |
|
|---|
| 111 | fh = (struct ecoff_filehdr *) z;
|
|---|
| 112 | if (fh->f_opthdr != sizeof (struct ecoff_aouthdr))
|
|---|
| 113 | {
|
|---|
| 114 | fprintf (stderr, "%s: unexpected opthdr size: is %u, want %u\n",
|
|---|
| 115 | argv[1], (unsigned int) fh->f_opthdr,
|
|---|
| 116 | (unsigned int) sizeof (struct ecoff_aouthdr));
|
|---|
| 117 | exit (1);
|
|---|
| 118 | }
|
|---|
| 119 |
|
|---|
| 120 | ah = (struct ecoff_aouthdr *) (z + sizeof (struct ecoff_filehdr));
|
|---|
| 121 | if (ah->magic != 0413)
|
|---|
| 122 | {
|
|---|
| 123 | fprintf (stderr, "%s: bad aouthdr magic number 0%o (want 0413)\n",
|
|---|
| 124 | argv[1], (unsigned int) ah->magic);
|
|---|
| 125 | exit (1);
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | /* We should clear the bss segment at this point. This is the
|
|---|
| 129 | ah->bsize bytes starting at ah->bss_start, To do this correctly,
|
|---|
| 130 | we would have to make sure our memory block is large enough. It
|
|---|
| 131 | so happens that our test case does not have any additional pages
|
|---|
| 132 | for the bss segment--it is contained within the data segment.
|
|---|
| 133 | So, we don't bother. */
|
|---|
| 134 | if (ah->bsize != 0)
|
|---|
| 135 | {
|
|---|
| 136 | fprintf (stderr,
|
|---|
| 137 | "%s: bss segment is %u bytes; non-zero sizes not supported\n",
|
|---|
| 138 | argv[1], ah->bsize);
|
|---|
| 139 | exit (1);
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | /* The text section starts just after all the headers, rounded to a
|
|---|
| 143 | 16 byte boundary. */
|
|---|
| 144 | toff = (sizeof (struct ecoff_filehdr) + sizeof (struct ecoff_aouthdr)
|
|---|
| 145 | + fh->f_nscns * ECOFF_SCNHDR_SIZE);
|
|---|
| 146 | toff += 15;
|
|---|
| 147 | toff &=~ 15;
|
|---|
| 148 | t = z + toff;
|
|---|
| 149 |
|
|---|
| 150 | /* The tsize field gives us the start of the data segment. */
|
|---|
| 151 | d = z + ah->tsize;
|
|---|
| 152 |
|
|---|
| 153 | /* Call the code as a function. */
|
|---|
| 154 | pfn = (int (*) ()) t;
|
|---|
| 155 | ret = (*pfn) (d);
|
|---|
| 156 |
|
|---|
| 157 | printf ("%s ran and returned %d\n", argv[1], ret);
|
|---|
| 158 |
|
|---|
| 159 | exit (0);
|
|---|
| 160 | }
|
|---|