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)) { 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 if (symbol->Bind() != STB_WEAK) { 381 *_foundInImage = otherImage; 382 return symbol; 383 } 384 385 if (candidateSymbol == NULL) { 386 candidateSymbol = symbol; 387 candidateImage = otherImage; 388 } 389 } 390 } 391 otherImage = otherImage->next; 392 } 393 394 if (candidateSymbol != NULL) 395 *_foundInImage = candidateImage; 396 397 return candidateSymbol; 398 } 399 400 401 elf_sym* 402 find_undefined_symbol_add_on(image_t* rootImage, image_t* image, 403 const SymbolLookupInfo& lookupInfo, image_t** _foundInImage) 404 { 405 // Similar to global load order symbol resolution: All loaded images are 406 // searched for the symbol in the order they have been loaded. We skip 407 // add-on images and RTLD_LOCAL images though. The root image (i.e. the 408 // add-on image) is skipped, too, but for the add-on itself we look up 409 // a symbol that hasn't been found anywhere else in the add-on image. 410 // The reason for skipping the add-on image is that we must not resolve 411 // library symbol references to symbol definitions in the add-on, as 412 // libraries can be shared between different add-ons and we must not 413 // introduce connections between add-ons. 414 415 // For the add-on image itself resolve non-weak symbols defined in the 416 // add-on to themselves. This makes the symbol resolution order inconsistent 417 // for those symbols, but avoids clashes of global symbols defined in the 418 // add-on with symbols defined e.g. in the application. There's really the 419 // same problem for weak symbols, but we don't have any way to discriminate 420 // weak symbols that must be resolved globally from those that should be 421 // resolved within the add-on. 422 if (rootImage == image) { 423 if (elf_sym* symbol = lookupInfo.requestingSymbol) { 424 if (symbol->st_shndx != SHN_UNDEF 425 && (symbol->Bind() == STB_GLOBAL)) { 426 *_foundInImage = image; 427 return symbol; 428 } 429 } 430 } 431 432 image_t* candidateImage = NULL; 433 elf_sym* candidateSymbol = NULL; 434 435 // If the requesting image is linked symbolically, look up the symbol there 436 // first. 437 bool symbolic = (image->flags & RFLAG_SYMBOLIC) != 0; 438 if (symbolic) { 439 candidateSymbol = find_symbol(image, lookupInfo); 440 if (candidateSymbol != NULL) { 441 if (candidateSymbol->Bind() != STB_WEAK) { 442 *_foundInImage = image; 443 return candidateSymbol; 444 } 445 446 candidateImage = image; 447 } 448 } 449 450 image_t* otherImage = get_loaded_images().head; 451 while (otherImage != NULL) { 452 if (otherImage != rootImage 453 && otherImage->type != B_ADD_ON_IMAGE 454 && (otherImage->flags 455 & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0) { 456 if (elf_sym* symbol = find_symbol(otherImage, lookupInfo)) { 457 if (symbol->Bind() != STB_WEAK) { 458 *_foundInImage = otherImage; 459 return symbol; 460 } 461 462 if (candidateSymbol == NULL) { 463 candidateSymbol = symbol; 464 candidateImage = otherImage; 465 } 466 } 467 } 468 otherImage = otherImage->next; 469 } 470 471 // If the symbol has not been found and we're trying to resolve a reference 472 // in the add-on image, we also try to look it up there. 473 if (!symbolic && candidateSymbol == NULL && image == rootImage) { 474 candidateSymbol = find_symbol(image, lookupInfo); 475 candidateImage = image; 476 } 477 478 if (candidateSymbol != NULL) 479 *_foundInImage = candidateImage; 480 481 return candidateSymbol; 482 } 483 484 485 int 486 resolve_symbol(image_t* rootImage, image_t* image, elf_sym* sym, 487 SymbolLookupCache* cache, addr_t* symAddress, image_t** symbolImage) 488 { 489 uint32 index = sym - image->syms; 490 491 // check the cache first 492 if (cache->IsSymbolValueCached(index)) { 493 *symAddress = cache->SymbolValueAt(index, symbolImage); 494 return B_OK; 495 } 496 497 elf_sym* sharedSym; 498 image_t* sharedImage; 499 const char* symName = SYMNAME(image, sym); 500 501 // get the symbol type 502 int32 type = B_SYMBOL_TYPE_ANY; 503 if (sym->Type() == STT_FUNC) 504 type = B_SYMBOL_TYPE_TEXT; 505 else if (sym->Type() == STT_OBJECT) 506 type = B_SYMBOL_TYPE_DATA; 507 508 if (sym->Bind() == STB_LOCAL) { 509 // Local symbols references are always resolved to the given symbol. 510 sharedImage = image; 511 sharedSym = sym; 512 } else { 513 // get the version info 514 const elf_version_info* versionInfo = NULL; 515 if (image->symbol_versions != NULL) { 516 uint32 versionIndex = VER_NDX(image->symbol_versions[index]); 517 if (versionIndex >= VER_NDX_INITIAL) 518 versionInfo = image->versions + versionIndex; 519 } 520 521 // search the symbol 522 sharedSym = rootImage->find_undefined_symbol(rootImage, image, 523 SymbolLookupInfo(symName, type, versionInfo, 0, sym), &sharedImage); 524 } 525 526 enum { 527 SUCCESS, 528 ERROR_NO_SYMBOL, 529 ERROR_WRONG_TYPE, 530 ERROR_NOT_EXPORTED, 531 ERROR_UNPATCHED 532 }; 533 uint32 lookupError = ERROR_UNPATCHED; 534 535 bool tlsSymbol = sym->Type() == STT_TLS; 536 void* location = NULL; 537 if (sharedSym == NULL) { 538 // symbol not found at all 539 lookupError = ERROR_NO_SYMBOL; 540 sharedImage = NULL; 541 } else if (sym->Type() != STT_NOTYPE 542 && sym->Type() != sharedSym->Type()) { 543 // symbol not of the requested type 544 lookupError = ERROR_WRONG_TYPE; 545 sharedImage = NULL; 546 } else if (sharedSym->Bind() != STB_GLOBAL 547 && sharedSym->Bind() != STB_WEAK) { 548 // symbol not exported 549 lookupError = ERROR_NOT_EXPORTED; 550 sharedImage = NULL; 551 } else { 552 // symbol is fine, get its location 553 location = (void*)sharedSym->st_value; 554 if (!tlsSymbol) { 555 location 556 = (void*)((addr_t)location + sharedImage->regions[0].delta); 557 } else 558 lookupError = SUCCESS; 559 } 560 561 if (!tlsSymbol) { 562 patch_undefined_symbol(rootImage, image, symName, &sharedImage, 563 &location, &type); 564 } 565 566 if (location == NULL && lookupError != SUCCESS) { 567 switch (lookupError) { 568 case ERROR_NO_SYMBOL: 569 FATAL("%s: Could not resolve symbol '%s'\n", 570 image->path, symName); 571 break; 572 case ERROR_WRONG_TYPE: 573 FATAL("%s: Found symbol '%s' in shared image but wrong " 574 "type\n", image->path, symName); 575 break; 576 case ERROR_NOT_EXPORTED: 577 FATAL("%s: Found symbol '%s', but not exported\n", 578 image->path, symName); 579 break; 580 case ERROR_UNPATCHED: 581 FATAL("%s: Found symbol '%s', but was hidden by symbol " 582 "patchers\n", image->path, symName); 583 break; 584 } 585 586 if (report_errors()) 587 gErrorMessage.AddString("missing symbol", symName); 588 589 return B_MISSING_SYMBOL; 590 } 591 592 cache->SetSymbolValueAt(index, (addr_t)location, sharedImage); 593 594 if (symbolImage) 595 *symbolImage = sharedImage; 596 *symAddress = (addr_t)location; 597 return B_OK; 598 } 599