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