2000-10-31 Philip Blundell <philb@gnu.org>
[binutils.git] / ld / testsuite / ld-empic / run.c
blob9a0377e02e5510d6cbfbbc378d6cec5927d5adc0
1 /* Load and run a MIPS position independent ECOFF file.
2 Written by Ian Lance Taylor <ian@cygnus.com>
3 Public domain. */
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.
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.
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. */
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/stat.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 */
44 struct ecoff_aouthdr
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)
62 static void
63 die (s)
64 char *s;
66 perror (s);
67 exit (1);
70 int
71 main (argc, argv)
72 int argc;
73 char **argv;
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;
85 if (argc != 2)
87 fprintf (stderr, "Usage: %s file\n", argv[0]);
88 exit (1);
91 f = fopen (argv[1], "r");
92 if (f == NULL)
93 die (argv[1]);
95 if (stat (argv[1], &s) < 0)
96 die ("stat");
98 z = (char *) malloc (s.st_size);
99 if (z == NULL)
100 die ("malloc");
102 if (fread (z, 1, s.st_size, f) != s.st_size)
103 die ("fread");
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));
117 exit (1);
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);
125 exit (1);
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)
136 fprintf (stderr,
137 "%s: bss segment is %u bytes; non-zero sizes not supported\n",
138 argv[1], ah->bsize);
139 exit (1);
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;
150 /* The tsize field gives us the start of the data segment. */
151 d = z + ah->tsize;
153 /* Call the code as a function. */
154 pfn = (int (*) ()) t;
155 ret = (*pfn) (d);
157 printf ("%s ran and returned %d\n", argv[1], ret);
159 exit (0);