[BACK]Return to elf.c CVS log [TXT][DIR] Up to [local] / prex-old / usr / server / exec

Annotation of prex-old/usr/server/exec/elf.c, Revision 1.1.1.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 loader
                     32:  */
                     33:
                     34: #include <prex/prex.h>
                     35: #include <server/fs.h>
                     36: #include <server/proc.h>
                     37: #include <sys/elf.h>
                     38: #include <sys/param.h>
                     39:
                     40: #include <string.h>
                     41: #include <limits.h>
                     42: #include <stdio.h>
                     43: #include <stdlib.h>
                     44: #include <errno.h>
                     45:
                     46: #include "exec.h"
                     47:
                     48: #define SHF_VALID      (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE)
                     49:
                     50: #ifndef CONFIG_MMU
                     51: static char *sect_addr[32];    /* Array of section address */
                     52: #endif
                     53:
                     54: #ifdef CONFIG_MMU
                     55: /*
                     56:  * Load executable ELF file
                     57:  */
                     58: static int
                     59: load_exec(Elf32_Ehdr *ehdr, task_t task, int fd, void **entry)
                     60: {
                     61:        Elf32_Phdr *phdr;
                     62:        void *addr, *mapped;
                     63:        size_t size = 0;
                     64:        int i;
                     65:
                     66:        phdr = (Elf32_Phdr *)((u_long)ehdr + ehdr->e_phoff);
                     67:        if (phdr == NULL)
                     68:                return ENOEXEC;
                     69:
                     70:        for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) {
                     71:                if (phdr->p_type != PT_LOAD)
                     72:                        continue;
                     73:
                     74:                addr = (void *)phdr->p_vaddr;
                     75:                size = phdr->p_memsz;
                     76:                if (size == 0)
                     77:                        continue;
                     78:
                     79:                if (vm_allocate(task, &addr, size, 0) != 0)
                     80:                        return ENOMEM;
                     81:
                     82:                if (vm_map(task, (void *)phdr->p_vaddr, size, &mapped) != 0)
                     83:                        return ENOEXEC;
                     84:                if (phdr->p_filesz > 0) {
                     85:                        if (lseek(fd, phdr->p_offset, SEEK_SET) == -(off_t)1)
                     86:                                goto err;
                     87:                        if (read(fd, mapped, phdr->p_filesz) < 0)
                     88:                                goto err;
                     89:                }
                     90:
                     91:                vm_free(task_self(), mapped);
                     92:
                     93:                /* Set read-only to text */
                     94:                if (phdr->p_flags & PF_X) {
                     95:                        if (vm_attribute(task, addr, VMA_READ) != 0)
                     96:                                return ENOEXEC;
                     97:                }
                     98:        }
                     99:        *entry = (void *)ehdr->e_entry;
                    100:        return 0;
                    101:
                    102:  err:
                    103:        vm_free(task_self(), mapped);
                    104:        return EIO;
                    105: }
                    106: #else /* !CONFIG_MMU */
                    107:
                    108: static int
                    109: relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela,
                    110:                      char *target_sect, int nr_reloc)
                    111: {
                    112:        Elf32_Sym *sym;
                    113:        Elf32_Addr sym_val;
                    114:        int i;
                    115:
                    116:        for (i = 0; i < nr_reloc; i++) {
                    117:                sym = &sym_table[ELF32_R_SYM(rela->r_info)];
                    118:                if (sym->st_shndx != STN_UNDEF) {
                    119:                        sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
                    120:                                + sym->st_value;
                    121:                        if (relocate_rela(rela, sym_val, target_sect) != 0)
                    122:                                return -1;
                    123:                } else if (ELF32_ST_BIND(sym->st_info) == STB_WEAK)
                    124:                        dprintf("undefined weak symbol for rela[%d]\n", i);
                    125:                rela++;
                    126:        }
                    127:        return 0;
                    128: }
                    129:
                    130: static int
                    131: relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel,
                    132:                     char *target_sect, int nr_reloc)
                    133: {
                    134:        Elf32_Sym *sym;
                    135:        Elf32_Addr sym_val;
                    136:        int i;
                    137:
                    138:        for (i = 0; i < nr_reloc; i++) {
                    139:                sym = &sym_table[ELF32_R_SYM(rel->r_info)];
                    140:                if (sym->st_shndx != STN_UNDEF) {
                    141:                        sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
                    142:                                + sym->st_value;
                    143:                        if (relocate_rel(rel, sym_val, target_sect) != 0)
                    144:                                return -1;
                    145:                } else if (ELF32_ST_BIND(sym->st_info) == STB_WEAK)
                    146:                        dprintf("undefined weak symbol for rel[%d]\n", i);
                    147:                rel++;
                    148:        }
                    149:        return 0;
                    150: }
                    151:
                    152: /*
                    153:  * Relocate ELF sections
                    154:  */
                    155: static int
                    156: relocate_section(Elf32_Shdr *shdr, char *rel_data)
                    157: {
                    158:        Elf32_Sym *sym_table;
                    159:        char *target_sect;
                    160:        int nr_reloc, err;
                    161:
                    162:        dprintf("relocate_sec\n");
                    163:        if (shdr->sh_entsize == 0)
                    164:                return 0;
                    165:        if ((target_sect = sect_addr[shdr->sh_info]) == 0)
                    166:                return -1;
                    167:        if ((sym_table = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0)
                    168:                return -1;
                    169:
                    170:        nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
                    171:        switch (shdr->sh_type) {
                    172:        case SHT_REL:
                    173:                err = relocate_section_rel(sym_table, (Elf32_Rel *)rel_data,
                    174:                                           target_sect, nr_reloc);
                    175:                break;
                    176:
                    177:        case SHT_RELA:
                    178:                err = relocate_section_rela(sym_table, (Elf32_Rela *)rel_data,
                    179:                                            target_sect, nr_reloc);
                    180:                break;
                    181:
                    182:        default:
                    183:                err = -1;
                    184:                break;
                    185:        }
                    186:        return err;
                    187: }
                    188:
                    189: /*
                    190:  * Load ELF relocatable file.
                    191:  */
                    192: static int
                    193: load_reloc(Elf32_Ehdr *ehdr, task_t task, int fd, void **entry)
                    194: {
                    195:        Elf32_Shdr *shdr;
                    196:        char *buf;
                    197:        void *base, *addr, *mapped;
                    198:        size_t shdr_size, total_size;
                    199:        int i, err = 0;
                    200:
                    201:        /* Read section header */
                    202:        shdr_size = ehdr->e_shentsize * ehdr->e_shnum;
                    203:        if ((buf = malloc(shdr_size)) == NULL)
                    204:                return ENOMEM;
                    205:
                    206:        if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0) {
                    207:                err = EIO;
                    208:                goto out1;
                    209:        }
                    210:        if (read(fd, buf, shdr_size) < 0) {
                    211:                err = EIO;
                    212:                goto out1;
                    213:        }
                    214:        /* Allocate memory for text, data and bss. */
                    215:        shdr = (Elf32_Shdr *)buf;
                    216:        total_size = 0;
                    217:        for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
                    218:                if (shdr->sh_type == SHT_NOBITS) { /* bss? */
                    219:                        total_size = shdr->sh_addr + shdr->sh_size;
                    220:                        break;
                    221:                }
                    222:        }
                    223:        if (total_size == 0) {
                    224:                err = ENOEXEC;
                    225:                goto out1;
                    226:        }
                    227:        if (vm_allocate(task, &base, total_size, 1) != 0) {
                    228:                err = ENOMEM;
                    229:                goto out1;
                    230:        }
                    231:
                    232:        if (vm_map(task, base, total_size, &mapped) != 0) {
                    233:                err = ENOMEM;
                    234:                goto out1;
                    235:        }
                    236:        /* Copy sections */
                    237:        shdr = (Elf32_Shdr *)buf;
                    238:        for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
                    239:                /*
                    240:                 *dprintf("section: type=%x addr=%x size=%d offset=%x flags=%x\n",
                    241:                 *   shdr->sh_type, shdr->sh_addr, shdr->sh_size,
                    242:                 *   shdr->sh_offset, shdr->sh_flags);
                    243:                 */
                    244:                sect_addr[i] = 0;
                    245:                if (shdr->sh_type == SHT_PROGBITS) {
                    246:                        switch (shdr->sh_flags & SHF_VALID) {
                    247:                        case (SHF_ALLOC | SHF_EXECINSTR): /* text */
                    248:                        case (SHF_ALLOC | SHF_WRITE): /* data */
                    249:                        case SHF_ALLOC: /* rodata */
                    250:                                break;
                    251:                        default:
                    252:                                continue;
                    253:                        }
                    254:                        addr = (char *)((u_long)mapped + shdr->sh_addr);
                    255:                        if (shdr->sh_size == 0) {
                    256:                                continue;
                    257:                        }
                    258:                } else if (shdr->sh_type == SHT_NOBITS) {
                    259:                        /* bss */
                    260:                        sect_addr[i] = \
                    261:                                (char *)((u_long)mapped + shdr->sh_addr);
                    262:                        continue;
                    263:                } else if (shdr->sh_type == SHT_SYMTAB ||
                    264:                           shdr->sh_type == SHT_RELA ||
                    265:                           shdr->sh_type == SHT_REL)
                    266:                {
                    267:
                    268:                        if ((addr = malloc(shdr->sh_size)) == NULL) {
                    269:                                err = ENOMEM;
                    270:                                goto out2;
                    271:                        }
                    272:                } else
                    273:                        continue;
                    274:
                    275:                if (lseek(fd, shdr->sh_offset, SEEK_SET) < 0) {
                    276:                        err = EIO;
                    277:                        goto out2;
                    278:                }
                    279:                if (read(fd, addr, shdr->sh_size) < 0) {
                    280:                        err = EIO;
                    281:                        goto out2;
                    282:                }
                    283:                sect_addr[i] = addr;
                    284:        }
                    285:        /* Process relocation */
                    286:        shdr = (Elf32_Shdr *)buf;
                    287:        for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
                    288:                if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
                    289:                        if (relocate_section(shdr, sect_addr[i]) != 0) {
                    290:                                err = EIO;
                    291:                                sys_log("exec: relocation failed\n");
                    292:                                goto out2;
                    293:                        }
                    294:                }
                    295:        }
                    296:        *entry = (void *)((u_long)mapped + ehdr->e_entry);
                    297:  out2:
                    298:        /* Release symbol table */
                    299:        shdr = (Elf32_Shdr *)buf;
                    300:        for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
                    301:                if (shdr->sh_type == SHT_SYMTAB ||
                    302:                    shdr->sh_type == SHT_RELA ||
                    303:                    shdr->sh_type == SHT_REL) {
                    304:                        if (sect_addr[i])
                    305:                                free(sect_addr[i]);
                    306:                }
                    307:        }
                    308:        vm_free(task_self(), mapped);
                    309:  out1:
                    310:        free(buf);
                    311:        return err;
                    312: }
                    313:
                    314: #endif /* !CONFIG_MMU */
                    315:
                    316:
                    317: /*
                    318:  * Load ELF file
                    319:  */
                    320: int
                    321: elf_load(void *header, task_t task, int fd, void **entry)
                    322: {
                    323:        int err;
                    324:
                    325: #ifdef CONFIG_MMU
                    326:        err = load_exec((Elf32_Ehdr *)header, task, fd, entry);
                    327: #else
                    328:        err = load_reloc((Elf32_Ehdr *)header, task, fd, entry);
                    329: #endif
                    330:        return err;
                    331: }
                    332:
                    333: /*
                    334:  * Probe ELF file
                    335:  */
                    336: int
                    337: elf_probe(void *header)
                    338: {
                    339:        Elf32_Ehdr *ehdr;
                    340:
                    341:        /* Check ELF header */
                    342:        ehdr = (Elf32_Ehdr *)header;
                    343:        if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
                    344:            (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
                    345:            (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
                    346:            (ehdr->e_ident[EI_MAG3] != ELFMAG3))
                    347:                return -1;
                    348: #ifdef CONFIG_MMU
                    349:        if (ehdr->e_type != ET_EXEC)
                    350:                return -1;
                    351: #else
                    352:        if (ehdr->e_type != ET_REL)
                    353:                return -1;
                    354: #endif
                    355:        return 0;
                    356: }
                    357:
                    358: void
                    359: elf_init(void)
                    360: {
                    361: }

CVSweb