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

Annotation of prex/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, (off_t)phdr->p_offset, SEEK_SET)
        !            86:                            == -(off_t)1)
        !            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;
        !           124:                } else if (ELF32_ST_BIND(sym->st_info) == STB_WEAK) {
        !           125:                        DPRINTF(("undefined weak symbol for rela[%d]\n", i));
        !           126:                }
        !           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;
        !           147:                } else if (ELF32_ST_BIND(sym->st_info) == STB_WEAK) {
        !           148:                        DPRINTF(("undefined weak symbol for rel[%d]\n", i));
        !           149:                }
        !           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:
        !           165:        DPRINTF(("relocate_sec\n"));
        !           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:                /*
        !           243:                 *DPRINTF(("section: type=%x addr=%x size=%d offset=%x flags=%x\n",
        !           244:                 *   shdr->sh_type, shdr->sh_addr, shdr->sh_size,
        !           245:                 *   shdr->sh_offset, shdr->sh_flags));
        !           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;
        !           294:                                DPRINTF(("exec: relocation failed\n"));
        !           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