elf2aout.c revision 1.2 1 /* $NetBSD: elf2aout.c,v 1.2 1996/09/29 22:01:44 jonathan Exp $ */
2
3 /*
4 * Copyright (c) 1995
5 * Ted Lemon (hereinafter referred to as the author)
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /* elf2aout.c
32
33 This program converts an elf executable to a NetBSD a.out executable.
34 The minimal symbol table is copied, but the debugging symbols and
35 other informational sections are not. */
36
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <machine/elf.h>
41 #include <stdio.h>
42 #include <a.out.h>
43 #include <sys/errno.h>
44 #include <string.h>
45 #include <limits.h>
46
47 struct sect {
48 unsigned long vaddr;
49 unsigned long len;
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;
67 struct sect text, data, bss;
68 struct exec aex;
69 int infile, outfile;
70 unsigned long cur_vma = ULONG_MAX;
71 int symflag = 0;
72
73 text.len = data.len = bss.len = 0;
74 text.vaddr = data.vaddr = bss.vaddr = 0;
75
76 /* Check args... */
77 if (argc < 3 || argc > 4)
78 {
79 usage:
80 fprintf (stderr,
81 "usage: elf2aout <elf executable> <a.out executable> [-s]\n");
82 exit (1);
83 }
84 if (argc == 4)
85 {
86 if (strcmp (argv [3], "-s"))
87 goto usage;
88 symflag = 1;
89 }
90
91 /* Try the input file... */
92 if ((infile = open (argv [1], O_RDONLY)) < 0)
93 {
94 fprintf (stderr, "Can't open %s for read: %s\n",
95 argv [1], strerror (errno));
96 exit (1);
97 }
98
99 /* Read the header, which is at the beginning of the file... */
100 i = read (infile, &ex, sizeof ex);
101 if (i != sizeof ex)
102 {
103 fprintf (stderr, "ex: %s: %s.\n",
104 argv [1], i ? strerror (errno) : "End of file reached");
105 exit (1);
106 }
107
108 /* Read the program headers... */
109 ph = (struct phdr *)saveRead (infile, ex.phoff,
110 ex.phcount * sizeof (struct phdr), "ph");
111 /* Read the section headers... */
112 sh = (struct shdr *)saveRead (infile, ex.shoff,
113 ex.shcount * sizeof (struct shdr), "sh");
114 /* Read in the section string table. */
115 shstrtab = saveRead (infile, sh [ex.shstrndx].offset,
116 sh [ex.shstrndx].size, "shstrtab");
117
118 /* Find space for a table matching ELF section indices to a.out symbol
119 types. */
120 symTypeTable = (int *)malloc (ex.shcount * sizeof (int));
121 if (!symTypeTable)
122 {
123 fprintf (stderr, "symTypeTable: can't allocate.\n");
124 exit (1);
125 }
126 memset (symTypeTable, 0, ex.shcount * sizeof (int));
127
128 /* Look for the symbol table and string table...
129 Also map section indices to symbol types for a.out */
130 for (i = 0; i < ex.shcount; i++)
131 {
132 char *name = shstrtab + sh [i].name;
133 if (!strcmp (name, ".symtab"))
134 symtabix = i;
135 else if (!strcmp (name, ".strtab"))
136 strtabix = i;
137 else if (!strcmp (name, ".text") || !strcmp (name, ".rodata"))
138 symTypeTable [i] = N_TEXT;
139 else if (!strcmp (name, ".data") || !strcmp (name, ".sdata") ||
140 !strcmp (name, ".lit4") || !strcmp (name, ".lit8"))
141 symTypeTable [i] = N_DATA;
142 else if (!strcmp (name, ".bss") || !strcmp (name, ".sbss"))
143 symTypeTable [i] = N_BSS;
144 }
145
146 /* Figure out if we can cram the program header into an a.out header...
147 Basically, we can't handle anything but loadable segments, but we
148 can ignore some kinds of segments. We can't handle holes in the
149 address space, and we handle start addresses other than 0x1000 by
150 hoping that the loader will know where to load - a.out doesn't have
151 an explicit load address. Segments may be out of order, so we
152 sort them first. */
153 qsort (ph, ex.phcount, sizeof (struct phdr), phcmp);
154 for (i = 0; i < ex.phcount; i++)
155 {
156 /* Section types we can ignore... */
157 if (ph [i].type == PT_NULL || ph [i].type == PT_NOTE ||
158 ph [i].type == PT_PHDR || ph [i].type == PT_MIPS_REGINFO)
159 continue;
160 /* Section types we can't handle... */
161 else if (ph [i].type != PT_LOAD)
162 {
163 fprintf (stderr, "Program header %d type %d can't be converted.\n");
164 exit (1);
165 }
166 /* Writable (data) segment? */
167 if (ph [i].flags & PF_W)
168 {
169 struct sect ndata, nbss;
170
171 ndata.vaddr = ph [i].vaddr;
172 ndata.len = ph [i].filesz;
173 nbss.vaddr = ph [i].vaddr + ph [i].filesz;
174 nbss.len = ph [i].memsz - ph [i].filesz;
175
176 combine (&data, &ndata, 0);
177 combine (&bss, &nbss, 1);
178 }
179 else
180 {
181 struct sect ntxt;
182
183 ntxt.vaddr = ph [i].vaddr;
184 ntxt.len = ph [i].filesz;
185
186 combine (&text, &ntxt);
187 }
188 /* Remember the lowest segment start address. */
189 if (ph [i].vaddr < cur_vma)
190 cur_vma = ph [i].vaddr;
191 }
192
193 /* Sections must be in order to be converted... */
194 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
195 text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
196 {
197 fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
198 exit (1);
199 }
200
201 /* If there's a data section but no text section, then the loader
202 combined everything into one section. That needs to be the
203 text section, so just make the data section zero length following
204 text. */
205 if (data.len && !text.len)
206 {
207 text = data;
208 data.vaddr = text.vaddr + text.len;
209 data.len = 0;
210 }
211
212 /* If there is a gap between text and data, we'll fill it when we copy
213 the data, so update the length of the text segment as represented in
214 a.out to reflect that, since a.out doesn't allow gaps in the program
215 address space. */
216 if (text.vaddr + text.len < data.vaddr)
217 text.len = data.vaddr - text.vaddr;
218
219 /* We now have enough information to cons up an a.out header... */
220 aex.a_midmag = htonl ((symflag << 26) | (MID_PMAX << 16) | OMAGIC);
221 aex.a_text = text.len;
222 aex.a_data = data.len;
223 aex.a_bss = bss.len;
224 aex.a_entry = ex.entry;
225 aex.a_syms = (sizeof (struct nlist) *
226 (symtabix != -1
227 ? sh [symtabix].size / sizeof (struct sym) : 0));
228 aex.a_trsize = 0;
229 aex.a_drsize = 0;
230
231 /* Make the output file... */
232 if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
233 {
234 fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
235 exit (1);
236 }
237 /* Write the header... */
238 i = write (outfile, &aex, sizeof aex);
239 if (i != sizeof aex)
240 {
241 perror ("aex: write");
242 exit (1);
243 }
244
245 /* Copy the loadable sections. Zero-fill any gaps less than 64k;
246 complain about any zero-filling, and die if we're asked to zero-fill
247 more than 64k. */
248 for (i = 0; i < ex.phcount; i++)
249 {
250 /* Unprocessable sections were handled above, so just verify that
251 the section can be loaded before copying. */
252 if (ph [i].type == PT_LOAD && ph [i].filesz)
253 {
254 if (cur_vma != ph [i].vaddr)
255 {
256 unsigned long gap = ph [i].vaddr - cur_vma;
257 char obuf [1024];
258 if (gap > 65536)
259 {
260 fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
261 gap);
262 exit (1);
263 }
264 fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
265 memset (obuf, 0, sizeof obuf);
266 while (gap)
267 {
268 int count = write (outfile, obuf, (gap > sizeof obuf
269 ? sizeof obuf : gap));
270 if (count < 0)
271 {
272 fprintf (stderr, "Error writing gap: %s\n",
273 strerror (errno));
274 exit (1);
275 }
276 gap -= count;
277 }
278 }
279 copy (outfile, infile, ph [i].offset, ph [i].filesz);
280 cur_vma = ph [i].vaddr + ph [i].filesz;
281 }
282 }
283
284 /* Copy and translate the symbol table... */
285 translate_syms (outfile, infile, sh [symtabix].offset, sh [symtabix].size,
286 sh [strtabix].offset, sh [strtabix].size);
287
288 /* Looks like we won... */
289 exit (0);
290 }
291
292 /* translate_syms (out, in, offset, size)
293
294 Read the ELF symbol table from in at offset; translate it into a.out
295 nlist format and write it to out. */
296
297 translate_syms (out, in, symoff, symsize, stroff, strsize)
298 int out, in;
299 off_t symoff, symsize;
300 off_t stroff, strsize;
301 {
302 # define SYMS_PER_PASS 64
303 struct sym inbuf [64];
304 struct nlist outbuf [64];
305 int i, remaining, cur;
306 char *oldstrings;
307 char *newstrings, *nsp;
308 int newstringsize;
309
310 /* Zero the unused fields in the output buffer.. */
311 memset (outbuf, 0, sizeof outbuf);
312
313 /* Find number of symbols to process... */
314 remaining = symsize / sizeof (struct sym);
315
316 /* Suck in the old string table... */
317 oldstrings = saveRead (in, stroff, strsize, "string table");
318
319 /* Allocate space for the new one. XXX We make the wild assumption that
320 no two symbol table entries will point at the same place in the
321 string table - if that assumption is bad, this could easily blow up. */
322 newstringsize = strsize + remaining;
323 newstrings = (char *)malloc (newstringsize);
324 if (!newstrings)
325 {
326 fprintf (stderr, "No memory for new string table!\n");
327 exit (1);
328 }
329 /* Initialize the table pointer... */
330 nsp = newstrings;
331
332 /* Go the the start of the ELF symbol table... */
333 if (lseek (in, symoff, SEEK_SET) < 0)
334 {
335 perror ("translate_syms: lseek");
336 exit (1);
337 }
338
339 /* Translate and copy symbols... */
340 while (remaining)
341 {
342 cur = remaining;
343 if (cur > SYMS_PER_PASS)
344 cur = SYMS_PER_PASS;
345 remaining -= cur;
346 if ((i = read (in, inbuf, cur * sizeof (struct sym)))
347 != cur * sizeof (struct sym))
348 {
349 if (i < 0)
350 perror ("translate_syms");
351 else
352 fprintf (stderr, "translate_syms: premature end of file.\n");
353 exit (1);
354 }
355
356 /* Do the translation... */
357 for (i = 0; i < cur; i++)
358 {
359 /* Copy the symbol into the new table, but prepend an underscore. */
360 *nsp = '_';
361 strcpy (nsp + 1, oldstrings + inbuf [i].name);
362 outbuf [i].n_un.n_strx = nsp - newstrings + 4;
363 nsp += strlen (nsp) + 1;
364
365 /* Convert ELF symbol type/section/etc info into a.out type info. */
366 if (inbuf [i].type == STT_FILE)
367 outbuf [i].n_type = N_FN;
368 else if (inbuf [i].shndx == SHN_UNDEF)
369 outbuf [i].n_type = N_UNDF;
370 else if (inbuf [i].shndx == SHN_ABS)
371 outbuf [i].n_type = N_ABS;
372 else if (inbuf [i].shndx == SHN_COMMON ||
373 inbuf [i].shndx == SHN_MIPS_ACOMMON)
374 outbuf [i].n_type = N_COMM;
375 else
376 outbuf [i].n_type = symTypeTable [inbuf [i].shndx];
377 if (inbuf [i].binding == STB_GLOBAL)
378 outbuf [i].n_type |= N_EXT;
379 /* Symbol values in executables should be compatible. */
380 outbuf [i].n_value = inbuf [i].value;
381 }
382 /* Write out the symbols... */
383 if ((i = write (out, outbuf, cur * sizeof (struct nlist)))
384 != cur * sizeof (struct nlist))
385 {
386 fprintf (stderr, "translate_syms: write: %s\n", strerror (errno));
387 exit (1);
388 }
389 }
390 /* Write out the string table length... */
391 if (write (out, &newstringsize, sizeof newstringsize)
392 != sizeof newstringsize)
393 {
394 fprintf (stderr,
395 "translate_syms: newstringsize: %s\n", strerror (errno));
396 exit (1);
397 }
398 /* Write out the string table... */
399 if (write (out, newstrings, newstringsize) != newstringsize)
400 {
401 fprintf (stderr, "translate_syms: newstrings: %s\n", strerror (errno));
402 exit (1);
403 }
404 }
405
406 copy (out, in, offset, size)
407 int out, in;
408 off_t offset, size;
409 {
410 char ibuf [4096];
411 int remaining, cur, count;
412
413 /* Go the the start of the ELF symbol table... */
414 if (lseek (in, offset, SEEK_SET) < 0)
415 {
416 perror ("copy: lseek");
417 exit (1);
418 }
419
420 remaining = size;
421 while (remaining)
422 {
423 cur = remaining;
424 if (cur > sizeof ibuf)
425 cur = sizeof ibuf;
426 remaining -= cur;
427 if ((count = read (in, ibuf, cur)) != cur)
428 {
429 fprintf (stderr, "copy: read: %s\n",
430 count ? strerror (errno) : "premature end of file");
431 exit (1);
432 }
433 if ((count = write (out, ibuf, cur)) != cur)
434 {
435 perror ("copy: write");
436 exit (1);
437 }
438 }
439 }
440
441 /* Combine two segments, which must be contiguous. If pad is true, it's
442 okay for there to be padding between. */
443 combine (base, new, pad)
444 struct sect *base, *new;
445 int pad;
446 {
447 if (!base -> len)
448 *base = *new;
449 else if (new -> len)
450 {
451 if (base -> vaddr + base -> len != new -> vaddr)
452 {
453 if (pad)
454 base -> len = new -> vaddr - base -> vaddr;
455 else
456 {
457 fprintf (stderr,
458 "Non-contiguous data can't be converted.\n");
459 exit (1);
460 }
461 }
462 base -> len += new -> len;
463 }
464 }
465
466 phcmp (h1, h2)
467 struct phdr *h1, *h2;
468 {
469 if (h1 -> vaddr > h2 -> vaddr)
470 return 1;
471 else if (h1 -> vaddr < h2 -> vaddr)
472 return -1;
473 else
474 return 0;
475 }
476
477 char *saveRead (int file, off_t offset, off_t len, char *name)
478 {
479 char *tmp;
480 int count;
481 off_t off;
482 if ((off = lseek (file, offset, SEEK_SET)) < 0)
483 {
484 fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
485 exit (1);
486 }
487 if (!(tmp = (char *)malloc (len)))
488 {
489 fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
490 exit (1);
491 }
492 count = read (file, tmp, len);
493 if (count != len)
494 {
495 fprintf (stderr, "%s: read: %s.\n",
496 name, count ? strerror (errno) : "End of file reached");
497 exit (1);
498 }
499 return tmp;
500 }
501