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

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