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