[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     ! 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