elf2ecoff.c revision 1.1 1 /*
2 * Copyright (c) 1995
3 * Ted Lemon (hereinafter referred to as the author)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /* elf2ecoff.c
30
31 This program converts an elf executable to an ECOFF executable.
32 No symbol table is retained. This is useful primarily in building
33 net-bootable kernels for machines (e.g., DECstation and Alpha) which
34 only support the ECOFF object file format. */
35
36 #include <sys/types.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <machine/elf.h>
40 #include <stdio.h>
41 #include <sys/exec_ecoff.h>
42 #include <sys/errno.h>
43 #include <string.h>
44 #include <limits.h>
45
46 struct sect {
47 unsigned long vaddr;
48 unsigned long len;
49 };
50
51 int phcmp ();
52 char *saveRead (int file, off_t offset, off_t len, char *name);
53 int copy (int, int, off_t, off_t);
54 int translate_syms (int, int, off_t, off_t, off_t, off_t);
55 extern int errno;
56 int *symTypeTable;
57
58 main (int argc, char **argv, char **envp)
59 {
60 struct ehdr ex;
61 struct phdr *ph;
62 struct shdr *sh;
63 struct sym *symtab;
64 char *shstrtab;
65 int strtabix, symtabix;
66 int i, pad;
67 struct sect text, data, bss;
68 struct ecoff_filehdr efh;
69 struct ecoff_aouthdr eah;
70 struct ecoff_scnhdr esecs [3];
71 int infile, outfile;
72 unsigned long cur_vma = ULONG_MAX;
73 int symflag = 0;
74
75 text.len = data.len = bss.len = 0;
76 text.vaddr = data.vaddr = bss.vaddr = 0;
77
78 /* Check args... */
79 if (argc < 3 || argc > 4)
80 {
81 usage:
82 fprintf (stderr,
83 "usage: elf2aout <elf executable> <a.out executable> [-s]\n");
84 exit (1);
85 }
86 if (argc == 4)
87 {
88 if (strcmp (argv [3], "-s"))
89 goto usage;
90 symflag = 1;
91 }
92
93 /* Try the input file... */
94 if ((infile = open (argv [1], O_RDONLY)) < 0)
95 {
96 fprintf (stderr, "Can't open %s for read: %s\n",
97 argv [1], strerror (errno));
98 exit (1);
99 }
100
101 /* Read the header, which is at the beginning of the file... */
102 i = read (infile, &ex, sizeof ex);
103 if (i != sizeof ex)
104 {
105 fprintf (stderr, "ex: %s: %s.\n",
106 argv [1], i ? strerror (errno) : "End of file reached");
107 exit (1);
108 }
109
110 /* Read the program headers... */
111 ph = (struct phdr *)saveRead (infile, ex.phoff,
112 ex.phcount * sizeof (struct phdr), "ph");
113 /* Read the section headers... */
114 sh = (struct shdr *)saveRead (infile, ex.shoff,
115 ex.shcount * sizeof (struct shdr), "sh");
116 /* Read in the section string table. */
117 shstrtab = saveRead (infile, sh [ex.shstrndx].offset,
118 sh [ex.shstrndx].size, "shstrtab");
119
120 /* Figure out if we can cram the program header into an ECOFF
121 header... Basically, we can't handle anything but loadable
122 segments, but we can ignore some kinds of segments. We can't
123 handle holes in the address space. Segments may be out of order,
124 so we sort them first. */
125
126 qsort (ph, ex.phcount, sizeof (struct phdr), phcmp);
127
128 for (i = 0; i < ex.phcount; i++)
129 {
130 /* Section types we can ignore... */
131 if (ph [i].type == PT_NULL || ph [i].type == PT_NOTE ||
132 ph [i].type == PT_PHDR || ph [i].type == PT_MIPS_REGINFO)
133 continue;
134 /* Section types we can't handle... */
135 else if (ph [i].type != PT_LOAD)
136 {
137 fprintf (stderr, "Program header %d type %d can't be converted.\n");
138 exit (1);
139 }
140 /* Writable (data) segment? */
141 if (ph [i].flags & PF_W)
142 {
143 struct sect ndata, nbss;
144
145 ndata.vaddr = ph [i].vaddr;
146 ndata.len = ph [i].filesz;
147 nbss.vaddr = ph [i].vaddr + ph [i].filesz;
148 nbss.len = ph [i].memsz - ph [i].filesz;
149
150 combine (&data, &ndata, 0);
151 combine (&bss, &nbss, 1);
152 }
153 else
154 {
155 struct sect ntxt;
156
157 ntxt.vaddr = ph [i].vaddr;
158 ntxt.len = ph [i].filesz;
159
160 combine (&text, &ntxt);
161 }
162 /* Remember the lowest segment start address. */
163 if (ph [i].vaddr < cur_vma)
164 cur_vma = ph [i].vaddr;
165 }
166
167 /* Sections must be in order to be converted... */
168 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
169 text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
170 {
171 fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
172 exit (1);
173 }
174
175 /* If there's a data section but no text section, then the loader
176 combined everything into one section. That needs to be the
177 text section, so just make the data section zero length following
178 text. */
179 if (data.len && !text.len)
180 {
181 text = data;
182 data.vaddr = text.vaddr + text.len;
183 data.len = 0;
184 }
185
186 /* If there is a gap between text and data, we'll fill it when we copy
187 the data, so update the length of the text segment as represented in
188 a.out to reflect that, since a.out doesn't allow gaps in the program
189 address space. */
190 if (text.vaddr + text.len < data.vaddr)
191 text.len = data.vaddr - text.vaddr;
192
193 /* We now have enough information to cons up an a.out header... */
194 eah.ea_magic = ECOFF_OMAGIC;
195 eah.ea_vstamp = 200;
196 eah.ea_tsize = text.len;
197 eah.ea_dsize = data.len;
198 eah.ea_bsize = bss.len;
199 eah.ea_entry = ex.entry;
200 eah.ea_text_start = text.vaddr;
201 eah.ea_data_start = data.vaddr;
202 eah.ea_bss_start = bss.vaddr;
203 eah.ea_gprmask = 0xf3fffffe;
204 bzero (&eah.ea_cprmask, sizeof eah.ea_cprmask);
205 eah.ea_gp_value = 0; /* unused. */
206
207 efh.ef_magic = ECOFF_MAGIC_MIPSEL;
208 efh.ef_nsecs = 3;
209 efh.ef_timestamp = 0; /* bogus */
210 efh.ef_symptr = 0;
211 efh.ef_syms = 0;
212 efh.ef_opthdr = sizeof eah;
213 efh.ef_flags = 0x100f; /* Stripped, not sharable. */
214
215 strcpy (esecs [0].es_name, ".text");
216 strcpy (esecs [1].es_name, ".data");
217 strcpy (esecs [2].es_name, ".bss");
218 esecs [0].es_physaddr = esecs [0].es_virtaddr = eah.ea_text_start;
219 esecs [1].es_physaddr = esecs [1].es_virtaddr = eah.ea_data_start;
220 esecs [2].es_physaddr = esecs [2].es_virtaddr = eah.ea_bss_start;
221 esecs [0].es_size = eah.ea_tsize;
222 esecs [1].es_size = eah.ea_dsize;
223 esecs [2].es_size = eah.ea_bsize;
224 esecs [0].es_raw_offset = ECOFF_TXTOFF (&efh, &eah);
225 esecs [1].es_raw_offset = ECOFF_DATOFF (&efh, &eah);
226 esecs [2].es_raw_offset = esecs [1].es_raw_offset +
227 ECOFF_ROUND (esecs [1].es_size, ECOFF_SEGMENT_ALIGNMENT (&eah));
228 esecs [0].es_reloc_offset = esecs [1].es_reloc_offset
229 = esecs [2].es_reloc_offset = 0;
230 esecs [0].es_line_offset = esecs [1].es_line_offset
231 = esecs [2].es_line_offset = 0;
232 esecs [0].es_nreloc = esecs [1].es_nreloc = esecs [2].es_nreloc = 0;
233 esecs [0].es_nline = esecs [1].es_nline = esecs [2].es_nline = 0;
234 esecs [0].es_flags = 0x20;
235 esecs [1].es_flags = 0x40;
236 esecs [2].es_flags = 0x82;
237
238 /* Make the output file... */
239 if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
240 {
241 fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
242 exit (1);
243 }
244
245 /* Write the headers... */
246 i = write (outfile, &efh, sizeof efh);
247 if (i != sizeof efh)
248 {
249 perror ("efh: write");
250 exit (1);
251
252 for (i = 0; i < 6; i++)
253 {
254 printf ("Section %d: %s phys %x size %x file offset %x\n",
255 i, esecs [i].es_name, esecs [i].es_physaddr,
256 esecs [i].es_size, esecs [i].es_raw_offset);
257 }
258 }
259 fprintf (stderr, "wrote %d byte file header.\n", i);
260
261 i = write (outfile, &eah, sizeof eah);
262 if (i != sizeof eah)
263 {
264 perror ("eah: write");
265 exit (1);
266 }
267 fprintf (stderr, "wrote %d byte a.out header.\n", i);
268
269 i = write (outfile, &esecs, sizeof esecs);
270 if (i != sizeof esecs)
271 {
272 perror ("esecs: write");
273 exit (1);
274 }
275 fprintf (stderr, "wrote %d bytes of section headers.\n", i);
276
277 if (pad = ((sizeof efh + sizeof eah + sizeof esecs) & 15))
278 {
279 pad = 16 - pad;
280 i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
281 if (i < 0)
282 {
283 perror ("ipad: write");
284 exit (1);
285 }
286 fprintf (stderr, "wrote %d byte pad.\n", i);
287 }
288
289 /* Copy the loadable sections. Zero-fill any gaps less than 64k;
290 complain about any zero-filling, and die if we're asked to zero-fill
291 more than 64k. */
292 for (i = 0; i < ex.phcount; i++)
293 {
294 /* Unprocessable sections were handled above, so just verify that
295 the section can be loaded before copying. */
296 if (ph [i].type == PT_LOAD && ph [i].filesz)
297 {
298 if (cur_vma != ph [i].vaddr)
299 {
300 unsigned long gap = ph [i].vaddr - cur_vma;
301 char obuf [1024];
302 if (gap > 65536)
303 {
304 fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
305 gap);
306 exit (1);
307 }
308 fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
309 memset (obuf, 0, sizeof obuf);
310 while (gap)
311 {
312 int count = write (outfile, obuf, (gap > sizeof obuf
313 ? sizeof obuf : gap));
314 if (count < 0)
315 {
316 fprintf (stderr, "Error writing gap: %s\n",
317 strerror (errno));
318 exit (1);
319 }
320 gap -= count;
321 }
322 }
323 fprintf (stderr, "writing %d bytes...\n", ph [i].filesz);
324 copy (outfile, infile, ph [i].offset, ph [i].filesz);
325 cur_vma = ph [i].vaddr + ph [i].filesz;
326 }
327 }
328
329 /* Looks like we won... */
330 exit (0);
331 }
332
333 copy (out, in, offset, size)
334 int out, in;
335 off_t offset, size;
336 {
337 char ibuf [4096];
338 int remaining, cur, count;
339
340 /* Go the the start of the ELF symbol table... */
341 if (lseek (in, offset, SEEK_SET) < 0)
342 {
343 perror ("copy: lseek");
344 exit (1);
345 }
346
347 remaining = size;
348 while (remaining)
349 {
350 cur = remaining;
351 if (cur > sizeof ibuf)
352 cur = sizeof ibuf;
353 remaining -= cur;
354 if ((count = read (in, ibuf, cur)) != cur)
355 {
356 fprintf (stderr, "copy: read: %s\n",
357 count ? strerror (errno) : "premature end of file");
358 exit (1);
359 }
360 if ((count = write (out, ibuf, cur)) != cur)
361 {
362 perror ("copy: write");
363 exit (1);
364 }
365 }
366 }
367
368 /* Combine two segments, which must be contiguous. If pad is true, it's
369 okay for there to be padding between. */
370 combine (base, new, pad)
371 struct sect *base, *new;
372 int pad;
373 {
374 if (!base -> len)
375 *base = *new;
376 else if (new -> len)
377 {
378 if (base -> vaddr + base -> len != new -> vaddr)
379 {
380 if (pad)
381 base -> len = new -> vaddr - base -> vaddr;
382 else
383 {
384 fprintf (stderr,
385 "Non-contiguous data can't be converted.\n");
386 exit (1);
387 }
388 }
389 base -> len += new -> len;
390 }
391 }
392
393 phcmp (h1, h2)
394 struct phdr *h1, *h2;
395 {
396 if (h1 -> vaddr > h2 -> vaddr)
397 return 1;
398 else if (h1 -> vaddr < h2 -> vaddr)
399 return -1;
400 else
401 return 0;
402 }
403
404 char *saveRead (int file, off_t offset, off_t len, char *name)
405 {
406 char *tmp;
407 int count;
408 off_t off;
409 if ((off = lseek (file, offset, SEEK_SET)) < 0)
410 {
411 fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
412 exit (1);
413 }
414 if (!(tmp = (char *)malloc (len)))
415 {
416 fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
417 exit (1);
418 }
419 count = read (file, tmp, len);
420 if (count != len)
421 {
422 fprintf (stderr, "%s: read: %s.\n",
423 name, count ? strerror (errno) : "End of file reached");
424 exit (1);
425 }
426 return tmp;
427 }
428