[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.5

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