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