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