[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     ! 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: }