Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/boot/common/elf.c

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

DEFINITIONS

This source file includes following definitions.
  1. load_elf
  2. load_executable
  3. relocate_section_rela
  4. relocate_section_rel
  5. relocate_section
  6. load_relocatable

   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 format support
  32  */
  33 
  34 #include <boot.h>
  35 #include <load.h>
  36 #include <sys/elf.h>
  37 #include <elf_reloc.h>
  38 
  39 /* forward declarations */
  40 static int      load_executable(char *, struct module *);
  41 static int      load_relocatable(char *, struct module *);
  42 
  43 #define SHF_VALID       (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE)
  44 
  45 static char *sect_addr[32];     /* array of section address */
  46 static int strshndx;            /* index of string section */
  47 
  48 /*
  49  * Load the program from specified ELF image stored in memory.
  50  * The boot information is filled after loading the program.
  51  */
  52 int
  53 load_elf(char *img, struct module *m)
  54 {
  55         Elf32_Ehdr *ehdr;
  56         Elf32_Phdr *phdr;
  57 
  58         ELFDBG(("\nelf_load\n"));
  59 
  60         ehdr = (Elf32_Ehdr *)img;
  61 
  62         /*  Check ELF header */
  63         if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
  64             (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
  65             (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
  66             (ehdr->e_ident[EI_MAG3] != ELFMAG3)) {
  67                 DPRINTF(("Invalid ELF image\n"));
  68                 return -1;
  69         }
  70 
  71         phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_ehsize);
  72 
  73         if (nr_img == 0) {
  74                 /*  Initialize the load address */
  75                 load_base = (vaddr_t)ptokv(phdr->p_paddr);
  76                 if (load_base == 0) {
  77                         DPRINTF(("Invalid load address\n"));
  78                         return -1;
  79                 }
  80                 ELFDBG(("kernel base=%lx\n", load_base));
  81                 load_start = load_base;
  82         }
  83         else if (nr_img == 1) {
  84                 /* 2nd image => Driver */
  85                 ELFDBG(("driver base=%lx\n", load_base));
  86         }
  87         else {
  88                 /* Other images => Boot tasks */
  89                 ELFDBG(("task base=%lx\n", load_base));
  90         }
  91 
  92         switch (ehdr->e_type) {
  93         case ET_EXEC:
  94                 if (load_executable(img, m) != 0)
  95                         return -1;
  96                 break;
  97         case ET_REL:
  98                 if (load_relocatable(img, m) != 0)
  99                         return -1;
 100                 break;
 101         default:
 102                 ELFDBG(("Unsupported file type\n"));
 103                 return -1;
 104         }
 105         nr_img++;
 106         return 0;
 107 }
 108 
 109 static int
 110 load_executable(char *img, struct module *m)
 111 {
 112         Elf32_Ehdr *ehdr;
 113         Elf32_Phdr *phdr;
 114         paddr_t phys_base;
 115         int i;
 116 
 117         phys_base = load_base;
 118         ehdr = (Elf32_Ehdr *)img;
 119         phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_phoff);
 120         m->phys = load_base;
 121         phys_base = load_base;
 122         ELFDBG(("phys addr=%lx\n", phys_base));
 123 
 124         for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) {
 125                 if (phdr->p_type != PT_LOAD)
 126                         continue;
 127 
 128                 ELFDBG(("p_flags=%x\n", (int)phdr->p_flags));
 129                 ELFDBG(("p_align=%x\n", (int)phdr->p_align));
 130                 ELFDBG(("p_paddr=%x\n", phdr->p_paddr));
 131 
 132                 if (i >= 2) {
 133                         ELFDBG(("skipping extra phdr\n"));
 134                         continue;
 135                 }
 136                 if (phdr->p_flags & PF_X) {
 137                         /* Text */
 138                         m->text = phdr->p_vaddr;
 139                         m->textsz = (size_t)phdr->p_memsz;
 140                 } else {
 141                         /* Data & BSS */
 142                         m->data = phdr->p_vaddr;
 143                         m->datasz = (size_t)phdr->p_filesz;
 144                         m->bsssz =
 145                                 (size_t)(phdr->p_memsz - phdr->p_filesz);
 146                         load_base = phys_base + (m->data - m->text);
 147                 }
 148                 if (phdr->p_filesz > 0) {
 149                         memcpy((char *)load_base, img + phdr->p_offset,
 150                                (size_t)phdr->p_filesz);
 151                         ELFDBG(("load: offset=%lx size=%x\n",
 152                                  load_base, (int)phdr->p_filesz));
 153                 }
 154                 if (!(phdr->p_flags & PF_X)) {
 155                         if (m->bsssz > 0) {
 156                                 /* Zero fill BSS */
 157                                 memset((char *)load_base + m->datasz,
 158                                        0, m->bsssz);
 159                         }
 160                         load_base += phdr->p_memsz;
 161                 }
 162         }
 163         /* workaround for data/bss size is 0 */
 164         if (m->data == 0)
 165                 load_base = phys_base + m->textsz;
 166 
 167         load_base = round_page(load_base);
 168         m->size = (size_t)(load_base - m->phys);
 169         m->entry = ehdr->e_entry;
 170         ELFDBG(("module size=%x entry=%lx\n", m->size, m->entry));
 171 
 172         if (m->size == 0)
 173                 panic("Module size is 0!");
 174         return 0;
 175 }
 176 
 177 static int
 178 relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela,
 179                       char *target_sect, int nr_reloc, char *strtab)
 180 {
 181         Elf32_Sym *sym;
 182         Elf32_Addr sym_val;
 183         int i;
 184 
 185         for (i = 0; i < nr_reloc; i++) {
 186                 sym = &sym_table[ELF32_R_SYM(rela->r_info)];
 187                 ELFDBG(("%s\n", strtab + sym->st_name));
 188                 if (sym->st_shndx != STN_UNDEF) {
 189                         sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
 190                                 + sym->st_value;
 191                         if (relocate_rela(rela, sym_val, target_sect) != 0)
 192                                 return -1;
 193                 } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
 194                         DPRINTF(("Undefined symbol for rela[%x] sym=%lx\n",
 195                                  i, (long)sym));
 196                         return -1;
 197                 } else {
 198                         DPRINTF(("Undefined weak symbol for rela[%x]\n", i));
 199                 }
 200                 rela++;
 201         }
 202         return 0;
 203 }
 204 
 205 static int
 206 relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel,
 207                      char *target_sect, int nr_reloc, char *strtab)
 208 {
 209         Elf32_Sym *sym;
 210         Elf32_Addr sym_val;
 211         int i;
 212 
 213         for (i = 0; i < nr_reloc; i++) {
 214                 sym = &sym_table[ELF32_R_SYM(rel->r_info)];
 215                 ELFDBG(("%s\n", strtab + sym->st_name));
 216                 if (sym->st_shndx != STN_UNDEF) {
 217                         sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
 218                                 + sym->st_value;
 219                         if (relocate_rel(rel, sym_val, target_sect) != 0)
 220                                 return -1;
 221                 } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
 222                         DPRINTF(("Undefined symbol for rel[%x] sym=%lx\n",
 223                                  i, (long)sym));
 224                         return -1;
 225                 } else {
 226                         DPRINTF(("Undefined weak symbol for rel[%x]\n", i));
 227                 }
 228                 rel++;
 229         }
 230         return 0;
 231 }
 232 
 233 static int
 234 relocate_section(char *img, Elf32_Shdr *shdr)
 235 {
 236         Elf32_Sym *symtab;
 237         char *target_sect;
 238         int nr_reloc, error;
 239         char *strtab;
 240 
 241         ELFDBG(("relocate_section\n"));
 242 
 243         if (shdr->sh_entsize == 0)
 244                 return 0;
 245         if ((target_sect = sect_addr[shdr->sh_info]) == 0)
 246                 return -1;
 247         if ((symtab = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0)
 248                 return -1;
 249         if ((strtab = sect_addr[strshndx]) == 0)
 250                 return -1;
 251         ELFDBG(("strtab=%x\n", strtab));
 252 
 253         nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
 254         switch (shdr->sh_type) {
 255         case SHT_REL:
 256                 error = relocate_section_rel(symtab,
 257                                 (Elf32_Rel *)(img + shdr->sh_offset),
 258                                 target_sect, nr_reloc, strtab);
 259                 break;
 260 
 261         case SHT_RELA:
 262                 error = relocate_section_rela(symtab,
 263                                 (Elf32_Rela *)(img + shdr->sh_offset),
 264                                 target_sect, nr_reloc, strtab);
 265                 break;
 266 
 267         default:
 268                 error = -1;
 269                 break;
 270         }
 271         return error;
 272 }
 273 
 274 static int
 275 load_relocatable(char *img, struct module *m)
 276 {
 277         Elf32_Ehdr *ehdr;
 278         Elf32_Shdr *shdr;
 279         paddr_t sect_base, bss_base;
 280         int i;
 281 
 282         strshndx = 0;
 283         ehdr = (Elf32_Ehdr *)img;
 284         shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff);
 285         bss_base = 0;
 286         m->phys = load_base;
 287         ELFDBG(("phys addr=%lx\n", load_base));
 288 
 289         /* Copy sections */
 290         for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
 291                 sect_addr[i] = 0;
 292                 if (shdr->sh_type == SHT_PROGBITS) {
 293 
 294                         ELFDBG(("sh_addr=%x\n", shdr->sh_addr));
 295                         ELFDBG(("sh_size=%x\n", shdr->sh_size));
 296                         ELFDBG(("sh_offset=%x\n", shdr->sh_offset));
 297                         ELFDBG(("sh_flags=%x\n", shdr->sh_flags));
 298 
 299                         switch (shdr->sh_flags & SHF_VALID) {
 300                         case (SHF_ALLOC | SHF_EXECINSTR):
 301                                 /* Text */
 302                                 m->text = (vaddr_t)ptokv(load_base);
 303                                 break;
 304                         case (SHF_ALLOC | SHF_WRITE):
 305                                 /* Data */
 306                                 if (m->data == 0) {
 307                                         m->data = (vaddr_t)ptokv(load_base +
 308                                                                  shdr->sh_addr);
 309                                 }
 310                                 break;
 311                         case SHF_ALLOC:
 312                                 /* rodata */
 313                                 /* Note: rodata is treated as text. */
 314                                 break;
 315                         default:
 316                                 continue;
 317                         }
 318                         sect_base = load_base + shdr->sh_addr;
 319                         memcpy((char *)sect_base, img + shdr->sh_offset,
 320                                (size_t)shdr->sh_size);
 321                         ELFDBG(("load: offset=%lx size=%x\n",
 322                                  sect_base, (int)shdr->sh_size));
 323 
 324                         sect_addr[i] = (char *)sect_base;
 325                 } else if (shdr->sh_type == SHT_NOBITS) {
 326                         /* BSS */
 327                         m->bsssz = (size_t)shdr->sh_size;
 328                         sect_base = load_base + shdr->sh_addr;
 329                         bss_base = sect_base;
 330 
 331                         /* Zero fill BSS */
 332                         memset((char *)bss_base, 0, (size_t)shdr->sh_size);
 333 
 334                         sect_addr[i] = (char *)sect_base;
 335                 } else if (shdr->sh_type == SHT_SYMTAB) {
 336                         /* Symbol table */
 337                         ELFDBG(("load: symtab index=%d link=%d\n",
 338                                 i, shdr->sh_link));
 339                         sect_addr[i] = img + shdr->sh_offset;
 340                         if (strshndx != 0)
 341                                 panic("Multiple symtab found!");
 342                         strshndx = (int)shdr->sh_link;
 343                 } else if (shdr->sh_type == SHT_STRTAB) {
 344                         /* String table */
 345                         sect_addr[i] = img + shdr->sh_offset;
 346                         ELFDBG(("load: strtab index=%d addr=%x\n",
 347                                 i, sect_addr[i]));
 348                 }
 349         }
 350         m->textsz = (size_t)(m->data - m->text);
 351         m->datasz = (size_t)((char *)ptokv(bss_base) - m->data);
 352 
 353         load_base = bss_base + m->bsssz;
 354         load_base = round_page(load_base);
 355 
 356         ELFDBG(("module load_base=%lx text=%lx\n", load_base, m->text));
 357         m->size = (size_t)(load_base - kvtop(m->text));
 358         m->entry = (vaddr_t)ptokv(ehdr->e_entry + m->phys);
 359         ELFDBG(("module size=%x entry=%lx\n", m->size, m->entry));
 360 
 361         /* Process relocation */
 362         shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff);
 363         for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
 364                 if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
 365                         if (relocate_section(img, shdr) != 0) {
 366                                 DPRINTF(("Relocation error: module=%s\n", m->name));
 367                                 return -1;
 368                         }
 369                 }
 370         }
 371         return 0;
 372 }

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