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

CVSweb