210-2-3
[darwin-xtools.git] / dyld / src / ImageLoader.cpp
blob58b22829d8b5bb5fe507f715e2d2f96964f7373a
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
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.
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #define __STDC_LIMIT_MACROS
26 #include <stdint.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <mach/mach.h>
30 #include <mach-o/fat.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <sys/param.h>
35 #include <sys/mount.h>
36 #include <libkern/OSAtomic.h>
38 #include "ImageLoader.h"
41 uint32_t ImageLoader::fgImagesUsedFromSharedCache = 0;
42 uint32_t ImageLoader::fgImagesWithUsedPrebinding = 0;
43 uint32_t ImageLoader::fgImagesRequiringCoalescing = 0;
44 uint32_t ImageLoader::fgImagesHasWeakDefinitions = 0;
45 uint32_t ImageLoader::fgTotalRebaseFixups = 0;
46 uint32_t ImageLoader::fgTotalBindFixups = 0;
47 uint32_t ImageLoader::fgTotalBindSymbolsResolved = 0;
48 uint32_t ImageLoader::fgTotalBindImageSearches = 0;
49 uint32_t ImageLoader::fgTotalLazyBindFixups = 0;
50 uint32_t ImageLoader::fgTotalPossibleLazyBindFixups = 0;
51 uint32_t ImageLoader::fgTotalSegmentsMapped = 0;
52 uint64_t ImageLoader::fgTotalBytesMapped = 0;
53 uint64_t ImageLoader::fgTotalBytesPreFetched = 0;
54 uint64_t ImageLoader::fgTotalLoadLibrariesTime;
55 uint64_t ImageLoader::fgTotalRebaseTime;
56 uint64_t ImageLoader::fgTotalBindTime;
57 uint64_t ImageLoader::fgTotalWeakBindTime;
58 uint64_t ImageLoader::fgTotalDOF;
59 uint64_t ImageLoader::fgTotalInitTime;
60 uint16_t ImageLoader::fgLoadOrdinal = 0;
61 std::vector<ImageLoader::InterposeTuple>ImageLoader::fgInterposingTuples;
62 uintptr_t ImageLoader::fgNextPIEDylibAddress = 0;
66 ImageLoader::ImageLoader(const char* path, unsigned int libCount)
67 : fPath(path), fRealPath(NULL), fDevice(0), fInode(0), fLastModified(0),
68 fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
69 fDynamicReferenceCount(0), fDynamicReferences(NULL), 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 fIsReferencedUpward(false), fWeakSymbolsBound(false)
78 if ( fPath != NULL )
79 fPathHash = hash(fPath);
83 void ImageLoader::deleteImage(ImageLoader* image)
85 // this cannot be done in destructor because libImage() is implemented
86 // in a subclass
87 DependentLibraryInfo libraryInfos[image->libraryCount()];
88 image->doGetDependentLibraries(libraryInfos);
89 for(unsigned int i=0; i < image->libraryCount(); ++i) {
90 ImageLoader* lib = image->libImage(i);
91 if ( (lib != NULL) && ! libraryInfos[i].upward )
92 lib->fStaticReferenceCount--;
94 delete image;
98 ImageLoader::~ImageLoader()
100 if ( fRealPath != NULL )
101 delete [] fRealPath;
102 if ( fPathOwnedByImage && (fPath != NULL) )
103 delete [] fPath;
104 if ( fDynamicReferences != NULL ) {
105 for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
106 const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
108 delete fDynamicReferences;
112 void ImageLoader::setFileInfo(dev_t device, ino_t inode, time_t modDate)
114 fDevice = device;
115 fInode = inode;
116 fLastModified = modDate;
119 void ImageLoader::setMapped(const LinkContext& context)
121 fState = dyld_image_state_mapped;
122 context.notifySingle(dyld_image_state_mapped, this); // note: can throw exception
125 void ImageLoader::addDynamicReference(const ImageLoader* target)
127 bool alreadyInVector = false;
128 if ( fDynamicReferences == NULL ) {
129 fDynamicReferences = new std::vector<const ImageLoader*>();
131 else {
132 for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
133 if ( *it == target ) {
134 alreadyInVector = true;
135 break;
139 if ( ! alreadyInVector ) {
140 fDynamicReferences->push_back(target);
141 const_cast<ImageLoader*>(target)->fDynamicReferenceCount++;
143 //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
146 int ImageLoader::compare(const ImageLoader* right) const
148 if ( this->fDepth == right->fDepth ) {
149 if ( this->fLoadOrder == right->fLoadOrder )
150 return 0;
151 else if ( this->fLoadOrder < right->fLoadOrder )
152 return -1;
153 else
154 return 1;
156 else {
157 if ( this->fDepth < right->fDepth )
158 return -1;
159 else
160 return 1;
164 void ImageLoader::setPath(const char* path)
166 if ( fPathOwnedByImage && (fPath != NULL) )
167 delete [] fPath;
168 fPath = new char[strlen(path)+1];
169 strcpy((char*)fPath, path);
170 fPathOwnedByImage = true; // delete fPath when this image is destructed
171 fPathHash = hash(fPath);
172 fRealPath = NULL;
175 void ImageLoader::setPathUnowned(const char* path)
177 if ( fPathOwnedByImage && (fPath != NULL) ) {
178 delete [] fPath;
180 fPath = path;
181 fPathOwnedByImage = false;
182 fPathHash = hash(fPath);
185 void ImageLoader::setPaths(const char* path, const char* realPath)
187 this->setPath(path);
188 fRealPath = new char[strlen(realPath)+1];
189 strcpy((char*)fRealPath, realPath);
192 const char* ImageLoader::getRealPath() const
194 if ( fRealPath != NULL )
195 return fRealPath;
196 else
197 return fPath;
201 uint32_t ImageLoader::hash(const char* path)
203 // this does not need to be a great hash
204 // it is just used to reduce the number of strcmp() calls
205 // of existing images when loading a new image
206 uint32_t h = 0;
207 for (const char* s=path; *s != '\0'; ++s)
208 h = h*5 + *s;
209 return h;
212 bool ImageLoader::matchInstallPath() const
214 return fMatchByInstallName;
217 void ImageLoader::setMatchInstallPath(bool match)
219 fMatchByInstallName = match;
222 bool ImageLoader::statMatch(const struct stat& stat_buf) const
224 return ( (this->fDevice == stat_buf.st_dev) && (this->fInode == stat_buf.st_ino) );
227 const char* ImageLoader::getShortName() const
229 // try to return leaf name
230 if ( fPath != NULL ) {
231 const char* s = strrchr(fPath, '/');
232 if ( s != NULL )
233 return &s[1];
235 return fPath;
238 void ImageLoader::setLeaveMapped()
240 fLeaveMapped = true;
243 void ImageLoader::setHideExports(bool hide)
245 fHideSymbols = hide;
248 bool ImageLoader::hasHiddenExports() const
250 return fHideSymbols;
253 bool ImageLoader::isLinked() const
255 return (fState >= dyld_image_state_bound);
258 time_t ImageLoader::lastModified() const
260 return fLastModified;
263 bool ImageLoader::containsAddress(const void* addr) const
265 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
266 const uint8_t* start = (const uint8_t*)segActualLoadAddress(i);
267 const uint8_t* end = (const uint8_t*)segActualEndAddress(i);
268 if ( (start <= addr) && (addr < end) && !segUnaccessible(i) )
269 return true;
271 return false;
274 bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) const
276 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
277 const uint8_t* segStart = (const uint8_t*)segActualLoadAddress(i);
278 const uint8_t* segEnd = (const uint8_t*)segActualEndAddress(i);
279 if ( strcmp(segName(i), "__UNIXSTACK") == 0 ) {
280 // __UNIXSTACK never slides. This is the only place that cares
281 // and checking for that segment name in segActualLoadAddress()
282 // is too expensive.
283 segStart -= getSlide();
284 segEnd -= getSlide();
286 if ( (start <= segStart) && (segStart < end) )
287 return true;
288 if ( (start <= segEnd) && (segEnd < end) )
289 return true;
290 if ( (segStart < start) && (end < segEnd) )
291 return true;
293 return false;
296 void ImageLoader::getMappedRegions(MappedRegion*& regions) const
298 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
299 MappedRegion region;
300 region.address = segActualLoadAddress(i);
301 region.size = segSize(i);
302 *regions++ = region;
307 static bool notInImgageList(const ImageLoader* image, const ImageLoader** dsiStart, const ImageLoader** dsiCur)
309 for (const ImageLoader** p = dsiStart; p < dsiCur; ++p)
310 if ( *p == image )
311 return false;
312 return true;
316 // private method that handles circular dependencies by only search any image once
317 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name,
318 const ImageLoader** dsiStart, const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const
320 const ImageLoader::Symbol* sym;
321 // search self
322 if ( notInImgageList(this, dsiStart, dsiCur) ) {
323 sym = this->findExportedSymbol(name, false, foundIn);
324 if ( sym != NULL )
325 return sym;
326 *dsiCur++ = this;
329 // search directly dependent libraries
330 for(unsigned int i=0; i < libraryCount(); ++i) {
331 ImageLoader* dependentImage = libImage(i);
332 if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
333 const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, false, foundIn);
334 if ( sym != NULL )
335 return sym;
339 // search indirectly dependent libraries
340 for(unsigned int i=0; i < libraryCount(); ++i) {
341 ImageLoader* dependentImage = libImage(i);
342 if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
343 *dsiCur++ = dependentImage;
344 const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dsiStart, dsiCur, dsiEnd, foundIn);
345 if ( sym != NULL )
346 return sym;
350 return NULL;
354 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
356 unsigned int imageCount = context.imageCount();
357 const ImageLoader* dontSearchImages[imageCount];
358 dontSearchImages[0] = this; // don't search this image
359 const ImageLoader** cur = &dontSearchImages[1];
360 return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
363 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
365 unsigned int imageCount = context.imageCount();
366 const ImageLoader* dontSearchImages[imageCount];
367 const ImageLoader** cur = &dontSearchImages[0];
368 return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
371 // this is called by initializeMainExecutable() to interpose on the initial set of images
372 void ImageLoader::applyInterposing(const LinkContext& context)
374 if ( fgInterposingTuples.size() != 0 )
375 this->recursiveApplyInterposing(context);
378 void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
380 //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
382 // clear error strings
383 (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
385 uint64_t t0 = mach_absolute_time();
386 this->recursiveLoadLibraries(context, preflightOnly, loaderRPaths);
387 context.notifyBatch(dyld_image_state_dependents_mapped);
389 // we only do the loading step for preflights
390 if ( preflightOnly )
391 return;
393 uint64_t t1 = mach_absolute_time();
394 context.clearAllDepths();
395 this->recursiveUpdateDepth(context.imageCount());
397 uint64_t t2 = mach_absolute_time();
398 this->recursiveRebase(context);
399 context.notifyBatch(dyld_image_state_rebased);
401 uint64_t t3 = mach_absolute_time();
402 this->recursiveBind(context, forceLazysBound);
404 uint64_t t4 = mach_absolute_time();
405 this->weakBind(context);
406 uint64_t t5 = mach_absolute_time();
408 context.notifyBatch(dyld_image_state_bound);
409 uint64_t t6 = mach_absolute_time();
411 std::vector<DOFInfo> dofs;
412 this->recursiveGetDOFSections(context, dofs);
413 context.registerDOFs(dofs);
414 uint64_t t7 = mach_absolute_time();
416 // interpose any dynamically loaded images
417 if ( !context.linkingMainExecutable && (fgInterposingTuples.size() != 0) ) {
418 this->recursiveApplyInterposing(context);
421 // clear error strings
422 (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
424 fgTotalLoadLibrariesTime += t1 - t0;
425 fgTotalRebaseTime += t3 - t2;
426 fgTotalBindTime += t4 - t3;
427 fgTotalWeakBindTime += t5 - t4;
428 fgTotalDOF += t7 - t6;
430 // done with initial dylib loads
431 fgNextPIEDylibAddress = 0;
435 void ImageLoader::printReferenceCounts()
437 dyld::log(" dlopen=%d, static=%d, dynamic=%d for %s\n",
438 fDlopenReferenceCount, fStaticReferenceCount, fDynamicReferenceCount, getPath() );
442 bool ImageLoader::decrementDlopenReferenceCount()
444 if ( fDlopenReferenceCount == 0 )
445 return true;
446 --fDlopenReferenceCount;
447 return false;
450 void ImageLoader::runInitializers(const LinkContext& context, InitializerTimingList& timingInfo)
452 uint64_t t1 = mach_absolute_time();
453 mach_port_t this_thread = mach_thread_self();
454 this->recursiveInitialization(context, this_thread, timingInfo);
455 context.notifyBatch(dyld_image_state_initialized);
456 mach_port_deallocate(mach_task_self(), this_thread);
457 uint64_t t2 = mach_absolute_time();
458 fgTotalInitTime += (t2 - t1);
462 void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive)
464 if ( ! fAllLazyPointersBound ) {
465 fAllLazyPointersBound = true;
467 if ( recursive ) {
468 // bind lower level libraries first
469 for(unsigned int i=0; i < libraryCount(); ++i) {
470 ImageLoader* dependentImage = libImage(i);
471 if ( dependentImage != NULL )
472 dependentImage->bindAllLazyPointers(context, recursive);
475 // bind lazies in this image
476 this->doBindJustLazies(context);
481 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
483 return fAllLibraryChecksumsAndLoadAddressesMatch;
487 unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
489 // the purpose of this phase is to make the images sortable such that
490 // in a sort list of images, every image that an image depends on
491 // occurs in the list before it.
492 if ( fDepth == 0 ) {
493 // break cycles
494 fDepth = maxDepth;
496 // get depth of dependents
497 unsigned int minDependentDepth = maxDepth;
498 for(unsigned int i=0; i < libraryCount(); ++i) {
499 ImageLoader* dependentImage = libImage(i);
500 if ( (dependentImage != NULL) && !libIsUpward(i) ) {
501 unsigned int d = dependentImage->recursiveUpdateDepth(maxDepth);
502 if ( d < minDependentDepth )
503 minDependentDepth = d;
507 // make me less deep then all my dependents
508 fDepth = minDependentDepth - 1;
511 return fDepth;
515 void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths)
517 if ( fState < dyld_image_state_dependents_mapped ) {
518 // break cycles
519 fState = dyld_image_state_dependents_mapped;
521 // get list of libraries this image needs
522 //dyld::log("ImageLoader::recursiveLoadLibraries() %ld = %d*%ld\n", fLibrariesCount*sizeof(DependentLibrary), fLibrariesCount, sizeof(DependentLibrary));
523 DependentLibraryInfo libraryInfos[fLibraryCount];
524 this->doGetDependentLibraries(libraryInfos);
526 // get list of rpaths that this image adds
527 std::vector<const char*> rpathsFromThisImage;
528 this->getRPaths(context, rpathsFromThisImage);
529 const RPathChain thisRPaths(&loaderRPaths, &rpathsFromThisImage);
531 // try to load each
532 bool canUsePrelinkingInfo = true;
533 for(unsigned int i=0; i < fLibraryCount; ++i){
534 ImageLoader* dependentLib;
535 bool depLibReExported = false;
536 bool depLibReRequired = false;
537 bool depLibCheckSumsMatch = false;
538 DependentLibraryInfo& requiredLibInfo = libraryInfos[i];
539 #if DYLD_SHARED_CACHE_SUPPORT
540 if ( preflightOnly && context.inSharedCache(requiredLibInfo.name) ) {
541 // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
542 // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded
543 setLibImage(i, NULL, false, false);
544 continue;
546 #endif
547 try {
548 dependentLib = context.loadLibrary(requiredLibInfo.name, true, this->getPath(), &thisRPaths);
549 if ( dependentLib == this ) {
550 // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168
551 dependentLib = context.loadLibrary(requiredLibInfo.name, false, NULL, NULL);
552 if ( dependentLib != this )
553 dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath());
555 if ( fNeverUnload )
556 dependentLib->setNeverUnload();
557 if ( requiredLibInfo.upward ) {
558 dependentLib->fIsReferencedUpward = true;
560 else {
561 dependentLib->fStaticReferenceCount += 1;
562 dependentLib->fIsReferencedDownward = true;
564 LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
565 depLibReRequired = requiredLibInfo.required;
566 depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum );
567 depLibReExported = requiredLibInfo.reExported;
568 if ( ! depLibReExported ) {
569 // for pre-10.5 binaries that did not use LC_REEXPORT_DYLIB
570 depLibReExported = dependentLib->isSubframeworkOf(context, this) || this->hasSubLibrary(context, dependentLib);
572 // check found library version is compatible
573 // <rdar://problem/89200806> 0xFFFFFFFF is wildcard that matches any version
574 if ( (requiredLibInfo.info.minVersion != 0xFFFFFFFF) && (actualInfo.minVersion < requiredLibInfo.info.minVersion) ) {
575 // record values for possible use by CrashReporter or Finder
576 dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
577 this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff,
578 dependentLib->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.minVersion & 0xff);
580 // prebinding for this image disabled if any dependent library changed
581 if ( !depLibCheckSumsMatch )
582 canUsePrelinkingInfo = false;
583 // prebinding for this image disabled unless both this and dependent are in the shared cache
584 if ( !dependentLib->inSharedCache() || !this->inSharedCache() )
585 canUsePrelinkingInfo = false;
587 //if ( context.verbosePrebinding ) {
588 // if ( !requiredLib.checksumMatches )
589 // fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n",
590 // requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(), dependentLib->getPath());
591 // if ( dependentLib->getSlide() != 0 )
592 // fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), dependentLib->getPath());
595 catch (const char* msg) {
596 //if ( context.verbosePrebinding )
597 // fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());
598 if ( requiredLibInfo.required ) {
599 fState = dyld_image_state_mapped;
600 // record values for possible use by CrashReporter or Finder
601 if ( strstr(msg, "Incompatible") != NULL )
602 (*context.setErrorStrings)(dyld_error_kind_dylib_version, this->getPath(), requiredLibInfo.name, NULL);
603 else if ( strstr(msg, "architecture") != NULL )
604 (*context.setErrorStrings)(dyld_error_kind_dylib_wrong_arch, this->getPath(), requiredLibInfo.name, NULL);
605 else
606 (*context.setErrorStrings)(dyld_error_kind_dylib_missing, this->getPath(), requiredLibInfo.name, NULL);
607 dyld::throwf("Library not loaded: %s\n Referenced from: %s\n Reason: %s", requiredLibInfo.name, this->getRealPath(), msg);
609 // ok if weak library not found
610 dependentLib = NULL;
611 canUsePrelinkingInfo = false; // this disables all prebinding, we may want to just slam import vectors for this lib to zero
613 setLibImage(i, dependentLib, depLibReExported, requiredLibInfo.upward);
615 fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo;
617 // tell each to load its dependents
618 for(unsigned int i=0; i < libraryCount(); ++i) {
619 ImageLoader* dependentImage = libImage(i);
620 if ( dependentImage != NULL ) {
621 dependentImage->recursiveLoadLibraries(context, preflightOnly, thisRPaths);
625 // do deep prebind check
626 if ( fAllLibraryChecksumsAndLoadAddressesMatch ) {
627 for(unsigned int i=0; i < libraryCount(); ++i){
628 ImageLoader* dependentImage = libImage(i);
629 if ( dependentImage != NULL ) {
630 if ( !dependentImage->allDependentLibrariesAsWhenPreBound() )
631 fAllLibraryChecksumsAndLoadAddressesMatch = false;
636 // free rpaths (getRPaths() malloc'ed each string)
637 for(std::vector<const char*>::iterator it=rpathsFromThisImage.begin(); it != rpathsFromThisImage.end(); ++it) {
638 const char* str = *it;
639 free((void*)str);
645 void ImageLoader::recursiveRebase(const LinkContext& context)
647 if ( fState < dyld_image_state_rebased ) {
648 // break cycles
649 fState = dyld_image_state_rebased;
651 try {
652 // rebase lower level libraries first
653 for(unsigned int i=0; i < libraryCount(); ++i) {
654 ImageLoader* dependentImage = libImage(i);
655 if ( dependentImage != NULL )
656 dependentImage->recursiveRebase(context);
659 // rebase this image
660 doRebase(context);
662 // notify
663 context.notifySingle(dyld_image_state_rebased, this);
665 catch (const char* msg) {
666 // this image is not rebased
667 fState = dyld_image_state_dependents_mapped;
668 CRSetCrashLogMessage2(NULL);
669 throw;
674 void ImageLoader::recursiveApplyInterposing(const LinkContext& context)
676 if ( ! fInterposed ) {
677 // break cycles
678 fInterposed = true;
680 try {
681 // interpose lower level libraries first
682 for(unsigned int i=0; i < libraryCount(); ++i) {
683 ImageLoader* dependentImage = libImage(i);
684 if ( dependentImage != NULL )
685 dependentImage->recursiveApplyInterposing(context);
688 // interpose this image
689 doInterpose(context);
691 catch (const char* msg) {
692 // this image is not interposed
693 fInterposed = false;
694 throw;
701 void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound)
703 // Normally just non-lazy pointers are bound immediately.
704 // The exceptions are:
705 // 1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately
706 // 2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately
707 if ( fState < dyld_image_state_bound ) {
708 // break cycles
709 fState = dyld_image_state_bound;
711 try {
712 // bind lower level libraries first
713 for(unsigned int i=0; i < libraryCount(); ++i) {
714 ImageLoader* dependentImage = libImage(i);
715 if ( dependentImage != NULL )
716 dependentImage->recursiveBind(context, forceLazysBound);
718 // bind this image
719 this->doBind(context, forceLazysBound);
720 // mark if lazys are also bound
721 if ( forceLazysBound || this->usablePrebinding(context) )
722 fAllLazyPointersBound = true;
724 context.notifySingle(dyld_image_state_bound, this);
726 catch (const char* msg) {
727 // restore state
728 fState = dyld_image_state_rebased;
729 CRSetCrashLogMessage2(NULL);
730 throw;
735 void ImageLoader::weakBind(const LinkContext& context)
737 if ( context.verboseWeakBind )
738 dyld::log("dyld: weak bind start:\n");
739 // get set of ImageLoaders that participate in coalecsing
740 ImageLoader* imagesNeedingCoalescing[fgImagesRequiringCoalescing];
741 int count = context.getCoalescedImages(imagesNeedingCoalescing);
743 // count how many have not already had weakbinding done
744 int countNotYetWeakBound = 0;
745 int countOfImagesWithWeakDefinitions = 0;
746 int countOfImagesWithWeakDefinitionsNotInSharedCache = 0;
747 for(int i=0; i < count; ++i) {
748 if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound )
749 ++countNotYetWeakBound;
750 if ( imagesNeedingCoalescing[i]->hasCoalescedExports() ) {
751 ++countOfImagesWithWeakDefinitions;
752 if ( ! imagesNeedingCoalescing[i]->inSharedCache() )
753 ++countOfImagesWithWeakDefinitionsNotInSharedCache;
757 // don't need to do any coalescing if only one image has overrides, or all have already been done
758 if ( (countOfImagesWithWeakDefinitionsNotInSharedCache > 0) && (countNotYetWeakBound > 0) ) {
759 // make symbol iterators for each
760 ImageLoader::CoalIterator iterators[count];
761 ImageLoader::CoalIterator* sortedIts[count];
762 for(int i=0; i < count; ++i) {
763 imagesNeedingCoalescing[i]->initializeCoalIterator(iterators[i], i);
764 sortedIts[i] = &iterators[i];
765 if ( context.verboseWeakBind )
766 dyld::log("dyld: weak bind load order %d/%d for %s\n", i, count, imagesNeedingCoalescing[i]->getPath());
769 // walk all symbols keeping iterators in sync by
770 // only ever incrementing the iterator with the lowest symbol
771 int doneCount = 0;
772 while ( doneCount != count ) {
773 //for(int i=0; i < count; ++i)
774 // dyld::log("sym[%d]=%s ", sortedIts[i]->loadOrder, sortedIts[i]->symbolName);
775 //dyld::log("\n");
776 // increment iterator with lowest symbol
777 if ( sortedIts[0]->image->incrementCoalIterator(*sortedIts[0]) )
778 ++doneCount;
779 // re-sort iterators
780 for(int i=1; i < count; ++i) {
781 int result = strcmp(sortedIts[i-1]->symbolName, sortedIts[i]->symbolName);
782 if ( result == 0 )
783 sortedIts[i-1]->symbolMatches = true;
784 if ( result > 0 ) {
785 // new one is bigger then next, so swap
786 ImageLoader::CoalIterator* temp = sortedIts[i-1];
787 sortedIts[i-1] = sortedIts[i];
788 sortedIts[i] = temp;
790 if ( result < 0 )
791 break;
793 // process all matching symbols just before incrementing the lowest one that matches
794 if ( sortedIts[0]->symbolMatches && !sortedIts[0]->done ) {
795 const char* nameToCoalesce = sortedIts[0]->symbolName;
796 // pick first symbol in load order (and non-weak overrides weak)
797 uintptr_t targetAddr = 0;
798 ImageLoader* targetImage = NULL;
799 for(int i=0; i < count; ++i) {
800 if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) {
801 if ( context.verboseWeakBind )
802 dyld::log("dyld: weak bind, found %s weak=%d in %s \n", nameToCoalesce, iterators[i].weakSymbol, iterators[i].image->getPath());
803 if ( iterators[i].weakSymbol ) {
804 if ( targetAddr == 0 ) {
805 targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context);
806 if ( targetAddr != 0 )
807 targetImage = iterators[i].image;
810 else {
811 targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context);
812 if ( targetAddr != 0 ) {
813 targetImage = iterators[i].image;
814 // strong implementation found, stop searching
815 break;
820 if ( context.verboseWeakBind )
821 dyld::log("dyld: weak binding all uses of %s to copy from %s\n", nameToCoalesce, targetImage->getShortName());
823 // tell each to bind to this symbol (unless already bound)
824 if ( targetAddr != 0 ) {
825 for(int i=0; i < count; ++i) {
826 if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) {
827 if ( context.verboseWeakBind )
828 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());
829 if ( ! iterators[i].image->fWeakSymbolsBound )
830 iterators[i].image->updateUsesCoalIterator(iterators[i], targetAddr, targetImage, context);
831 iterators[i].symbolMatches = false;
839 // mark all as having all weak symbols bound
840 for(int i=0; i < count; ++i) {
841 imagesNeedingCoalescing[i]->fWeakSymbolsBound = true;
844 if ( context.verboseWeakBind )
845 dyld::log("dyld: weak bind end\n");
850 void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs)
852 if ( ! fRegisteredDOF ) {
853 // break cycles
854 fRegisteredDOF = true;
856 // gather lower level libraries first
857 for(unsigned int i=0; i < libraryCount(); ++i) {
858 ImageLoader* dependentImage = libImage(i);
859 if ( dependentImage != NULL )
860 dependentImage->recursiveGetDOFSections(context, dofs);
862 this->doGetDOFSections(context, dofs);
867 void ImageLoader::recursiveSpinLock(recursive_lock& rlock)
869 // try to set image's ivar fInitializerRecursiveLock to point to this lock_info
870 // keep trying until success (spin)
871 while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL, &rlock, (void**)&fInitializerRecursiveLock) ) {
872 // if fInitializerRecursiveLock already points to a different lock_info, if it is for
873 // the same thread we are on, the increment the lock count, otherwise continue to spin
874 if ( (fInitializerRecursiveLock != NULL) && (fInitializerRecursiveLock->thread == rlock.thread) )
875 break;
877 ++(fInitializerRecursiveLock->count);
880 void ImageLoader::recursiveSpinUnLock()
882 if ( --(fInitializerRecursiveLock->count) == 0 )
883 fInitializerRecursiveLock = NULL;
887 void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, InitializerTimingList& timingInfo)
889 recursive_lock lock_info(this_thread);
890 recursiveSpinLock(lock_info);
892 if ( fState < dyld_image_state_dependents_initialized-1 ) {
893 uint8_t oldState = fState;
894 // break cycles
895 fState = dyld_image_state_dependents_initialized-1;
896 try {
897 bool hasUpwards = false;
898 // initialize lower level libraries first
899 for(unsigned int i=0; i < libraryCount(); ++i) {
900 ImageLoader* dependentImage = libImage(i);
901 if ( dependentImage != NULL ) {
902 // don't try to initialize stuff "above" me
903 bool isUpward = libIsUpward(i);
904 if ( (dependentImage->fDepth >= fDepth) && !isUpward ) {
905 dependentImage->recursiveInitialization(context, this_thread, timingInfo);
907 hasUpwards |= isUpward;
911 // record termination order
912 if ( this->needsTermination() )
913 context.terminationRecorder(this);
915 // let objc know we are about to initialize this image
916 uint64_t t1 = mach_absolute_time();
917 fState = dyld_image_state_dependents_initialized;
918 oldState = fState;
919 context.notifySingle(dyld_image_state_dependents_initialized, this);
921 // initialize this image
922 bool hasInitializers = this->doInitialization(context);
924 // <rdar://problem/10491874> initialize any upward depedencies
925 if ( hasUpwards ) {
926 for(unsigned int i=0; i < libraryCount(); ++i) {
927 ImageLoader* dependentImage = libImage(i);
928 // <rdar://problem/10643239> ObjC CG hang
929 // only init upward lib here if lib is not downwardly referenced somewhere
930 if ( (dependentImage != NULL) && libIsUpward(i) && !dependentImage->isReferencedDownward() ) {
931 dependentImage->recursiveInitialization(context, this_thread, timingInfo);
936 // let anyone know we finished initializing this image
937 fState = dyld_image_state_initialized;
938 oldState = fState;
939 context.notifySingle(dyld_image_state_initialized, this);
941 if ( hasInitializers ) {
942 uint64_t t2 = mach_absolute_time();
943 timingInfo.images[timingInfo.count].image = this;
944 timingInfo.images[timingInfo.count].initTime = (t2-t1);
945 timingInfo.count++;
948 catch (const char* msg) {
949 // this image is not initialized
950 fState = oldState;
951 recursiveSpinUnLock();
952 throw;
956 recursiveSpinUnLock();
960 static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
962 static uint64_t sUnitsPerSecond = 0;
963 if ( sUnitsPerSecond == 0 ) {
964 struct mach_timebase_info timeBaseInfo;
965 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
966 sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
969 if ( partTime < sUnitsPerSecond ) {
970 uint32_t milliSecondsTimesHundred = (partTime*100000)/sUnitsPerSecond;
971 uint32_t milliSeconds = milliSecondsTimesHundred/100;
972 uint32_t percentTimesTen = (partTime*1000)/totalTime;
973 uint32_t percent = percentTimesTen/10;
974 dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimesHundred-milliSeconds*100, percent, percentTimesTen-percent*10);
976 else {
977 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
978 uint32_t seconds = secondsTimeTen/10;
979 uint32_t percentTimesTen = (partTime*1000)/totalTime;
980 uint32_t percent = percentTimesTen/10;
981 dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
985 static char* commatize(uint64_t in, char* out)
987 uint64_t div10 = in / 10;
988 uint8_t delta = in - div10*10;
989 char* s = &out[32];
990 int digitCount = 1;
991 *s = '\0';
992 *(--s) = '0' + delta;
993 in = div10;
994 while ( in != 0 ) {
995 if ( (digitCount % 3) == 0 )
996 *(--s) = ',';
997 div10 = in / 10;
998 delta = in - div10*10;
999 *(--s) = '0' + delta;
1000 in = div10;
1001 ++digitCount;
1003 return s;
1007 void ImageLoader::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo)
1009 uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalWeakBindTime + fgTotalDOF + fgTotalInitTime;
1010 char commaNum1[40];
1011 char commaNum2[40];
1013 printTime("total time", totalTime, totalTime);
1014 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1015 if ( fgImagesUsedFromSharedCache != 0 )
1016 dyld::log("total images loaded: %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache);
1017 else
1018 dyld::log("total images loaded: %d\n", imageCount);
1019 #else
1020 dyld::log("total images loaded: %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache);
1021 #endif
1022 dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped, fgTotalBytesMapped/4096, fgTotalBytesPreFetched/4096);
1023 printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime);
1024 printTime("total dtrace DOF registration time", fgTotalDOF, totalTime);
1025 dyld::log("total rebase fixups: %s\n", commatize(fgTotalRebaseFixups, commaNum1));
1026 printTime("total rebase fixups time", fgTotalRebaseTime, totalTime);
1027 dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1));
1028 if ( fgTotalBindSymbolsResolved != 0 ) {
1029 uint32_t avgTimesTen = (fgTotalBindImageSearches * 10) / fgTotalBindSymbolsResolved;
1030 uint32_t avgInt = fgTotalBindImageSearches / fgTotalBindSymbolsResolved;
1031 uint32_t avgTenths = avgTimesTen - (avgInt*10);
1032 dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n",
1033 commatize(fgTotalBindSymbolsResolved, commaNum1), avgInt, avgTenths);
1035 printTime("total binding fixups time", fgTotalBindTime, totalTime);
1036 printTime("total weak binding fixups time", fgTotalWeakBindTime, totalTime);
1037 dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2));
1038 printTime("total initializer time", fgTotalInitTime, totalTime);
1039 for (uintptr_t i=0; i < timingInfo.count; ++i) {
1040 dyld::log("%21s ", timingInfo.images[i].image->getShortName());
1041 printTime("", timingInfo.images[i].initTime, totalTime);
1048 // copy path and add suffix to result
1050 // /path/foo.dylib _debug => /path/foo_debug.dylib
1051 // foo.dylib _debug => foo_debug.dylib
1052 // foo _debug => foo_debug
1053 // /path/bar _debug => /path/bar_debug
1054 // /path/bar.A.dylib _debug => /path/bar.A_debug.dylib
1056 void ImageLoader::addSuffix(const char* path, const char* suffix, char* result)
1058 strcpy(result, path);
1060 char* start = strrchr(result, '/');
1061 if ( start != NULL )
1062 start++;
1063 else
1064 start = result;
1066 char* dot = strrchr(start, '.');
1067 if ( dot != NULL ) {
1068 strcpy(dot, suffix);
1069 strcat(&dot[strlen(suffix)], &path[dot-result]);
1071 else {
1072 strcat(result, suffix);