|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/boot/common/elf.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |