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