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