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 debug %ld 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 default: 254 dprintf("unhandled pheader type 0x%lx\n", header.p_type); 255 continue; 256 } 257 258 elf_region *region; 259 if (header.IsReadWrite()) { 260 if (image->data_region.size != 0) { 261 dprintf("elf: rw already handled!\n"); 262 continue; 263 } 264 region = &image->data_region; 265 } else if (header.IsExecutable()) { 266 if (image->text_region.size != 0) { 267 dprintf("elf: ro already handled!\n"); 268 continue; 269 } 270 region = &image->text_region; 271 } else 272 continue; 273 274 region->start = ROUNDOWN(header.p_vaddr, B_PAGE_SIZE); 275 region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), 276 B_PAGE_SIZE); 277 region->delta = -region->start; 278 279 TRACE(("segment %d: start = %p, size = %lu, delta = %lx\n", i, 280 region->start, region->size, region->delta)); 281 } 282 283 // found both, text and data? 284 if (image->data_region.size == 0 || image->text_region.size == 0) { 285 dprintf("Couldn't find both text and data segment!\n"); 286 status = B_BAD_DATA; 287 goto error1; 288 } 289 290 // get the segment order 291 elf_region *firstRegion; 292 elf_region *secondRegion; 293 if (image->text_region.start < image->data_region.start) { 294 firstRegion = &image->text_region; 295 secondRegion = &image->data_region; 296 } else { 297 firstRegion = &image->data_region; 298 secondRegion = &image->text_region; 299 } 300 301 // Check whether the segments have an unreasonable amount of unused space 302 // inbetween. 303 totalSize = secondRegion->start + secondRegion->size - firstRegion->start; 304 if (totalSize > image->text_region.size + image->data_region.size 305 + 8 * 1024) { 306 status = B_BAD_DATA; 307 goto error1; 308 } 309 310 // The kernel and the modules are relocatable, thus 311 // platform_allocate_region() can automatically allocate an address, 312 // but shall prefer the specified base address. 313 if (platform_allocate_region((void **)&firstRegion->start, totalSize, 314 B_READ_AREA | B_WRITE_AREA, false) < B_OK) { 315 status = B_NO_MEMORY; 316 goto error1; 317 } 318 319 // initialize the region pointers to the allocated region 320 secondRegion->start += firstRegion->start + firstRegion->delta; 321 322 image->data_region.delta += image->data_region.start; 323 image->text_region.delta += image->text_region.start; 324 325 // load program data 326 327 for (int i = 0; i < elfHeader.e_phnum; i++) { 328 Elf32_Phdr &header = programHeaders[i]; 329 330 if (header.p_type != PT_LOAD) 331 continue; 332 333 elf_region *region; 334 if (header.IsReadWrite()) 335 region = &image->data_region; 336 else if (header.IsExecutable()) 337 region = &image->text_region; 338 else 339 continue; 340 341 TRACE(("load segment %d (%ld bytes)...\n", i, header.p_filesz)); 342 343 length = read_pos(fd, header.p_offset, 344 (void *)(region->start + (header.p_vaddr % B_PAGE_SIZE)), 345 header.p_filesz); 346 if (length < (ssize_t)header.p_filesz) { 347 status = B_BAD_DATA; 348 dprintf("error reading in seg %d\n", i); 349 goto error2; 350 } 351 352 // Clear anything above the file size (that may also contain the BSS 353 // area) 354 355 uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; 356 if (offset < region->size) 357 memset((void *)(region->start + offset), 0, region->size - offset); 358 } 359 360 // offset dynamic section, and program entry addresses by the delta of the 361 // regions 362 image->dynamic_section.start += image->text_region.delta; 363 image->elf_header.e_entry += image->text_region.delta; 364 365 image->num_debug_symbols = 0; 366 image->debug_symbols = NULL; 367 image->debug_string_table = NULL; 368 369 // ToDo: this should be enabled by kernel settings! 370 if (1) 371 load_elf_symbol_table(fd, image); 372 373 free(programHeaders); 374 375 return B_OK; 376 377 error2: 378 if (image->text_region.start != 0) 379 platform_free_region((void *)image->text_region.start, totalSize); 380 error1: 381 free(programHeaders); 382 383 return status; 384 } 385 386 387 status_t 388 elf_load_image(Directory *directory, const char *path) 389 { 390 preloaded_image *image; 391 392 TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path)); 393 394 int fd = open_from(directory, path, O_RDONLY); 395 if (fd < 0) 396 return fd; 397 398 // check if this file has already been loaded 399 400 struct stat stat; 401 fstat(fd, &stat); 402 403 image = gKernelArgs.preloaded_images; 404 for (; image != NULL; image = image->next) { 405 if (image->inode == stat.st_ino) { 406 // file has already been loaded, no need to load it twice! 407 close(fd); 408 return B_OK; 409 } 410 } 411 412 // we still need to load it, so do it 413 414 image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image)); 415 if (image == NULL) { 416 close(fd); 417 return B_NO_MEMORY; 418 } 419 420 status_t status = elf_load_image(fd, image); 421 if (status == B_OK) { 422 image->name = kernel_args_strdup(path); 423 image->inode = stat.st_ino; 424 425 // insert to kernel args 426 image->next = gKernelArgs.preloaded_images; 427 gKernelArgs.preloaded_images = image; 428 } else 429 kernel_args_free(image); 430 431 close(fd); 432 return status; 433 } 434 435 436 status_t 437 elf_relocate_image(struct preloaded_image *image) 438 { 439 status_t status = elf_parse_dynamic_section(image); 440 if (status != B_OK) 441 return status; 442 443 // deal with the rels first 444 if (image->rel) { 445 TRACE(("total %i relocs\n", 446 image->rel_len / (int)sizeof(struct Elf32_Rel))); 447 448 status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len); 449 if (status < B_OK) 450 return status; 451 } 452 453 if (image->pltrel) { 454 TRACE(("total %i plt-relocs\n", 455 image->pltrel_len / (int)sizeof(struct Elf32_Rel))); 456 457 if (image->pltrel_type == DT_REL) { 458 status = boot_arch_elf_relocate_rel(image, image->pltrel, 459 image->pltrel_len); 460 } else { 461 status = boot_arch_elf_relocate_rela(image, 462 (struct Elf32_Rela *)image->pltrel, image->pltrel_len); 463 } 464 if (status < B_OK) 465 return status; 466 } 467 468 if (image->rela) { 469 status = boot_arch_elf_relocate_rela(image, image->rela, 470 image->rela_len); 471 if (status < B_OK) 472 return status; 473 } 474 475 return B_OK; 476 } 477 478 479 status_t 480 boot_elf_resolve_symbol(struct preloaded_image *image, 481 struct Elf32_Sym *symbol, addr_t *symbolAddress) 482 { 483 switch (symbol->st_shndx) { 484 case SHN_UNDEF: 485 // Since we do that only for the kernel, there shouldn't be 486 // undefined symbols. 487 return B_MISSING_SYMBOL; 488 case SHN_ABS: 489 *symbolAddress = symbol->st_value; 490 return B_NO_ERROR; 491 case SHN_COMMON: 492 // ToDo: finish this 493 TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n")); 494 return B_ERROR; 495 default: 496 // standard symbol 497 *symbolAddress = symbol->st_value + image->text_region.delta; 498 return B_NO_ERROR; 499 } 500 } 501