elf2aout.c revision 1.19 1 /* $NetBSD: elf2aout.c,v 1.19 2016/03/07 22:16:38 martin 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 #if HAVE_NBTOOL_CONFIG_H
38 #include "nbtool_config.h"
39 #endif
40
41 #ifndef TARGET_BYTE_ORDER
42 #define TARGET_BYTE_ORDER BYTE_ORDER
43 #endif
44
45 #include <sys/types.h>
46 #include <sys/exec_aout.h>
47 #include <sys/exec_elf.h>
48
49 #include <a.out.h>
50 #include <err.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <limits.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59
60 struct sect {
61 /* should be unsigned long, but assume no a.out binaries on LP64 */
62 uint32_t vaddr;
63 uint32_t len;
64 };
65
66 void combine(struct sect *, struct sect *, int);
67 int phcmp(const void *, const void *);
68 void *saveRead(int file, off_t offset, size_t len, const char *name);
69 void copy(int, int, off_t, off_t);
70 void translate_syms(int, int, off_t, off_t, off_t, off_t);
71
72 #if TARGET_BYTE_ORDER != BYTE_ORDER
73 void bswap32_region(int32_t* , int);
74 #endif
75
76 int *symTypeTable;
77
78 int
79 main(int argc, char **argv)
80 {
81 Elf32_Ehdr ex;
82 Elf32_Phdr *ph;
83 Elf32_Shdr *sh;
84 char *shstrtab;
85 ssize_t i, strtabix, symtabix;
86 struct sect text, data, bss;
87 struct exec aex;
88 int infile, outfile;
89 uint32_t cur_vma = UINT32_MAX;
90 uint32_t mid;
91 int symflag = 0;
92
93 strtabix = symtabix = 0;
94 text.len = data.len = bss.len = 0;
95 text.vaddr = data.vaddr = bss.vaddr = 0;
96
97 /* Check args... */
98 if (argc < 3 || argc > 4) {
99 usage:
100 fprintf(stderr,
101 "Usage: %s <elf executable> <a.out executable> [-s]\n",
102 getprogname());
103 exit(EXIT_FAILURE);
104 }
105 if (argc == 4) {
106 if (strcmp(argv[3], "-s"))
107 goto usage;
108 symflag = 1;
109 }
110 /* Try the input file... */
111 if ((infile = open(argv[1], O_RDONLY)) < 0)
112 err(EXIT_FAILURE, "Can't open `%s' for read", argv[1]);
113
114 /* Read the header, which is at the beginning of the file... */
115 i = read(infile, &ex, sizeof ex);
116 if (i != sizeof ex) {
117 if (i == -1)
118 err(EXIT_FAILURE, "Error reading `%s'", argv[1]);
119 else
120 errx(EXIT_FAILURE, "End of file reading `%s'", argv[1]);
121 }
122 #if TARGET_BYTE_ORDER != BYTE_ORDER
123 ex.e_type = bswap16(ex.e_type);
124 ex.e_machine = bswap16(ex.e_machine);
125 ex.e_version = bswap32(ex.e_version);
126 ex.e_entry = bswap32(ex.e_entry);
127 ex.e_phoff = bswap32(ex.e_phoff);
128 ex.e_shoff = bswap32(ex.e_shoff);
129 ex.e_flags = bswap32(ex.e_flags);
130 ex.e_ehsize = bswap16(ex.e_ehsize);
131 ex.e_phentsize = bswap16(ex.e_phentsize);
132 ex.e_phnum = bswap16(ex.e_phnum);
133 ex.e_shentsize = bswap16(ex.e_shentsize);
134 ex.e_shnum = bswap16(ex.e_shnum);
135 ex.e_shstrndx = bswap16(ex.e_shstrndx);
136 #endif
137 /* Read the program headers... */
138 ph = saveRead(infile, ex.e_phoff,
139 (size_t)ex.e_phnum * sizeof(Elf32_Phdr), "ph");
140 #if TARGET_BYTE_ORDER != BYTE_ORDER
141 bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
142 #endif
143 /* Read the section headers... */
144 sh = saveRead(infile, ex.e_shoff,
145 (size_t)ex.e_shnum * sizeof(Elf32_Shdr), "sh");
146 #if TARGET_BYTE_ORDER != BYTE_ORDER
147 bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
148 #endif
149 /* Read in the section string table. */
150 shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
151 (size_t)sh[ex.e_shstrndx].sh_size, "shstrtab");
152
153 /* Find space for a table matching ELF section indices to a.out symbol
154 * types. */
155 symTypeTable = malloc(ex.e_shnum * sizeof(int));
156 if (symTypeTable == NULL)
157 err(EXIT_FAILURE, "symTypeTable: can't allocate");
158 memset(symTypeTable, 0, ex.e_shnum * sizeof(int));
159
160 /* Look for the symbol table and string table... Also map section
161 * indices to symbol types for a.out */
162 for (i = 0; i < ex.e_shnum; i++) {
163 char *name = shstrtab + sh[i].sh_name;
164 if (!strcmp(name, ".symtab"))
165 symtabix = i;
166 else
167 if (!strcmp(name, ".strtab"))
168 strtabix = i;
169 else
170 if (!strcmp(name, ".text") || !strcmp(name, ".rodata"))
171 symTypeTable[i] = N_TEXT;
172 else
173 if (!strcmp(name, ".data") || !strcmp(name, ".sdata") ||
174 !strcmp(name, ".lit4") || !strcmp(name, ".lit8"))
175 symTypeTable[i] = N_DATA;
176 else
177 if (!strcmp(name, ".bss") || !strcmp(name, ".sbss"))
178 symTypeTable[i] = N_BSS;
179 }
180
181 /* Figure out if we can cram the program header into an a.out
182 * header... Basically, we can't handle anything but loadable
183 * segments, but we can ignore some kinds of segments. We can't
184 * handle holes in the address space, and we handle start addresses
185 * other than 0x1000 by hoping that the loader will know where to load
186 * - a.out doesn't have an explicit load address. Segments may be
187 * out of order, so we sort them first. */
188 qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
189 for (i = 0; i < ex.e_phnum; i++) {
190 /* Section types we can ignore... */
191 if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
192 ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
193 continue;
194 /* Section types we can't handle... */
195 else
196 if (ph[i].p_type != PT_LOAD)
197 errx(EXIT_FAILURE, "Program header %zd "
198 "type %d can't be converted.",
199 i, ph[i].p_type);
200 /* Writable (data) segment? */
201 if (ph[i].p_flags & PF_W) {
202 struct sect ndata, nbss;
203
204 ndata.vaddr = ph[i].p_vaddr;
205 ndata.len = ph[i].p_filesz;
206 nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
207 nbss.len = ph[i].p_memsz - ph[i].p_filesz;
208
209 combine(&data, &ndata, 0);
210 combine(&bss, &nbss, 1);
211 } else {
212 struct sect ntxt;
213
214 ntxt.vaddr = ph[i].p_vaddr;
215 ntxt.len = ph[i].p_filesz;
216
217 combine(&text, &ntxt, 0);
218 }
219 /* Remember the lowest segment start address. */
220 if (ph[i].p_vaddr < cur_vma)
221 cur_vma = ph[i].p_vaddr;
222 }
223
224 /* Sections must be in order to be converted... */
225 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
226 text.vaddr + text.len > data.vaddr ||
227 data.vaddr + data.len > bss.vaddr)
228 errx(EXIT_FAILURE, "Sections ordering prevents a.out "
229 "conversion.");
230 /* If there's a data section but no text section, then the loader
231 * combined everything into one section. That needs to be the text
232 * section, so just make the data section zero length following text. */
233 if (data.len && text.len == 0) {
234 text = data;
235 data.vaddr = text.vaddr + text.len;
236 data.len = 0;
237 }
238 /* If there is a gap between text and data, we'll fill it when we copy
239 * the data, so update the length of the text segment as represented
240 * in a.out to reflect that, since a.out doesn't allow gaps in the
241 * program address space. */
242 if (text.vaddr + text.len < data.vaddr)
243 text.len = data.vaddr - text.vaddr;
244
245 /* We now have enough information to cons up an a.out header... */
246 switch (ex.e_machine) {
247 case EM_SPARC:
248 mid = MID_SPARC;
249 break;
250 case EM_386:
251 mid = MID_PC386;
252 break;
253 case EM_68K:
254 mid = MID_M68K;
255 break;
256 case EM_MIPS:
257 if (ex.e_ident[EI_DATA] == ELFDATA2LSB)
258 mid = MID_PMAX;
259 else
260 mid = MID_MIPS;
261 break;
262 case EM_PPC:
263 mid = MID_POWERPC;
264 break;
265 case EM_ARM:
266 mid = MID_ARM6;
267 break;
268 case EM_VAX:
269 mid = MID_VAX;
270 break;
271 case EM_NONE:
272 default:
273 mid = MID_ZERO;
274 }
275 aex.a_midmag = (u_long)htonl(((u_long)symflag << 26)
276 | ((u_long)mid << 16) | OMAGIC);
277
278 aex.a_text = text.len;
279 aex.a_data = data.len;
280 aex.a_bss = bss.len;
281 aex.a_entry = ex.e_entry;
282 aex.a_syms = (sizeof(struct nlist) *
283 (symtabix != -1
284 ? sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0));
285 aex.a_trsize = 0;
286 aex.a_drsize = 0;
287 #if TARGET_BYTE_ORDER != BYTE_ORDER
288 aex.a_text = bswap32(aex.a_text);
289 aex.a_data = bswap32(aex.a_data);
290 aex.a_bss = bswap32(aex.a_bss);
291 aex.a_entry = bswap32(aex.a_entry);
292 aex.a_syms = bswap32(aex.a_syms);
293 aex.a_trsize = bswap32(aex.a_trsize);
294 aex.a_drsize = bswap32(aex.a_drsize);
295 #endif
296
297 /* Make the output file... */
298 if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0)
299 err(EXIT_FAILURE, "Unable to create `%s'", argv[2]);
300 /* Truncate file... */
301 if (ftruncate(outfile, 0)) {
302 warn("ftruncate %s", argv[2]);
303 }
304 /* Write the header... */
305 i = write(outfile, &aex, sizeof aex);
306 if (i != sizeof aex)
307 err(EXIT_FAILURE, "Can't write `%s'", argv[2]);
308 /* Copy the loadable sections. Zero-fill any gaps less than 64k;
309 * complain about any zero-filling, and die if we're asked to
310 * zero-fill more than 64k. */
311 for (i = 0; i < ex.e_phnum; i++) {
312 /* Unprocessable sections were handled above, so just verify
313 * that the section can be loaded before copying. */
314 if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
315 if (cur_vma != ph[i].p_vaddr) {
316 uint32_t gap = ph[i].p_vaddr - cur_vma;
317 char obuf[1024];
318 if (gap > 65536)
319 errx(EXIT_FAILURE,
320 "Intersegment gap (%u bytes) too large", gap);
321 #ifdef DEBUG
322 warnx("%u byte intersegment gap", gap);
323 #endif
324 memset(obuf, 0, sizeof obuf);
325 while (gap) {
326 ssize_t count = write(outfile, obuf,
327 (gap > sizeof obuf
328 ? sizeof obuf : gap));
329 if (count < 0)
330 err(EXIT_FAILURE,
331 "Error writing gap");
332 gap -= (uint32_t)count;
333 }
334 }
335 copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
336 cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
337 }
338 }
339
340 /* Copy and translate the symbol table... */
341 translate_syms(outfile, infile,
342 sh[symtabix].sh_offset, sh[symtabix].sh_size,
343 sh[strtabix].sh_offset, sh[strtabix].sh_size);
344
345 free(ph);
346 free(sh);
347 free(shstrtab);
348 free(symTypeTable);
349 /* Looks like we won... */
350 return EXIT_SUCCESS;
351 }
352 /* translate_syms (out, in, offset, size)
353
354 Read the ELF symbol table from in at offset; translate it into a.out
355 nlist format and write it to out. */
356
357 void
358 translate_syms(int out, int in, off_t symoff, off_t symsize,
359 off_t stroff, off_t strsize)
360 {
361 #define SYMS_PER_PASS 64
362 Elf32_Sym inbuf[64];
363 struct nlist outbuf[64];
364 ssize_t i, remaining, cur;
365 char *oldstrings;
366 char *newstrings, *nsp;
367 size_t newstringsize, stringsizebuf;
368
369 /* Zero the unused fields in the output buffer.. */
370 memset(outbuf, 0, sizeof outbuf);
371
372 /* Find number of symbols to process... */
373 remaining = (ssize_t)(symsize / (off_t)sizeof(Elf32_Sym));
374
375 /* Suck in the old string table... */
376 oldstrings = saveRead(in, stroff, (size_t)strsize, "string table");
377
378 /* Allocate space for the new one. XXX We make the wild assumption
379 * that no two symbol table entries will point at the same place in
380 * the string table - if that assumption is bad, this could easily
381 * blow up. */
382 newstringsize = (size_t)(strsize + remaining);
383 newstrings = malloc(newstringsize);
384 if (newstrings == NULL)
385 err(EXIT_FAILURE, "No memory for new string table!");
386 /* Initialize the table pointer... */
387 nsp = newstrings;
388
389 /* Go the start of the ELF symbol table... */
390 if (lseek(in, symoff, SEEK_SET) < 0)
391 err(EXIT_FAILURE, "Can't seek");
392 /* Translate and copy symbols... */
393 while (remaining) {
394 cur = remaining;
395 if (cur > SYMS_PER_PASS)
396 cur = SYMS_PER_PASS;
397 remaining -= cur;
398 if ((i = read(in, inbuf, (size_t)cur * sizeof(Elf32_Sym)))
399 != cur * (ssize_t)sizeof(Elf32_Sym)) {
400 if (i < 0)
401 err(EXIT_FAILURE, "%s: read error", __func__);
402 else
403 errx(EXIT_FAILURE, "%s: premature end of file",
404 __func__);
405 }
406 /* Do the translation... */
407 for (i = 0; i < cur; i++) {
408 int binding, type;
409
410 #if TARGET_BYTE_ORDER != BYTE_ORDER
411 inbuf[i].st_name = bswap32(inbuf[i].st_name);
412 inbuf[i].st_value = bswap32(inbuf[i].st_value);
413 inbuf[i].st_size = bswap32(inbuf[i].st_size);
414 inbuf[i].st_shndx = bswap16(inbuf[i].st_shndx);
415 #endif
416 /* Copy the symbol into the new table, but prepend an
417 * underscore. */
418 *nsp = '_';
419 strcpy(nsp + 1, oldstrings + inbuf[i].st_name);
420 outbuf[i].n_un.n_strx = nsp - newstrings + 4;
421 nsp += strlen(nsp) + 1;
422
423 type = ELF32_ST_TYPE(inbuf[i].st_info);
424 binding = ELF32_ST_BIND(inbuf[i].st_info);
425
426 /* Convert ELF symbol type/section/etc info into a.out
427 * type info. */
428 if (type == STT_FILE)
429 outbuf[i].n_type = N_FN;
430 else
431 if (inbuf[i].st_shndx == SHN_UNDEF)
432 outbuf[i].n_type = N_UNDF;
433 else
434 if (inbuf[i].st_shndx == SHN_ABS)
435 outbuf[i].n_type = N_ABS;
436 else
437 if (inbuf[i].st_shndx == SHN_COMMON ||
438 inbuf[i].st_shndx == SHN_MIPS_ACOMMON)
439 outbuf[i].n_type = N_COMM;
440 else
441 outbuf[i].n_type = (unsigned char)symTypeTable[inbuf[i].st_shndx];
442 if (binding == STB_GLOBAL)
443 outbuf[i].n_type |= N_EXT;
444 /* Symbol values in executables should be compatible. */
445 outbuf[i].n_value = inbuf[i].st_value;
446 #if TARGET_BYTE_ORDER != BYTE_ORDER
447 outbuf[i].n_un.n_strx = bswap32(outbuf[i].n_un.n_strx);
448 outbuf[i].n_desc = bswap16(outbuf[i].n_desc);
449 outbuf[i].n_value = bswap32(outbuf[i].n_value);
450 #endif
451 }
452 /* Write out the symbols... */
453 if ((i = write(out, outbuf, (size_t)cur * sizeof(struct nlist)))
454 != cur * (ssize_t)sizeof(struct nlist))
455 err(EXIT_FAILURE, "%s: write failed", __func__);
456 }
457 /* Write out the string table length... */
458 stringsizebuf = newstringsize;
459 #if TARGET_BYTE_ORDER != BYTE_ORDER
460 stringsizebuf = bswap32(stringsizebuf);
461 #endif
462 if (write(out, &stringsizebuf, sizeof stringsizebuf)
463 != sizeof stringsizebuf)
464 err(EXIT_FAILURE, "%s: newstringsize: write failed", __func__);
465 /* Write out the string table... */
466 if (write(out, newstrings, newstringsize) != (ssize_t)newstringsize)
467 err(EXIT_FAILURE, "%s: newstrings: write failed", __func__);
468 free(newstrings);
469 free(oldstrings);
470 }
471
472 void
473 copy(int out, int in, off_t offset, off_t size)
474 {
475 char ibuf[4096];
476 ssize_t remaining, cur, count;
477
478 /* Go to the start of the ELF symbol table... */
479 if (lseek(in, offset, SEEK_SET) < 0)
480 err(EXIT_FAILURE, "%s: lseek failed", __func__);
481 if (size > SSIZE_MAX)
482 err(EXIT_FAILURE, "%s: can not copy this much", __func__);
483 remaining = (ssize_t)size;
484 while (remaining) {
485 cur = remaining;
486 if (cur > (int)sizeof ibuf)
487 cur = sizeof ibuf;
488 remaining -= cur;
489 if ((count = read(in, ibuf, (size_t)cur)) != cur) {
490 if (count < 0)
491 err(EXIT_FAILURE, "%s: read error", __func__);
492 else
493 errx(EXIT_FAILURE, "%s: premature end of file",
494 __func__);
495 }
496 if ((count = write(out, ibuf, (size_t)cur)) != cur)
497 err(EXIT_FAILURE, "%s: write failed", __func__);
498 }
499 }
500 /* Combine two segments, which must be contiguous. If pad is true, it's
501 okay for there to be padding between. */
502 void
503 combine(struct sect *base, struct sect *new, int pad)
504 {
505
506 if (base->len == 0)
507 *base = *new;
508 else
509 if (new->len) {
510 if (base->vaddr + base->len != new->vaddr) {
511 if (pad)
512 base->len = new->vaddr - base->vaddr;
513 else
514 errx(EXIT_FAILURE, "Non-contiguous "
515 "data can't be converted");
516 }
517 base->len += new->len;
518 }
519 }
520
521 int
522 phcmp(const void *vh1, const void *vh2)
523 {
524 const Elf32_Phdr *h1, *h2;
525
526 h1 = (const Elf32_Phdr *)vh1;
527 h2 = (const Elf32_Phdr *)vh2;
528
529 if (h1->p_vaddr > h2->p_vaddr)
530 return 1;
531 else
532 if (h1->p_vaddr < h2->p_vaddr)
533 return -1;
534 else
535 return 0;
536 }
537
538 void *
539 saveRead(int file, off_t offset, size_t len, const char *name)
540 {
541 char *tmp;
542 ssize_t count;
543 off_t off;
544
545 if ((off = lseek(file, offset, SEEK_SET)) < 0)
546 errx(EXIT_FAILURE, "%s: seek failed", name);
547 if ((tmp = malloc(len)) == NULL)
548 errx(EXIT_FAILURE,
549 "%s: Can't allocate %jd bytes.", name, (intmax_t)len);
550 count = read(file, tmp, len);
551 if ((size_t)count != len) {
552 if (count < 0)
553 err(EXIT_FAILURE, "%s: read error", name);
554 else
555 errx(EXIT_FAILURE, "%s: premature end of file",
556 name);
557 }
558 return tmp;
559 }
560
561 #if TARGET_BYTE_ORDER != BYTE_ORDER
562 /* swap a 32bit region */
563 void
564 bswap32_region(int32_t* p, int len)
565 {
566 size_t i;
567
568 for (i = 0; i < len / sizeof(int32_t); i++, p++)
569 *p = bswap32(*p);
570 }
571 #endif
572