[BACK]Return to elf2ecoff.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / elf2ecoff

Annotation of src/usr.bin/elf2ecoff/elf2ecoff.c, Revision 1.2

1.2     ! maja        1: /*     $OpenBSD$       */
        !             2: /*     $NetBSD: elf2ecoff.c,v 1.8 1997/07/20 03:50:54 jonathan Exp $   */
        !             3:
1.1       pefo        4: /*
1.2     ! maja        5:  * Copyright (c) 1997 Jonathan Stone
        !             6:  *    All rights reserved.
1.1       pefo        7:  * Copyright (c) 1995
                      8:  *     Ted Lemon (hereinafter referred to as the author)
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33:
1.2     ! maja       34: /* elf2ecoff.c
        !            35:
        !            36:    This program converts an elf executable to an ECOFF executable.
        !            37:    No symbol table is retained.   This is useful primarily in building
        !            38:    net-bootable kernels for machines (e.g., DECstation and Alpha) which
        !            39:    only support the ECOFF object file format. */
        !            40:
1.1       pefo       41: #include <sys/types.h>
                     42: #include <fcntl.h>
                     43: #include <unistd.h>
                     44: #include <elf_abi.h>
                     45: #include <machine/elf_abi.h>
                     46: #include <stdio.h>
                     47: #include <sys/exec_ecoff.h>
                     48: #include <sys/errno.h>
                     49: #include <string.h>
                     50: #include <limits.h>
                     51:
                     52: extern char *__progname;
                     53:
                     54: struct sect {
                     55:   unsigned long vaddr;
                     56:   unsigned long len;
                     57: };
                     58:
                     59: int phcmp ();
                     60: char *saveRead (int file, off_t offset, off_t len, char *name);
                     61: int copy (int, int, off_t, off_t);
                     62: int translate_syms (int, int, off_t, off_t, off_t, off_t);
                     63: extern int errno;
                     64: int *symTypeTable;
                     65:
                     66: main (int argc, char **argv, char **envp)
                     67: {
                     68:   Elf32_Ehdr ex;
                     69:   Elf32_Phdr *ph;
                     70:   Elf32_Shdr *sh;
                     71:   struct sym *symtab;
                     72:   char *shstrtab;
                     73:   int strtabix, symtabix;
                     74:   int i, pad;
                     75:   struct sect text, data, bss;
                     76:   struct ecoff_exechdr eh;
                     77:   struct ecoff_scnhdr esecs [3];
                     78:   int infile, outfile;
                     79:   unsigned long cur_vma = ULONG_MAX;
                     80:
                     81:   text.len = data.len = bss.len = 0;
                     82:   text.vaddr = data.vaddr = bss.vaddr = 0;
                     83:
                     84:   /* Check args... */
                     85:   if (argc < 3 || argc > 4)
                     86:     {
                     87:     usage:
                     88:       fprintf (stderr,
                     89:               "usage: %s <elf executable> <ecoff executable>\n", __progname);
                     90:       exit (1);
                     91:     }
                     92:
                     93:   /* Try the input file... */
                     94:   if ((infile = open (argv [1], O_RDONLY)) < 0)
                     95:     {
                     96:       fprintf (stderr, "Can't open %s for read: %s\n",
                     97:               argv [1], strerror (errno));
                     98:       exit (1);
                     99:     }
                    100:
                    101:   /* Read the header, which is at the beginning of the file... */
                    102:   i = read (infile, &ex, sizeof ex);
                    103:   if (i != sizeof ex)
                    104:     {
                    105:       fprintf (stderr, "ex: %s: %s.\n",
                    106:               argv [1], i ? strerror (errno) : "End of file reached");
                    107:       exit (1);
                    108:     }
                    109:
                    110:   /* Read the program headers... */
                    111:   ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
                    112:                                ex.e_phnum * sizeof (Elf32_Phdr), "ph");
                    113:   /* Read the section headers... */
                    114:   sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
                    115:                                ex.e_shnum * sizeof (Elf32_Shdr), "sh");
                    116:   /* Read in the section string table. */
                    117:   shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
                    118:                       sh [ex.e_shstrndx].sh_size, "shstrtab");
                    119:
                    120:   /* Figure out if we can cram the program header into an ECOFF
                    121:      header...  Basically, we can't handle anything but loadable
                    122:      segments, but we can ignore some kinds of segments.  We can't
                    123:      handle holes in the address space.  Segments may be out of order,
                    124:      so we sort them first. */
                    125:
                    126:   qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);
                    127:
                    128:   for (i = 0; i < ex.e_phnum; i++)
                    129:     {
                    130:       /* Section types we can ignore... */
                    131:       if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE ||
                    132:          ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO)
                    133:        continue;
                    134:       /* Section types we can't handle... */
                    135:       else if (ph [i].p_type != PT_LOAD)
                    136:         {
                    137:          fprintf (stderr, "Program header %d type %d can't be converted.\n");
                    138:          exit (1);
                    139:        }
                    140:       /* Writable (data) segment? */
                    141:       if (ph [i].p_flags & PF_W)
                    142:        {
                    143:          struct sect ndata, nbss;
                    144:
                    145:          ndata.vaddr = ph [i].p_vaddr;
                    146:          ndata.len = ph [i].p_filesz;
                    147:          nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
                    148:          nbss.len = ph [i].p_memsz - ph [i].p_filesz;
                    149:
                    150:          combine (&data, &ndata, 0);
                    151:          combine (&bss, &nbss, 1);
                    152:        }
                    153:       else
                    154:        {
                    155:          struct sect ntxt;
                    156:
                    157:          ntxt.vaddr = ph [i].p_vaddr;
                    158:          ntxt.len = ph [i].p_filesz;
                    159:
                    160:          combine (&text, &ntxt);
                    161:        }
                    162:       /* Remember the lowest segment start address. */
                    163:       if (ph [i].p_vaddr < cur_vma)
                    164:        cur_vma = ph [i].p_vaddr;
                    165:     }
                    166:
                    167:   /* Sections must be in order to be converted... */
                    168:   if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
                    169:       text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
                    170:     {
                    171:       fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
                    172:       exit (1);
                    173:     }
                    174:
                    175:   /* If there's a data section but no text section, then the loader
                    176:      combined everything into one section.   That needs to be the
                    177:      text section, so just make the data section zero length following
                    178:      text. */
                    179:   if (data.len && !text.len)
                    180:     {
                    181:       text = data;
                    182:       data.vaddr = text.vaddr + text.len;
                    183:       data.len = 0;
                    184:     }
                    185:
                    186:   /* If there is a gap between text and data, we'll fill it when we copy
                    187:      the data, so update the length of the text segment as represented in
                    188:      a.out to reflect that, since a.out doesn't allow gaps in the program
                    189:      address space. */
                    190:   if (text.vaddr + text.len < data.vaddr)
                    191:     text.len = data.vaddr - text.vaddr;
                    192:
                    193:   /* We now have enough information to cons up an a.out header... */
                    194:   eh.a.magic = ECOFF_OMAGIC;
                    195:   eh.a.vstamp = 200;
                    196:   eh.a.tsize = text.len;
                    197:   eh.a.dsize = data.len;
                    198:   eh.a.bsize = bss.len;
                    199:   eh.a.entry = ex.e_entry;
                    200:   eh.a.text_start = text.vaddr;
                    201:   eh.a.data_start = data.vaddr;
                    202:   eh.a.bss_start = bss.vaddr;
                    203:   eh.a.ea_gprmask = 0xf3fffffe;
                    204:   bzero (&eh.a.ea_cprmask, sizeof eh.a.ea_cprmask);
                    205:   eh.a.ea_gp_value = 0; /* unused. */
                    206:
                    207:   eh.f.f_magic = ECOFF_MAGIC_MIPSEL;
                    208:   eh.f.f_nscns = 3;
                    209:   eh.f.f_timdat = 0;   /* bogus */
                    210:   eh.f.f_symptr = 0;
                    211:   eh.f.f_nsyms = 0;
                    212:   eh.f.f_opthdr = sizeof eh.a;
                    213:   eh.f.f_flags = 0x100f; /* Stripped, not sharable. */
                    214:
                    215:   strcpy (esecs [0].s_name, ".text");
                    216:   strcpy (esecs [1].s_name, ".data");
                    217:   strcpy (esecs [2].s_name, ".bss");
                    218:   esecs [0].s_paddr = esecs [0].s_vaddr = eh.a.text_start;
                    219:   esecs [1].s_paddr = esecs [1].s_vaddr = eh.a.data_start;
                    220:   esecs [2].s_paddr = esecs [2].s_vaddr = eh.a.bss_start;
                    221:   esecs [0].s_size = eh.a.tsize;
                    222:   esecs [1].s_size = eh.a.dsize;
                    223:   esecs [2].s_size = eh.a.bsize;
                    224:   esecs [0].s_scnptr = ECOFF_TXTOFF (&eh);
                    225:   esecs [1].s_scnptr = ECOFF_DATOFF (&eh);
                    226:   esecs [2].s_scnptr = esecs [1].s_scnptr +
                    227:          ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eh));
                    228:   esecs [0].s_relptr = esecs [1].s_relptr = esecs [2].s_relptr = 0;
                    229:   esecs [0].s_lnnoptr = esecs [1].s_lnnoptr = esecs [2].s_lnnoptr = 0;
                    230:   esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;
                    231:   esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;
                    232:   esecs [0].s_flags = 0x20;
                    233:   esecs [1].s_flags = 0x40;
                    234:   esecs [2].s_flags = 0x82;
                    235:
                    236:   /* Make the output file... */
                    237:   if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
                    238:     {
                    239:       fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
                    240:       exit (1);
                    241:     }
                    242:
                    243:   /* Write the headers... */
                    244:   i = write (outfile, &eh.f, sizeof(struct ecoff_filehdr));
                    245:   if (i != sizeof(struct ecoff_filehdr))
                    246:     {
                    247:       perror ("efh: write");
                    248:       exit (1);
                    249:
                    250:   for (i = 0; i < 6; i++)
                    251:     {
                    252:       printf ("Section %d: %s phys %x  size %x  file offset %x\n",
                    253:              i, esecs [i].s_name, esecs [i].s_paddr,
                    254:              esecs [i].s_size, esecs [i].s_scnptr);
                    255:     }
                    256:     }
                    257:   fprintf (stderr, "wrote %d byte file header.\n", i);
                    258:
                    259:   i = write (outfile, &eh.a, sizeof(struct ecoff_aouthdr));
                    260:   if (i != sizeof(struct ecoff_aouthdr))
                    261:     {
                    262:       perror ("eah: write");
                    263:       exit (1);
                    264:     }
                    265:   fprintf (stderr, "wrote %d byte a.out header.\n", i);
                    266:
                    267:   i = write (outfile, &esecs, sizeof esecs);
                    268:   if (i != sizeof esecs)
                    269:     {
                    270:       perror ("esecs: write");
                    271:       exit (1);
                    272:     }
                    273:   fprintf (stderr, "wrote %d bytes of section headers.\n", i);
                    274:
                    275:   if (pad = ((sizeof eh + sizeof esecs) & 15))
                    276:     {
                    277:       pad = 16 - pad;
                    278:       i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
                    279:       if (i < 0)
                    280:        {
                    281:          perror ("ipad: write");
                    282:          exit (1);
                    283:        }
                    284:       fprintf (stderr, "wrote %d byte pad.\n", i);
                    285:     }
                    286:
                    287:   /* Copy the loadable sections.   Zero-fill any gaps less than 64k;
                    288:      complain about any zero-filling, and die if we're asked to zero-fill
                    289:      more than 64k. */
                    290:   for (i = 0; i < ex.e_phnum; i++)
                    291:     {
                    292:       /* Unprocessable sections were handled above, so just verify that
                    293:         the section can be loaded before copying. */
                    294:       if (ph [i].p_type == PT_LOAD && ph [i].p_filesz)
                    295:        {
                    296:          if (cur_vma != ph [i].p_vaddr)
                    297:            {
                    298:              unsigned long gap = ph [i].p_vaddr - cur_vma;
                    299:              char obuf [1024];
                    300:              if (gap > 65536)
                    301:                {
                    302:                  fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
                    303:                           gap);
                    304:                  exit (1);
                    305:                }
                    306:              fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
                    307:              memset (obuf, 0, sizeof obuf);
                    308:              while (gap)
                    309:                {
                    310:                  int count = write (outfile, obuf, (gap > sizeof obuf
                    311:                                                     ? sizeof obuf : gap));
                    312:                  if (count < 0)
                    313:                    {
                    314:                      fprintf (stderr, "Error writing gap: %s\n",
                    315:                               strerror (errno));
                    316:                      exit (1);
                    317:                    }
                    318:                  gap -= count;
                    319:                }
                    320:            }
                    321: fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);
                    322:          copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
                    323:          cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
                    324:        }
                    325:     }
