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

Annotation of src/usr.bin/elf2ecoff/elf2ecoff.c, Revision 1.5

1.5     ! henning     1: /* $OpenBSD: elf2ecoff.c,v 1.4 2003/06/10 22:20:46 deraadt Exp $        */
1.3       deraadt     2: /* $NetBSD: elf2ecoff.c,v 1.8 1997/07/20 03:50:54 jonathan Exp $        */
1.2       maja        3:
1.1       pefo        4: /*
1.2       maja        5:  * Copyright (c) 1997 Jonathan Stone
                      6:  *    All rights reserved.
1.1       pefo        7:  * Copyright (c) 1995
                      8:  *     Ted Lemon (hereinafter referred to as the author)
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33:
1.3       deraadt    34: /*
                     35:  * elf2ecoff.c
                     36:  *
                     37:  * This program converts an elf executable to an ECOFF executable. No symbol
                     38:  * table is retained.   This is useful primarily in building net-bootable
                     39:  * kernels for machines (e.g., DECstation and Alpha) which only support the
                     40:  * ECOFF object file format.
                     41:  */
1.2       maja       42:
1.1       pefo       43: #include <sys/types.h>
                     44: #include <fcntl.h>
                     45: #include <unistd.h>
                     46: #include <elf_abi.h>
                     47: #include <machine/elf_abi.h>
                     48: #include <stdio.h>
                     49: #include <sys/exec_ecoff.h>
                     50: #include <sys/errno.h>
                     51: #include <string.h>
                     52: #include <limits.h>
                     53:
1.3       deraadt    54: extern char    *__progname;
1.1       pefo       55:
                     56: struct sect {
1.3       deraadt    57:        unsigned long   vaddr;
                     58:        unsigned long   len;
1.1       pefo       59: };
                     60:
1.3       deraadt    61: int    phcmp();
                     62: char   *saveRead(int file, off_t offset, off_t len, char *name);
                     63: int    copy(int, int, off_t, off_t);
                     64: int    translate_syms(int, int, off_t, off_t, off_t, off_t);
                     65: int    *symTypeTable;
1.1       pefo       66:
1.3       deraadt    67: int
                     68: main(int argc, char *argv[])
1.1       pefo       69: {
1.3       deraadt    70:        Elf32_Ehdr      ex;
                     71:        Elf32_Phdr     *ph;
                     72:        Elf32_Shdr     *sh;
                     73:        struct sym     *symtab;
                     74:        char       *shstrtab;
                     75:        int          strtabix, symtabix;
                     76:        int          i, pad;
                     77:        struct sect     text, data, bss;
                     78:        struct ecoff_exechdr eh;
                     79:        struct ecoff_scnhdr esecs[3];
                     80:        int          infile, outfile;
                     81:        unsigned long   cur_vma = ULONG_MAX;
                     82:
                     83:        text.len = data.len = bss.len = 0;
                     84:        text.vaddr = data.vaddr = bss.vaddr = 0;
                     85:
                     86:        /* Check args... */
                     87:        if (argc < 3 || argc > 4) {
                     88: usage:
                     89:                fprintf(stderr,
                     90:                    "usage: %s <elf executable> <ecoff executable>\n", __progname);
                     91:                exit(1);
                     92:        }
                     93:        /* Try the input file... */
                     94:        if ((infile = open(argv[1], O_RDONLY)) < 0) {
                     95:                fprintf(stderr, "Can't open %s for read: %s\n",
                     96:                    argv[1], strerror(errno));
                     97:                exit(1);
                     98:        }
                     99:        /* Read the header, which is at the beginning of the file... */
                    100:        i = read(infile, &ex, sizeof ex);
                    101:        if (i != sizeof ex) {
                    102:                fprintf(stderr, "ex: %s: %s.\n",
                    103:                    argv[1], i ? strerror(errno) : "End of file reached");
                    104:                exit(1);
                    105:        }
                    106:        /* Read the program headers... */
                    107:        ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
                    108:        ex.e_phnum * sizeof(Elf32_Phdr), "ph");
                    109:        /* Read the section headers... */
                    110:        sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
                    111:            ex.e_shnum * sizeof(Elf32_Shdr), "sh");
                    112:        /* Read in the section string table. */
                    113:        shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
                    114:            sh[ex.e_shstrndx].sh_size, "shstrtab");
                    115:
                    116:        /*
                    117:         * Figure out if we can cram the program header into an ECOFF
                    118:         * header...  Basically, we can't handle anything but loadable
                    119:         * segments, but we can ignore some kinds of segments.  We can't
                    120:         * handle holes in the address space.  Segments may be out of order,
                    121:         * so we sort them first.
                    122:         */
                    123:
                    124:        qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
                    125:
                    126:        for (i = 0; i < ex.e_phnum; i++) {
                    127:                /* Section types we can ignore... */
                    128:                if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
                    129:                    ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
                    130:                        continue;
                    131:                /* Section types we can't handle... */
                    132:                else if (ph[i].p_type != PT_LOAD) {
                    133:                        fprintf(stderr,
1.5     ! henning   134:                            "Program header %d type %d can't be converted.\n",
        !           135:                            i, ph[i].p_type);
1.3       deraadt   136:                        exit(1);
                    137:                }
                    138:                /* Writable (data) segment? */
                    139:                if (ph[i].p_flags & PF_W) {
                    140:                        struct sect     ndata, nbss;
                    141:
                    142:                        ndata.vaddr = ph[i].p_vaddr;
                    143:                        ndata.len = ph[i].p_filesz;
                    144:                        nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
                    145:                        nbss.len = ph[i].p_memsz - ph[i].p_filesz;
                    146:
                    147:                        combine(&data, &ndata, 0);
                    148:                        combine(&bss, &nbss, 1);
                    149:                } else {
                    150:                        struct sect     ntxt;
                    151:
                    152:                        ntxt.vaddr = ph[i].p_vaddr;
                    153:                        ntxt.len = ph[i].p_filesz;
                    154:                        combine(&text, &ntxt);
                    155:                }
                    156:                /* Remember the lowest segment start address. */
                    157:                if (ph[i].p_vaddr < cur_vma)
                    158:                        cur_vma = ph[i].p_vaddr;
1.1       pefo      159:        }
                    160:
