1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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
29 #include <mach/mach.h>
30 #include <mach-o/fat.h>
31 #include <sys/types.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::fgImagesRequiringNoFixups
= 0;
44 uint32_t ImageLoader::fgImagesRequiringCoalescing
= 0;
45 uint32_t ImageLoader::fgImagesHasWeakDefinitions
= 0;
46 uint32_t ImageLoader::fgTotalRebaseFixups
= 0;
47 uint32_t ImageLoader::fgTotalBindFixups
= 0;
48 uint32_t ImageLoader::fgTotalBindSymbolsResolved
= 0;
49 uint32_t ImageLoader::fgTotalBindImageSearches
= 0;
50 uint32_t ImageLoader::fgTotalLazyBindFixups
= 0;
51 uint32_t ImageLoader::fgTotalPossibleLazyBindFixups
= 0;
52 uint32_t ImageLoader::fgTotalSegmentsMapped
= 0;
53 uint64_t ImageLoader::fgTotalBytesMapped
= 0;
54 uint64_t ImageLoader::fgTotalBytesPreFetched
= 0;
55 uint64_t ImageLoader::fgTotalLoadLibrariesTime
;
56 uint64_t ImageLoader::fgTotalRebaseTime
;
57 uint64_t ImageLoader::fgTotalBindTime
;
58 uint64_t ImageLoader::fgTotalWeakBindTime
;
59 uint64_t ImageLoader::fgTotalDOF
;
60 uint64_t ImageLoader::fgTotalInitTime
;
61 uint16_t ImageLoader::fgLoadOrdinal
= 0;
62 uintptr_t ImageLoader::fgNextPIEDylibAddress
= 0;
66 ImageLoader::ImageLoader(const char* path
, unsigned int libCount
)
67 : fPath(path
), fDevice(0), fInode(0), fLastModified(0),
68 fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
69 fDynamicReferenceCount(0), fDynamicReferences(NULL
), fInitializerRecursiveLock(NULL
),
70 fDepth(0), fLoadOrder(0), fState(0), fLibraryCount(libCount
),
71 fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false),
72 fHideSymbols(false), fMatchByInstallName(false),
73 fRegisteredDOF(false), fAllLazyPointersBound(false), fBeingRemoved(false), fAddFuncNotified(false),
74 fPathOwnedByImage(false), fWeakSymbolsBound(false)
77 fPathHash
= hash(fPath
);
81 void ImageLoader::deleteImage(ImageLoader
* image
)
83 // this cannot be done in destructor because libImage() is implemented
85 for(unsigned int i
=0; i
< image
->libraryCount(); ++i
) {
86 ImageLoader
* lib
= image
->libImage(i
);
88 lib
->fStaticReferenceCount
--;
94 ImageLoader::~ImageLoader()
96 if ( fPathOwnedByImage
&& (fPath
!= NULL
) )
98 if ( fDynamicReferences
!= NULL
) {
99 for (std::set
<const ImageLoader
*>::iterator it
= fDynamicReferences
->begin(); it
!= fDynamicReferences
->end(); ++it
) {
100 const_cast<ImageLoader
*>(*it
)->fDynamicReferenceCount
--;
102 delete fDynamicReferences
;
106 void ImageLoader::setFileInfo(dev_t device
, ino_t inode
, time_t modDate
)
110 fLastModified
= modDate
;
113 void ImageLoader::setMapped(const LinkContext
& context
)
115 fState
= dyld_image_state_mapped
;
116 context
.notifySingle(dyld_image_state_mapped
, this); // note: can throw exception
119 void ImageLoader::addDynamicReference(const ImageLoader
* target
)
121 if ( fDynamicReferences
== NULL
)
122 fDynamicReferences
= new std::set
<const ImageLoader
*>();
123 if ( fDynamicReferences
->count(target
) == 0 ) {
124 fDynamicReferences
->insert(target
);
125 const_cast<ImageLoader
*>(target
)->fDynamicReferenceCount
++;
127 //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
130 int ImageLoader::compare(const ImageLoader
* right
) const
132 if ( this->fDepth
== right
->fDepth
) {
133 if ( this->fLoadOrder
== right
->fLoadOrder
)
135 else if ( this->fLoadOrder
< right
->fLoadOrder
)
141 if ( this->fDepth
< right
->fDepth
)
148 void ImageLoader::setPath(const char* path
)
150 if ( fPathOwnedByImage
&& (fPath
!= NULL
) )
152 fPath
= new char[strlen(path
)+1];
153 strcpy((char*)fPath
, path
);
154 fPathOwnedByImage
= true; // delete fPath when this image is destructed
155 fPathHash
= hash(fPath
);
158 void ImageLoader::setPathUnowned(const char* path
)
160 if ( fPathOwnedByImage
&& (fPath
!= NULL
) ) {
164 fPathOwnedByImage
= false;
165 fPathHash
= hash(fPath
);
169 uint32_t ImageLoader::hash(const char* path
)
171 // this does not need to be a great hash
172 // it is just used to reduce the number of strcmp() calls
173 // of existing images when loading a new image
175 for (const char* s
=path
; *s
!= '\0'; ++s
)
180 bool ImageLoader::matchInstallPath() const
182 return fMatchByInstallName
;
185 void ImageLoader::setMatchInstallPath(bool match
)
187 fMatchByInstallName
= match
;
190 bool ImageLoader::statMatch(const struct stat
& stat_buf
) const
192 return ( (this->fDevice
== stat_buf
.st_dev
) && (this->fInode
== stat_buf
.st_ino
) );
195 const char* ImageLoader::getShortName() const
197 // try to return leaf name
198 if ( fPath
!= NULL
) {
199 const char* s
= strrchr(fPath
, '/');
206 void ImageLoader::setLeaveMapped()
211 void ImageLoader::setHideExports(bool hide
)
216 bool ImageLoader::hasHiddenExports() const
221 bool ImageLoader::isLinked() const
223 return (fState
>= dyld_image_state_bound
);
226 time_t ImageLoader::lastModified() const
228 return fLastModified
;
231 bool ImageLoader::containsAddress(const void* addr
) const
233 if ( ! this->isLinked() )
235 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
236 const uint8_t* start
= (const uint8_t*)segActualLoadAddress(i
);
237 const uint8_t* end
= (const uint8_t*)segActualEndAddress(i
);
238 if ( (start
<= addr
) && (addr
< end
) && !segUnaccessible(i
) )
244 bool ImageLoader::overlapsWithAddressRange(const void* start
, const void* end
) const
246 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
247 const uint8_t* segStart
= (const uint8_t*)segActualLoadAddress(i
);
248 const uint8_t* segEnd
= (const uint8_t*)segActualEndAddress(i
);
249 if ( (start
<= segStart
) && (segStart
< end
) )
251 if ( (start
<= segEnd
) && (segEnd
< end
) )
253 if ( (segStart
< start
) && (end
< segEnd
) )
259 void ImageLoader::getMappedRegions(MappedRegion
*& regions
) const
261 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
263 region
.address
= segActualLoadAddress(i
);
264 region
.size
= segSize(i
);
270 static bool notInImgageList(const ImageLoader
* image
, const ImageLoader
** dsiStart
, const ImageLoader
** dsiCur
)
272 for (const ImageLoader
** p
= dsiStart
; p
< dsiCur
; ++p
)
279 // private method that handles circular dependencies by only search any image once
280 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name
,
281 const ImageLoader
** dsiStart
, const ImageLoader
**& dsiCur
, const ImageLoader
** dsiEnd
, const ImageLoader
** foundIn
) const
283 const ImageLoader::Symbol
* sym
;
286 if ( notInImgageList(this, dsiStart
, dsiCur
) ) {
287 sym
= this->findExportedSymbol(name
, false, foundIn
);
293 // search directly dependent libraries
294 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
295 ImageLoader
* dependentImage
= libImage(i
);
296 if ( (dependentImage
!= NULL
) && notInImgageList(dependentImage
, dsiStart
, dsiCur
) ) {
297 const ImageLoader::Symbol
* sym
= dependentImage
->findExportedSymbol(name
, false, foundIn
);
303 // search indirectly dependent libraries
304 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
305 ImageLoader
* dependentImage
= libImage(i
);
306 if ( (dependentImage
!= NULL
) && notInImgageList(dependentImage
, dsiStart
, dsiCur
) ) {
307 *dsiCur
++ = dependentImage
;
308 const ImageLoader::Symbol
* sym
= dependentImage
->findExportedSymbolInDependentImagesExcept(name
, dsiStart
, dsiCur
, dsiEnd
, foundIn
);
318 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInDependentImages(const char* name
, const LinkContext
& context
, const ImageLoader
** foundIn
) const
320 unsigned int imageCount
= context
.imageCount();
321 const ImageLoader
* dontSearchImages
[imageCount
];
322 dontSearchImages
[0] = this; // don't search this image
323 const ImageLoader
** cur
= &dontSearchImages
[1];
324 return this->findExportedSymbolInDependentImagesExcept(name
, &dontSearchImages
[0], cur
, &dontSearchImages
[imageCount
], foundIn
);
327 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name
, const LinkContext
& context
, const ImageLoader
** foundIn
) const
329 unsigned int imageCount
= context
.imageCount();
330 const ImageLoader
* dontSearchImages
[imageCount
];
331 const ImageLoader
** cur
= &dontSearchImages
[0];
332 return this->findExportedSymbolInDependentImagesExcept(name
, &dontSearchImages
[0], cur
, &dontSearchImages
[imageCount
], foundIn
);
336 void ImageLoader::link(const LinkContext
& context
, bool forceLazysBound
, bool preflightOnly
, const RPathChain
& loaderRPaths
)
338 //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
340 uint64_t t0
= mach_absolute_time();
341 this->recursiveLoadLibraries(context
, preflightOnly
, loaderRPaths
);
342 context
.notifyBatch(dyld_image_state_dependents_mapped
);
344 // we only do the loading step for preflights
348 uint64_t t1
= mach_absolute_time();
349 context
.clearAllDepths();
350 this->recursiveUpdateDepth(context
.imageCount());
352 uint64_t t2
= mach_absolute_time();
353 this->recursiveRebase(context
);
354 context
.notifyBatch(dyld_image_state_rebased
);
356 uint64_t t3
= mach_absolute_time();
357 this->recursiveBind(context
, forceLazysBound
);
359 uint64_t t4
= mach_absolute_time();
360 this->weakBind(context
);
361 context
.notifyBatch(dyld_image_state_bound
);
363 uint64_t t5
= mach_absolute_time();
364 std::vector
<DOFInfo
> dofs
;
365 this->recursiveGetDOFSections(context
, dofs
);
366 context
.registerDOFs(dofs
);
367 uint64_t t6
= mach_absolute_time();
370 fgTotalLoadLibrariesTime
+= t1
- t0
;
371 fgTotalRebaseTime
+= t3
- t2
;
372 fgTotalBindTime
+= t4
- t3
;
373 fgTotalWeakBindTime
+= t5
- t4
;
374 fgTotalDOF
+= t6
- t5
;
376 // done with initial dylib loads
377 fgNextPIEDylibAddress
= 0;
381 void ImageLoader::printReferenceCounts()
383 dyld::log(" dlopen=%d, static=%d, dynamic=%d for %s\n",
384 fDlopenReferenceCount
, fStaticReferenceCount
, fDynamicReferenceCount
, getPath() );
388 bool ImageLoader::decrementDlopenReferenceCount()
390 if ( fDlopenReferenceCount
== 0 )
392 --fDlopenReferenceCount
;
396 void ImageLoader::runInitializers(const LinkContext
& context
)
398 uint64_t t1
= mach_absolute_time();
399 mach_port_t this_thread
= mach_thread_self();
400 this->recursiveInitialization(context
, this_thread
);
401 context
.notifyBatch(dyld_image_state_initialized
);
402 mach_port_deallocate(mach_task_self(), this_thread
);
403 uint64_t t2
= mach_absolute_time();
404 fgTotalInitTime
+= (t2
- t1
);
408 void ImageLoader::bindAllLazyPointers(const LinkContext
& context
, bool recursive
)
410 if ( ! fAllLazyPointersBound
) {
411 fAllLazyPointersBound
= true;
414 // bind lower level libraries first
415 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
416 ImageLoader
* dependentImage
= libImage(i
);
417 if ( dependentImage
!= NULL
)
418 dependentImage
->bindAllLazyPointers(context
, recursive
);
421 // bind lazies in this image
422 this->doBindJustLazies(context
);
427 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
429 return fAllLibraryChecksumsAndLoadAddressesMatch
;
433 unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth
)
435 // the purpose of this phase is to make the images sortable such that
436 // in a sort list of images, every image that an image depends on
437 // occurs in the list before it.
442 // get depth of dependents
443 unsigned int minDependentDepth
= maxDepth
;
444 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
445 ImageLoader
* dependentImage
= libImage(i
);
446 if ( dependentImage
!= NULL
) {
447 unsigned int d
= dependentImage
->recursiveUpdateDepth(maxDepth
);
448 if ( d
< minDependentDepth
)
449 minDependentDepth
= d
;
453 // make me less deep then all my dependents
454 fDepth
= minDependentDepth
- 1;
461 void ImageLoader::recursiveLoadLibraries(const LinkContext
& context
, bool preflightOnly
, const RPathChain
& loaderRPaths
)
463 if ( fState
< dyld_image_state_dependents_mapped
) {
465 fState
= dyld_image_state_dependents_mapped
;
467 // get list of libraries this image needs
468 //dyld::log("ImageLoader::recursiveLoadLibraries() %ld = %d*%ld\n", fLibrariesCount*sizeof(DependentLibrary), fLibrariesCount, sizeof(DependentLibrary));
469 DependentLibraryInfo libraryInfos
[fLibraryCount
];
470 this->doGetDependentLibraries(libraryInfos
);
472 // get list of rpaths that this image adds
473 std::vector
<const char*> rpathsFromThisImage
;
474 this->getRPaths(context
, rpathsFromThisImage
);
475 const RPathChain
thisRPaths(&loaderRPaths
, &rpathsFromThisImage
);
478 bool canUsePrelinkingInfo
= true;
479 for(unsigned int i
=0; i
< fLibraryCount
; ++i
){
480 ImageLoader
* dependentLib
;
481 bool depLibReExported
= false;
482 bool depLibReRequired
= false;
483 bool depLibCheckSumsMatch
= false;
484 DependentLibraryInfo
& requiredLibInfo
= libraryInfos
[i
];
485 #if DYLD_SHARED_CACHE_SUPPORT
486 if ( preflightOnly
&& context
.inSharedCache(requiredLibInfo
.name
) ) {
487 // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
488 // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded
489 setLibImage(i
, NULL
, false);
494 dependentLib
= context
.loadLibrary(requiredLibInfo
.name
, true, this->getPath(), &thisRPaths
);
495 if ( dependentLib
== this ) {
496 // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168
497 dependentLib
= context
.loadLibrary(requiredLibInfo
.name
, false, NULL
, NULL
);
498 if ( dependentLib
!= this )
499 dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath());
502 dependentLib
->setNeverUnload();
503 dependentLib
->fStaticReferenceCount
+= 1;
504 LibraryInfo actualInfo
= dependentLib
->doGetLibraryInfo();
505 depLibReRequired
= requiredLibInfo
.required
;
506 depLibCheckSumsMatch
= ( actualInfo
.checksum
== requiredLibInfo
.info
.checksum
);
507 depLibReExported
= requiredLibInfo
.reExported
;
508 if ( ! depLibReExported
) {
509 // for pre-10.5 binaries that did not use LC_REEXPORT_DYLIB
510 depLibReExported
= dependentLib
->isSubframeworkOf(context
, this) || this->hasSubLibrary(context
, dependentLib
);
512 // check found library version is compatible
513 if ( actualInfo
.minVersion
< requiredLibInfo
.info
.minVersion
) {
514 dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
515 this->getShortName(), requiredLibInfo
.info
.minVersion
>> 16, (requiredLibInfo
.info
.minVersion
>> 8) & 0xff, requiredLibInfo
.info
.minVersion
& 0xff,
516 dependentLib
->getShortName(), actualInfo
.minVersion
>> 16, (actualInfo
.minVersion
>> 8) & 0xff, actualInfo
.minVersion
& 0xff);
518 // prebinding for this image disabled if any dependent library changed or slid
519 if ( !depLibCheckSumsMatch
|| (dependentLib
->getSlide() != 0) )
520 canUsePrelinkingInfo
= false;
521 //if ( context.verbosePrebinding ) {
522 // if ( !requiredLib.checksumMatches )
523 // fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n",
524 // requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(), dependentLib->getPath());
525 // if ( dependentLib->getSlide() != 0 )
526 // fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), dependentLib->getPath());
529 catch (const char* msg
) {
530 //if ( context.verbosePrebinding )
531 // fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());
532 if ( requiredLibInfo
.required
) {
533 fState
= dyld_image_state_mapped
;
534 dyld::throwf("Library not loaded: %s\n Referenced from: %s\n Reason: %s", requiredLibInfo
.name
, this->getPath(), msg
);
536 // ok if weak library not found
538 canUsePrelinkingInfo
= false; // this disables all prebinding, we may want to just slam import vectors for this lib to zero
540 setLibImage(i
, dependentLib
, depLibReExported
);
542 fAllLibraryChecksumsAndLoadAddressesMatch
= canUsePrelinkingInfo
;
544 // tell each to load its dependents
545 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
546 ImageLoader
* dependentImage
= libImage(i
);
547 if ( dependentImage
!= NULL
) {
548 dependentImage
->recursiveLoadLibraries(context
, preflightOnly
, thisRPaths
);
552 // do deep prebind check
553 if ( fAllLibraryChecksumsAndLoadAddressesMatch
) {
554 for(unsigned int i
=0; i
< libraryCount(); ++i
){
555 ImageLoader
* dependentImage
= libImage(i
);
556 if ( dependentImage
!= NULL
) {
557 if ( !dependentImage
->allDependentLibrariesAsWhenPreBound() )
558 fAllLibraryChecksumsAndLoadAddressesMatch
= false;
563 // free rpaths (getRPaths() malloc'ed each string)
564 for(std::vector
<const char*>::iterator it
=rpathsFromThisImage
.begin(); it
!= rpathsFromThisImage
.end(); ++it
) {
565 const char* str
= *it
;
572 void ImageLoader::recursiveRebase(const LinkContext
& context
)
574 if ( fState
< dyld_image_state_rebased
) {
576 fState
= dyld_image_state_rebased
;
579 // rebase lower level libraries first
580 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
581 ImageLoader
* dependentImage
= libImage(i
);
582 if ( dependentImage
!= NULL
)
583 dependentImage
->recursiveRebase(context
);
590 context
.notifySingle(dyld_image_state_rebased
, this);
592 catch (const char* msg
) {
593 // this image is not rebased
594 fState
= dyld_image_state_dependents_mapped
;
603 void ImageLoader::recursiveBind(const LinkContext
& context
, bool forceLazysBound
)
605 // Normally just non-lazy pointers are bound immediately.
606 // The exceptions are:
607 // 1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately
608 // 2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately
609 if ( fState
< dyld_image_state_bound
) {
611 fState
= dyld_image_state_bound
;
614 // bind lower level libraries first
615 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
616 ImageLoader
* dependentImage
= libImage(i
);
617 if ( dependentImage
!= NULL
)
618 dependentImage
->recursiveBind(context
, forceLazysBound
);
621 this->doBind(context
, forceLazysBound
);
622 // mark if lazys are also bound
623 if ( forceLazysBound
|| this->usablePrebinding(context
) )
624 fAllLazyPointersBound
= true;
626 context
.notifySingle(dyld_image_state_bound
, this);
628 catch (const char* msg
) {
630 fState
= dyld_image_state_rebased
;
636 void ImageLoader::weakBind(const LinkContext
& context
)
638 if ( context
.verboseWeakBind
)
639 dyld::log("dyld: weak bind start:\n");
640 // get set of ImageLoaders that participate in coalecsing
641 ImageLoader
* imagesNeedingCoalescing
[fgImagesRequiringCoalescing
];
642 int count
= context
.getCoalescedImages(imagesNeedingCoalescing
);
644 // count how many have not already had weakbinding done
645 int countNotYetWeakBound
= 0;
646 int countOfImagesWithWeakDefinitions
= 0;
647 for(int i
=0; i
< count
; ++i
) {
648 if ( ! imagesNeedingCoalescing
[i
]->fWeakSymbolsBound
)
649 ++countNotYetWeakBound
;
650 if ( imagesNeedingCoalescing
[i
]->hasCoalescedExports() )
651 ++countOfImagesWithWeakDefinitions
;
654 // don't need to do any coalescing if only one image has overrides, or all have already been done
655 if ( (countOfImagesWithWeakDefinitions
> 1) && (countNotYetWeakBound
> 0) ) {
656 // make symbol iterators for each
657 ImageLoader::CoalIterator iterators
[count
];
658 ImageLoader::CoalIterator
* sortedIts
[count
];
659 for(int i
=0; i
< count
; ++i
) {
660 imagesNeedingCoalescing
[i
]->initializeCoalIterator(iterators
[i
], i
);
661 sortedIts
[i
] = &iterators
[i
];
662 if ( context
.verboseWeakBind
)
663 dyld::log("dyld: weak bind load order %d/%d for %s\n", i
, count
, imagesNeedingCoalescing
[i
]->getPath());
666 // walk all symbols keeping iterators in sync by
667 // only ever incrementing the iterator with the lowest symbol
669 while ( doneCount
!= count
) {
670 //for(int i=0; i < count; ++i)
671 // dyld::log("sym[%d]=%s ", sortedIts[i]->loadOrder, sortedIts[i]->symbolName);
673 // increment iterator with lowest symbol
674 if ( sortedIts
[0]->image
->incrementCoalIterator(*sortedIts
[0]) )
677 for(int i
=1; i
< count
; ++i
) {
678 int result
= strcmp(sortedIts
[i
-1]->symbolName
, sortedIts
[i
]->symbolName
);
680 sortedIts
[i
-1]->symbolMatches
= true;
682 // new one is bigger then next, so swap
683 ImageLoader::CoalIterator
* temp
= sortedIts
[i
-1];
684 sortedIts
[i
-1] = sortedIts
[i
];
690 // process all matching symbols just before incrementing the lowest one that matches
691 if ( sortedIts
[0]->symbolMatches
&& !sortedIts
[0]->done
) {
692 const char* nameToCoalesce
= sortedIts
[0]->symbolName
;
693 // pick first symbol in load order (and non-weak overrides weak)
694 uintptr_t targetAddr
= 0;
695 ImageLoader
* targetImage
= NULL
;
696 for(int i
=0; i
< count
; ++i
) {
697 if ( strcmp(iterators
[i
].symbolName
, nameToCoalesce
) == 0 ) {
698 if ( context
.verboseWeakBind
)
699 dyld::log("dyld: weak bind, found %s weak=%d in %s \n", nameToCoalesce
, iterators
[i
].weakSymbol
, iterators
[i
].image
->getPath());
700 if ( iterators
[i
].weakSymbol
) {
701 if ( targetAddr
== 0 ) {
702 targetAddr
= iterators
[i
].image
->getAddressCoalIterator(iterators
[i
], context
);
703 if ( targetAddr
!= 0 )
704 targetImage
= iterators
[i
].image
;
708 targetAddr
= iterators
[i
].image
->getAddressCoalIterator(iterators
[i
], context
);
709 if ( targetAddr
!= 0 ) {
710 targetImage
= iterators
[i
].image
;
711 // strong implementation found, stop searching
717 if ( context
.verboseWeakBind
)
718 dyld::log("dyld: weak binding all uses of %s to copy from %s\n", nameToCoalesce
, targetImage
->getShortName());
720 // tell each to bind to this symbol (unless already bound)
721 if ( targetAddr
!= 0 ) {
722 for(int i
=0; i
< count
; ++i
) {
723 if ( strcmp(iterators
[i
].symbolName
, nameToCoalesce
) == 0 ) {
724 if ( context
.verboseWeakBind
)
725 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());
726 if ( ! iterators
[i
].image
->fWeakSymbolsBound
)
727 iterators
[i
].image
->updateUsesCoalIterator(iterators
[i
], targetAddr
, targetImage
, context
);
728 iterators
[i
].symbolMatches
= false;
736 // mark all as having all weak symbols bound
737 for(int i
=0; i
< count
; ++i
) {
738 imagesNeedingCoalescing
[i
]->fWeakSymbolsBound
= true;
741 if ( context
.verboseWeakBind
)
742 dyld::log("dyld: weak bind end\n");
747 void ImageLoader::recursiveGetDOFSections(const LinkContext
& context
, std::vector
<DOFInfo
>& dofs
)
749 if ( ! fRegisteredDOF
) {
751 fRegisteredDOF
= true;
753 // gather lower level libraries first
754 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
755 ImageLoader
* dependentImage
= libImage(i
);
756 if ( dependentImage
!= NULL
)
757 dependentImage
->recursiveGetDOFSections(context
, dofs
);
759 this->doGetDOFSections(context
, dofs
);
764 void ImageLoader::recursiveSpinLock(recursive_lock
& rlock
)
766 // try to set image's ivar fInitializerRecursiveLock to point to this lock_info
767 // keep trying until success (spin)
768 while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL
, &rlock
, (void**)&fInitializerRecursiveLock
) ) {
769 // if fInitializerRecursiveLock already points to a different lock_info, if it is for
770 // the same thread we are on, the increment the lock count, otherwise continue to spin
771 if ( (fInitializerRecursiveLock
!= NULL
) && (fInitializerRecursiveLock
->thread
== rlock
.thread
) )
774 ++(fInitializerRecursiveLock
->count
);
777 void ImageLoader::recursiveSpinUnLock()
779 if ( --(fInitializerRecursiveLock
->count
) == 0 )
780 fInitializerRecursiveLock
= NULL
;
784 void ImageLoader::recursiveInitialization(const LinkContext
& context
, mach_port_t this_thread
)
786 recursive_lock
lock_info(this_thread
);
787 recursiveSpinLock(lock_info
);
789 if ( fState
< dyld_image_state_dependents_initialized
-1 ) {
790 uint8_t oldState
= fState
;
792 fState
= dyld_image_state_dependents_initialized
-1;
794 // initialize lower level libraries first
795 for(unsigned int i
=0; i
< libraryCount(); ++i
) {
796 ImageLoader
* dependentImage
= libImage(i
);
797 if ( dependentImage
!= NULL
)
798 // don't try to initialize stuff "above" me
799 if ( (dependentImage
!= NULL
) && (dependentImage
->fDepth
>= fDepth
) )
800 dependentImage
->recursiveInitialization(context
, this_thread
);
803 // record termination order
804 if ( this->needsTermination() )
805 context
.terminationRecorder(this);
807 // let objc know we are about to initalize this image
808 fState
= dyld_image_state_dependents_initialized
;
810 context
.notifySingle(dyld_image_state_dependents_initialized
, this);
812 // initialize this image
813 this->doInitialization(context
);
815 // let anyone know we finished initalizing this image
816 fState
= dyld_image_state_initialized
;
818 context
.notifySingle(dyld_image_state_initialized
, this);
820 catch (const char* msg
) {
821 // this image is not initialized
823 recursiveSpinUnLock();
828 recursiveSpinUnLock();
832 static void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
834 static uint64_t sUnitsPerSecond
= 0;
835 if ( sUnitsPerSecond
== 0 ) {
836 struct mach_timebase_info timeBaseInfo
;
837 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
838 sUnitsPerSecond
= 1000000000ULL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
841 if ( partTime
< sUnitsPerSecond
) {
842 uint32_t milliSecondsTimesHundred
= (partTime
*100000)/sUnitsPerSecond
;
843 uint32_t milliSeconds
= milliSecondsTimesHundred
/100;
844 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
845 uint32_t percent
= percentTimesTen
/10;
846 dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimesHundred
-milliSeconds
*100, percent
, percentTimesTen
-percent
*10);
849 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
850 uint32_t seconds
= secondsTimeTen
/10;
851 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
852 uint32_t percent
= percentTimesTen
/10;
853 dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
857 static char* commatize(uint64_t in
, char* out
)
859 uint64_t div10
= in
/ 10;
860 uint8_t delta
= in
- div10
*10;
864 *(--s
) = '0' + delta
;
867 if ( (digitCount
% 3) == 0 )
870 delta
= in
- div10
*10;
871 *(--s
) = '0' + delta
;
879 void ImageLoader::printStatistics(unsigned int imageCount
)
881 uint64_t totalTime
= fgTotalLoadLibrariesTime
+ fgTotalRebaseTime
+ fgTotalBindTime
+ fgTotalWeakBindTime
+ fgTotalDOF
+ fgTotalInitTime
;
885 printTime("total time", totalTime
, totalTime
);
886 dyld::log("total images loaded: %d (%u from dyld shared cache, %u needed no fixups)\n", imageCount
, fgImagesUsedFromSharedCache
, fgImagesRequiringNoFixups
);
887 dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped
, fgTotalBytesMapped
/4096, fgTotalBytesPreFetched
/4096);
888 printTime("total images loading time", fgTotalLoadLibrariesTime
, totalTime
);
889 printTime("total dtrace DOF registration time", fgTotalDOF
, totalTime
);
890 dyld::log("total rebase fixups: %s\n", commatize(fgTotalRebaseFixups
, commaNum1
));
891 printTime("total rebase fixups time", fgTotalRebaseTime
, totalTime
);
892 dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups
, commaNum1
));
893 if ( fgTotalBindSymbolsResolved
!= 0 ) {
894 uint32_t avgTimesTen
= (fgTotalBindImageSearches
* 10) / fgTotalBindSymbolsResolved
;
895 uint32_t avgInt
= fgTotalBindImageSearches
/ fgTotalBindSymbolsResolved
;
896 uint32_t avgTenths
= avgTimesTen
- (avgInt
*10);
897 dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n",
898 commatize(fgTotalBindSymbolsResolved
, commaNum1
), avgInt
, avgTenths
);
900 printTime("total binding fixups time", fgTotalBindTime
, totalTime
);
901 printTime("total weak binding fixups time", fgTotalWeakBindTime
, totalTime
);
902 dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups
, commaNum1
), commatize(fgTotalPossibleLazyBindFixups
, commaNum2
));
903 printTime("total initializer time", fgTotalInitTime
, totalTime
);
908 // copy path and add suffix to result
910 // /path/foo.dylib _debug => /path/foo_debug.dylib
911 // foo.dylib _debug => foo_debug.dylib
912 // foo _debug => foo_debug
913 // /path/bar _debug => /path/bar_debug
914 // /path/bar.A.dylib _debug => /path/bar.A_debug.dylib
916 void ImageLoader::addSuffix(const char* path
, const char* suffix
, char* result
)
918 strcpy(result
, path
);
920 char* start
= strrchr(result
, '/');
926 char* dot
= strrchr(start
, '.');
929 strcat(&dot
[strlen(suffix
)], &path
[dot
-result
]);
932 strcat(result
, suffix
);