1.2     ! maja      326:
        !           327:   /*
        !           328:    * Write a page of padding for boot PROMS that read entire pages.
        !           329:    * Without this, they may attempt to read past the end of the
        !           330:    * data section, incur an error, and refuse to boot.
        !           331:    */
        !           332:    {
        !           333:      char obuf [4096];
        !           334:      memset (obuf, 0, sizeof obuf);
        !           335:      if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
        !           336:        fprintf(stderr, "Error writing PROM padding: %s\n",
        !           337:                strerror(errno));
        !           338:        exit(1);
        !           339:      }
        !           340:    }
1.1       pefo      341:
                    342:   /* Looks like we won... */
                    343:   exit (0);
                    344: }
                    345:
                    346: copy (out, in, offset, size)
                    347:      int out, in;
                    348:      off_t offset, size;
                    349: {
                    350:   char ibuf [4096];
                    351:   int remaining, cur, count;
                    352:
                    353:   /* Go the the start of the ELF symbol table... */
                    354:   if (lseek (in, offset, SEEK_SET) < 0)
                    355:     {
                    356:       perror ("copy: lseek");
                    357:       exit (1);
                    358:     }
                    359:
                    360:   remaining = size;
                    361:   while (remaining)
                    362:     {
                    363:       cur = remaining;
                    364:       if (cur > sizeof ibuf)
                    365:        cur = sizeof ibuf;
                    366:       remaining -= cur;
                    367:       if ((count = read (in, ibuf, cur)) != cur)
                    368:        {
                    369:          fprintf (stderr, "copy: read: %s\n",
                    370:                   count ? strerror (errno) : "premature end of file");
                    371:          exit (1);
                    372:        }
                    373:       if ((count = write (out, ibuf, cur)) != cur)
                    374:        {
                    375:          perror ("copy: write");
                    376:          exit (1);
                    377:        }
                    378:     }
                    379: }
                    380:
                    381: /* Combine two segments, which must be contiguous.   If pad is true, it's
                    382:    okay for there to be padding between. */
                    383: combine (base, new, pad)
                    384:      struct sect *base, *new;
                    385:      int pad;
                    386: {
                    387:   if (!base -> len)
                    388:     *base = *new;
                    389:   else if (new -> len)
                    390:     {
                    391:       if (base -> vaddr + base -> len != new -> vaddr)
                    392:        {
                    393:          if (pad)
                    394:            base -> len = new -> vaddr - base -> vaddr;
                    395:          else
                    396:            {
                    397:              fprintf (stderr,
                    398:                       "Non-contiguous data can't be converted.\n");
                    399:              exit (1);
                    400:            }
                    401:        }
                    402:       base -> len += new -> len;
                    403:     }
                    404: }
                    405:
                    406: phcmp (h1, h2)
                    407:      Elf32_Phdr *h1, *h2;
                    408: {
                    409:   if (h1 -> p_vaddr > h2 -> p_vaddr)
                    410:     return 1;
                    411:   else if (h1 -> p_vaddr < h2 -> p_vaddr)
                    412:     return -1;
                    413:   else
                    414:     return 0;
                    415: }
                    416:
                    417: char *saveRead (int file, off_t offset, off_t len, char *name)
                    418: {
                    419:   char *tmp;
                    420:   int count;
                    421:   off_t off;
                    422:   if ((off = lseek (file, offset, SEEK_SET)) < 0)
                    423:     {
                    424:       fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
                    425:       exit (1);
                    426:     }
                    427:   if (!(tmp = (char *)malloc (len)))
                    428:     {
                    429:       fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
                    430:       exit (1);
                    431:     }
                    432:   count = read (file, tmp, len);
                    433:   if (count != len)
                    434:     {
                    435:       fprintf (stderr, "%s: read: %s.\n",
                    436:               name, count ? strerror (errno) : "End of file reached");
                    437:       exit (1);
                    438:     }
                    439:   return tmp;
                    440: }