[BACK]Return to elf.c CVS log [TXT][DIR] Up to [local] / prex-old / boot / common

Annotation of prex-old/boot/common/elf.c, Revision 1.1.1.1.2.1

1.1       nbrk        1: /*-
                      2:  * Copyright (c) 2005-2006, Kohsuke Ohtani
                      3:  * All rights reserved.
                      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. Neither the name of the author nor the names of any co-contributors
                     14:  *    may be used to endorse or promote products derived from this software
                     15:  *    without specific prior written permission.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: /*
                     31:  * elf.c - ELF file format support
                     32:  */
                     33:
                     34: #include <boot.h>
                     35: #include <prex/bootinfo.h>
                     36: #include <sys/elf.h>
                     37: #include <platform.h>
                     38:
1.1.1.1.2.1! nbrk       39: #ifdef DEBUG_ELF
        !            40: #define DPRINTF(a) printf a
        !            41: #else
        !            42: #define DPRINTF(a) do {} while (0)
        !            43: #endif
        !            44:
1.1       nbrk       45: extern int nr_img;             /* number of images */
                     46:
                     47: #define SHF_VALID      (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE)
                     48:
                     49: static char *sect_addr[32];    /* array of section address */
                     50:
                     51: static int
                     52: load_executable(char *img, struct module *m)
                     53: {
                     54:        Elf32_Ehdr *ehdr;
                     55:        Elf32_Phdr *phdr;
1.1.1.1.2.1! nbrk       56:        paddr_t phys_base;
1.1       nbrk       57:        int i;
                     58:
                     59:        phys_base = load_base;
                     60:        ehdr = (Elf32_Ehdr *)img;
1.1.1.1.2.1! nbrk       61:        phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_phoff);
1.1       nbrk       62:        m->phys = load_base;
                     63:        phys_base = load_base;
1.1.1.1.2.1! nbrk       64:        DPRINTF(("phys addr=%x\n", phys_base));
1.1       nbrk       65:
                     66:        for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) {
                     67:                if (phdr->p_type != PT_LOAD)
                     68:                        continue;
                     69:
1.1.1.1.2.1! nbrk       70:                DPRINTF(("p_flags=%x\n", (int)phdr->p_flags));
        !            71:                DPRINTF(("p_align=%x\n", (int)phdr->p_align));
        !            72:                DPRINTF(("p_paddr=%x\n", (int)phdr->p_paddr));
1.1       nbrk       73:
                     74:                if (i >= 2) {
1.1.1.1.2.1! nbrk       75:                        DPRINTF(("skipping extra phdr\n"));
1.1       nbrk       76:                        continue;
                     77:                }
                     78:                if (phdr->p_flags & PF_X) {
                     79:                        /* Text */
                     80:                        m->text = phdr->p_vaddr;
                     81:                        m->textsz = (size_t)phdr->p_memsz;
                     82:                } else {
                     83:                        /* Data & BSS */
                     84:                        m->data = phdr->p_vaddr;
                     85:                        m->datasz = (size_t)phdr->p_filesz;
                     86:                        m->bsssz =
                     87:                                (size_t)(phdr->p_memsz - phdr->p_filesz);
                     88:                        load_base = phys_base + (m->data - m->text);
                     89:                }
                     90:                if (phdr->p_filesz > 0) {
                     91:                        memcpy((char *)load_base, img + phdr->p_offset,
                     92:                               (size_t)phdr->p_filesz);
1.1.1.1.2.1! nbrk       93:                        DPRINTF(("load: offset=%x size=%x\n",
        !            94:                                 load_base, (int)phdr->p_filesz));
1.1       nbrk       95:                }
                     96:                if (!(phdr->p_flags & PF_X)) {
                     97:                        if (m->bsssz > 0) {
                     98:                                /* Zero fill BSS */
                     99:                                memset((char *)load_base + m->datasz,
                    100:                                       0, m->bsssz);
                    101:                        }
                    102:                        load_base += phdr->p_memsz;
                    103:                }
                    104:        }
                    105:        /* workaround for data/bss size is 0 */
                    106:        if (m->data == 0)
                    107:                load_base = phys_base + m->textsz;
                    108:
                    109:        load_base = PAGE_ALIGN(load_base);
                    110:        m->size = (size_t)(load_base - m->phys);
                    111:        m->entry = ehdr->e_entry;
