1 /* Load and run a MIPS position independent ECOFF file.
2 Written by Ian Lance Taylor <ian@cygnus.com>
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
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
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
26 #include <sys/types.h>
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. */
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 */
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 */
60 #define ECOFF_SCNHDR_SIZE (40)
78 struct ecoff_filehdr
*fh
;
79 struct ecoff_aouthdr
*ah
;
87 fprintf (stderr
, "Usage: %s file\n", argv
[0]);
91 f
= fopen (argv
[1], "r");
95 if (stat (argv
[1], &s
) < 0)
98 z
= (char *) malloc (s
.st_size
);
102 if (fread (z
, 1, s
.st_size
, f
) != s
.st_size
)
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. */
111 fh
= (struct ecoff_filehdr
*) z
;
112 if (fh
->f_opthdr
!= sizeof (struct ecoff_aouthdr
))
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
));
120 ah
= (struct ecoff_aouthdr
*) (z
+ sizeof (struct ecoff_filehdr
));
121 if (ah
->magic
!= 0413)
123 fprintf (stderr
, "%s: bad aouthdr magic number 0%o (want 0413)\n",
124 argv
[1], (unsigned int) ah
->magic
);
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. */
137 "%s: bss segment is %u bytes; non-zero sizes not supported\n",
142 /* The text section starts just after all the headers, rounded to a
144 toff
= (sizeof (struct ecoff_filehdr
) + sizeof (struct ecoff_aouthdr
)
145 + fh
->f_nscns
* ECOFF_SCNHDR_SIZE
);
150 /* The tsize field gives us the start of the data segment. */
153 /* Call the code as a function. */
154 pfn
= (int (*) ()) t
;
157 printf ("%s ran and returned %d\n", argv
[1], ret
);