1 /* 2 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "elf.h" 8 9 #include <boot/arch.h> 10 #include <boot/platform.h> 11 #include <boot/stage2.h> 12 #include <driver_settings.h> 13 #include <elf32.h> 14 #include <kernel.h> 15 16 #include <unistd.h> 17 #include <string.h> 18 #include <stdlib.h> 19 20 //#define TRACE_ELF 21 #ifdef TRACE_ELF 22 # define TRACE(x) dprintf x 23 #else 24 # define TRACE(x) ; 25 #endif 26 27 28 static bool sLoadElfSymbols = true; 29 30 31 void 32 elf_init() 33 { 34 // TODO: This cannot work, since the driver settings are loaded *after* the 35 // kernel has been loaded successfully. 36 #if 0 37 void *settings = load_driver_settings("kernel"); 38 if (settings == NULL) 39 return; 40 41 sLoadElfSymbols = !get_driver_boolean_parameter(settings, "load_symbols", 42 false, false); 43 unload_driver_settings(settings); 44 #endif 45 } 46 47 48 static status_t 49 verify_elf_header(struct Elf32_Ehdr &header) 50 { 51 if (memcmp(header.e_ident, ELF_MAGIC, 4) != 0 52 || header.e_ident[4] != ELFCLASS32 53 || header.e_phoff == 0 54 || !header.IsHostEndian() 55 || header.e_phentsize != sizeof(struct Elf32_Phdr)) 56 return B_BAD_TYPE; 57 58 return B_OK; 59 } 60 61 62 static status_t 63 elf_parse_dynamic_section(struct preloaded_image *image) 64 { 65 image->syms = 0; 66 image->rel = 0; 67 image->rel_len = 0; 68 image->rela = 0; 69 image->rela_len = 0; 70 image->pltrel = 0; 71 image->pltrel_len = 0; 72 image->pltrel_type = 0; 73 74 struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_section.start; 75 if (!d) 76 return B_ERROR; 77 78 for (int i = 0; d[i].d_tag != DT_NULL; i++) { 79 switch (d[i].d_tag) { 80 case DT_HASH: 81 case DT_STRTAB: 82 break; 83 case DT_SYMTAB: 84 image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr 85 + image->text_region.delta); 86 break; 87 case DT_REL: 88 image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr 89 + image->text_region.delta); 90 break; 91 case DT_RELSZ: 92 image->rel_len = d[i].d_un.d_val; 93 break; 94 case DT_RELA: 95 image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr 96 + image->text_region.delta); 97 break; 98 case DT_RELASZ: 99 image->rela_len = d[i].d_un.d_val; 100 break; 101 case DT_JMPREL: 102 image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr 103 + image->text_region.delta); 104 break; 105 case DT_PLTRELSZ: 106 image->pltrel_len = d[i].d_un.d_val; 107 break; 108 case DT_PLTREL: 109 image->pltrel_type = d[i].d_un.d_val; 110 break; 111 112 default: 113 continue; 114 } 115 } 116 117 // lets make sure we found all the required sections 118 if (image->syms == NULL) 119 return B_ERROR; 120 121 return B_OK; 122 } 123 124 125 static status_t 126 load_elf_symbol_table(int fd, preloaded_image *image) 127 { 128 struct Elf32_Ehdr &elfHeader = image->elf_header; 129 Elf32_Sym *symbolTable = NULL; 130 Elf32_Shdr *stringHeader = NULL; 131 uint32 numSymbols = 0; 132 char *stringTable; 133 status_t status; 134 135 // get section headers 136 137 ssize_t size = elfHeader.e_shnum * elfHeader.e_shentsize; 138 Elf32_Shdr *sectionHeaders = (struct Elf32_Shdr *)malloc(size); 139 if (sectionHeaders == NULL) { 140 dprintf("error allocating space for section headers\n"); 141 return B_NO_MEMORY; 142 } 143 144 ssize_t length = read_pos(fd, elfHeader.e_shoff, sectionHeaders, size); 145 if (length < size) { 146 TRACE(("error reading in program headers\n")); 147 status = B_ERROR; 148 goto error1; 149 } 150 151 // find symbol table in section headers 152 153 for (int32 i = 0; i < elfHeader.e_shnum; i++) { 154 if (sectionHeaders[i].sh_type == SHT_SYMTAB) { 155 stringHeader = §ionHeaders[sectionHeaders[i].sh_link]; 156 157 if (stringHeader->sh_type != SHT_STRTAB) { 158 TRACE(("doesn't link to string table\n")); 159 status = B_BAD_DATA; 160 goto error1; 161 } 162 163 // read in symbol table 164 symbolTable = (Elf32_Sym *)kernel_args_malloc( 165 size = sectionHeaders[i].sh_size); 166 if (symbolTable == NULL) { 167 status = B_NO_MEMORY; 168 goto error1; 169 } 170 171 length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable, 172 size); 173 if (length < size) { 174 TRACE(("error reading in symbol table\n")); 175 status = B_ERROR; 176 goto error1; 177 } 178 179 numSymbols = size / sizeof(Elf32_Sym); 180 break; 181 } 182 } 183 184 if (symbolTable == NULL) { 185 TRACE(("no symbol table\n")); 186 status = B_BAD_VALUE; 187 goto error1; 188 } 189 190 // read in string table 191 192 stringTable = (char *)kernel_args_malloc(size = stringHeader->sh_size); 193 if (stringTable == NULL) { 194 status = B_NO_MEMORY; 195 goto error2; 196 } 197 198 length = read_pos(fd, stringHeader->sh_offset, stringTable, size); 199 if (length < size) { 200 TRACE(("error reading in string table\n")); 201 status = B_ERROR; 202 goto error3; 203 } 204 205 TRACE(("loaded %ld debug symbols\n", numSymbols)); 206 207 // insert tables into image 208 image->debug_symbols = symbolTable; 209 image->num_debug_symbols = numSymbols; 210 image->debug_string_table = stringTable; 211 image->debug_string_table_size = size; 212 213 free(sectionHeaders); 214 return B_OK; 215 216 error3: 217 kernel_args_free(stringTable); 218 error2: 219 kernel_args_free(symbolTable); 220 error1: 221 free(sectionHeaders); 222 223 return status; 224 } 225 226 227 status_t 228 elf_load_image(int fd, preloaded_image *image) 229 { 230 size_t totalSize; 231 status_t status; 232 233 TRACE(("elf_load_image(fd = %d, image = %p)\n", fd, image)); 234 235 struct Elf32_Ehdr &elfHeader = image->elf_header; 236 237 ssize_t length = read_pos(fd, 0, &elfHeader, sizeof(Elf32_Ehdr)); 238 if (length < (ssize_t)sizeof(Elf32_Ehdr)) 239 return B_BAD_TYPE; 240 241 status = verify_elf_header(elfHeader); 242 if (status < B_OK) 243 return status; 244 245 ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize; 246 Elf32_Phdr *programHeaders = (struct Elf32_Phdr *)malloc(size); 247 if (programHeaders == NULL) { 248 dprintf("error allocating space for program headers\n"); 249 return B_NO_MEMORY; 250 } 251 252 length = read_pos(fd, elfHeader.e_phoff, programHeaders, size); 253 if (length < size) { 254 TRACE(("error reading in program headers\n")); 255 status = B_ERROR; 256 goto error1; 257 } 258 259 // create an area large enough to hold the image 260 261 image->data_region.size = 0; 262 image->text_region.size = 0; 263 264 for (int32 i = 0; i < elfHeader.e_phnum; i++) { 265 Elf32_Phdr &header = programHeaders[i]; 266 267 switch (header.p_type) { 268 case PT_LOAD: 269 break; 270 case PT_DYNAMIC: 271 image->dynamic_section.start = header.p_vaddr; 272 image->dynamic_section.size = header.p_memsz; 273 continue; 274 case PT_INTERP: 275 case PT_PHDR: 276 // known but unused type 277 continue; 278 default: 279 dprintf("unhandled pheader type 0x%lx\n", header.p_type); 280 continue; 281 } 282 283 elf_region *region; 284 if (header.IsReadWrite()) { 285 if (image->data_region.size != 0) { 286 dprintf("elf: rw already handled!\n"); 287 continue; 288 } 289 region = &image->data_region; 290 } else if (header.IsExecutable()) { 291 if (image->text_region.size != 0) { 292 dprintf("elf: ro already handled!\n"); 293 continue; 294 } 295 region = &image->text_region; 296 } else 297 continue; 298 299 region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE); 300 region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), 301 B_PAGE_SIZE); 302 region->delta = -region->start; 303 304 TRACE(("segment %d: start = %p, size = %lu, delta = %lx\n", i, 305 region->start, region->size, region->delta)); 306 } 307 308 // found both, text and data? 309 if (image->data_region.size == 0 || image->text_region.size == 0) { 310 dprintf("Couldn't find both text and data segment!\n"); 311 status = B_BAD_DATA; 312 goto error1; 313 } 314 315 // get the segment order 316 elf_region *firstRegion; 317 elf_region *secondRegion; 318 if (image->text_region.start < image->data_region.start) { 319 firstRegion = &image->text_region; 320 secondRegion = &image->data_region; 321 } else { 322 firstRegion = &image->data_region; 323 secondRegion = &image->text_region; 324 } 325 326 // Check whether the segments have an unreasonable amount of unused space 327 // inbetween. 328 totalSize = secondRegion->start + secondRegion->size - firstRegion->start; 329 if (totalSize > image->text_region.size + image->data_region.size 330 + 8 * 1024) { 331 status = B_BAD_DATA; 332 goto error1; 333 } 334 335 // The kernel and the modules are relocatable, thus 336 // platform_allocate_region() can automatically allocate an address, 337 // but shall prefer the specified base address. 338 if (platform_allocate_region((void **)&firstRegion->start, totalSize, 339 B_READ_AREA | B_WRITE_AREA, false) < B_OK) { 340 status = B_NO_MEMORY; 341 goto error1; 342 } 343 344 // initialize the region pointers to the allocated region 345 secondRegion->start += firstRegion->start + firstRegion->delta; 346 347 image->data_region.delta += image->data_region.start; 348 image->text_region.delta += image->text_region.start; 349 350 // load program data 351 352 for (int i = 0; i < elfHeader.e_phnum; i++) { 353 Elf32_Phdr &header = programHeaders[i]; 354 355 if (header.p_type != PT_LOAD) 356 continue; 357 358 elf_region *region; 359 if (header.IsReadWrite()) 360 region = &image->data_region; 361 else if (header.IsExecutable()) 362 region = &image->text_region; 363 else 364 continue; 365 366 TRACE(("load segment %d (%ld bytes)...\n", i, header.p_filesz)); 367 368 length = read_pos(fd, header.p_offset, 369 (void *)(region->start + (header.p_vaddr % B_PAGE_SIZE)), 370 header.p_filesz); 371 if (length < (ssize_t)header.p_filesz) { 372 status = B_BAD_DATA; 373 dprintf("error reading in seg %d\n", i); 374 goto error2; 375 } 376 377 // Clear anything above the file size (that may also contain the BSS 378 // area) 379 380 uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; 381 if (offset < region->size) 382 memset((void *)(region->start + offset), 0, region->size - offset); 383 } 384 385 // offset dynamic section, and program entry addresses by the delta of the 386 // regions 387 image->dynamic_section.start += image->text_region.delta; 388 image->elf_header.e_entry += image->text_region.delta; 389 390 image->num_debug_symbols = 0; 391 image->debug_symbols = NULL; 392 image->debug_string_table = NULL; 393 394 if (sLoadElfSymbols) 395 load_elf_symbol_table(fd, image); 396 397 free(programHeaders); 398 399 return B_OK; 400 401 error2: 402 if (image->text_region.start != 0) 403 platform_free_region((void *)image->text_region.start, totalSize); 404 error1: 405 free(programHeaders); 406 407 return status; 408 } 409 410 411 status_t 412 elf_load_image(Directory *directory, const char *path) 413 { 414 preloaded_image *image; 415 416 TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path)); 417 418 int fd = open_from(directory, path, O_RDONLY); 419 if (fd < 0) 420 return fd; 421 422 // check if this file has already been loaded 423 424 struct stat stat; 425 fstat(fd, &stat); 426 427 image = gKernelArgs.preloaded_images; 428 for (; image != NULL; image = image->next) { 429 if (image->inode == stat.st_ino) { 430 // file has already been loaded, no need to load it twice! 431 close(fd); 432 return B_OK; 433 } 434 } 435 436 // we still need to load it, so do it 437 438 image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image)); 439 if (image == NULL) { 440 close(fd); 441 return B_NO_MEMORY; 442 } 443 444 status_t status = elf_load_image(fd, image); 445 if (status == B_OK) { 446 image->name = kernel_args_strdup(path); 447 image->inode = stat.st_ino; 448 449 // insert to kernel args 450 image->next = gKernelArgs.preloaded_images; 451 gKernelArgs.preloaded_images = image; 452 } else 453 kernel_args_free(image); 454 455 close(fd); 456 return status; 457 } 458 459 460 status_t 461 elf_relocate_image(struct preloaded_image *image) 462 { 463 status_t status = elf_parse_dynamic_section(image); 464 if (status != B_OK) 465 return status; 466 467 // deal with the rels first 468 if (image->rel) { 469 TRACE(("total %i relocs\n", 470 image->rel_len / (int)sizeof(struct Elf32_Rel))); 471 472 status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len); 473 if (status < B_OK) 474 return status; 475 } 476 477 if (image->pltrel) { 478 TRACE(("total %i plt-relocs\n", 479 image->pltrel_len / (int)sizeof(struct Elf32_Rel))); 480 481 if (image->pltrel_type == DT_REL) { 482 status = boot_arch_elf_relocate_rel(image, image->pltrel, 483 image->pltrel_len); 484 } else { 485 status = boot_arch_elf_relocate_rela(image, 486 (struct Elf32_Rela *)image->pltrel, image->pltrel_len); 487 } 488 if (status < B_OK) 489 return status; 490 } 491 492 if (image->rela) { 493 TRACE(("total %i rela relocs\n", 494 image->rela_len / (int)sizeof(struct Elf32_Rela))); 495 status = boot_arch_elf_relocate_rela(image, image->rela, 496 image->rela_len); 497 if (status < B_OK) 498 return status; 499 } 500 501 return B_OK; 502 } 503 504 505 status_t 506 boot_elf_resolve_symbol(struct preloaded_image *image, 507 struct Elf32_Sym *symbol, addr_t *symbolAddress) 508 { 509 switch (symbol->st_shndx) { 510 case SHN_UNDEF: 511 // Since we do that only for the kernel, there shouldn't be 512 // undefined symbols. 513 return B_MISSING_SYMBOL; 514 case SHN_ABS: 515 *symbolAddress = symbol->st_value; 516 return B_NO_ERROR; 517 case SHN_COMMON: 518 // ToDo: finish this 519 TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n")); 520 return B_ERROR; 521 default: 522 // standard symbol 523 *symbolAddress = symbol->st_value + image->text_region.delta; 524 return B_NO_ERROR; 525 } 526 } 527