1.3       deraadt   161:        /* Sections must be in order to be converted... */
                    162:        if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
                    163:            text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
                    164:                fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
                    165:                exit(1);
                    166:        }
                    167:        /*
                    168:         * If there's a data section but no text section, then the loader
                    169:         * combined everything into one section.   That needs to be the text
                    170:         * section, so just make the data section zero length following text.
                    171:         */
                    172:        if (data.len && !text.len) {
                    173:                text = data;
                    174:                data.vaddr = text.vaddr + text.len;
                    175:                data.len = 0;
                    176:        }
                    177:        /*
                    178:         * If there is a gap between text and data, we'll fill it when we
                    179:         * copy the data, so update the length of the text segment as
                    180:         * represented in a.out to reflect that, since a.out doesn't allow
                    181:         * gaps in the program address space.
                    182:         */
                    183:        if (text.vaddr + text.len < data.vaddr)
                    184:                text.len = data.vaddr - text.vaddr;
                    185:
                    186:        /* We now have enough information to cons up an a.out header... */
                    187:        eh.a.magic = ECOFF_OMAGIC;
                    188:        eh.a.vstamp = 200;
                    189:        eh.a.tsize = text.len;
                    190:        eh.a.dsize = data.len;
                    191:        eh.a.bsize = bss.len;
                    192:        eh.a.entry = ex.e_entry;
                    193:        eh.a.text_start = text.vaddr;
                    194:        eh.a.data_start = data.vaddr;
                    195:        eh.a.bss_start = bss.vaddr;
                    196:        eh.a.ea_gprmask = 0xf3fffffe;
                    197:        bzero(&eh.a.ea_cprmask, sizeof eh.a.ea_cprmask);
                    198:        eh.a.ea_gp_value = 0;   /* unused. */
                    199:
                    200:        eh.f.f_magic = ECOFF_MAGIC_MIPSEL;
                    201:        eh.f.f_nscns = 3;
                    202:        eh.f.f_timdat = 0;      /* bogus */
                    203:        eh.f.f_symptr = 0;
                    204:        eh.f.f_nsyms = 0;
                    205:        eh.f.f_opthdr = sizeof eh.a;
                    206:        eh.f.f_flags = 0x100f;  /* Stripped, not sharable. */
                    207:
                    208:        strlcpy(esecs[0].s_name, ".text", sizeof(esecs[0].s_name));
                    209:        strlcpy(esecs[1].s_name, ".data", sizeof(esecs[0].s_name));
                    210:        strlcpy(esecs[2].s_name, ".bss", sizeof(esecs[0].s_name));
                    211:        esecs[0].s_paddr = esecs[0].s_vaddr = eh.a.text_start;
                    212:        esecs[1].s_paddr = esecs[1].s_vaddr = eh.a.data_start;
                    213:        esecs[2].s_paddr = esecs[2].s_vaddr = eh.a.bss_start;
                    214:        esecs[0].s_size = eh.a.tsize;
                    215:        esecs[1].s_size = eh.a.dsize;
                    216:        esecs[2].s_size = eh.a.bsize;
                    217:        esecs[0].s_scnptr = ECOFF_TXTOFF(&eh);
                    218:        esecs[1].s_scnptr = ECOFF_DATOFF(&eh);
                    219:        esecs[2].s_scnptr = esecs[1].s_scnptr +
                    220:            ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eh));
                    221:        esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
                    222:        esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
                    223:        esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
                    224:        esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
                    225:        esecs[0].s_flags = 0x20;
                    226:        esecs[1].s_flags = 0x40;
                    227:        esecs[2].s_flags = 0x82;
                    228:
                    229:        /* Make the output file... */
                    230:        if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
                    231:                fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
                    232:                exit(1);
                    233:        }
                    234:        /* Write the headers... */
                    235:        i = write(outfile, &eh.f, sizeof(struct ecoff_filehdr));
                    236:        if (i != sizeof(struct ecoff_filehdr)) {
                    237:                perror("efh: write");
                    238:                exit(1);
                    239:
                    240:                for (i = 0; i < 6; i++) {
                    241:                        printf("Section %d: %s phys %x  size %x  file offset %x\n",
                    242:                            i, esecs[i].s_name, esecs[i].s_paddr,
                    243:                            esecs[i].s_size, esecs[i].s_scnptr);
                    244:                }
                    245:        }
                    246:        fprintf(stderr, "wrote %d byte file header.\n", i);
