1 /* 2 ** Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 ** Distributed under the terms of the Haiku 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 // image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->text_region.delta); 61 break; 62 case DT_STRTAB: 63 // image->strtab = (char *)(d[i].d_un.d_ptr + image->text_region.delta); 64 break; 65 case DT_SYMTAB: 66 image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->text_region.delta); 67 break; 68 case DT_REL: 69 image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->text_region.delta); 70 break; 71 case DT_RELSZ: 72 image->rel_len = d[i].d_un.d_val; 73 break; 74 case DT_RELA: 75 image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + 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 + image->text_region.delta); 82 break; 83 case DT_PLTRELSZ: 84 image->pltrel_len = d[i].d_un.d_val; 85 break; 86 case DT_PLTREL: 87 image->pltrel_type = d[i].d_un.d_val; 88 break; 89 90 default: 91 continue; 92 } 93 } 94 95 // lets make sure we found all the required sections 96 // if (!image->symhash || !image->syms || !image->strtab) 97 if (/* !image->symhash ||*/ !image->syms /*|| !image->strtab*/) 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(size = sectionHeaders[i].sh_size); 144 if (symbolTable == NULL) { 145 status = B_NO_MEMORY; 146 goto error1; 147 } 148 149 length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable, size); 150 if (length < size) { 151 TRACE(("error reading in symbol table\n")); 152 status = B_ERROR; 153 goto error1; 154 } 155 156 numSymbols = size / sizeof(Elf32_Sym); 157 break; 158 } 159 } 160 161 if (symbolTable == NULL) { 162 TRACE(("no symbol table\n")); 163 status = B_BAD_VALUE; 164 goto error1; 165 } 166 167 // read in string table 168 169 stringTable = (char *)kernel_args_malloc(size = stringHeader->sh_size); 170 if (stringTable == NULL) { 171 status = B_NO_MEMORY; 172 goto error2; 173 } 174 175 length = read_pos(fd, stringHeader->sh_offset, stringTable, size); 176 if (length < size) { 177 TRACE(("error reading in string table\n")); 178 status = B_ERROR; 179 goto error3; 180 } 181 182 TRACE(("loaded debug %ld symbols\n", numSymbols)); 183 184 // insert tables into image 185 image->debug_symbols = symbolTable; 186 image->num_debug_symbols = numSymbols; 187 image->debug_string_table = stringTable; 188 image->debug_string_table_size = size; 189 190 free(sectionHeaders); 191 return B_OK; 192 193 error3: 194 kernel_args_free(stringTable); 195 error2: 196 kernel_args_free(symbolTable); 197 error1: 198 free(sectionHeaders); 199 200 return status; 201 } 202 203 204 status_t 205 elf_load_image(int fd, preloaded_image *image) 206 { 207 size_t totalSize; 208 status_t status; 209 210 TRACE(("elf_load_image(fd = %d, image = %p)\n", fd, image)); 211 212 struct Elf32_Ehdr &elfHeader = image->elf_header; 213 214 ssize_t length = read_pos(fd, 0, &elfHeader, sizeof(Elf32_Ehdr)); 215 if (length < (ssize_t)sizeof(Elf32_Ehdr)) 216 return B_BAD_TYPE; 217 218 status = verify_elf_header(elfHeader); 219 if (status < B_OK) 220 return status; 221 222 ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize; 223 Elf32_Phdr *programHeaders = (struct Elf32_Phdr *)malloc(size); 224 if (programHeaders == NULL) { 225 dprintf("error allocating space for program headers\n"); 226 return B_NO_MEMORY; 227 } 228 229 length = read_pos(fd, elfHeader.e_phoff, programHeaders, size); 230 if (length < size) { 231 TRACE(("error reading in program headers\n")); 232 status = B_ERROR; 233 goto error1; 234 } 235 236 // create an area large enough to hold the image 237 238 image->data_region.size = 0; 239 image->text_region.size = 0; 240 241 for (int32 i = 0; i < elfHeader.e_phnum; i++) { 242 Elf32_Phdr &header = programHeaders[i]; 243 244 switch (header.p_type) { 245 case PT_LOAD: 246 break; 247 case PT_DYNAMIC: 248 image->dynamic_section.start = header.p_vaddr; 249 image->dynamic_section.size = header.p_memsz; 250 continue; 251 default: 252 dprintf("unhandled pheader type 0x%lx\n", header.p_type); 253 continue; 254 } 255 256 elf_region *region; 257 if (header.IsReadWrite()) { 258 if (image->data_region.size != 0) { 259 dprintf("elf: rw already handled!\n"); 260 continue; 261 } 262 region = &image->data_region; 263 } else if (header.IsExecutable()) { 264 if (image->text_region.size != 0) { 265 dprintf("elf: ro already handled!\n"); 266 continue; 267 } 268 region = &image->text_region; 269 } else 270 continue; 271 272 region->start = ROUNDOWN(header.p_vaddr, B_PAGE_SIZE); 273 region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); 274 region->delta = -region->start; 275 276 TRACE(("segment %d: start = %p, size = %lu, delta = %lx\n", i, 277 region->start, region->size, region->delta)); 278 } 279 280 // found both, text and data? 281 if (image->data_region.size == 0 || image->text_region.size == 0) { 282 dprintf("Couldn't find both text and data segment!\n"); 283 status = B_BAD_DATA; 284 goto error1; 285 } 286 287 // get the segment order 288 elf_region *firstRegion; 289 elf_region *secondRegion; 290 if (image->text_region.start < image->data_region.start) { 291 firstRegion = &image->text_region; 292 secondRegion = &image->data_region; 293 } else { 294 firstRegion = &image->data_region; 295 secondRegion = &image->text_region; 296 } 297 298 // Check whether the segments have an unreasonable amount of unused space 299 // inbetween. 300 totalSize = secondRegion->start + secondRegion->size - firstRegion->start; 301 if (totalSize > image->text_region.size + image->data_region.size 302 + 8 * 1024) { 303 status = B_BAD_DATA; 304 goto error1; 305 } 306 307 // The kernel and the modules are relocatable, thus 308 // platform_allocate_region() can automatically allocate an address, 309 // but shall prefer the specified base address. 310 if (platform_allocate_region((void **)&firstRegion->start, totalSize, 311 B_READ_AREA | B_WRITE_AREA, false) < B_OK) { 312 status = B_NO_MEMORY; 313 goto error1; 314 } 315 316 // initialize the region pointers to the allocated region 317 secondRegion->start += firstRegion->start + firstRegion->delta; 318 319 image->data_region.delta += image->data_region.start; 320 image->text_region.delta += image->text_region.start; 321 322 // load program data 323 324 for (int i = 0; i < elfHeader.e_phnum; i++) { 325 Elf32_Phdr &header = programHeaders[i]; 326 327 if (header.p_type != PT_LOAD) 328 continue; 329 330 elf_region *region; 331 if (header.IsReadWrite()) 332 region = &image->data_region; 333 else if (header.IsExecutable()) 334 region = &image->text_region; 335 else 336 continue; 337 338 TRACE(("load segment %d (%ld bytes)...\n", i, header.p_filesz)); 339 340 length = read_pos(fd, header.p_offset, 341 (void *)(region->start + (header.p_vaddr % B_PAGE_SIZE)), header.p_filesz); 342 if (length < (ssize_t)header.p_filesz) { 343 status = B_BAD_DATA; 344 dprintf("error reading in seg %d\n", i); 345 goto error2; 346 } 347 348 // clear anything above the file size (that may also contain the BSS area) 349 350 uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; 351 if (offset < region->size) 352 memset((void *)(region->start + offset), 0, region->size - offset); 353 } 354 355 // offset dynamic section, and program entry addresses by the delta of the 356 // regions 357 image->dynamic_section.start += image->text_region.delta; 358 image->elf_header.e_entry += image->text_region.delta; 359 360 image->num_debug_symbols = 0; 361 image->debug_symbols = NULL; 362 image->debug_string_table = NULL; 363 364 // ToDo: this should be enabled by kernel settings! 365 if (1) 366 load_elf_symbol_table(fd, image); 367 368 free(programHeaders); 369 370 return B_OK; 371 372 error2: 373 if (image->text_region.start != NULL) 374 platform_free_region((void *)image->text_region.start, totalSize); 375 error1: 376 free(programHeaders); 377 378 return status; 379 } 380 381 382 status_t 383 elf_load_image(Directory *directory, const char *path) 384 { 385 preloaded_image *image; 386 387 TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path)); 388 389 int fd = open_from(directory, path, O_RDONLY); 390 if (fd < 0) 391 return fd; 392 393 // check if this file has already been loaded 394 395 struct stat stat; 396 fstat(fd, &stat); 397 398 image = gKernelArgs.preloaded_images; 399 for (; image != NULL; image = image->next) { 400 if (image->inode == stat.st_ino) { 401 // file has already been loaded, no need to load it twice! 402 close(fd); 403 return B_OK; 404 } 405 } 406 407 // we still need to load it, so do it 408 409 image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image)); 410 if (image == NULL) { 411 close(fd); 412 return B_NO_MEMORY; 413 } 414 415 status_t status = elf_load_image(fd, image); 416 if (status == B_OK) { 417 image->name = kernel_args_strdup(path); 418 image->inode = stat.st_ino; 419 420 // insert to kernel args 421 image->next = gKernelArgs.preloaded_images; 422 gKernelArgs.preloaded_images = image; 423 } else 424 kernel_args_free(image); 425 426 close(fd); 427 return status; 428 } 429 430 431 status_t 432 elf_relocate_image(struct preloaded_image *image) 433 { 434 status_t status = elf_parse_dynamic_section(image); 435 if (status != B_OK) 436 return status; 437 438 // deal with the rels first 439 if (image->rel) { 440 TRACE(("total %i relocs\n", 441 image->rel_len / (int)sizeof(struct Elf32_Rel))); 442 443 status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len); 444 if (status < B_OK) 445 return status; 446 } 447 448 if (image->pltrel) { 449 TRACE(("total %i plt-relocs\n", 450 image->pltrel_len / (int)sizeof(struct Elf32_Rel))); 451 452 if (image->pltrel_type == DT_REL) { 453 status = boot_arch_elf_relocate_rel(image, image->pltrel, 454 image->pltrel_len); 455 } else { 456 status = boot_arch_elf_relocate_rela(image, 457 (struct Elf32_Rela *)image->pltrel, image->pltrel_len); 458 } 459 if (status < B_OK) 460 return status; 461 } 462 463 if (image->rela) { 464 status = boot_arch_elf_relocate_rela(image, image->rela, 465 image->rela_len); 466 if (status < B_OK) 467 return status; 468 } 469 470 return B_OK; 471 } 472 473 474 status_t 475 boot_elf_resolve_symbol(struct preloaded_image *image, 476 struct Elf32_Sym *symbol, addr_t *symbolAddress) 477 { 478 switch (symbol->st_shndx) { 479 case SHN_UNDEF: 480 // Since we do that only for the kernel, there shouldn't be 481 // undefined symbols. 482 return B_MISSING_SYMBOL; 483 case SHN_ABS: 484 *symbolAddress = symbol->st_value; 485 return B_NO_ERROR; 486 case SHN_COMMON: 487 // ToDo: finish this 488 TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n")); 489 return B_ERROR; 490 default: 491 // standard symbol 492 *symbolAddress = symbol->st_value + image->text_region.delta; 493 return B_NO_ERROR; 494 } 495 } 496