1.1.1.1.2.1! nbrk      112:        DPRINTF(("module size=%x entry=%x\n", m->size, m->entry));
1.1       nbrk      113:        return 0;
                    114: }
                    115:
                    116: static int
                    117: relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela,
                    118:                      char *target_sect, int nr_reloc)
                    119: {
                    120:        Elf32_Sym *sym;
                    121:        Elf32_Addr sym_val;
                    122:        int i;
                    123:
                    124:        for (i = 0; i < nr_reloc; i++) {
                    125:                sym = &sym_table[ELF32_R_SYM(rela->r_info)];
                    126:                if (sym->st_shndx != STN_UNDEF) {
                    127:                        sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
                    128:                                + sym->st_value;
                    129:                        if (relocate_rela(rela, sym_val, target_sect) != 0)
                    130:                                return -1;
                    131:                } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
1.1.1.1.2.1! nbrk      132:                        DPRINTF(("Undefined symbol for rela[%x] sym=%x\n",
        !           133:                                 i, sym));
1.1       nbrk      134:                        return -1;
                    135:                } else {
1.1.1.1.2.1! nbrk      136:                        DPRINTF(("Undefined weak symbol for rela[%x]\n", i));
1.1       nbrk      137:                }
                    138:                rela++;
                    139:        }
                    140:        return 0;
                    141: }
                    142:
                    143: static int
                    144: relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel,
                    145:                     char *target_sect, int nr_reloc)
                    146: {
                    147:        Elf32_Sym *sym;
                    148:        Elf32_Addr sym_val;
                    149:        int i;
                    150:
                    151:        for (i = 0; i < nr_reloc; i++) {
                    152:                sym = &sym_table[ELF32_R_SYM(rel->r_info)];
                    153:                if (sym->st_shndx != STN_UNDEF) {
                    154:                        sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
                    155:                                + sym->st_value;
                    156:                        if (relocate_rel(rel, sym_val, target_sect) != 0)
                    157:                                return -1;
                    158:                } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
1.1.1.1.2.1! nbrk      159:                        DPRINTF(("Undefined symbol for rel[%x] sym=%x\n",
        !           160:                                 i, sym));
1.1       nbrk      161:                        return -1;
                    162:                } else {
1.1.1.1.2.1! nbrk      163:                        DPRINTF(("Undefined weak symbol for rel[%x]\n", i));
1.1       nbrk      164:                }
                    165:                rel++;
                    166:        }
                    167:        return 0;
                    168: }
                    169:
                    170: static int
                    171: relocate_section(char *img, Elf32_Shdr *shdr)
                    172: {
                    173:        Elf32_Sym *sym_table;
                    174:        char *target_sect;
                    175:        int nr_reloc, err;
                    176:
                    177:        if (shdr->sh_entsize == 0)
                    178:                return 0;
                    179:        if ((target_sect = sect_addr[shdr->sh_info]) == 0)
                    180:                return -1;
                    181:        if ((sym_table = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0)
                    182:                return -1;
                    183:
                    184:        nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
                    185:        switch (shdr->sh_type) {
                    186:        case SHT_REL:
                    187:                err = relocate_section_rel(sym_table,
                    188:                                (Elf32_Rel *)(img + shdr->sh_offset),
                    189:                                target_sect, nr_reloc);
                    190:                break;
                    191:
                    192:        case SHT_RELA:
                    193:                err = relocate_section_rela(sym_table,
                    194:                                (Elf32_Rela *)(img + shdr->sh_offset),
                    195:                                target_sect, nr_reloc);
                    196:                break;
                    197:
                    198:        default:
                    199:                err = -1;
                    200:                break;
                    201:        }
                    202:        return err;
                    203: }
                    204:
                    205: static int
                    206: load_relocatable(char *img, struct module *m)
                    207: {
                    208:        Elf32_Ehdr *ehdr;
                    209:        Elf32_Shdr *shdr;
1.1.1.1.2.1! nbrk      210:        paddr_t sect_base, bss_base;
1.1       nbrk      211:        int i;
                    212:
                    213:        ehdr = (Elf32_Ehdr *)img;
1.1.1.1.2.1! nbrk      214:        shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff);
1.1       nbrk      215:        bss_base = 0;
                    216:        m->phys = load_base;
1.1.1.1.2.1! nbrk      217:        DPRINTF(("phys addr=%x\n", load_base));
1.1       nbrk      218:
                    219:        /* Copy sections */
                    220:        for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
                    221:                sect_addr[i] = 0;
                    222:                if (shdr->sh_type == SHT_PROGBITS) {
                    223:
1.1.1.1.2.1! nbrk      224:                        DPRINTF(("sh_addr=%x\n", shdr->sh_addr));
        !           225:                        DPRINTF(("sh_size=%x\n", shdr->sh_size));
        !           226:                        DPRINTF(("sh_offset=%x\n", shdr->sh_offset));
        !           227:                        DPRINTF(("sh_flags=%x\n", shdr->sh_flags));
1.1       nbrk      228:
                    229:                        switch (shdr->sh_flags & SHF_VALID) {
                    230:                        case (SHF_ALLOC | SHF_EXECINSTR):
                    231:                                /* Text */
1.1.1.1.2.1! nbrk      232:                                m->text = (vaddr_t)phys_to_virt(load_base);
1.1       nbrk      233:                                break;
                    234:                        case (SHF_ALLOC | SHF_WRITE):
                    235:                                /* Data */
                    236:                                if (m->data == 0)
                    237:                                        m->data =
1.1.1.1.2.1! nbrk      238:                                                (vaddr_t)phys_to_virt(load_base + shdr->sh_addr);
1.1       nbrk      239:                                break;
                    240:                        case SHF_ALLOC:
                    241:                                /* rodata */
                    242:                                /* Note: rodata is treated as text. */
                    243:                                break;
                    244:                        default:
                    245:                                continue;
                    246:                        }
                    247:                        sect_base = load_base + shdr->sh_addr;
                    248:                        memcpy((char *)sect_base, img + shdr->sh_offset,
                    249:                               (size_t)shdr->sh_size);
1.1.1.1.2.1! nbrk      250:                        DPRINTF(("load: offset=%x size=%x\n",
        !           251:                                 sect_base, (int)shdr->sh_size));
1.1       nbrk      252:
                    253:                        sect_addr[i] = (char *)sect_base;
                    254:                } else if (shdr->sh_type == SHT_NOBITS) {
                    255:                        /* BSS */
                    256:                        m->bsssz = (size_t)shdr->sh_size;
                    257:                        sect_base = load_base + shdr->sh_addr;
                    258:                        bss_base = sect_base;
                    259:
                    260:                        /* Zero fill BSS */
                    261:                        memset((char *)sect_base, 0, (size_t)shdr->sh_size);
                    262:
                    263:                        sect_addr[i] = (char *)sect_base;
                    264:                } else if (shdr->sh_type == SHT_SYMTAB) {
                    265:                        /* Symbol table */
                    266:                        sect_addr[i] = img + shdr->sh_offset;
                    267:                }
                    268:        }
                    269:        m->textsz = (size_t)(m->data - m->text);
                    270:        m->datasz = (size_t)(bss_base - m->data);
                    271:
                    272:        load_base = bss_base + m->bsssz;
                    273:        load_base = PAGE_ALIGN(load_base);
                    274:
