[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.1.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: }