1 /* 2 * Copyright 2008-2009, 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 static bool 24 equals_image_name(image_t* image, const char* name) 25 { 26 const char* lastSlash = strrchr(name, '/'); 27 return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0; 28 } 29 30 31 // #pragma mark - 32 33 34 uint32 35 elf_hash(const char* _name) 36 { 37 const uint8* name = (const uint8*)_name; 38 39 uint32 hash = 0; 40 uint32 temp; 41 42 while (*name) { 43 hash = (hash << 4) + *name++; 44 if ((temp = hash & 0xf0000000)) { 45 hash ^= temp >> 24; 46 } 47 hash &= ~temp; 48 } 49 return hash; 50 } 51 52 53 void 54 patch_defined_symbol(image_t* image, const char* name, void** symbol, 55 int32* type) 56 { 57 RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers; 58 while (patcher != NULL && *symbol != 0) { 59 image_t* inImage = image; 60 patcher->patcher(patcher->cookie, NULL, image, name, &inImage, 61 symbol, type); 62 patcher = patcher->next; 63 } 64 } 65 66 67 void 68 patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name, 69 image_t** foundInImage, void** symbol, int32* type) 70 { 71 if (*foundInImage != NULL) 72 patch_defined_symbol(*foundInImage, name, symbol, type); 73 74 RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers; 75 while (patcher != NULL) { 76 patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage, 77 symbol, type); 78 patcher = patcher->next; 79 } 80 } 81 82 83 Elf32_Sym* 84 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo) 85 { 86 if (image->dynamic_ptr == 0) 87 return NULL; 88 89 Elf32_Sym* versionedSymbol = NULL; 90 uint32 versionedSymbolCount = 0; 91 92 uint32 bucket = lookupInfo.hash % HASHTABSIZE(image); 93 94 for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF; 95 i = HASHCHAINS(image)[i]) { 96 Elf32_Sym* symbol = &image->syms[i]; 97 98 if (symbol->st_shndx != SHN_UNDEF 99 && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) 100 || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) 101 && !strcmp(SYMNAME(image, symbol), lookupInfo.name)) { 102 103 // check if the type matches 104 uint32 type = ELF32_ST_TYPE(symbol->st_info); 105 if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC) 106 || (lookupInfo.type == B_SYMBOL_TYPE_DATA 107 && type != STT_OBJECT)) { 108 continue; 109 } 110 111 // check the version 112 113 // Handle the simple cases -- the image doesn't have version 114 // information -- first. 115 if (image->symbol_versions == NULL) { 116 if (lookupInfo.version == NULL) { 117 // No specific symbol version was requested either, so the 118 // symbol is just fine. 119 return symbol; 120 } 121 122 // A specific version is requested. If it's the dependency 123 // referred to by the requested version, it's apparently an 124 // older version of the dependency and we're not happy. 125 if (equals_image_name(image, lookupInfo.version->file_name)) { 126 // TODO: That should actually be kind of fatal! 127 return NULL; 128 } 129 130 // This is some other image. We accept the symbol. 131 return symbol; 132 } 133 134 // The image has version information. Let's see what we've got. 135 uint32 versionID = image->symbol_versions[i]; 136 uint32 versionIndex = VER_NDX(versionID); 137 elf_version_info& version = image->versions[versionIndex]; 138 139 // skip local versions 140 if (versionIndex == VER_NDX_LOCAL) 141 continue; 142 143 if (lookupInfo.version != NULL) { 144 // a specific version is requested 145 146 // compare the versions 147 if (version.hash == lookupInfo.version->hash 148 && strcmp(version.name, lookupInfo.version->name) == 0) { 149 // versions match 150 return symbol; 151 } 152 153 // The versions don't match. We're still fine with the 154 // base version, if it is public and we're not looking for 155 // the default version. 156 if ((versionID & VER_NDX_FLAG_HIDDEN) == 0 157 && versionIndex == VER_NDX_GLOBAL 158 && (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) 159 == 0) { 160 // TODO: Revise the default version case! That's how 161 // FreeBSD implements it, but glibc doesn't handle it 162 // specially. 163 return symbol; 164 } 165 } else { 166 // No specific version requested, but the image has version 167 // information. This can happen in either of these cases: 168 // 169 // * The dependent object was linked against an older version 170 // of the now versioned dependency. 171 // * The symbol is looked up via find_image_symbol() or dlsym(). 172 // 173 // In the first case we return the base version of the symbol 174 // (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't 175 // exist, the unique, non-hidden versioned symbol. 176 // 177 // In the second case we want to return the public default 178 // version of the symbol. The handling is pretty similar to the 179 // first case, with the exception that we treat VER_NDX_INITIAL 180 // as regular version. 181 182 // VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if 183 // we don't look for the default version. 184 if (versionIndex == VER_NDX_GLOBAL 185 || ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0 186 && versionIndex == VER_NDX_INITIAL)) { 187 return symbol; 188 } 189 190 // If not hidden, remember the version -- we'll return it, if 191 // it is the only one. 192 if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) { 193 versionedSymbolCount++; 194 versionedSymbol = symbol; 195 } 196 } 197 } 198 } 199 200 return versionedSymbolCount == 1 ? versionedSymbol : NULL; 201 } 202 203 204 status_t 205 find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo, 206 void **_location) 207 { 208 // get the symbol in the image 209 Elf32_Sym* symbol = find_symbol(image, lookupInfo); 210 if (symbol == NULL) 211 return B_ENTRY_NOT_FOUND; 212 213 void* location = (void*)(symbol->st_value + image->regions[0].delta); 214 int32 symbolType = lookupInfo.type; 215 patch_defined_symbol(image, lookupInfo.name, &location, &symbolType); 216 217 if (_location != NULL) 218 *_location = location; 219 220 return B_OK; 221 } 222 223 224 status_t 225 find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo, 226 image_t** _foundInImage, void** _location) 227 { 228 image_t* queue[count_loaded_images()]; 229 uint32 count = 0; 230 uint32 index = 0; 231 queue[count++] = image; 232 image->flags |= RFLAG_VISITED; 233 234 bool found = false; 235 while (index < count) { 236 // pop next image 237 image = queue[index++]; 238 239 if (find_symbol(image, lookupInfo, _location) == B_OK) { 240 if (_foundInImage != NULL) 241 *_foundInImage = image; 242 found = true; 243 break; 244 } 245 246 // push needed images 247 for (uint32 i = 0; i < image->num_needed; i++) { 248 image_t* needed = image->needed[i]; 249 if ((needed->flags & RFLAG_VISITED) == 0) { 250 queue[count++] = needed; 251 needed->flags |= RFLAG_VISITED; 252 } 253 } 254 } 255 256 // clear visited flags 257 for (uint32 i = 0; i < count; i++) 258 queue[i]->flags &= ~RFLAG_VISITED; 259 260 return found ? B_OK : B_ENTRY_NOT_FOUND; 261 } 262 263 264 Elf32_Sym* 265 find_undefined_symbol_beos(image_t* rootImage, image_t* image, 266 const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 267 { 268 // BeOS style symbol resolution: It is sufficient to check the direct 269 // dependencies. The linker would have complained, if the symbol wasn't 270 // there. 271 for (uint32 i = 0; i < image->num_needed; i++) { 272 if (image->needed[i]->dynamic_ptr) { 273 Elf32_Sym *symbol = find_symbol(image->needed[i], 274 lookupInfo); 275 if (symbol) { 276 *foundInImage = image->needed[i]; 277 return symbol; 278 } 279 } 280 } 281 282 return NULL; 283 } 284 285 286 Elf32_Sym* 287 find_undefined_symbol_global(image_t* rootImage, image_t* image, 288 const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 289 { 290 // Global load order symbol resolution: All loaded images are searched for 291 // the symbol in the order they have been loaded. We skip add-on images and 292 // RTLD_LOCAL images though. 293 image_t* otherImage = get_loaded_images().head; 294 while (otherImage != NULL) { 295 if (otherImage == rootImage 296 || (otherImage->type != B_ADD_ON_IMAGE 297 && (otherImage->flags 298 & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) { 299 Elf32_Sym *symbol = find_symbol(otherImage, lookupInfo); 300 if (symbol) { 301 *foundInImage = otherImage; 302 return symbol; 303 } 304 } 305 otherImage = otherImage->next; 306 } 307 308 return NULL; 309 } 310 311 312 Elf32_Sym* 313 find_undefined_symbol_add_on(image_t* rootImage, image_t* image, 314 const SymbolLookupInfo& lookupInfo, image_t** foundInImage) 315 { 316 // Do a breadth-first resolution in the add-on dependency scope, 317 // skipping the add-on itself. 318 Elf32_Sym* foundSymbol = NULL; 319 320 image_t* queue[count_loaded_images()]; 321 uint32 count = 0; 322 uint32 index = 0; 323 queue[count++] = image; 324 image->flags |= RFLAG_VISITED; 325 326 image_t* currentImage; 327 while (index < count) { 328 // pop next image 329 currentImage = queue[index++]; 330 331 if (currentImage != image) { 332 foundSymbol = find_symbol(currentImage, lookupInfo); 333 if (foundSymbol != NULL) { 334 if (foundInImage != NULL) 335 *foundInImage = currentImage; 336 break; 337 } 338 } 339 340 // push needed images 341 for (uint32 i = 0; i < currentImage->num_needed; i++) { 342 image_t* needed = currentImage->needed[i]; 343 if ((needed->flags & RFLAG_VISITED) == 0) { 344 queue[count++] = needed; 345 needed->flags |= RFLAG_VISITED; 346 } 347 } 348 } 349 350 // clear visited flags 351 for (uint32 i = 0; i < count; i++) 352 queue[i]->flags &= ~RFLAG_VISITED; 353 354 return foundSymbol; 355 } 356 357 358 int 359 resolve_symbol(image_t* rootImage, image_t* image, struct Elf32_Sym* sym, 360 addr_t* symAddress) 361 { 362 switch (sym->st_shndx) { 363 case SHN_UNDEF: 364 { 365 struct Elf32_Sym* sharedSym; 366 image_t* sharedImage; 367 const char* symName = SYMNAME(image, sym); 368 369 // get the version info 370 const elf_version_info* versionInfo = NULL; 371 if (image->symbol_versions != NULL) { 372 uint32 index = sym - image->syms; 373 uint32 versionIndex = VER_NDX(image->symbol_versions[index]); 374 if (versionIndex >= VER_NDX_INITIAL) 375 versionInfo = image->versions + versionIndex; 376 } 377 378 int32 type = B_SYMBOL_TYPE_ANY; 379 if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC) 380 type = B_SYMBOL_TYPE_TEXT; 381 else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT) 382 type = B_SYMBOL_TYPE_DATA; 383 384 // it's undefined, must be outside this image, try the other images 385 sharedSym = rootImage->find_undefined_symbol(rootImage, image, 386 SymbolLookupInfo(symName, type, versionInfo), &sharedImage); 387 void* location = NULL; 388 389 enum { 390 ERROR_NO_SYMBOL, 391 ERROR_WRONG_TYPE, 392 ERROR_NOT_EXPORTED, 393 ERROR_UNPATCHED 394 }; 395 uint32 lookupError = ERROR_UNPATCHED; 396 397 if (sharedSym == NULL) { 398 // symbol not found at all 399 lookupError = ERROR_NO_SYMBOL; 400 sharedImage = NULL; 401 } else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE 402 && ELF32_ST_TYPE(sym->st_info) 403 != ELF32_ST_TYPE(sharedSym->st_info)) { 404 // symbol not of the requested type 405 lookupError = ERROR_WRONG_TYPE; 406 sharedImage = NULL; 407 } else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL 408 && ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) { 409 // symbol not exported 410 lookupError = ERROR_NOT_EXPORTED; 411 sharedImage = NULL; 412 } else { 413 // symbol is fine, get its location 414 location = (void*)(sharedSym->st_value 415 + sharedImage->regions[0].delta); 416 } 417 418 patch_undefined_symbol(rootImage, image, symName, &sharedImage, 419 &location, &type); 420 421 if (location == NULL) { 422 switch (lookupError) { 423 case ERROR_NO_SYMBOL: 424 FATAL("%s: Could not resolve symbol '%s'\n", 425 image->path, symName); 426 break; 427 case ERROR_WRONG_TYPE: 428 FATAL("%s: Found symbol '%s' in shared image but wrong " 429 "type\n", image->path, symName); 430 break; 431 case ERROR_NOT_EXPORTED: 432 FATAL("%s: Found symbol '%s', but not exported\n", 433 image->path, symName); 434 break; 435 case ERROR_UNPATCHED: 436 FATAL("%s: Found symbol '%s', but was hidden by symbol " 437 "patchers\n", image->path, symName); 438 break; 439 } 440 441 if (report_errors()) 442 gErrorMessage.AddString("missing symbol", symName); 443 444 return B_MISSING_SYMBOL; 445 } 446 447 *symAddress = (addr_t)location; 448 return B_OK; 449 } 450 451 case SHN_ABS: 452 *symAddress = sym->st_value + image->regions[0].delta; 453 return B_NO_ERROR; 454 455 case SHN_COMMON: 456 // TODO: finish this 457 FATAL("%s: elf_resolve_symbol: COMMON symbol, finish me!\n", 458 image->path); 459 return B_ERROR; //ERR_NOT_IMPLEMENTED_YET; 460 461 default: 462 // standard symbol 463 *symAddress = sym->st_value + image->regions[0].delta; 464 return B_NO_ERROR; 465 } 466 } 467