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