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