Annotation of src/usr.bin/elf2ecoff/elf2ecoff.c, Revision 1.1
1.1 ! pefo 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 <sys/exec_ecoff.h>
! 36: #include <sys/errno.h>
! 37: #include <string.h>
! 38: #include <limits.h>
! 39:
! 40: extern char *__progname;
! 41:
! 42: struct sect {
! 43: unsigned long vaddr;
! 44: unsigned long len;
! 45: };
! 46:
! 47: int phcmp ();
! 48: char *saveRead (int file, off_t offset, off_t len, char *name);
! 49: int copy (int, int, off_t, off_t);
! 50: int translate_syms (int, int, off_t, off_t, off_t, off_t);
! 51: extern int errno;
! 52: int *symTypeTable;
! 53:
! 54: main (int argc, char **argv, char **envp)
! 55: {
! 56: Elf32_Ehdr ex;
! 57: Elf32_Phdr *ph;
! 58: Elf32_Shdr *sh;
! 59: struct sym *symtab;
! 60: char *shstrtab;
! 61: int strtabix, symtabix;
! 62: int i, pad;
! 63: struct sect text, data, bss;
! 64: struct ecoff_exechdr eh;
! 65: struct ecoff_scnhdr esecs [3];
! 66: int infile, outfile;
! 67: unsigned long cur_vma = ULONG_MAX;
! 68:
! 69: text.len = data.len = bss.len = 0;
! 70: text.vaddr = data.vaddr = bss.vaddr = 0;
! 71:
! 72: /* Check args... */
! 73: if (argc < 3 || argc > 4)
! 74: {
! 75: usage:
! 76: fprintf (stderr,
! 77: "usage: %s <elf executable> <ecoff executable>\n", __progname);
! 78: exit (1);
! 79: }
! 80:
! 81: /* Try the input file... */
! 82: if ((infile = open (argv [1], O_RDONLY)) < 0)
! 83: {
! 84: fprintf (stderr, "Can't open %s for read: %s\n",
! 85: argv [1], strerror (errno));
! 86: exit (1);
! 87: }
! 88:
! 89: /* Read the header, which is at the beginning of the file... */
! 90: i = read (infile, &ex, sizeof ex);
! 91: if (i != sizeof ex)
! 92: {
! 93: fprintf (stderr, "ex: %s: %s.\n",
! 94: argv [1], i ? strerror (errno) : "End of file reached");
! 95: exit (1);
! 96: }
! 97:
! 98: /* Read the program headers... */
! 99: ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
! 100: ex.e_phnum * sizeof (Elf32_Phdr), "ph");
! 101: /* Read the section headers... */
! 102: sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
! 103: ex.e_shnum * sizeof (Elf32_Shdr), "sh");
! 104: /* Read in the section string table. */
! 105: shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
! 106: sh [ex.e_shstrndx].sh_size, "shstrtab");
! 107:
! 108: /* Figure out if we can cram the program header into an ECOFF
! 109: header... Basically, we can't handle anything but loadable
! 110: segments, but we can ignore some kinds of segments. We can't
! 111: handle holes in the address space. Segments may be out of order,
! 112: so we sort them first. */
! 113:
! 114: qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);
! 115:
! 116: for (i = 0; i < ex.e_phnum; i++)
! 117: {
! 118: /* Section types we can ignore... */
! 119: if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE ||
! 120: ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO)
! 121: continue;
! 122: /* Section types we can't handle... */
! 123: else if (ph [i].p_type != PT_LOAD)
! 124: {
! 125: fprintf (stderr, "Program header %d type %d can't be converted.\n");
! 126: exit (1);
! 127: }
! 128: /* Writable (data) segment? */
! 129: if (ph [i].p_flags & PF_W)
! 130: {
! 131: struct sect ndata, nbss;
! 132:
! 133: ndata.vaddr = ph [i].p_vaddr;
! 134: ndata.len = ph [i].p_filesz;
! 135: nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
! 136: nbss.len = ph [i].p_memsz - ph [i].p_filesz;
! 137:
! 138: combine (&data, &ndata, 0);
! 139: combine (&bss, &nbss, 1);
! 140: }
! 141: else
! 142: {
! 143: struct sect ntxt;
! 144:
! 145: ntxt.vaddr = ph [i].p_vaddr;
! 146: ntxt.len = ph [i].p_filesz;
! 147:
! 148: combine (&text, &ntxt);
! 149: }
! 150: /* Remember the lowest segment start address. */
! 151: if (ph [i].p_vaddr < cur_vma)
! 152: cur_vma = ph [i].p_vaddr;
! 153: }
! 154:
! 155: /* Sections must be in order to be converted... */
! 156: if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
! 157: text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
! 158: {
! 159: fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
! 160: exit (1);
! 161: }
! 162:
! 163: /* If there's a data section but no text section, then the loader
! 164: combined everything into one section. That needs to be the
! 165: text section, so just make the data section zero length following
! 166: text. */
! 167: if (data.len && !text.len)
! 168: {
! 169: text = data;
! 170: data.vaddr = text.vaddr + text.len;
! 171: data.len = 0;
! 172: }
! 173:
! 174: /* If there is a gap between text and data, we'll fill it when we copy
! 175: the data, so update the length of the text segment as represented in
! 176: a.out to reflect that, since a.out doesn't allow gaps in the program
! 177: address space. */
! 178: if (text.vaddr + text.len < data.vaddr)
! 179: text.len = data.vaddr - text.vaddr;
! 180:
! 181: /* We now have enough information to cons up an a.out header... */
! 182: eh.a.magic = ECOFF_OMAGIC;
! 183: eh.a.vstamp = 200;
! 184: eh.a.tsize = text.len;
! 185: eh.a.dsize = data.len;
! 186: eh.a.bsize = bss.len;
! 187: eh.a.entry = ex.e_entry;
! 188: eh.a.text_start = text.vaddr;
! 189: eh.a.data_start = data.vaddr;
! 190: eh.a.bss_start = bss.vaddr;
! 191: eh.a.ea_gprmask = 0xf3fffffe;
! 192: bzero (&eh.a.ea_cprmask, sizeof eh.a.ea_cprmask);
! 193: eh.a.ea_gp_value = 0; /* unused. */
! 194:
! 195: eh.f.f_magic = ECOFF_MAGIC_MIPSEL;
! 196: eh.f.f_nscns = 3;
! 197: eh.f.f_timdat = 0; /* bogus */
! 198: eh.f.f_symptr = 0;
! 199: eh.f.f_nsyms = 0;
! 200: eh.f.f_opthdr = sizeof eh.a;
! 201: eh.f.f_flags = 0x100f; /* Stripped, not sharable. */
! 202:
! 203: strcpy (esecs [0].s_name, ".text");
! 204: strcpy (esecs [1].s_name, ".data");
! 205: strcpy (esecs [2].s_name, ".bss");
! 206: esecs [0].s_paddr = esecs [0].s_vaddr = eh.a.text_start;
! 207: esecs [1].s_paddr = esecs [1].s_vaddr = eh.a.data_start;
! 208: esecs [2].s_paddr = esecs [2].s_vaddr = eh.a.bss_start;
! 209: esecs [0].s_size = eh.a.tsize;
! 210: esecs [1].s_size = eh.a.dsize;
! 211: esecs [2].s_size = eh.a.bsize;
! 212: esecs [0].s_scnptr = ECOFF_TXTOFF (&eh);
! 213: esecs [1].s_scnptr = ECOFF_DATOFF (&eh);
! 214: esecs [2].s_scnptr = esecs [1].s_scnptr +
! 215: ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eh));
! 216: esecs [0].s_relptr = esecs [1].s_relptr = esecs [2].s_relptr = 0;
! 217: esecs [0].s_lnnoptr = esecs [1].s_lnnoptr = esecs [2].s_lnnoptr = 0;
! 218: esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;
! 219: esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;
! 220: esecs [0].s_flags = 0x20;
! 221: esecs [1].s_flags = 0x40;
! 222: esecs [2].s_flags = 0x82;
! 223:
! 224: /* Make the output file... */
! 225: if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
! 226: {
! 227: fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
! 228: exit (1);
! 229: }
! 230:
! 231: /* Write the headers... */
! 232: i = write (outfile, &eh.f, sizeof(struct ecoff_filehdr));
! 233: if (i != sizeof(struct ecoff_filehdr))
! 234: {
! 235: perror ("efh: write");
! 236: exit (1);
! 237:
! 238: for (i = 0; i < 6; i++)
! 239: {
! 240: printf ("Section %d: %s phys %x size %x file offset %x\n",
! 241: i, esecs [i].s_name, esecs [i].s_paddr,
! 242: esecs [i].s_size, esecs [i].s_scnptr);
! 243: }
! 244: }
! 245: fprintf (stderr, "wrote %d byte file header.\n", i);
! 246:
! 247: i = write (outfile, &eh.a, sizeof(struct ecoff_aouthdr));
! 248: if (i != sizeof(struct ecoff_aouthdr))
! 249: {
! 250: perror ("eah: write");
! 251: exit (1);
! 252: }
! 253: fprintf (stderr, "wrote %d byte a.out header.\n", i);
! 254:
! 255: i = write (outfile, &esecs, sizeof esecs);
! 256: if (i != sizeof esecs)
! 257: {
! 258: perror ("esecs: write");
! 259: exit (1);
! 260: }
! 261: fprintf (stderr, "wrote %d bytes of section headers.\n", i);
! 262:
! 263: if (pad = ((sizeof eh + sizeof esecs) & 15))
! 264: {
! 265: pad = 16 - pad;
! 266: i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
! 267: if (i < 0)
! 268: {
! 269: perror ("ipad: write");
! 270: exit (1);
! 271: }
! 272: fprintf (stderr, "wrote %d byte pad.\n", i);
! 273: }
! 274:
! 275: /* Copy the loadable sections. Zero-fill any gaps less than 64k;
! 276: complain about any zero-filling, and die if we're asked to zero-fill
! 277: more than 64k. */
! 278: for (i = 0; i < ex.e_phnum; i++)
! 279: {
! 280: /* Unprocessable sections were handled above, so just verify that
! 281: the section can be loaded before copying. */
! 282: if (ph [i].p_type == PT_LOAD && ph [i].p_filesz)
! 283: {
! 284: if (cur_vma != ph [i].p_vaddr)
! 285: {
! 286: unsigned long gap = ph [i].p_vaddr - cur_vma;
! 287: char obuf [1024];
! 288: if (gap > 65536)
! 289: {
! 290: fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
! 291: gap);
! 292: exit (1);
! 293: }
! 294: fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
! 295: memset (obuf, 0, sizeof obuf);
! 296: while (gap)
! 297: {
! 298: int count = write (outfile, obuf, (gap > sizeof obuf
! 299: ? sizeof obuf : gap));
! 300: if (count < 0)
! 301: {
! 302: fprintf (stderr, "Error writing gap: %s\n",
! 303: strerror (errno));
! 304: exit (1);
! 305: }
! 306: gap -= count;
! 307: }
! 308: }
! 309: fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);
! 310: copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
! 311: cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
! 312: }
! 313: }
! 314:
! 315: /* Looks like we won... */
! 316: exit (0);
! 317: }
! 318:
! 319: copy (out, in, offset, size)
! 320: int out, in;
! 321: off_t offset, size;
! 322: {
! 323: char ibuf [4096];
! 324: int remaining, cur, count;
! 325:
! 326: /* Go the the start of the ELF symbol table... */
! 327: if (lseek (in, offset, SEEK_SET) < 0)
! 328: {
! 329: perror ("copy: lseek");
! 330: exit (1);
! 331: }
! 332:
! 333: remaining = size;
! 334: while (remaining)
! 335: {
! 336: cur = remaining;
! 337: if (cur > sizeof ibuf)
! 338: cur = sizeof ibuf;
! 339: remaining -= cur;
! 340: if ((count = read (in, ibuf, cur)) != cur)
! 341: {
! 342: fprintf (stderr, "copy: read: %s\n",
! 343: count ? strerror (errno) : "premature end of file");
! 344: exit (1);
! 345: }
! 346: if ((count = write (out, ibuf, cur)) != cur)
! 347: {
! 348: perror ("copy: write");
! 349: exit (1);
! 350: }
! 351: }
! 352: }
! 353:
! 354: /* Combine two segments, which must be contiguous. If pad is true, it's
! 355: okay for there to be padding between. */
! 356: combine (base, new, pad)
! 357: struct sect *base, *new;
! 358: int pad;
! 359: {
! 360: if (!base -> len)
! 361: *base = *new;
! 362: else if (new -> len)
! 363: {
! 364: if (base -> vaddr + base -> len != new -> vaddr)
! 365: {
! 366: if (pad)
! 367: base -> len = new -> vaddr - base -> vaddr;
! 368: else
! 369: {
! 370: fprintf (stderr,
! 371: "Non-contiguous data can't be converted.\n");
! 372: exit (1);
! 373: }
! 374: }
! 375: base -> len += new -> len;
! 376: }
! 377: }
! 378:
! 379: phcmp (h1, h2)
! 380: Elf32_Phdr *h1, *h2;
! 381: {
! 382: if (h1 -> p_vaddr > h2 -> p_vaddr)
! 383: return 1;
! 384: else if (h1 -> p_vaddr < h2 -> p_vaddr)
! 385: return -1;
! 386: else
! 387: return 0;
! 388: }
! 389:
! 390: char *saveRead (int file, off_t offset, off_t len, char *name)
! 391: {
! 392: char *tmp;
! 393: int count;
! 394: off_t off;
! 395: if ((off = lseek (file, offset, SEEK_SET)) < 0)
! 396: {
! 397: fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
! 398: exit (1);
! 399: }
! 400: if (!(tmp = (char *)malloc (len)))
! 401: {
! 402: fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
! 403: exit (1);
! 404: }
! 405: count = read (file, tmp, len);
! 406: if (count != len)
! 407: {
! 408: fprintf (stderr, "%s: read: %s.\n",
! 409: name, count ? strerror (errno) : "End of file reached");
! 410: exit (1);
! 411: }
! 412: return tmp;
! 413: }