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

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

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