Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/exec/exec_elf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. load_exec
  2. relocate_section_rela
  3. relocate_section_rel
  4. relocate_section
  5. load_reloc
  6. elf_load
  7. elf_probe
  8. elf_init

   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  * exec_elf.c - ELF file loader
  32  */
  33 
  34 #include <sys/prex.h>
  35 #include <ipc/fs.h>
  36 #include <ipc/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, vaddr_t *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, PROT_READ) != 0)
  97                                 return ENOEXEC;
  98                 }
  99         }
 100         *entry = (vaddr_t)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, error;
 164 
 165         if (shdr->sh_entsize == 0)
 166                 return 0;
 167         if ((target_sect = sect_addr[shdr->sh_info]) == 0)
 168                 return -1;
 169         if ((sym_table = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0)
 170                 return -1;
 171 
 172         nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
 173         switch (shdr->sh_type) {
 174         case SHT_REL:
 175                 error = relocate_section_rel(sym_table, (Elf32_Rel *)rel_data,
 176                                            target_sect, nr_reloc);
 177                 break;
 178 
 179         case SHT_RELA:
 180                 error = relocate_section_rela(sym_table, (Elf32_Rela *)rel_data,
 181                                             target_sect, nr_reloc);
 182                 break;
 183 
 184         default:
 185                 error = -1;
 186                 break;
 187         }
 188         return error;
 189 }
 190 
 191 /*
 192  * Load ELF relocatable file.
 193  */
 194 static int
 195 load_reloc(Elf32_Ehdr *ehdr, task_t task, int fd, vaddr_t *entry)
 196 {
 197         Elf32_Shdr *shdr;
 198         char *buf;
 199         void *base, *addr, *mapped;
 200         size_t shdr_size, total_size;
 201         int i, error = 0;
 202 
 203         DPRINTF(("exec: load_reloc\n"));
 204 
 205         /* Read section header */
 206         shdr_size = ehdr->e_shentsize * ehdr->e_shnum;
 207         if ((buf = malloc(shdr_size)) == NULL) {
 208                 error = ENOMEM;
 209                 goto out0;
 210         }
 211 
 212         if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0) {
 213                 error = EIO;
 214                 goto out1;
 215         }
 216         if (read(fd, buf, shdr_size) < 0) {
 217                 error = EIO;
 218                 goto out1;
 219         }
 220 
 221         /* Allocate memory for text, data and bss. */
 222         shdr = (Elf32_Shdr *)buf;
 223         total_size = 0;
 224         for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
 225                 if (shdr->sh_type == SHT_NOBITS) { /* bss? */
 226                         total_size = shdr->sh_addr + shdr->sh_size;
 227                         break;
 228                 }
 229         }
 230         if (total_size == 0) {
 231                 error = ENOEXEC;
 232                 goto out1;
 233         }
 234         if (vm_allocate(task, &base, total_size, 1) != 0) {
 235                 DPRINTF(("exec: out of text\n"));
 236                 error = ENOMEM;
 237                 goto out1;
 238         }
 239 
 240         if (vm_map(task, base, total_size, &mapped) != 0) {
 241                 error = ENOMEM;
 242                 goto out1;
 243         }
 244 
 245         /* Copy sections */
 246         shdr = (Elf32_Shdr *)buf;
 247         for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
 248                 /*
 249                  *DPRINTF(("section: type=%x addr=%x size=%d offset=%x flags=%x\n",
 250                  *   shdr->sh_type, shdr->sh_addr, shdr->sh_size,
 251                  *   shdr->sh_offset, shdr->sh_flags));
 252                  */
 253                 sect_addr[i] = 0;
 254                 if (shdr->sh_type == SHT_PROGBITS) {
 255                         switch (shdr->sh_flags & SHF_VALID) {
 256                         case (SHF_ALLOC | SHF_EXECINSTR): /* text */
 257                         case (SHF_ALLOC | SHF_WRITE): /* data */
 258                         case SHF_ALLOC: /* rodata */
 259                                 break;
 260                         default:
 261                                 continue;
 262                         }
 263                         addr = (char *)((u_long)mapped + shdr->sh_addr);
 264                         if (shdr->sh_size == 0) {
 265                                 continue;
 266                         }
 267                 } else if (shdr->sh_type == SHT_NOBITS) {
 268                         /* bss */
 269                         sect_addr[i] = \
 270                                 (char *)((u_long)mapped + shdr->sh_addr);
 271                         continue;
 272                 } else if (shdr->sh_type == SHT_SYMTAB ||
 273                            shdr->sh_type == SHT_RELA ||
 274                            shdr->sh_type == SHT_REL)
 275                 {
 276 
 277                         if ((addr = malloc(shdr->sh_size)) == NULL) {
 278                                 error = ENOMEM;
 279                                 goto out2;
 280                         }
 281                 } else
 282                         continue;
 283 
 284                 if (lseek(fd, shdr->sh_offset, SEEK_SET) < 0) {
 285                         error = EIO;
 286                         goto out2;
 287                 }
 288                 if (read(fd, addr, shdr->sh_size) < 0) {
 289                         error = EIO;
 290                         goto out2;
 291                 }
 292                 sect_addr[i] = addr;
 293         }
 294 
 295         /* Process relocation */
 296         shdr = (Elf32_Shdr *)buf;
 297         for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
 298                 if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
 299                         if (relocate_section(shdr, sect_addr[i]) != 0) {
 300                                 error = EIO;
 301                                 DPRINTF(("exec: relocation failed\n"));
 302                                 goto out2;
 303                         }
 304                 }
 305         }
 306         *entry = (vaddr_t)((u_long)mapped + ehdr->e_entry);
 307         DPRINTF(("exec: entry=%x\n", *entry));
 308  out2:
 309         /* Release symbol table */
 310         shdr = (Elf32_Shdr *)buf;
 311         for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
 312                 if (shdr->sh_type == SHT_SYMTAB ||
 313                     shdr->sh_type == SHT_RELA ||
 314                     shdr->sh_type == SHT_REL) {
 315                         if (sect_addr[i])
 316                                 free(sect_addr[i]);
 317                 }
 318         }
 319         vm_free(task_self(), mapped);
 320  out1:
 321         free(buf);
 322  out0:
 323         DPRINTF(("exec: load_reloc ret=%d\n", error));
 324         return error;
 325 }
 326 
 327 #endif /* !CONFIG_MMU */
 328 
 329 
 330 /*
 331  * Load ELF file
 332  */
 333 int
 334 elf_load(struct exec *exec)
 335 {
 336         int error, fd;
 337 
 338         /*
 339          * Check permission.
 340          */
 341         if (access(exec->path, X_OK) == -1) {
 342                 DPRINTF(("exec: no exec access\n"));
 343                 return errno;
 344         }
 345 
 346         if ((fd = open(exec->path, O_RDONLY)) == -1)
 347                 return ENOENT;
 348 
 349 #ifdef CONFIG_MMU
 350         error = load_exec((Elf32_Ehdr *)exec->header, exec->task,
 351                           fd, &exec->entry);
 352 #else
 353         error = load_reloc((Elf32_Ehdr *)exec->header, exec->task,
 354                           fd, &exec->entry);
 355 #endif
 356         close(fd);
 357         return error;
 358 }
 359 
 360 /*
 361  * Probe ELF file
 362  */
 363 int
 364 elf_probe(struct exec *exec)
 365 {
 366         Elf32_Ehdr *ehdr;
 367 
 368         /* Check ELF header */
 369         ehdr = (Elf32_Ehdr *)exec->header;
 370         DPRINTF(("exec: ELF magic %c %c %c %c\n",
 371                  ehdr->e_ident[EI_MAG0],
 372                  ehdr->e_ident[EI_MAG1],
 373                  ehdr->e_ident[EI_MAG2],
 374                  ehdr->e_ident[EI_MAG3]));
 375 
 376         if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
 377             (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
 378             (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
 379             (ehdr->e_ident[EI_MAG3] != ELFMAG3))
 380                 return PROBE_ERROR;
 381 
 382 #ifdef CONFIG_MMU
 383         if (ehdr->e_type != ET_EXEC)
 384                 return PROBE_ERROR;
 385 #else
 386         if (ehdr->e_type != ET_REL)
 387                 return PROBE_ERROR;
 388 #endif
 389         return PROBE_MATCH;
 390 }
 391 
 392 void
 393 elf_init(void)
 394 {
 395 }

/* [<][>][^][v][top][bottom][index][help] */