Annotation of src/usr.bin/elf2aout/elf2aout.c, Revision 1.3
1.3 ! deraadt 1: /* $OpenBSD: elf2aout.c,v 1.2 2001/01/29 01:57:56 niklas Exp $ */
1.2 niklas 2:
1.1 graichen 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: #include <sys/types.h>
32: #include <fcntl.h>
33: #include <unistd.h>
34: #include <elf_abi.h>
35: #include <machine/elf_abi.h>
36: #include <stdio.h>
37: #include <a.out.h>
38: #include <sys/errno.h>
39: #include <string.h>
40: #include <limits.h>
41:
42: #define SHN_MIPS_ACOMMON 0xfff0
43:
1.3 ! deraadt 44: extern char *__progname;
1.1 graichen 45:
46: struct sect {
1.3 ! deraadt 47: unsigned long vaddr;
! 48: unsigned long len;
1.1 graichen 49: };
1.3 ! deraadt 50: int phcmp();
! 51: char *saveRead(int file, off_t offset, off_t len, char *name);
! 52: int copy(int, int, off_t, off_t);
! 53: int translate_syms(int, int, off_t, off_t, off_t, off_t);
! 54: extern int errno;
! 55: int *symTypeTable;
1.1 graichen 56:
57: /* Symbol table entry... */
58: struct sym {
1.3 ! deraadt 59: unsigned long name; /* Index into strtab of symbol name. */
! 60: unsigned long value; /* Section offset, virt addr or common align. */
! 61: unsigned long size; /* Size of object referenced. */
! 62: unsigned type:4; /* Symbol type (e.g., function, data)... */
! 63: unsigned binding:4; /* Symbol binding (e.g., global,
! 64: * local)... */
! 65: unsigned char other; /* Unused. */
! 66: unsigned short shndx; /* Section containing symbol. */
1.1 graichen 67: };
68:
69: struct phdr {
1.3 ! deraadt 70: unsigned long type; /* Segment type... */
! 71: unsigned long offset; /* File offset... */
! 72: unsigned long vaddr; /* Virtual address... */
! 73: unsigned long paddr; /* Physical address... */
! 74: unsigned long filesz; /* Size of segment in file... */
! 75: unsigned long memsz; /* Size of segment in memory... */
! 76: unsigned long flags; /* Segment flags... */
! 77: unsigned long align; /* Alighment, file and memory... */
1.1 graichen 78: };
79:
1.3 ! deraadt 80: int
! 81: main(int argc, char *argv[])
1.1 graichen 82: {
1.3 ! deraadt 83: Elf32_Ehdr ex;
! 84: Elf32_Phdr *ph;
! 85: Elf32_Shdr *sh;
! 86: struct sym *symtab;
! 87: char *shstrtab;
! 88: int strtabix, symtabix;
! 89: int i;
! 90: struct sect text, data, bss;
! 91: struct exec aex;
! 92: int infile, outfile;
! 93: unsigned long cur_vma = ULONG_MAX;
! 94: int symflag = 0;
! 95:
! 96: text.len = data.len = bss.len = 0;
! 97: text.vaddr = data.vaddr = bss.vaddr = 0;
! 98:
! 99: /* Check args... */
! 100: if (argc < 3 || argc > 4) {
! 101: usage:
! 102: fprintf(stderr,
! 103: "usage: %s elf a.out\n", __progname);
! 104: exit(1);
! 105: }
! 106: /* Try the input file... */
! 107: if ((infile = open(argv[1], O_RDONLY)) < 0) {
! 108: fprintf(stderr, "Can't open %s for read: %s\n",
! 109: argv[1], strerror(errno));
! 110: exit(1);
! 111: }
! 112: /* Read the header, which is at the beginning of the file... */
! 113: i = read(infile, &ex, sizeof ex);
! 114: if (i != sizeof ex) {
! 115: fprintf(stderr, "ex: %s: %s.\n",
! 116: argv[1], i ? strerror(errno) : "End of file reached");
! 117: exit(1);
! 118: }
! 119: /* Read the program headers... */
! 120: ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
! 121: ex.e_phnum * sizeof(Elf32_Phdr), "ph");
! 122: /* Read the section headers... */
! 123: sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
! 124: ex.e_shnum * sizeof(Elf32_Shdr), "sh");
! 125: /* Read in the section string table. */
! 126: shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
! 127: sh[ex.e_shstrndx].sh_size, "shstrtab");
! 128:
! 129: /*
! 130: * Find space for a table matching ELF section indices to a.out
! 131: * symbol types.
! 132: */
! 133: symTypeTable = (int *) malloc(ex.e_shnum * sizeof(int));
! 134: if (!symTypeTable) {
! 135: fprintf(stderr, "symTypeTable: can't allocate.\n");
! 136: exit(1);
! 137: }
! 138: memset(symTypeTable, 0, ex.e_shnum * sizeof(int));
! 139:
! 140: /*
! 141: * Look for the symbol table and string table... Also map section
! 142: * indices to symbol types for a.out
! 143: */
! 144: for (i = 0; i < ex.e_shnum; i++) {
! 145: char *name = shstrtab + sh[i].sh_name;
! 146: if (!strcmp(name, ".symtab"))
! 147: symtabix = i;
! 148: else if (!strcmp(name, ".strtab"))
! 149: strtabix = i;
! 150: else if (!strcmp(name, ".text") || !strcmp(name, ".rodata"))
! 151: symTypeTable[i] = N_TEXT;
! 152: else if (!strcmp(name, ".data") || !strcmp(name, ".sdata") ||
! 153: !strcmp(name, ".lit4") || !strcmp(name, ".lit8"))
! 154: symTypeTable[i] = N_DATA;
! 155: else if (!strcmp(name, ".bss") || !strcmp(name, ".sbss"))
! 156: symTypeTable[i] = N_BSS;
! 157: }
! 158:
! 159: /*
! 160: * Figure out if we can cram the program header into an a.out
! 161: * header... Basically, we can't handle anything but loadable
! 162: * segments, but we can ignore some kinds of segments. We can't
! 163: * handle holes in the address space, and we handle start addresses
! 164: * other than 0x1000 by hoping that the loader will know where to
! 165: * load - a.out doesn't have an explicit load address. Segments may
! 166: * be out of order, so we sort them first.
! 167: */
! 168: qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
! 169: for (i = 0; i < ex.e_phnum; i++) {
! 170: /* Section types we can ignore... */
! 171: if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
! 172: ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
! 173: continue;
! 174: /* Section types we can't handle... */
! 175: else if (ph[i].p_type != PT_LOAD) {
! 176: fprintf(stderr,
! 177: "Program header %d type %d can't be converted.\n");
! 178: exit(1);
! 179: }
! 180: /* Writable (data) segment? */
! 181: if (ph[i].p_flags & PF_W) {
! 182: struct sect ndata, nbss;
! 183:
! 184: ndata.vaddr = ph[i].p_vaddr;
! 185: ndata.len = ph[i].p_filesz;
! 186: nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
! 187: nbss.len = ph[i].p_memsz - ph[i].p_filesz;
! 188:
! 189: combine(&data, &ndata, 0);
! 190: combine(&bss, &nbss, 1);
! 191: } else {
! 192: struct sect ntxt;
! 193:
! 194: ntxt.vaddr = ph[i].p_vaddr;
! 195: ntxt.len = ph[i].p_filesz;
! 196:
! 197: combine(&text, &ntxt);
1.1 graichen 198: }
1.3 ! deraadt 199: /* Remember the lowest segment start address. */
! 200: if (ph[i].p_vaddr < cur_vma)
! 201: cur_vma = ph[i].p_vaddr;
! 202: }
! 203:
! 204: /* Sections must be in order to be converted... */
! 205: if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
! 206: text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
! 207: fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
! 208: exit(1);
! 209: }
! 210: /*
! 211: * If there's a data section but no text section, then the loader
! 212: * combined everything into one section. That needs to be the text
! 213: * section, so just make the data section zero length following text.
! 214: */
! 215: if (data.len && !text.len) {
! 216: text = data;
! 217: data.vaddr = text.vaddr + text.len;
! 218: data.len = 0;
! 219: }
! 220: /*
! 221: * If there is a gap between text and data, we'll fill it when we
! 222: * copy the data, so update the length of the text segment as
! 223: * represented in a.out to reflect that, since a.out doesn't allow
! 224: * gaps in the program address space.
! 225: */
! 226: if (text.vaddr + text.len < data.vaddr)
! 227: text.len = data.vaddr - text.vaddr;
! 228:
! 229: /* We now have enough information to cons up an a.out header... */
! 230: aex.a_midmag = htonl((symflag << 26) | (MID_PMAX << 16) | OMAGIC);
! 231: aex.a_text = text.len;
! 232: aex.a_data = data.len;
! 233: aex.a_bss = bss.len;
! 234: aex.a_entry = ex.e_entry;
! 235: aex.a_syms = (sizeof(struct nlist) *
! 236: (symtabix != -1
! 237: ? sh[symtabix].sh_size / sizeof(struct sym) : 0));
! 238: aex.a_trsize = 0;
! 239: aex.a_drsize = 0;
! 240:
! 241: /* Make the output file... */
! 242: if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
! 243: fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
! 244: exit(1);
! 245: }
! 246: /* Write the header... */
! 247: i = write(outfile, &aex, sizeof aex);
! 248: if (i != sizeof aex) {
! 249: perror("aex: write");
! 250: exit(1);
! 251: }
! 252: /*
! 253: * Copy the loadable sections. Zero-fill any gaps less than 64k;
! 254: * complain about any zero-filling, and die if we're asked to
! 255: * zero-fill more than 64k.
! 256: */
! 257: for (i = 0; i < ex.e_phnum; i++) {
! 258: /*
! 259: * Unprocessable sections were handled above, so just verify
! 260: * that the section can be loaded before copying.
! 261: */
! 262: if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
! 263: if (cur_vma != ph[i].p_vaddr) {
! 264: unsigned long gap = ph[i].p_vaddr - cur_vma;
! 265: char obuf[1024];
! 266:
! 267: if (gap > 65536) {
! 268: fprintf(stderr,
! 269: "Intersegment gap (%d bytes) too large.\n",
! 270: gap);
! 271: exit(1);
! 272: }
! 273: fprintf(stderr,
! 274: "Warning: %d byte intersegment gap.\n", gap);
! 275: memset(obuf, 0, sizeof obuf);
! 276: while (gap) {
! 277: int count = write(outfile, obuf,
! 278: (gap > sizeof obuf ? sizeof obuf : gap));
! 279: if (count < 0) {
! 280: fprintf(stderr,
! 281: "Error writing gap: %s\n",
! 282: strerror(errno));
! 283: exit(1);
! 284: }
! 285: gap -= count;
! 286: }
! 287: }
! 288: copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
! 289: cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
1.1 graichen 290: }
1.3 ! deraadt 291: }
! 292:
! 293: /* Copy and translate the symbol table... */
! 294: translate_syms(outfile, infile, sh[symtabix].sh_offset,
! 295: sh[symtabix].sh_size,
! 296: sh[strtabix].sh_offset, sh[strtabix].sh_size);
1.1 graichen 297:
1.3 ! deraadt 298: /* Looks like we won... */
! 299: exit(0);
1.1 graichen 300: }
301:
1.3 ! deraadt 302: /*
! 303: * translate_syms (out, in, offset, size)
! 304: *
! 305: * Read the ELF symbol table from in at offset; translate it into a.out nlist
! 306: * format and write it to out.
! 307: */
1.1 graichen 308:
1.3 ! deraadt 309: translate_syms(int out, int in, off_t symoff, off_t symsize, off_t stroff,
! 310: off_t strsize)
! 311: {
! 312: #define SYMS_PER_PASS 64
! 313: struct sym inbuf[64];
! 314: struct nlist outbuf[64];
! 315: int i, remaining, cur;
! 316: char *oldstrings;
! 317: char *newstrings, *nsp;
! 318: int newstringsize;
! 319:
! 320: /* Zero the unused fields in the output buffer.. */
! 321: memset(outbuf, 0, sizeof outbuf);
! 322:
! 323: /* Find number of symbols to process... */
! 324: remaining = symsize / sizeof(struct sym);
! 325:
! 326: /* Suck in the old string table... */
! 327: oldstrings = saveRead(in, stroff, strsize, "string table");
! 328:
! 329: /*
! 330: * Allocate space for the new one. XXX We make the wild assumption
! 331: * that no two symbol table entries will point at the same place in
! 332: * the string table - if that assumption is bad, this could easily
! 333: * blow up.
! 334: */
! 335: newstringsize = strsize + remaining;
! 336: newstrings = (char *) malloc(newstringsize);
! 337: if (!newstrings) {
! 338: fprintf(stderr, "No memory for new string table!\n");
! 339: exit(1);
! 340: }
! 341: /* Initialize the table pointer... */
! 342: nsp = newstrings;
1.1 graichen 343:
1.3 ! deraadt 344: /* Go the the start of the ELF symbol table... */
! 345: if (lseek(in, symoff, SEEK_SET) < 0) {
! 346: perror("translate_syms: lseek");
! 347: exit(1);
! 348: }
! 349: /* Translate and copy symbols... */
! 350: while (remaining) {
! 351: cur = remaining;
! 352: if (cur > SYMS_PER_PASS)
! 353: cur = SYMS_PER_PASS;
! 354: remaining -= cur;
! 355: if ((i = read(in, inbuf, cur * sizeof(struct sym)))
! 356: != cur * sizeof(struct sym)) {
! 357: if (i < 0)
! 358: perror("translate_syms");
! 359: else
! 360: fprintf(stderr,
! 361: "translate_syms: premature end of file.\n");
! 362: exit(1);
! 363: }
! 364: /* Do the translation... */
! 365: for (i = 0; i < cur; i++) {
! 366: /*
! 367: * Copy the symbol into the new table, but prepend an
! 368: * underscore.
! 369: */
! 370: *nsp = '_';
! 371: strcpy(nsp + 1, oldstrings + inbuf[i].name);
! 372: outbuf[i].n_un.n_strx = nsp - newstrings + 4;
! 373: nsp += strlen(nsp) + 1;
! 374:
! 375: /*
! 376: * Convert ELF symbol type/section/etc info into
! 377: * a.out type info.
! 378: */
! 379: if (inbuf[i].type == STT_FILE)
! 380: outbuf[i].n_type = N_FN;
! 381: else if (inbuf[i].shndx == SHN_UNDEF)
! 382: outbuf[i].n_type = N_UNDF;
! 383: else if (inbuf[i].shndx == SHN_ABS)
! 384: outbuf[i].n_type = N_ABS;
! 385: else if (inbuf[i].shndx == SHN_COMMON ||
! 386: inbuf[i].shndx == SHN_MIPS_ACOMMON)
! 387: outbuf[i].n_type = N_COMM;
! 388: else
! 389: outbuf[i].n_type = symTypeTable[inbuf[i].shndx];
! 390: if (inbuf[i].binding == STB_GLOBAL)
! 391: outbuf[i].n_type |= N_EXT;
! 392: /* Symbol values in executables should be compatible. */
! 393: outbuf[i].n_value = inbuf[i].value;
! 394: }
! 395: /* Write out the symbols... */
! 396: if ((i = write(out, outbuf, cur * sizeof(struct nlist)))
! 397: != cur * sizeof(struct nlist)) {
! 398: fprintf(stderr, "translate_syms: write: %s\n", strerror(errno));
! 399: exit(1);
! 400: }
! 401: }
! 402: /* Write out the string table length... */
! 403: if (write(out, &newstringsize, sizeof newstringsize)
! 404: != sizeof newstringsize) {
! 405: fprintf(stderr,
! 406: "translate_syms: newstringsize: %s\n", strerror(errno));
! 407: exit(1);
! 408: }
! 409: /* Write out the string table... */
! 410: if (write(out, newstrings, newstringsize) != newstringsize) {
! 411: fprintf(stderr, "translate_syms: newstrings: %s\n", strerror(errno));
! 412: exit(1);
! 413: }
1.1 graichen 414: }
1.3 ! deraadt 415:
! 416: copy(int out, int in, off_t offset, off_t size)
1.1 graichen 417: {
1.3 ! deraadt 418: char ibuf[4096];
! 419: int remaining, cur, count;
1.1 graichen 420:
1.3 ! deraadt 421: /* Go the the start of the ELF symbol table... */
! 422: if (lseek(in, offset, SEEK_SET) < 0) {
! 423: perror("copy: lseek");
! 424: exit(1);
! 425: }
! 426: remaining = size;
! 427: while (remaining) {
! 428: cur = remaining;
! 429: if (cur > sizeof ibuf)
! 430: cur = sizeof ibuf;
! 431: remaining -= cur;
! 432: if ((count = read(in, ibuf, cur)) != cur) {
! 433: fprintf(stderr, "copy: read: %s\n",
! 434: count ? strerror(errno) : "premature end of file");
! 435: exit(1);
! 436: }
! 437: if ((count = write(out, ibuf, cur)) != cur) {
! 438: perror("copy: write");
! 439: exit(1);
! 440: }
1.1 graichen 441: }
442: }
443:
1.3 ! deraadt 444: /*
! 445: * Combine two segments, which must be contiguous. If pad is true, it's
! 446: * okay for there to be padding between.
! 447: */
! 448: combine(struct sect * base, struct sect * new, int pad)
1.1 graichen 449: {
1.3 ! deraadt 450: if (!base->len)
! 451: *base = *new;
! 452: else if (new->len) {
! 453: if (base->vaddr + base->len != new->vaddr) {
! 454: if (pad)
! 455: base->len = new->vaddr - base->vaddr;
! 456: else {
! 457: fprintf(stderr,
! 458: "Non-contiguous data can't be converted.\n");
! 459: exit(1);
! 460: }
! 461: }
! 462: base->len += new->len;
1.1 graichen 463: }
464: }
465:
1.3 ! deraadt 466: phcmp(struct phdr * h1, struct phdr * h2)
1.1 graichen 467: {
1.3 ! deraadt 468: if (h1->vaddr > h2->vaddr)
! 469: return 1;
! 470: else if (h1->vaddr < h2->vaddr)
! 471: return -1;
! 472: else
! 473: return 0;
1.1 graichen 474: }
475:
1.3 ! deraadt 476: char *
! 477: saveRead(int file, off_t offset, off_t len, char *name)
1.1 graichen 478: {
1.3 ! deraadt 479: char *tmp;
! 480: int count;
! 481: off_t off;
! 482:
! 483: if ((off = lseek(file, offset, SEEK_SET)) < 0) {
! 484: fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
! 485: exit(1);
! 486: }
! 487: if (!(tmp = (char *) malloc(len))) {
! 488: fprintf(stderr, "%s: Can't allocate %d bytes.\n", name, len);
! 489: exit(1);
! 490: }
! 491: count = read(file, tmp, len);
! 492: if (count != len) {
! 493: fprintf(stderr, "%s: read: %s.\n",
! 494: name, count ? strerror(errno) : "End of file reached");
! 495: exit(1);
! 496: }
! 497: return tmp;
1.1 graichen 498: }