1.1.1.1.2.1! nbrk      275:        DPRINTF(("module load_base=%x text=%x\n", load_base, m->text));
        !           276:        m->size = (size_t)(load_base - (paddr_t)virt_to_phys(m->text));
        !           277:        m->entry = (vaddr_t)phys_to_virt(ehdr->e_entry + m->phys);
        !           278:        DPRINTF(("module size=%x entry=%x\n", m->size, m->entry));
1.1       nbrk      279:
                    280:        /* Process relocation */
1.1.1.1.2.1! nbrk      281:        shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff);
1.1       nbrk      282:        for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
                    283:                if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
                    284:                        if (relocate_section(img, shdr) != 0)
                    285:                                return -1;
                    286:                }
                    287:        }
                    288:        return 0;
                    289: }
                    290:
                    291: /*
                    292:  * Load the program from specified ELF image data stored in memory.
                    293:  * The boot information is filled after loading the program.
                    294:  */
                    295: int
                    296: elf_load(char *img, struct module *m)
                    297: {
                    298:        Elf32_Ehdr *ehdr;
                    299:        Elf32_Phdr *phdr;
                    300:
1.1.1.1.2.1! nbrk      301:        DPRINTF(("\nelf_load\n"));
1.1       nbrk      302:
                    303:        ehdr = (Elf32_Ehdr *)img;
                    304:
                    305:        /*  Check ELF header */
                    306:        if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
                    307:            (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
                    308:            (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
                    309:            (ehdr->e_ident[EI_MAG3] != ELFMAG3))
                    310:                return -1;
                    311:
1.1.1.1.2.1! nbrk      312:        phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_ehsize);
1.1       nbrk      313:
                    314:        if (nr_img == 0) {
                    315:                /*  Initialize the load address */
1.1.1.1.2.1! nbrk      316:                load_base = (vaddr_t)phys_to_virt(phdr->p_paddr);
1.1       nbrk      317:                if (load_base == 0)
                    318:                        return -1;
1.1.1.1.2.1! nbrk      319:                DPRINTF(("kernel base=%x\n", load_base));
1.1       nbrk      320:                load_start = load_base;
                    321:        }
                    322:        else if (nr_img == 1) {
                    323:                /*  Second image => Driver */
1.1.1.1.2.1! nbrk      324:                DPRINTF(("driver base=%x\n", load_base));
1.1       nbrk      325:        }
                    326:        else {
                    327:                /* Other images => Boot tasks */
1.1.1.1.2.1! nbrk      328:                DPRINTF(("task base=%x\n", load_base));
1.1       nbrk      329:        }
                    330:
                    331:        switch (ehdr->e_type) {
                    332:        case ET_EXEC:
                    333:                if (load_executable(img, m) != 0)
                    334:                        return -1;
                    335:                break;
                    336:        case ET_REL:
                    337:                if (load_relocatable(img, m) != 0)
                    338:                        return -1;
                    339:                break;
                    340:        default:
1.1.1.1.2.1! nbrk      341:                DPRINTF(("Unsupported file type\n"));
1.1       nbrk      342:                return -1;
                    343:        }
                    344:        nr_img++;
                    345:        return 0;
                    346: }

CVSweb