1.1       pefo      247:
1.3       deraadt   248:        i = write(outfile, &eh.a, sizeof(struct ecoff_aouthdr));
                    249:        if (i != sizeof(struct ecoff_aouthdr)) {
                    250:                perror("eah: write");
                    251:                exit(1);
1.1       pefo      252:        }
1.3       deraadt   253:        fprintf(stderr, "wrote %d byte a.out header.\n", i);
1.1       pefo      254:
1.3       deraadt   255:        i = write(outfile, &esecs, sizeof esecs);
                    256:        if (i != sizeof esecs) {
                    257:                perror("esecs: write");
                    258:                exit(1);
                    259:        }
                    260:        fprintf(stderr, "wrote %d bytes of section headers.\n", i);
1.1       pefo      261:
1.3       deraadt   262:        if (pad = ((sizeof eh + sizeof esecs) & 15)) {
                    263:                pad = 16 - pad;
                    264:                i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
                    265:                if (i < 0) {
                    266:                        perror("ipad: write");
                    267:                        exit(1);
                    268:                }
                    269:                fprintf(stderr, "wrote %d byte pad.\n", i);
1.1       pefo      270:        }
1.3       deraadt   271:        /*
                    272:         * Copy the loadable sections.   Zero-fill any gaps less than 64k;
                    273:         * complain about any zero-filling, and die if we're asked to
                    274:         * zero-fill more than 64k.
                    275:         */
                    276:        for (i = 0; i < ex.e_phnum; i++) {
                    277:                /*
                    278:                 * Unprocessable sections were handled above, so just verify
                    279:                 * that the section can be loaded before copying.
                    280:                 */
                    281:                if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
                    282:                        if (cur_vma != ph[i].p_vaddr) {
                    283:                                unsigned long   gap = ph[i].p_vaddr - cur_vma;
                    284:                                char        obuf[1024];
                    285:                                if (gap > 65536) {
1.4       deraadt   286:                                        fprintf(stderr,
                    287:                                            "Intersegment gap (%d bytes) too large.\n",
                    288:                                            gap);
1.3       deraadt   289:                                        exit(1);
                    290:                                }
1.4       deraadt   291:                                fprintf(stderr,
                    292:                                    "Warning: %d byte intersegment gap.\n", gap);
1.3       deraadt   293:                                memset(obuf, 0, sizeof obuf);
                    294:                                while (gap) {
                    295:                                        int count = write(outfile, obuf,
                    296:                                            (gap > sizeof obuf
                    297:                                            ? sizeof obuf : gap));
                    298:                                        if (count < 0) {
                    299:                                                fprintf(stderr,
                    300:                                                    "Error writing gap: %s\n",
                    301:                                                    strerror(errno));
                    302:                                                exit(1);
                    303:                                        }
                    304:                                        gap -= count;
                    305:                                }
                    306:                        }
                    307:                        fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
                    308:                        copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
                    309:                        cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
                    310:                }
