1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#define __STDC_LIMIT_MACROS 26#include <stdint.h> 27#include <stdlib.h> 28#include <errno.h> 29#include <fcntl.h> 30#include <mach/mach.h> 31#include <mach-o/fat.h> 32#include <sys/types.h> 33#include <sys/stat.h> 34#include <sys/mman.h> 35#include <sys/param.h> 36#include <sys/mount.h> 37#include <libkern/OSAtomic.h> 38 39#include "ImageLoader.h" 40 41 42uint32_t ImageLoader::fgImagesUsedFromSharedCache = 0; 43uint32_t ImageLoader::fgImagesWithUsedPrebinding = 0; 44uint32_t ImageLoader::fgImagesRequiringCoalescing = 0; 45uint32_t ImageLoader::fgImagesHasWeakDefinitions = 0; 46uint32_t ImageLoader::fgTotalRebaseFixups = 0; 47uint32_t ImageLoader::fgTotalBindFixups = 0; 48uint32_t ImageLoader::fgTotalBindSymbolsResolved = 0; 49uint32_t ImageLoader::fgTotalBindImageSearches = 0; 50uint32_t ImageLoader::fgTotalLazyBindFixups = 0; 51uint32_t ImageLoader::fgTotalPossibleLazyBindFixups = 0; 52uint32_t ImageLoader::fgTotalSegmentsMapped = 0; 53uint64_t ImageLoader::fgTotalBytesMapped = 0; 54uint64_t ImageLoader::fgTotalBytesPreFetched = 0; 55uint64_t ImageLoader::fgTotalLoadLibrariesTime; 56uint64_t ImageLoader::fgTotalRebaseTime; 57uint64_t ImageLoader::fgTotalBindTime; 58uint64_t ImageLoader::fgTotalWeakBindTime; 59uint64_t ImageLoader::fgTotalDOF; 60uint64_t ImageLoader::fgTotalInitTime; 61uint16_t ImageLoader::fgLoadOrdinal = 0; 62std::vector<ImageLoader::InterposeTuple>ImageLoader::fgInterposingTuples; 63uintptr_t ImageLoader::fgNextPIEDylibAddress = 0; 64 65 66 67ImageLoader::ImageLoader(const char* path, unsigned int libCount) 68 : fPath(path), fRealPath(NULL), fDevice(0), fInode(0), fLastModified(0), 69 fPathHash(0), fDlopenReferenceCount(0), fInitializerRecursiveLock(NULL), 70 fDepth(0), fLoadOrder(fgLoadOrdinal++), fState(0), fLibraryCount(libCount), 71 fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false), 72 fHideSymbols(false), fMatchByInstallName(false), 73 fInterposed(false), fRegisteredDOF(false), fAllLazyPointersBound(false), 74 fBeingRemoved(false), fAddFuncNotified(false), 75 fPathOwnedByImage(false), fIsReferencedDownward(false), 76 fWeakSymbolsBound(false) 77{ 78 if ( fPath != NULL ) 79 fPathHash = hash(fPath); 80 if ( libCount > 512 ) 81 dyld::throwf("too many dependent dylibs in %s", path); 82} 83 84 85void ImageLoader::deleteImage(ImageLoader* image) 86{ 87 delete image; 88} 89 90 91ImageLoader::~ImageLoader() 92{ 93 if ( fRealPath != NULL ) 94 delete [] fRealPath; 95 if ( fPathOwnedByImage && (fPath != NULL) ) 96 delete [] fPath; 97} 98 99void ImageLoader::setFileInfo(dev_t device, ino_t inode, time_t modDate) 100{ 101 fDevice = device; 102 fInode = inode; 103 fLastModified = modDate; 104} 105 106void ImageLoader::setMapped(const LinkContext& context) 107{ 108 fState = dyld_image_state_mapped; 109 context.notifySingle(dyld_image_state_mapped, this); // note: can throw exception 110} 111 112int ImageLoader::compare(const ImageLoader* right) const 113{ 114 if ( this->fDepth == right->fDepth ) { 115 if ( this->fLoadOrder == right->fLoadOrder ) 116 return 0; 117 else if ( this->fLoadOrder < right->fLoadOrder ) 118 return -1; 119 else 120 return 1; 121 } 122 else { 123 if ( this->fDepth < right->fDepth ) 124 return -1; 125 else 126 return 1; 127 } 128} 129 130void ImageLoader::setPath(const char* path) 131{ 132 if ( fPathOwnedByImage && (fPath != NULL) ) 133 delete [] fPath; 134 fPath = new char[strlen(path)+1]; 135 strcpy((char*)fPath, path); 136 fPathOwnedByImage = true; // delete fPath when this image is destructed 137 fPathHash = hash(fPath); 138 fRealPath = NULL; 139} 140 141void ImageLoader::setPathUnowned(const char* path) 142{ 143 if ( fPathOwnedByImage && (fPath != NULL) ) { 144 delete [] fPath; 145 } 146 fPath = path; 147 fPathOwnedByImage = false; 148 fPathHash = hash(fPath); 149} 150 151void ImageLoader::setPaths(const char* path, const char* realPath) 152{ 153 this->setPath(path); 154 fRealPath = new char[strlen(realPath)+1]; 155 strcpy((char*)fRealPath, realPath); 156} 157 158const char* ImageLoader::getRealPath() const 159{ 160 if ( fRealPath != NULL ) 161 return fRealPath; 162 else 163 return fPath; 164} 165 166 167uint32_t ImageLoader::hash(const char* path) 168{ 169 // this does not need to be a great hash 170 // it is just used to reduce the number of strcmp() calls 171 // of existing images when loading a new image 172 uint32_t h = 0; 173 for (const char* s=path; *s != '\0'; ++s) 174 h = h*5 + *s; 175 return h; 176} 177 178bool ImageLoader::matchInstallPath() const 179{ 180 return fMatchByInstallName; 181} 182 183void ImageLoader::setMatchInstallPath(bool match) 184{ 185 fMatchByInstallName = match; 186} 187 188bool ImageLoader::statMatch(const struct stat& stat_buf) const 189{ 190 return ( (this->fDevice == stat_buf.st_dev) && (this->fInode == stat_buf.st_ino) ); 191} 192 193const char* ImageLoader::getShortName() const 194{ 195 // try to return leaf name 196 if ( fPath != NULL ) { 197 const char* s = strrchr(fPath, '/'); 198 if ( s != NULL ) 199 return &s[1]; 200 } 201 return fPath; 202} 203 204void ImageLoader::setLeaveMapped() 205{ 206 fLeaveMapped = true; 207} 208 209void ImageLoader::setHideExports(bool hide) 210{ 211 fHideSymbols = hide; 212} 213 214bool ImageLoader::hasHiddenExports() const 215{ 216 return fHideSymbols; 217} 218 219bool ImageLoader::isLinked() const 220{ 221 return (fState >= dyld_image_state_bound); 222} 223 224time_t ImageLoader::lastModified() const 225{ 226 return fLastModified; 227} 228 229bool ImageLoader::containsAddress(const void* addr) const 230{ 231 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 232 const uint8_t* start = (const uint8_t*)segActualLoadAddress(i); 233 const uint8_t* end = (const uint8_t*)segActualEndAddress(i); 234 if ( (start <= addr) && (addr < end) && !segUnaccessible(i) ) 235 return true; 236 } 237 return false; 238} 239 240bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) const 241{ 242 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 243 const uint8_t* segStart = (const uint8_t*)segActualLoadAddress(i); 244 const uint8_t* segEnd = (const uint8_t*)segActualEndAddress(i); 245 if ( strcmp(segName(i), "__UNIXSTACK") == 0 ) { 246 // __UNIXSTACK never slides. This is the only place that cares 247 // and checking for that segment name in segActualLoadAddress() 248 // is too expensive. 249 segStart -= getSlide(); 250 segEnd -= getSlide(); 251 } 252 if ( (start <= segStart) && (segStart < end) ) 253 return true; 254 if ( (start <= segEnd) && (segEnd < end) ) 255 return true; 256 if ( (segStart < start) && (end < segEnd) ) 257 return true; 258 } 259 return false; 260} 261 262void ImageLoader::getMappedRegions(MappedRegion*& regions) const 263{ 264 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 265 MappedRegion region; 266 region.address = segActualLoadAddress(i); 267 region.size = segSize(i); 268 *regions++ = region; 269 } 270} 271 272 273 274bool ImageLoader::dependsOn(ImageLoader* image) { 275 for(unsigned int i=0; i < libraryCount(); ++i) { 276 if ( libImage(i) == image ) 277 return true; 278 } 279 return false; 280} 281 282 283static bool notInImgageList(const ImageLoader* image, const ImageLoader** dsiStart, const ImageLoader** dsiCur) 284{ 285 for (const ImageLoader** p = dsiStart; p < dsiCur; ++p) 286 if ( *p == image ) 287 return false; 288 return true; 289} 290 291 292// private method that handles circular dependencies by only search any image once 293const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name, 294 const ImageLoader** dsiStart, const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const 295{ 296 const ImageLoader::Symbol* sym; 297 // search self 298 if ( notInImgageList(this, dsiStart, dsiCur) ) { 299 sym = this->findExportedSymbol(name, false, foundIn); 300 if ( sym != NULL ) 301 return sym; 302 *dsiCur++ = this; 303 } 304 305 // search directly dependent libraries 306 for(unsigned int i=0; i < libraryCount(); ++i) { 307 ImageLoader* dependentImage = libImage(i); 308 if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) { 309 const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, false, foundIn); 310 if ( sym != NULL ) 311 return sym; 312 } 313 } 314 315 // search indirectly dependent libraries 316 for(unsigned int i=0; i < libraryCount(); ++i) { 317 ImageLoader* dependentImage = libImage(i); 318 if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) { 319 *dsiCur++ = dependentImage; 320 const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dsiStart, dsiCur, dsiEnd, foundIn); 321 if ( sym != NULL ) 322 return sym; 323 } 324 } 325 326 return NULL; 327} 328 329 330const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const 331{ 332 unsigned int imageCount = context.imageCount(); 333 const ImageLoader* dontSearchImages[imageCount]; 334 dontSearchImages[0] = this; // don't search this image 335 const ImageLoader** cur = &dontSearchImages[1]; 336 return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn); 337} 338 339const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const 340{ 341 unsigned int imageCount = context.imageCount(); 342 const ImageLoader* dontSearchImages[imageCount]; 343 const ImageLoader** cur = &dontSearchImages[0]; 344 return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn); 345} 346 347// this is called by initializeMainExecutable() to interpose on the initial set of images 348void ImageLoader::applyInterposing(const LinkContext& context) 349{ 350 if ( fgInterposingTuples.size() != 0 ) 351 this->recursiveApplyInterposing(context); 352} 353 354void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, bool neverUnload, const RPathChain& loaderRPaths) 355{ 356 //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fDlopenReferenceCount, fNeverUnload); 357 358 // clear error strings 359 (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL); 360 361 uint64_t t0 = mach_absolute_time(); 362 this->recursiveLoadLibraries(context, preflightOnly, loaderRPaths); 363 context.notifyBatch(dyld_image_state_dependents_mapped); 364 365 // we only do the loading step for preflights 366 if ( preflightOnly ) 367 return; 368 369 uint64_t t1 = mach_absolute_time(); 370 context.clearAllDepths(); 371 this->recursiveUpdateDepth(context.imageCount()); 372 373 uint64_t t2 = mach_absolute_time(); 374 this->recursiveRebase(context); 375 context.notifyBatch(dyld_image_state_rebased); 376 377 uint64_t t3 = mach_absolute_time(); 378 this->recursiveBind(context, forceLazysBound, neverUnload); 379 380 uint64_t t4 = mach_absolute_time(); 381 if ( !context.linkingMainExecutable ) 382 this->weakBind(context); 383 uint64_t t5 = mach_absolute_time(); 384 385 context.notifyBatch(dyld_image_state_bound); 386 uint64_t t6 = mach_absolute_time(); 387 388 std::vector<DOFInfo> dofs; 389 this->recursiveGetDOFSections(context, dofs); 390 context.registerDOFs(dofs); 391 uint64_t t7 = mach_absolute_time(); 392 393 // interpose any dynamically loaded images 394 if ( !context.linkingMainExecutable && (fgInterposingTuples.size() != 0) ) { 395 this->recursiveApplyInterposing(context); 396 } 397 398 // clear error strings 399 (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL); 400 401 fgTotalLoadLibrariesTime += t1 - t0; 402 fgTotalRebaseTime += t3 - t2; 403 fgTotalBindTime += t4 - t3; 404 fgTotalWeakBindTime += t5 - t4; 405 fgTotalDOF += t7 - t6; 406 407 // done with initial dylib loads 408 fgNextPIEDylibAddress = 0; 409} 410 411 412void ImageLoader::printReferenceCounts() 413{ 414 dyld::log(" dlopen=%d for %s\n", fDlopenReferenceCount, getPath() ); 415} 416 417 418bool ImageLoader::decrementDlopenReferenceCount() 419{ 420 if ( fDlopenReferenceCount == 0 ) 421 return true; 422 --fDlopenReferenceCount; 423 return false; 424} 425 426void ImageLoader::runInitializers(const LinkContext& context, InitializerTimingList& timingInfo) 427{ 428 uint64_t t1 = mach_absolute_time(); 429 mach_port_t this_thread = mach_thread_self(); 430 this->recursiveInitialization(context, this_thread, timingInfo); 431 context.notifyBatch(dyld_image_state_initialized); 432 mach_port_deallocate(mach_task_self(), this_thread); 433 uint64_t t2 = mach_absolute_time(); 434 fgTotalInitTime += (t2 - t1); 435} 436 437 438void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive) 439{ 440 if ( ! fAllLazyPointersBound ) { 441 fAllLazyPointersBound = true; 442 443 if ( recursive ) { 444 // bind lower level libraries first 445 for(unsigned int i=0; i < libraryCount(); ++i) { 446 ImageLoader* dependentImage = libImage(i); 447 if ( dependentImage != NULL ) 448 dependentImage->bindAllLazyPointers(context, recursive); 449 } 450 } 451 // bind lazies in this image 452 this->doBindJustLazies(context); 453 } 454} 455 456 457bool ImageLoader::allDependentLibrariesAsWhenPreBound() const 458{ 459 return fAllLibraryChecksumsAndLoadAddressesMatch; 460} 461 462 463void ImageLoader::markedUsedRecursive(const std::vector<DynamicReference>& dynamicReferences) 464{ 465 // already visited here 466 if ( fMarkedInUse ) 467 return; 468 fMarkedInUse = true; 469 470 // clear mark on all statically dependent dylibs 471 for(unsigned int i=0; i < libraryCount(); ++i) { 472 ImageLoader* dependentImage = libImage(i); 473 if ( dependentImage != NULL ) { 474 dependentImage->markedUsedRecursive(dynamicReferences); 475 } 476 } 477 478 // clear mark on all dynamically dependent dylibs 479 for (std::vector<ImageLoader::DynamicReference>::const_iterator it=dynamicReferences.begin(); it != dynamicReferences.end(); ++it) { 480 if ( it->from == this ) 481 it->to->markedUsedRecursive(dynamicReferences); 482 } 483 484} 485 486unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth) 487{ 488 // the purpose of this phase is to make the images sortable such that 489 // in a sort list of images, every image that an image depends on 490 // occurs in the list before it. 491 if ( fDepth == 0 ) { 492 // break cycles 493 fDepth = maxDepth; 494 495 // get depth of dependents 496 unsigned int minDependentDepth = maxDepth; 497 for(unsigned int i=0; i < libraryCount(); ++i) { 498 ImageLoader* dependentImage = libImage(i); 499 if ( (dependentImage != NULL) && !libIsUpward(i) ) { 500 unsigned int d = dependentImage->recursiveUpdateDepth(maxDepth); 501 if ( d < minDependentDepth ) 502 minDependentDepth = d; 503 } 504 } 505 506 // make me less deep then all my dependents 507 fDepth = minDependentDepth - 1; 508 } 509 510 return fDepth; 511} 512 513 514void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths) 515{ 516 if ( fState < dyld_image_state_dependents_mapped ) { 517 // break cycles 518 fState = dyld_image_state_dependents_mapped; 519 520 // get list of libraries this image needs 521 //dyld::log("ImageLoader::recursiveLoadLibraries() %ld = %d*%ld\n", fLibrariesCount*sizeof(DependentLibrary), fLibrariesCount, sizeof(DependentLibrary)); 522 DependentLibraryInfo libraryInfos[fLibraryCount]; 523 this->doGetDependentLibraries(libraryInfos); 524 525 // get list of rpaths that this image adds 526 std::vector<const char*> rpathsFromThisImage; 527 this->getRPaths(context, rpathsFromThisImage); 528 const RPathChain thisRPaths(&loaderRPaths, &rpathsFromThisImage); 529 530 // try to load each 531 bool canUsePrelinkingInfo = true; 532 for(unsigned int i=0; i < fLibraryCount; ++i){ 533 ImageLoader* dependentLib; 534 bool depLibReExported = false; 535 bool depLibReRequired = false; 536 bool depLibCheckSumsMatch = false; 537 DependentLibraryInfo& requiredLibInfo = libraryInfos[i]; 538#if DYLD_SHARED_CACHE_SUPPORT 539 if ( preflightOnly && context.inSharedCache(requiredLibInfo.name) ) { 540 // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized 541 // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded 542 setLibImage(i, NULL, false, false); 543 continue; 544 } 545#endif 546 try { 547 dependentLib = context.loadLibrary(requiredLibInfo.name, true, this->getPath(), &thisRPaths); 548 if ( dependentLib == this ) { 549 // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168 550 dependentLib = context.loadLibrary(requiredLibInfo.name, false, NULL, NULL); 551 if ( dependentLib != this ) 552 dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath()); 553 } 554 if ( fNeverUnload ) 555 dependentLib->setNeverUnload(); 556 if ( requiredLibInfo.upward ) { 557 } 558 else { 559 dependentLib->fIsReferencedDownward = true; 560 } 561 LibraryInfo actualInfo = dependentLib->doGetLibraryInfo(); 562 depLibReRequired = requiredLibInfo.required; 563 depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum ); 564 depLibReExported = requiredLibInfo.reExported; 565 if ( ! depLibReExported ) { 566 // for pre-10.5 binaries that did not use LC_REEXPORT_DYLIB 567 depLibReExported = dependentLib->isSubframeworkOf(context, this) || this->hasSubLibrary(context, dependentLib); 568 } 569 // check found library version is compatible 570 // <rdar://problem/89200806> 0xFFFFFFFF is wildcard that matches any version 571 if ( (requiredLibInfo.info.minVersion != 0xFFFFFFFF) && (actualInfo.minVersion < requiredLibInfo.info.minVersion) ) { 572 // record values for possible use by CrashReporter or Finder 573 dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d", 574 this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff, 575 dependentLib->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.minVersion & 0xff); 576 } 577 // prebinding for this image disabled if any dependent library changed 578 if ( !depLibCheckSumsMatch ) 579 canUsePrelinkingInfo = false; 580 // prebinding for this image disabled unless both this and dependent are in the shared cache 581 if ( !dependentLib->inSharedCache() || !this->inSharedCache() ) 582 canUsePrelinkingInfo = false; 583 584 //if ( context.verbosePrebinding ) { 585 // if ( !requiredLib.checksumMatches ) 586 // fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n", 587 // requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(), dependentLib->getPath()); 588 // if ( dependentLib->getSlide() != 0 ) 589 // fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), dependentLib->getPath()); 590 //} 591 } 592 catch (const char* msg) { 593 //if ( context.verbosePrebinding ) 594 // fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath()); 595 if ( requiredLibInfo.required ) { 596 fState = dyld_image_state_mapped; 597 // record values for possible use by CrashReporter or Finder 598 if ( strstr(msg, "Incompatible") != NULL ) 599 (*context.setErrorStrings)(dyld_error_kind_dylib_version, this->getPath(), requiredLibInfo.name, NULL); 600 else if ( strstr(msg, "architecture") != NULL ) 601 (*context.setErrorStrings)(dyld_error_kind_dylib_wrong_arch, this->getPath(), requiredLibInfo.name, NULL); 602 else 603 (*context.setErrorStrings)(dyld_error_kind_dylib_missing, this->getPath(), requiredLibInfo.name, NULL); 604 dyld::throwf("Library not loaded: %s\n Referenced from: %s\n Reason: %s", requiredLibInfo.name, this->getRealPath(), msg); 605 } 606 // ok if weak library not found 607 dependentLib = NULL; 608 canUsePrelinkingInfo = false; // this disables all prebinding, we may want to just slam import vectors for this lib to zero 609 } 610 setLibImage(i, dependentLib, depLibReExported, requiredLibInfo.upward); 611 } 612 fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo; 613 614 // tell each to load its dependents 615 for(unsigned int i=0; i < libraryCount(); ++i) { 616 ImageLoader* dependentImage = libImage(i); 617 if ( dependentImage != NULL ) { 618 dependentImage->recursiveLoadLibraries(context, preflightOnly, thisRPaths); 619 } 620 } 621 622 // do deep prebind check 623 if ( fAllLibraryChecksumsAndLoadAddressesMatch ) { 624 for(unsigned int i=0; i < libraryCount(); ++i){ 625 ImageLoader* dependentImage = libImage(i); 626 if ( dependentImage != NULL ) { 627 if ( !dependentImage->allDependentLibrariesAsWhenPreBound() ) 628 fAllLibraryChecksumsAndLoadAddressesMatch = false; 629 } 630 } 631 } 632 633 // free rpaths (getRPaths() malloc'ed each string) 634 for(std::vector<const char*>::iterator it=rpathsFromThisImage.begin(); it != rpathsFromThisImage.end(); ++it) { 635 const char* str = *it; 636 free((void*)str); 637 } 638 639 } 640} 641 642void ImageLoader::recursiveRebase(const LinkContext& context) 643{ 644 if ( fState < dyld_image_state_rebased ) { 645 // break cycles 646 fState = dyld_image_state_rebased; 647 648 try { 649 // rebase lower level libraries first 650 for(unsigned int i=0; i < libraryCount(); ++i) { 651 ImageLoader* dependentImage = libImage(i); 652 if ( dependentImage != NULL ) 653 dependentImage->recursiveRebase(context); 654 } 655 656 // rebase this image 657 doRebase(context); 658 659 // notify 660 context.notifySingle(dyld_image_state_rebased, this); 661 } 662 catch (const char* msg) { 663 // this image is not rebased 664 fState = dyld_image_state_dependents_mapped; 665 CRSetCrashLogMessage2(NULL); 666 throw; 667 } 668 } 669} 670 671void ImageLoader::recursiveApplyInterposing(const LinkContext& context) 672{ 673 if ( ! fInterposed ) { 674 // break cycles 675 fInterposed = true; 676 677 try { 678 // interpose lower level libraries first 679 for(unsigned int i=0; i < libraryCount(); ++i) { 680 ImageLoader* dependentImage = libImage(i); 681 if ( dependentImage != NULL ) 682 dependentImage->recursiveApplyInterposing(context); 683 } 684 685 // interpose this image 686 doInterpose(context); 687 } 688 catch (const char* msg) { 689 // this image is not interposed 690 fInterposed = false; 691 throw; 692 } 693 } 694} 695 696 697 698void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload) 699{ 700 // Normally just non-lazy pointers are bound immediately. 701 // The exceptions are: 702 // 1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately 703 // 2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately 704 if ( fState < dyld_image_state_bound ) { 705 // break cycles 706 fState = dyld_image_state_bound; 707 708 try { 709 // bind lower level libraries first 710 for(unsigned int i=0; i < libraryCount(); ++i) { 711 ImageLoader* dependentImage = libImage(i); 712 if ( dependentImage != NULL ) 713 dependentImage->recursiveBind(context, forceLazysBound, neverUnload); 714 } 715 // bind this image 716 this->doBind(context, forceLazysBound); 717 // mark if lazys are also bound 718 if ( forceLazysBound || this->usablePrebinding(context) ) 719 fAllLazyPointersBound = true; 720 // mark as never-unload if requested 721 if ( neverUnload ) 722 this->setNeverUnload(); 723 724 context.notifySingle(dyld_image_state_bound, this); 725 } 726 catch (const char* msg) { 727 // restore state 728 fState = dyld_image_state_rebased; 729 CRSetCrashLogMessage2(NULL); 730 throw; 731 } 732 } 733} 734 735void ImageLoader::weakBind(const LinkContext& context) 736{ 737 if ( context.verboseWeakBind ) 738 dyld::log("dyld: weak bind start:\n"); 739 uint64_t t1 = mach_absolute_time(); 740 // get set of ImageLoaders that participate in coalecsing 741 ImageLoader* imagesNeedingCoalescing[fgImagesRequiringCoalescing]; 742 int count = context.getCoalescedImages(imagesNeedingCoalescing); 743 744 // count how many have not already had weakbinding done 745 int countNotYetWeakBound = 0; 746 int countOfImagesWithWeakDefinitions = 0; 747 int countOfImagesWithWeakDefinitionsNotInSharedCache = 0; 748 for(int i=0; i < count; ++i) { 749 if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound ) 750 ++countNotYetWeakBound; 751 if ( imagesNeedingCoalescing[i]->hasCoalescedExports() ) { 752 ++countOfImagesWithWeakDefinitions; 753 if ( ! imagesNeedingCoalescing[i]->inSharedCache() ) 754 ++countOfImagesWithWeakDefinitionsNotInSharedCache; 755 } 756 } 757 758 // don't need to do any coalescing if only one image has overrides, or all have already been done 759 if ( (countOfImagesWithWeakDefinitionsNotInSharedCache > 0) && (countNotYetWeakBound > 0) ) { 760 // make symbol iterators for each 761 ImageLoader::CoalIterator iterators[count]; 762 ImageLoader::CoalIterator* sortedIts[count]; 763 for(int i=0; i < count; ++i) { 764 imagesNeedingCoalescing[i]->initializeCoalIterator(iterators[i], i); 765 sortedIts[i] = &iterators[i]; 766 if ( context.verboseWeakBind ) 767 dyld::log("dyld: weak bind load order %d/%d for %s\n", i, count, imagesNeedingCoalescing[i]->getPath()); 768 } 769 770 // walk all symbols keeping iterators in sync by 771 // only ever incrementing the iterator with the lowest symbol 772 int doneCount = 0; 773 while ( doneCount != count ) { 774 //for(int i=0; i < count; ++i) 775 // dyld::log("sym[%d]=%s ", sortedIts[i]->loadOrder, sortedIts[i]->symbolName); 776 //dyld::log("\n"); 777 // increment iterator with lowest symbol 778 if ( sortedIts[0]->image->incrementCoalIterator(*sortedIts[0]) ) 779 ++doneCount; 780 // re-sort iterators 781 for(int i=1; i < count; ++i) { 782 int result = strcmp(sortedIts[i-1]->symbolName, sortedIts[i]->symbolName); 783 if ( result == 0 ) 784 sortedIts[i-1]->symbolMatches = true; 785 if ( result > 0 ) { 786 // new one is bigger then next, so swap 787 ImageLoader::CoalIterator* temp = sortedIts[i-1]; 788 sortedIts[i-1] = sortedIts[i]; 789 sortedIts[i] = temp; 790 } 791 if ( result < 0 ) 792 break; 793 } 794 // process all matching symbols just before incrementing the lowest one that matches 795 if ( sortedIts[0]->symbolMatches && !sortedIts[0]->done ) { 796 const char* nameToCoalesce = sortedIts[0]->symbolName; 797 // pick first symbol in load order (and non-weak overrides weak) 798 uintptr_t targetAddr = 0; 799 ImageLoader* targetImage = NULL; 800 for(int i=0; i < count; ++i) { 801 if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) { 802 if ( context.verboseWeakBind ) 803 dyld::log("dyld: weak bind, found %s weak=%d in %s \n", nameToCoalesce, iterators[i].weakSymbol, iterators[i].image->getPath()); 804 if ( iterators[i].weakSymbol ) { 805 if ( targetAddr == 0 ) { 806 targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context); 807 if ( targetAddr != 0 ) 808 targetImage = iterators[i].image; 809 } 810 } 811 else { 812 targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context); 813 if ( targetAddr != 0 ) { 814 targetImage = iterators[i].image; 815 // strong implementation found, stop searching 816 break; 817 } 818 } 819 } 820 } 821 if ( context.verboseWeakBind ) 822 dyld::log("dyld: weak binding all uses of %s to copy from %s\n", nameToCoalesce, targetImage->getShortName()); 823 824 // tell each to bind to this symbol (unless already bound) 825 if ( targetAddr != 0 ) { 826 for(int i=0; i < count; ++i) { 827 if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) { 828 if ( context.verboseWeakBind ) 829 dyld::log("dyld: weak bind, setting all uses of %s in %s to 0x%lX from %s\n", nameToCoalesce, iterators[i].image->getShortName(), targetAddr, targetImage->getShortName()); 830 if ( ! iterators[i].image->fWeakSymbolsBound ) 831 iterators[i].image->updateUsesCoalIterator(iterators[i], targetAddr, targetImage, context); 832 iterators[i].symbolMatches = false; 833 } 834 } 835 } 836 837 } 838 } 839 840 // mark all as having all weak symbols bound 841 for(int i=0; i < count; ++i) { 842 imagesNeedingCoalescing[i]->fWeakSymbolsBound = true; 843 } 844 } 845 uint64_t t2 = mach_absolute_time(); 846 fgTotalWeakBindTime += t2 - t1; 847 848 if ( context.verboseWeakBind ) 849 dyld::log("dyld: weak bind end\n"); 850} 851 852 853 854void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) 855{ 856 if ( ! fRegisteredDOF ) { 857 // break cycles 858 fRegisteredDOF = true; 859 860 // gather lower level libraries first 861 for(unsigned int i=0; i < libraryCount(); ++i) { 862 ImageLoader* dependentImage = libImage(i); 863 if ( dependentImage != NULL ) 864 dependentImage->recursiveGetDOFSections(context, dofs); 865 } 866 this->doGetDOFSections(context, dofs); 867 } 868} 869 870void ImageLoader::setNeverUnloadRecursive() { 871 if ( ! fNeverUnload ) { 872 // break cycles 873 fNeverUnload = true; 874 875 // gather lower level libraries first 876 for(unsigned int i=0; i < libraryCount(); ++i) { 877 ImageLoader* dependentImage = libImage(i); 878 if ( dependentImage != NULL ) 879 dependentImage->setNeverUnloadRecursive(); 880 } 881 } 882} 883 884void ImageLoader::recursiveSpinLock(recursive_lock& rlock) 885{ 886 // try to set image's ivar fInitializerRecursiveLock to point to this lock_info 887 // keep trying until success (spin) 888 while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL, &rlock, (void**)&fInitializerRecursiveLock) ) { 889 // if fInitializerRecursiveLock already points to a different lock_info, if it is for 890 // the same thread we are on, the increment the lock count, otherwise continue to spin 891 if ( (fInitializerRecursiveLock != NULL) && (fInitializerRecursiveLock->thread == rlock.thread) ) 892 break; 893 } 894 ++(fInitializerRecursiveLock->count); 895} 896 897void ImageLoader::recursiveSpinUnLock() 898{ 899 if ( --(fInitializerRecursiveLock->count) == 0 ) 900 fInitializerRecursiveLock = NULL; 901} 902 903 904void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, InitializerTimingList& timingInfo) 905{ 906 recursive_lock lock_info(this_thread); 907 recursiveSpinLock(lock_info); 908 909 if ( fState < dyld_image_state_dependents_initialized-1 ) { 910 uint8_t oldState = fState; 911 // break cycles 912 fState = dyld_image_state_dependents_initialized-1; 913 try { 914 bool hasUpwards = false; 915 // initialize lower level libraries first 916 for(unsigned int i=0; i < libraryCount(); ++i) { 917 ImageLoader* dependentImage = libImage(i); 918 if ( dependentImage != NULL ) { 919 // don't try to initialize stuff "above" me 920 bool isUpward = libIsUpward(i); 921 if ( (dependentImage->fDepth >= fDepth) && !isUpward ) { 922 dependentImage->recursiveInitialization(context, this_thread, timingInfo); 923 } 924 hasUpwards |= isUpward; 925 } 926 } 927 928 // record termination order 929 if ( this->needsTermination() ) 930 context.terminationRecorder(this); 931 932 // let objc know we are about to initialize this image 933 uint64_t t1 = mach_absolute_time(); 934 fState = dyld_image_state_dependents_initialized; 935 oldState = fState; 936 context.notifySingle(dyld_image_state_dependents_initialized, this); 937 938 // initialize this image 939 bool hasInitializers = this->doInitialization(context); 940 941 // <rdar://problem/10491874> initialize any upward depedencies 942 if ( hasUpwards ) { 943 for(unsigned int i=0; i < libraryCount(); ++i) { 944 ImageLoader* dependentImage = libImage(i); 945 // <rdar://problem/10643239> ObjC CG hang 946 // only init upward lib here if lib is not downwardly referenced somewhere 947 if ( (dependentImage != NULL) && libIsUpward(i) && !dependentImage->isReferencedDownward() ) { 948 dependentImage->recursiveInitialization(context, this_thread, timingInfo); 949 } 950 } 951 } 952 953 // let anyone know we finished initializing this image 954 fState = dyld_image_state_initialized; 955 oldState = fState; 956 context.notifySingle(dyld_image_state_initialized, this); 957 958 if ( hasInitializers ) { 959 uint64_t t2 = mach_absolute_time(); 960 timingInfo.images[timingInfo.count].image = this; 961 timingInfo.images[timingInfo.count].initTime = (t2-t1); 962 timingInfo.count++; 963 } 964 } 965 catch (const char* msg) { 966 // this image is not initialized 967 fState = oldState; 968 recursiveSpinUnLock(); 969 throw; 970 } 971 } 972 973 recursiveSpinUnLock(); 974} 975 976 977static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime) 978{ 979 static uint64_t sUnitsPerSecond = 0; 980 if ( sUnitsPerSecond == 0 ) { 981 struct mach_timebase_info timeBaseInfo; 982 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) { 983 sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer; 984 } 985 } 986 if ( partTime < sUnitsPerSecond ) { 987 uint32_t milliSecondsTimesHundred = (partTime*100000)/sUnitsPerSecond; 988 uint32_t milliSeconds = milliSecondsTimesHundred/100; 989 uint32_t percentTimesTen = (partTime*1000)/totalTime; 990 uint32_t percent = percentTimesTen/10; 991 dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimesHundred-milliSeconds*100, percent, percentTimesTen-percent*10); 992 } 993 else { 994 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond; 995 uint32_t seconds = secondsTimeTen/10; 996 uint32_t percentTimesTen = (partTime*1000)/totalTime; 997 uint32_t percent = percentTimesTen/10; 998 dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10); 999 } 1000} 1001 1002static char* commatize(uint64_t in, char* out) 1003{ 1004 uint64_t div10 = in / 10; 1005 uint8_t delta = in - div10*10; 1006 char* s = &out[32]; 1007 int digitCount = 1; 1008 *s = '\0'; 1009 *(--s) = '0' + delta; 1010 in = div10; 1011 while ( in != 0 ) { 1012 if ( (digitCount % 3) == 0 ) 1013 *(--s) = ','; 1014 div10 = in / 10; 1015 delta = in - div10*10; 1016 *(--s) = '0' + delta; 1017 in = div10; 1018 ++digitCount; 1019 } 1020 return s; 1021} 1022 1023 1024void ImageLoader::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo) 1025{ 1026 uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalWeakBindTime + fgTotalDOF + fgTotalInitTime; 1027 char commaNum1[40]; 1028 char commaNum2[40]; 1029 1030 printTime("total time", totalTime, totalTime); 1031#if __IPHONE_OS_VERSION_MIN_REQUIRED 1032 if ( fgImagesUsedFromSharedCache != 0 ) 1033 dyld::log("total images loaded: %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache); 1034 else 1035 dyld::log("total images loaded: %d\n", imageCount); 1036#else 1037 dyld::log("total images loaded: %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache); 1038#endif 1039 dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped, fgTotalBytesMapped/4096, fgTotalBytesPreFetched/4096); 1040 printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime); 1041 printTime("total dtrace DOF registration time", fgTotalDOF, totalTime); 1042 dyld::log("total rebase fixups: %s\n", commatize(fgTotalRebaseFixups, commaNum1)); 1043 printTime("total rebase fixups time", fgTotalRebaseTime, totalTime); 1044 dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1)); 1045 if ( fgTotalBindSymbolsResolved != 0 ) { 1046 uint32_t avgTimesTen = (fgTotalBindImageSearches * 10) / fgTotalBindSymbolsResolved; 1047 uint32_t avgInt = fgTotalBindImageSearches / fgTotalBindSymbolsResolved; 1048 uint32_t avgTenths = avgTimesTen - (avgInt*10); 1049 dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n", 1050 commatize(fgTotalBindSymbolsResolved, commaNum1), avgInt, avgTenths); 1051 } 1052 printTime("total binding fixups time", fgTotalBindTime, totalTime); 1053 printTime("total weak binding fixups time", fgTotalWeakBindTime, totalTime); 1054 dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2)); 1055 printTime("total initializer time", fgTotalInitTime, totalTime); 1056 for (uintptr_t i=0; i < timingInfo.count; ++i) { 1057 dyld::log("%21s ", timingInfo.images[i].image->getShortName()); 1058 printTime("", timingInfo.images[i].initTime, totalTime); 1059 } 1060 1061} 1062 1063 1064// 1065// copy path and add suffix to result 1066// 1067// /path/foo.dylib _debug => /path/foo_debug.dylib 1068// foo.dylib _debug => foo_debug.dylib 1069// foo _debug => foo_debug 1070// /path/bar _debug => /path/bar_debug 1071// /path/bar.A.dylib _debug => /path/bar.A_debug.dylib 1072// 1073void ImageLoader::addSuffix(const char* path, const char* suffix, char* result) 1074{ 1075 strcpy(result, path); 1076 1077 char* start = strrchr(result, '/'); 1078 if ( start != NULL ) 1079 start++; 1080 else 1081 start = result; 1082 1083 char* dot = strrchr(start, '.'); 1084 if ( dot != NULL ) { 1085 strcpy(dot, suffix); 1086 strcat(&dot[strlen(suffix)], &path[dot-result]); 1087 } 1088 else { 1089 strcat(result, suffix); 1090 } 1091} 1092 1093 1094VECTOR_NEVER_DESTRUCTED_IMPL(ImageLoader::InterposeTuple); 1095VECTOR_NEVER_DESTRUCTED_IMPL(ImagePair); 1096 1097 1098 1099