1 /* 2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2002, Manuel J. Petit. All rights reserved. 7 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 11 #include "elf_symbol_lookup.h" 12 13 #include <dlfcn.h> 14 #include <stdio.h> 15 #include <string.h> 16 17 #include "add_ons.h" 18 #include "errors.h" 19 #include "images.h" 20 #include "runtime_loader_private.h" 21 22 23 /*! Checks whether \a name matches the name of \a image. 24 25 It is expected that \a name does not contain directory components. It is 26 compared with the base name of \a image's name. 27 28 \param image The image. 29 \param name The name to check against. Can be NULL, in which case \c false 30 is returned. 31 \return \c true, iff \a name is non-NULL and matches the name of \a image. 32 */ 33 static bool 34 equals_image_name(const image_t* image, const char* name) 35 { 36 if (name == NULL) 37 return false; 38 39 const char* lastSlash = strrchr(name, '/'); 40 return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0; 41 } 42 43 44 // #pragma mark - 45 46 47 uint32 48 elf_hash(const char* _name) 49 { 50 const uint8* name = (const uint8*)_name; 51 52 uint32 h = 0; 53 while (*name != '\0') { 54 h = (h << 4) + *name++; 55 h ^= (h >> 24) & 0xf0; 56 } 57 return (h & 0x0fffffff); 58 } 59 60 61 uint32 62 elf_gnuhash(const char* _name) 63 { 64 const uint8* name = (const uint8*)_name; 65 66 uint32 h = 5381; 67 for (uint8 c = *name; c != '\0'; c = *++name) 68 h = (h * 33) + c; 69 70 return h; 71 } 72 73 74 struct match_result { 75 elf_sym* symbol; 76 elf_sym* versioned_symbol; 77 uint32 versioned_symbol_count; 78 79 match_result() : symbol(NULL), versioned_symbol(NULL), versioned_symbol_count(0) {} 80 }; 81 82 83 static bool 84 match_symbol(const image_t* image, const SymbolLookupInfo& lookupInfo, uint32 symIdx, 85 match_result& result) 86 { 87 elf_sym* symbol = &image->syms[symIdx]; 88 if (symbol->st_shndx == SHN_UNDEF) 89 return false; 90 if (symbol->Bind() != STB_GLOBAL && symbol->Bind() != STB_WEAK) 91 return false; 92 93 // check if the type matches 94 uint32 type = symbol->Type(); 95 if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC) 96 || (lookupInfo.type == B_SYMBOL_TYPE_DATA 97 && type != STT_OBJECT && type != STT_FUNC)) { 98 return false; 99 } 100 101 // check the symbol name 102 if (strcmp(SYMNAME(image, symbol), lookupInfo.name) != 0) 103 return false; 104 105 // check the version 106 107 // Handle the simple cases -- the image doesn't have version 108 // information -- first. 109 if (image->symbol_versions == NULL) { 110 if (lookupInfo.version == NULL) { 111 // No specific symbol version was requested either, so the 112 // symbol is just fine. 113 result.symbol = symbol; 114 return true; 115 } 116 117 // A specific version is requested. If it's the dependency 118 // referred to by the requested version, it's apparently an 119 // older version of the dependency and we're not happy. 120 if (equals_image_name(image, lookupInfo.version->file_name)) { 121 // TODO: That should actually be kind of fatal! 122 return false; 123 } 124 125 // This is some other image. We accept the symbol. 126 result.symbol = symbol; 127 return true; 128 } 129 130 // The image has version information. Let's see what we've got. 131 uint32 versionID = image->symbol_versions[symIdx]; 132 uint32 versionIndex = VER_NDX(versionID); 133 elf_version_info& version = image->versions[versionIndex]; 134 135 // skip local versions 136 if (versionIndex == VER_NDX_LOCAL) 137 return false; 138 139 if (lookupInfo.version != NULL) { 140 // a specific version is requested 141 142 // compare the versions 143 if (version.hash == lookupInfo.version->hash 144 && strcmp(version.name, lookupInfo.version->name) == 0) { 145 // versions match 146 result.symbol = symbol; 147 return true; 148 } 149 150 // The versions don't match. We're still fine with the 151 // base version, if it is public and we're not looking for 152 // the default version. 153 if ((versionID & VER_NDX_FLAG_HIDDEN) == 0 154 && versionIndex == VER_NDX_GLOBAL 155 && (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) 156 == 0) { 157 // TODO: Revise the default version case! That's how 158 // FreeBSD implements it, but glibc doesn't handle it 159 // specially. 160 result.symbol = symbol; 161 return true; 162 } 163 } else { 164 // No specific version requested, but the image has version 165 // information. This can happen in either of these cases: 166 // 167 // * The dependent object was linked against an older version 168 // of the now versioned dependency. 169 // * The symbol is looked up via find_image_symbol() or dlsym(). 170 // 171 // In the first case we return the base version of the symbol 172 // (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't 173 // exist, the unique, non-hidden versioned symbol. 174 // 175 // In the second case we want to return the public default 176 // version of the symbol. The handling is pretty similar to the 177 // first case, with the exception that we treat VER_NDX_INITIAL 178 // as regular version. 179 180 // VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if 181 // we don't look for the default version. 182 if (versionIndex == VER_NDX_GLOBAL 183 || ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0 184 && versionIndex == VER_NDX_INITIAL)) { 185 result.symbol = symbol; 186 return true; 187 } 188 189 // If not hidden, remember the version -- we'll return it, if 190 // it is the only one. 191 if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) { 192 result.versioned_symbol_count++; 193 result.versioned_symbol = symbol; 194 } 195 } 196 return false; 197 } 198 199 200 static elf_sym* 201 find_symbol_gnuhash(const image_t* image, const SymbolLookupInfo& lookupInfo) 202 { 203 // Test against the Bloom filter. 204 const uint32 wordSize = sizeof(elf_addr) * 8; 205 const uint32 firstHash = lookupInfo.gnuhash & (wordSize - 1); 206 const uint32 secondHash = lookupInfo.gnuhash >> image->gnuhash.shift2; 207 const uint32 index = (lookupInfo.gnuhash / wordSize) & image->gnuhash.mask_words_count_mask; 208 const elf_addr bloomWord = image->gnuhash.bloom[index]; 209 if (((bloomWord >> firstHash) & (bloomWord >> secondHash) & 1) == 0) 210 return NULL; 211 212 // Locate hash chain and corresponding value element. 213 const uint32 bucket = image->gnuhash.buckets[lookupInfo.gnuhash % image->gnuhash.bucket_count]; 214 if (bucket == 0) 215 return NULL; 216 217 match_result result; 218 const uint32* chain0 = image->gnuhash.chain0; 219 const uint32* hashValue = &chain0[bucket]; 220 do { 221 if (((*hashValue ^ lookupInfo.gnuhash) >> 1) != 0) 222 continue; 223 224 uint32 symIndex = hashValue - chain0; 225 if (match_symbol(image, lookupInfo, symIndex, result)) 226 return result.symbol; 227 } while ((*hashValue++ & 1) == 0); 228 229 if (result.versioned_symbol_count == 1) 230 return result.versioned_symbol; 231 return NULL; 232 } 233 234 235 static elf_sym* 236 find_symbol_sysv(const image_t* image, const SymbolLookupInfo& lookupInfo) 237 { 238 if (image->dynamic_ptr == 0) 239 return NULL; 240 241 match_result result; 242 243 uint32 bucket = lookupInfo.hash % HASHTABSIZE(image); 244 for (uint32 symIndex = HASHBUCKETS(image)[bucket]; symIndex != STN_UNDEF; 245 symIndex = HASHCHAINS(image)[symIndex]) { 246 if (match_symbol(image, lookupInfo, symIndex, result)) 247 return result.symbol; 248 } 249 250 if (result.versioned_symbol_count == 1) 251 return result.versioned_symbol; 252 return NULL; 253 } 254 255 256 elf_sym* 257 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo) 258 { 259 if (image->gnuhash.buckets != NULL) { 260 if (lookupInfo.gnuhash == 0) 261 const_cast<uint32&>(lookupInfo.gnuhash) = elf_gnuhash(lookupInfo.name); 262 return find_symbol_gnuhash(image, lookupInfo); 263 } 264 265 if (lookupInfo.hash == 0) 266 const_cast<uint32&>(lookupInfo.hash) = elf_hash(lookupInfo.name); 267 return find_symbol_sysv(image, lookupInfo); 268 } 269 270 271 void 272 patch_defined_symbol(image_t* image, const char* name, void** symbol, 273 int32* type) 274 { 275 RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers; 276 while (patcher != NULL && *symbol != 0) { 277 image_t* inImage = image; 278 patcher->patcher(patcher->cookie, NULL, image, name, &inImage, 279 symbol, type); 280 patcher = patcher->next; 281 } 282 } 283 284 285 void 286 patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 287 image_t** foundInImage, void** symbol, int32* type) 288 { 289 if (*foundInImage != NULL) 290 patch_defined_symbol(*foundInImage, name, symbol, type); 291 292 RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers; 293 while (patcher != NULL) { 294 patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage, 295 symbol, type); 296 patcher = patcher->next; 297 } 298 } 299 300 301 status_t 302 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo, 303 void **_location) 304 { 305 // get the symbol in the image 306 elf_sym* symbol = find_symbol(image, lookupInfo); 307 if (symbol == NULL) 308 return B_ENTRY_NOT_FOUND; 309 310 void* location = (void*)(symbol->st_value + image->regions[0].delta); 311 int32 symbolType = lookupInfo.type; 312 patch_defined_symbol(image, lookupInfo.name, &location, &symbolType); 313 314 if (_location != NULL) 315 *_location = location; 316 317 return B_OK; 318 } 319 320 321 status_t 322 find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo, 323 image_t** _foundInImage, void** _location) 324 { 325 image_t* queue[count_loaded_images()]; 326 uint32 count = 0; 327 uint32 index = 0; 328 queue[count++] = image; 329 image->flags |= RFLAG_VISITED; 330 331 elf_sym* candidateSymbol = NULL; 332 image_t* candidateImage = NULL; 333 334 while (index < count) { 335 // pop next image 336 image = queue[index++]; 337 338 elf_sym* symbol = find_symbol(image, lookupInfo); 339 if (symbol != NULL) { 340 bool isWeak = symbol->Bind() == STB_WEAK; 341 if (candidateImage == NULL || !isWeak) { 342 candidateSymbol = symbol; 343 candidateImage = image; 344 345 if (!isWeak) 346 break; 347 } 348 } 349 350 // push needed images 351 for (uint32 i = 0; i < image->num_needed; i++) { 352 image_t* needed = image->needed[i]; 353 if ((needed->flags & RFLAG_VISITED) == 0) { 354 queue[count++] = needed; 355 needed->flags |= RFLAG_VISITED; 356 } 357 } 358 } 359 360 // clear visited flags 361 for (uint32 i = 0; i < count; i++) 362 queue[i]->flags &= ~RFLAG_VISITED; 363 364 if (candidateSymbol == NULL) 365 return B_ENTRY_NOT_FOUND; 366 367 // compute the symbol location 368 *_location = (void*)(candidateSymbol->st_value 369 + candidateImage->regions[0].delta); 370 int32 symbolType = lookupInfo.type; 371 patch_defined_symbol(candidateImage, lookupInfo.name, _location, 372 &symbolType); 373 374 if (_foundInImage != NULL) 375 *_foundInImage = candidateImage; 376 377 return B_OK; 378 } 379 380 381 elf_sym* 382 find_undefined_symbol_beos(image_t* rootImage, image_t* image, 383 const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 384 { 385 // BeOS style symbol resolution: It is sufficient to check the image itself 386 // and its direct dependencies. The linker would have complained, if the 387 // symbol wasn't there. First we check whether the requesting symbol is 388 // defined already -- then we can simply return it, since, due to symbolic 389 // linking, that's the one we'd find anyway. 390 if (elf_sym* symbol = lookupInfo.requestingSymbol) { 391 if (symbol->st_shndx != SHN_UNDEF 392 && ((symbol->Bind() == STB_GLOBAL) 393 || (symbol->Bind() == STB_WEAK))) { 394 *foundInImage = image; 395 return symbol; 396 } 397 } 398 399 // lookup in image 400 elf_sym* symbol = find_symbol(image, lookupInfo); 401 if (symbol != NULL) { 402 *foundInImage = image; 403 return symbol; 404 } 405 406 // lookup in dependencies 407 for (uint32 i = 0; i < image->num_needed; i++) { 408 if (image->needed[i]->dynamic_ptr) { 409 symbol = find_symbol(image->needed[i], lookupInfo); 410 if (symbol != NULL) { 411 *foundInImage = image->needed[i]; 412 return symbol; 413 } 414 } 415 } 416 417 return NULL; 418 } 419 420 421 elf_sym* 422 find_undefined_symbol_global(image_t* rootImage, image_t* image, 423 const SymbolLookupInfo& lookupInfo, image_t** _foundInImage) 424 { 425 // Global load order symbol resolution: All loaded images are searched for 426 // the symbol in the order they have been loaded. We skip add-on images and 427 // RTLD_LOCAL images though. 428 image_t* candidateImage = NULL; 429 elf_sym* candidateSymbol = NULL; 430 431 // If the requesting image is linked symbolically, look up the symbol there 432 // first. 433 bool symbolic = (image->flags & RFLAG_SYMBOLIC) != 0; 434 if (symbolic) { 435 candidateSymbol = find_symbol(image, lookupInfo); 436 if (candidateSymbol != NULL) { 437 if (candidateSymbol->Bind() != STB_WEAK) { 438 *_foundInImage = image; 439 return candidateSymbol; 440 } 441 442 candidateImage = image; 443 } 444 } 445 446 image_t* otherImage = get_loaded_images().head; 447 while (otherImage != NULL) { 448 if (otherImage == rootImage 449 ? !symbolic 450 : (otherImage->type != B_ADD_ON_IMAGE 451 && (otherImage->flags 452 & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) { 453 if (elf_sym* symbol = find_symbol(otherImage, lookupInfo)) { 454 *_foundInImage = otherImage; 455 return symbol; 456 } 457 } 458 otherImage = otherImage->next; 459 } 460 461 if (candidateSymbol != NULL) 462 *_foundInImage = candidateImage; 463 464 return candidateSymbol; 465 } 466 467 468 elf_sym* 469 find_undefined_symbol_add_on(image_t* rootImage, image_t* image, 470 const SymbolLookupInfo& lookupInfo, image_t** _foundInImage) 471 { 472 // Similar to global load order symbol resolution: All loaded images are 473 // searched for the symbol in the order they have been loaded. We skip 474 // add-on images and RTLD_LOCAL images though. The root image (i.e. the 475 // add-on image) is skipped, too, but for the add-on itself we look up 476 // a symbol that hasn't been found anywhere else in the add-on image. 477 // The reason for skipping the add-on image is that we must not resolve 478 // library symbol references to symbol definitions in the add-on, as 479 // libraries can be shared between different add-ons and we must not 480 // introduce connections between add-ons. 481 482 // For the add-on image itself resolve non-weak symbols defined in the 483 // add-on to themselves. This makes the symbol resolution order inconsistent 484 // for those symbols, but avoids clashes of global symbols defined in the 485 // add-on with symbols defined e.g. in the application. There's really the 486 // same problem for weak symbols, but we don't have any way to discriminate 487 // weak symbols that must be resolved globally from those that should be 488 // resolved within the add-on. 489 if (rootImage == image) { 490 if (elf_sym* symbol = lookupInfo.requestingSymbol) { 491 if (symbol->st_shndx != SHN_UNDEF 492 && (symbol->Bind() == STB_GLOBAL)) { 493 *_foundInImage = image; 494 return symbol; 495 } 496 } 497 } 498 499 image_t* candidateImage = NULL; 500 elf_sym* candidateSymbol = NULL; 501 502 // If the requesting image is linked symbolically, look up the symbol there 503 // first. 504 bool symbolic = (image->flags & RFLAG_SYMBOLIC) != 0; 505 if (symbolic) { 506 candidateSymbol = find_symbol(image, lookupInfo); 507 if (candidateSymbol != NULL) { 508 if (candidateSymbol->Bind() != STB_WEAK) { 509 *_foundInImage = image; 510 return candidateSymbol; 511 } 512 513 candidateImage = image; 514 } 515 } 516 517 image_t* otherImage = get_loaded_images().head; 518 while (otherImage != NULL) { 519 if (otherImage != rootImage 520 && otherImage->type != B_ADD_ON_IMAGE 521 && (otherImage->flags 522 & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0) { 523 if (elf_sym* symbol = find_symbol(otherImage, lookupInfo)) { 524 if (symbol->Bind() != STB_WEAK) { 525 *_foundInImage = otherImage; 526 return symbol; 527 } 528 529 if (candidateSymbol == NULL) { 530 candidateSymbol = symbol; 531 candidateImage = otherImage; 532 } 533 } 534 } 535 otherImage = otherImage->next; 536 } 537 538 // If the symbol has not been found and we're trying to resolve a reference 539 // in the add-on image, we also try to look it up there. 540 if (!symbolic && candidateSymbol == NULL && image == rootImage) { 541 candidateSymbol = find_symbol(image, lookupInfo); 542 candidateImage = image; 543 } 544 545 if (candidateSymbol != NULL) 546 *_foundInImage = candidateImage; 547 548 return candidateSymbol; 549 } 550 551 552 int 553 resolve_symbol(image_t* rootImage, image_t* image, elf_sym* sym, 554 SymbolLookupCache* cache, addr_t* symAddress, image_t** symbolImage) 555 { 556 uint32 index = sym - image->syms; 557 558 // check the cache first 559 if (cache->IsSymbolValueCached(index)) { 560 *symAddress = cache->SymbolValueAt(index, symbolImage); 561 return B_OK; 562 } 563 564 elf_sym* sharedSym; 565 image_t* sharedImage; 566 const char* symName = SYMNAME(image, sym); 567 568 // get the symbol type 569 int32 type = B_SYMBOL_TYPE_ANY; 570 if (sym->Type() == STT_FUNC) 571 type = B_SYMBOL_TYPE_TEXT; 572 573 if (sym->Bind() == STB_LOCAL) { 574 // Local symbols references are always resolved to the given symbol. 575 sharedImage = image; 576 sharedSym = sym; 577 } else { 578 // get the version info 579 const elf_version_info* versionInfo = NULL; 580 if (image->symbol_versions != NULL) { 581 uint32 versionIndex = VER_NDX(image->symbol_versions[index]); 582 if (versionIndex >= VER_NDX_INITIAL) 583 versionInfo = image->versions + versionIndex; 584 } 585 586 // search the symbol 587 sharedSym = rootImage->find_undefined_symbol(rootImage, image, 588 SymbolLookupInfo(symName, type, versionInfo, 0, sym), &sharedImage); 589 } 590 591 enum { 592 SUCCESS, 593 ERROR_NO_SYMBOL, 594 ERROR_WRONG_TYPE, 595 ERROR_NOT_EXPORTED, 596 ERROR_UNPATCHED 597 }; 598 uint32 lookupError = ERROR_UNPATCHED; 599 600 bool tlsSymbol = sym->Type() == STT_TLS; 601 void* location = NULL; 602 if (sharedSym == NULL) { 603 // symbol not found at all 604 if (sym->Bind() == STB_WEAK) { 605 // weak symbol: treat as NULL 606 location = sharedImage = NULL; 607 } else { 608 lookupError = ERROR_NO_SYMBOL; 609 sharedImage = NULL; 610 } 611 } else if (sym->Type() != STT_NOTYPE 612 && sym->Type() != sharedSym->Type() 613 && (sym->Type() != STT_OBJECT || sharedSym->Type() != STT_FUNC)) { 614 // symbol not of the requested type, except object which can match function 615 lookupError = ERROR_WRONG_TYPE; 616 sharedImage = NULL; 617 } else if (sharedSym->Bind() != STB_GLOBAL 618 && sharedSym->Bind() != STB_WEAK) { 619 // symbol not exported 620 lookupError = ERROR_NOT_EXPORTED; 621 sharedImage = NULL; 622 } else { 623 // symbol is fine, get its location 624 location = (void*)sharedSym->st_value; 625 if (!tlsSymbol) { 626 location 627 = (void*)((addr_t)location + sharedImage->regions[0].delta); 628 } else 629 lookupError = SUCCESS; 630 } 631 632 if (!tlsSymbol) { 633 patch_undefined_symbol(rootImage, image, symName, &sharedImage, 634 &location, &type); 635 } 636 637 if (type == 0 || (location == NULL && sym->Bind() != STB_WEAK && lookupError != SUCCESS)) { 638 switch (lookupError) { 639 case ERROR_NO_SYMBOL: 640 FATAL("%s: Could not resolve symbol '%s'\n", 641 image->path, symName); 642 break; 643 case ERROR_WRONG_TYPE: 644 FATAL("%s: Found symbol '%s' in shared image but wrong " 645 "type\n", image->path, symName); 646 break; 647 case ERROR_NOT_EXPORTED: 648 FATAL("%s: Found symbol '%s', but not exported\n", 649 image->path, symName); 650 break; 651 case ERROR_UNPATCHED: 652 FATAL("%s: Found symbol '%s', but was hidden by symbol " 653 "patchers\n", image->path, symName); 654 break; 655 } 656 657 if (report_errors()) 658 gErrorMessage.AddString("missing symbol", symName); 659 660 return B_MISSING_SYMBOL; 661 } 662 663 cache->SetSymbolValueAt(index, (addr_t)location, sharedImage); 664 665 if (symbolImage) 666 *symbolImage = sharedImage; 667 *symAddress = (addr_t)location; 668 return B_OK; 669 } 670