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