1.1       pefo      311:        }
                    312:
1.3       deraadt   313:        /*
                    314:         * Write a page of padding for boot PROMS that read entire pages.
                    315:         * Without this, they may attempt to read past the end of the
                    316:         * data section, incur an error, and refuse to boot.
                    317:         */
1.1       pefo      318:        {
1.3       deraadt   319:                char        obuf[4096];
                    320:                memset(obuf, 0, sizeof obuf);
                    321:                if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
                    322:                        fprintf(stderr, "Error writing PROM padding: %s\n",
                    323:                                strerror(errno));
                    324:                        exit(1);
1.1       pefo      325:                }
1.3       deraadt   326:        }
1.1       pefo      327:
1.3       deraadt   328:        /* Looks like we won... */
                    329:        exit(0);
1.1       pefo      330: }
                    331:
1.4       deraadt   332: void
                    333: copy(int out, int in, off_t offset, off_t size)
1.1       pefo      334: {
1.3       deraadt   335:        char        ibuf[4096];
                    336:        int         remaining, cur, count;
1.1       pefo      337:
1.5     ! henning   338:        /* Go to the start of the ELF symbol table... */
1.3       deraadt   339:        if (lseek(in, offset, SEEK_SET) < 0) {
                    340:                perror("copy: lseek");
                    341:                exit(1);
1.1       pefo      342:        }
1.3       deraadt   343:        remaining = size;
                    344:        while (remaining) {
                    345:                cur = remaining;
                    346:                if (cur > sizeof ibuf)
                    347:                        cur = sizeof ibuf;
                    348:                remaining -= cur;
                    349:                if ((count = read(in, ibuf, cur)) != cur) {
                    350:                        fprintf(stderr, "copy: read: %s\n",
                    351:                         count ? strerror(errno) : "premature end of file");
                    352:                        exit(1);
                    353:                }
                    354:                if ((count = write(out, ibuf, cur)) != cur) {
                    355:                        perror("copy: write");
                    356:                        exit(1);
                    357:                }
1.1       pefo      358:        }
                    359: }
                    360:
1.3       deraadt   361: /*
                    362:  * Combine two segments, which must be contiguous.   If pad is true, it's
                    363:  * okay for there to be padding between.
                    364:  */
1.4       deraadt   365: void
                    366: combine(struct sect *base, struct sect *new, int pad)
1.1       pefo      367: {
1.3       deraadt   368:        if (!base->len)
                    369:                *base = *new;
                    370:        else if (new->len) {
                    371:                if (base->vaddr + base->len != new->vaddr) {
                    372:                        if (pad)
                    373:                                base->len = new->vaddr - base->vaddr;
                    374:                        else {
                    375:                                fprintf(stderr,
                    376:                                "Non-contiguous data can't be converted.\n");
                    377:                                exit(1);
                    378:                        }
                    379:                }
                    380:                base->len += new->len;
1.1       pefo      381:        }
                    382: }
                    383:
1.4       deraadt   384: int
                    385: phcmp(Elf32_Phdr *h1, Elf32_Phdr *h2)
1.1       pefo      386: {
1.3       deraadt   387:        if (h1->p_vaddr > h2->p_vaddr)
                    388:                return 1;
                    389:        else if (h1->p_vaddr < h2->p_vaddr)
                    390:                return -1;
                    391:        else
                    392:                return 0;
1.1       pefo      393: }
                    394:
1.4       deraadt   395: char *
1.3       deraadt   396: saveRead(int file, off_t offset, off_t len, char *name)
1.1       pefo      397: {
1.3       deraadt   398:        char       *tmp;
                    399:        int          count;
                    400:        off_t      off;
                    401:
                    402:        if ((off = lseek(file, offset, SEEK_SET)) < 0) {
                    403:                fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
                    404:                exit(1);
                    405:        }
                    406:        if (!(tmp = (char *) malloc(len))) {
                    407:                fprintf(stderr, "%s: Can't allocate %d bytes.\n", name, len);
                    408:                exit(1);
                    409:        }
                    410:        count = read(file, tmp, len);
                    411:        if (count != len) {
                    412:                fprintf(stderr, "%s: read: %s.\n",
                    413:                    name, count ? strerror(errno) : "End of file reached");
                    414:                exit(1);
                    415:        }
                    416:        return tmp;
1.1       pefo      417: }