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 extern "C" void _spin_lock(uint32_t*);
42 extern "C" void _spin_unlock(uint32_t*);
44 uint32_t ImageLoader::fgImagesUsedFromSharedCache
= 0;
45 uint32_t ImageLoader::fgImagesWithUsedPrebinding
= 0;
46 uint32_t ImageLoader::fgImagesRequiringNoFixups
= 0;
47 uint32_t ImageLoader::fgTotalRebaseFixups
= 0;
48 uint32_t ImageLoader::fgTotalBindFixups
= 0;
49 uint32_t ImageLoader::fgTotalBindSymbolsResolved
= 0;
50 uint32_t ImageLoader::fgTotalBindImageSearches
= 0;
51 uint32_t ImageLoader::fgTotalLazyBindFixups
= 0;
52 uint32_t ImageLoader::fgTotalPossibleLazyBindFixups
= 0;
53 uint32_t ImageLoader::fgTotalSegmentsMapped
= 0;
54 uint64_t ImageLoader::fgTotalBytesMapped
= 0;
55 uint64_t ImageLoader::fgTotalBytesPreFetched
= 0;
56 uint64_t ImageLoader::fgTotalLoadLibrariesTime
;
57 uint64_t ImageLoader::fgTotalRebaseTime
;
58 uint64_t ImageLoader::fgTotalBindTime
;
59 uint64_t ImageLoader::fgTotalInitTime
;
60 uintptr_t ImageLoader::fgNextSplitSegAddress
= 0x90000000;
61 uint16_t ImageLoader::fgLoadOrdinal
= 0;
62 uintptr_t Segment::fgNextPIEDylibAddress
= 0;
65 void ImageLoader::init(const char* path
, uint64_t offsetInFat
, dev_t device
, ino_t inode
, time_t modDate
)
72 fLastModified
= modDate
;
73 fOffsetInFatFile
= offsetInFat
;
76 fDlopenReferenceCount
= 0;
77 fStaticReferenceCount
= 0;
78 fDynamicReferenceCount
= 0;
79 fDynamicReferences
= NULL
;
81 fLoadOrder
= fgLoadOrdinal
++;
83 fAllLibraryChecksumsAndLoadAddressesMatch
= false;
87 fMatchByInstallName
= false;
88 fRegisteredDOF
= false;
89 #if IMAGE_NOTIFY_SUPPORT
92 fAllLazyPointersBound
= false;
93 fBeingRemoved
= false;
94 fPathOwnedByImage
= false;
95 #if RECURSIVE_INITIALIZER_LOCK
96 fInitializerRecursiveLock
= NULL
;
101 fPathHash
= hash(fPath
);
105 ImageLoader::ImageLoader(const char* path
, uint64_t offsetInFat
, const struct stat
& info
)
107 init(path
, offsetInFat
, info
.st_dev
, info
.st_ino
, info
.st_mtime
);
110 ImageLoader::ImageLoader(const char* moduleName
)
112 init(moduleName
, 0, 0, 0, 0);
116 ImageLoader::~ImageLoader()
118 if ( fPathOwnedByImage
&& (fPath
!= NULL
) )
120 if ( fLogicalPath
!= NULL
)
121 delete [] fLogicalPath
;
122 if ( fLibraries
!= NULL
) {
123 for (uint32_t i
= 0; i
< fLibrariesCount
; ++i
) {
124 if ( fLibraries
[i
].image
!= NULL
)
125 fLibraries
[i
].image
->fStaticReferenceCount
--;
127 delete [] fLibraries
;
129 if ( fDynamicReferences
!= NULL
) {
130 for (std::set
<const ImageLoader
*>::iterator it
= fDynamicReferences
->begin(); it
!= fDynamicReferences
->end(); ++it
) {
131 const_cast<ImageLoader
*>(*it
)->fDynamicReferenceCount
--;
133 delete fDynamicReferences
;
137 void ImageLoader::setMapped(const LinkContext
& context
)
139 fState
= dyld_image_state_mapped
;
140 context
.notifySingle(dyld_image_state_mapped
, this->machHeader(), fPath
, fLastModified
);
143 void ImageLoader::addDynamicReference(const ImageLoader
* target
)
145 if ( fDynamicReferences
== NULL
)
146 fDynamicReferences
= new std::set
<const ImageLoader
*>();
147 if ( fDynamicReferences
->count(target
) == 0 ) {
148 fDynamicReferences
->insert(target
);
149 const_cast<ImageLoader
*>(target
)->fDynamicReferenceCount
++;
151 //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
154 int ImageLoader::compare(const ImageLoader
* right
) const
156 if ( this->fDepth
== right
->fDepth
) {
157 if ( this->fLoadOrder
== right
->fLoadOrder
)
159 else if ( this->fLoadOrder
< right
->fLoadOrder
)
165 if ( this->fDepth
< right
->fDepth
)
172 void ImageLoader::setPath(const char* path
)
174 if ( fPathOwnedByImage
&& (fPath
!= NULL
) )
176 fPath
= new char[strlen(path
)+1];
177 strcpy((char*)fPath
, path
);
178 fPathOwnedByImage
= true; // delete fPath when this image is destructed
179 fPathHash
= hash(fPath
);
182 void ImageLoader::setPathUnowned(const char* path
)
184 if ( fPathOwnedByImage
&& (fPath
!= NULL
) ) {
188 fPathOwnedByImage
= false;
189 fPathHash
= hash(fPath
);
192 void ImageLoader::setLogicalPath(const char* path
)
194 if ( fPath
== NULL
) {
195 // no physical path set yet, so use this path as physical
198 else if ( strcmp(path
, fPath
) == 0 ) {
199 // do not set logical path because it is the same as the physical path
203 fLogicalPath
= new char[strlen(path
)+1];
204 strcpy((char*)fLogicalPath
, path
);
208 const char* ImageLoader::getLogicalPath() const
210 if ( fLogicalPath
!= NULL
)
216 uint32_t ImageLoader::hash(const char* path
)
218 // this does not need to be a great hash
219 // it is just used to reduce the number of strcmp() calls
220 // of existing images when loading a new image
222 for (const char* s
=path
; *s
!= '\0'; ++s
)
227 bool ImageLoader::matchInstallPath() const
229 return fMatchByInstallName
;
232 void ImageLoader::setMatchInstallPath(bool match
)
234 fMatchByInstallName
= match
;
237 bool ImageLoader::statMatch(const struct stat
& stat_buf
) const
239 return ( (this->fDevice
== stat_buf
.st_dev
) && (this->fInode
== stat_buf
.st_ino
) );
242 const char* ImageLoader::getShortName() const
244 // try to return leaf name
245 if ( fPath
!= NULL
) {
246 const char* s
= strrchr(fPath
, '/');
253 uint64_t ImageLoader::getOffsetInFatFile() const
255 return fOffsetInFatFile
;
258 void ImageLoader::setLeaveMapped()
263 void ImageLoader::setHideExports(bool hide
)
268 bool ImageLoader::hasHiddenExports() const
273 bool ImageLoader::isLinked() const
275 return (fState
>= dyld_image_state_bound
);
278 time_t ImageLoader::lastModified() const
280 return fLastModified
;
283 bool ImageLoader::containsAddress(const void* addr
) const
285 if ( ! this->isLinked() )
287 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
289 const uint8_t* start
= (const uint8_t*)seg
->getActualLoadAddress(this);
290 const uint8_t* end
= start
+ seg
->getSize();
291 if ( (start
<= addr
) && (addr
< end
) && !seg
->unaccessible() )
297 bool ImageLoader::overlapsWithAddressRange(const void* start
, const void* end
) const
299 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
301 const uint8_t* segStart
= (const uint8_t*)(seg
->getActualLoadAddress(this));
302 const uint8_t* segEnd
= segStart
+ seg
->getSize();
303 if ( (start
<= segStart
) && (segStart
< end
) )
305 if ( (start
<= segEnd
) && (segEnd
< end
) )
307 if ( (segStart
< start
) && (end
< segEnd
) )
313 void ImageLoader::getMappedRegions(MappedRegion
*& regions
) const
315 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
318 region
.address
= seg
->getActualLoadAddress(this);
319 region
.size
= seg
->getSize();
325 static bool notInImgageList(const ImageLoader
* image
, const ImageLoader
** dsiStart
, const ImageLoader
** dsiCur
)
327 for (const ImageLoader
** p
= dsiStart
; p
< dsiCur
; ++p
)
334 // private method that handles circular dependencies by only search any image once
335 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name
,
336 const ImageLoader
** dsiStart
, const ImageLoader
**& dsiCur
, const ImageLoader
** dsiEnd
, const ImageLoader
** foundIn
) const
338 const ImageLoader::Symbol
* sym
;
341 if ( notInImgageList(this, dsiStart
, dsiCur
) ) {
342 sym
= this->findExportedSymbol(name
, NULL
, false, foundIn
);
348 // search directly dependent libraries
349 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
350 ImageLoader
* dependentImage
= fLibraries
[i
].image
;
351 if ( (dependentImage
!= NULL
) && notInImgageList(dependentImage
, dsiStart
, dsiCur
) ) {
352 const ImageLoader::Symbol
* sym
= dependentImage
->findExportedSymbol(name
, NULL
, false, foundIn
);
358 // search indirectly dependent libraries
359 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
360 ImageLoader
* dependentImage
= fLibraries
[i
].image
;
361 if ( (dependentImage
!= NULL
) && notInImgageList(dependentImage
, dsiStart
, dsiCur
) ) {
362 *dsiCur
++ = dependentImage
;
363 const ImageLoader::Symbol
* sym
= dependentImage
->findExportedSymbolInDependentImagesExcept(name
, dsiStart
, dsiCur
, dsiEnd
, foundIn
);
373 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInDependentImages(const char* name
, const LinkContext
& context
, const ImageLoader
** foundIn
) const
375 unsigned int imageCount
= context
.imageCount();
376 const ImageLoader
* dontSearchImages
[imageCount
];
377 dontSearchImages
[0] = this; // don't search this image
378 const ImageLoader
** cur
= &dontSearchImages
[1];
379 return this->findExportedSymbolInDependentImagesExcept(name
, &dontSearchImages
[0], cur
, &dontSearchImages
[imageCount
], foundIn
);
382 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name
, const LinkContext
& context
, const ImageLoader
** foundIn
) const
384 unsigned int imageCount
= context
.imageCount();
385 const ImageLoader
* dontSearchImages
[imageCount
];
386 const ImageLoader
** cur
= &dontSearchImages
[0];
387 return this->findExportedSymbolInDependentImagesExcept(name
, &dontSearchImages
[0], cur
, &dontSearchImages
[imageCount
], foundIn
);
391 void ImageLoader::link(const LinkContext
& context
, bool forceLazysBound
, bool preflightOnly
, const RPathChain
& loaderRPaths
)
393 //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
395 uint64_t t0
= mach_absolute_time();
396 this->recursiveLoadLibraries(context
,loaderRPaths
);
397 context
.notifyBatch(dyld_image_state_dependents_mapped
);
399 // we only do the loading step for preflights
403 uint64_t t1
= mach_absolute_time();
404 context
.clearAllDepths();
405 this->recursiveUpdateDepth(context
.imageCount());
407 uint64_t t2
= mach_absolute_time();
408 this->recursiveRebase(context
);
409 context
.notifyBatch(dyld_image_state_rebased
);
411 uint64_t t3
= mach_absolute_time();
412 this->recursiveBind(context
, forceLazysBound
);
413 context
.notifyBatch(dyld_image_state_bound
);
415 uint64_t t4
= mach_absolute_time();
416 std::vector
<DOFInfo
> dofs
;
417 this->recursiveGetDOFSections(context
, dofs
);
418 context
.registerDOFs(dofs
);
421 fgTotalLoadLibrariesTime
+= t1
- t0
;
422 fgTotalRebaseTime
+= t3
- t2
;
423 fgTotalBindTime
+= t4
- t3
;
425 // done with initial dylib loads
426 Segment::fgNextPIEDylibAddress
= 0;
430 void ImageLoader::printReferenceCounts()
432 dyld::log(" dlopen=%d, static=%d, dynamic=%d for %s\n",
433 fDlopenReferenceCount
, fStaticReferenceCount
, fDynamicReferenceCount
, getPath() );
437 bool ImageLoader::decrementDlopenReferenceCount()
439 if ( fDlopenReferenceCount
== 0 )
441 --fDlopenReferenceCount
;
445 void ImageLoader::runInitializers(const LinkContext
& context
)
447 #if IMAGE_NOTIFY_SUPPORT
448 ImageLoader
* newImages
[context
.imageCount()];
449 ImageLoader
** end
= newImages
;
450 this->recursiveImageAnnouncement(context
, end
); // build bottom up list images being added
451 context
.notifyAdding(newImages
, end
-newImages
); // tell anyone who cares about these
454 uint64_t t1
= mach_absolute_time();
455 this->recursiveInitialization(context
, mach_thread_self());
456 context
.notifyBatch(dyld_image_state_initialized
);
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;
468 // bind lower level libraries first
469 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
470 DependentLibrary
& libInfo
= fLibraries
[i
];
471 if ( libInfo
.image
!= NULL
)
472 libInfo
.image
->bindAllLazyPointers(context
, recursive
);
475 // bind lazys in this image
476 this->doBind(context
, true);
481 intptr_t ImageLoader::assignSegmentAddresses(const LinkContext
& context
)
483 // preflight and calculate slide if needed
485 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
486 bool needsToSlide
= false;
487 uintptr_t lowAddr
= UINTPTR_MAX
;
488 uintptr_t highAddr
= 0;
489 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
491 const uintptr_t segLow
= seg
->getPreferredLoadAddress();
492 const uintptr_t segHigh
= (segLow
+ seg
->getSize() + 4095) & -4096;
493 if ( segLow
< lowAddr
)
495 if ( segHigh
> highAddr
)
498 if ( !seg
->hasPreferredLoadAddress() || !Segment::reserveAddressRange(seg
->getPreferredLoadAddress(), seg
->getSize()) )
501 if ( needsToSlide
) {
502 // find a chunk of address space to hold all segments
503 uintptr_t addr
= Segment::reserveAnAddressRange(highAddr
-lowAddr
, context
);
504 slide
= addr
- lowAddr
;
507 else if ( ! this->segmentsCanSlide() ) {
508 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
510 if ( strcmp(seg
->getName(), "__PAGEZERO") == 0 )
512 if ( !Segment::reserveAddressRange(seg
->getPreferredLoadAddress(), seg
->getSize()) )
517 // mach-o does not support independently sliding segments
523 void ImageLoader::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
525 if ( context
.verboseMapping
)
526 dyld::log("dyld: Mapping %s\n", this->getPath());
527 // find address range for image
528 intptr_t slide
= this->assignSegmentAddresses(context
);
529 // map in all segments
530 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
532 seg
->map(fd
, offsetInFat
, slide
, this, context
);
534 // update slide to reflect load location
535 this->setSlide(slide
);
538 void ImageLoader::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
)
540 if ( context
.verboseMapping
)
541 dyld::log("dyld: Mapping memory %p\n", memoryImage
);
542 // find address range for image
543 intptr_t slide
= this->assignSegmentAddresses(context
);
544 // map in all segments
545 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
547 seg
->map(memoryImage
, slide
, this, context
);
549 // update slide to reflect load location
550 this->setSlide(slide
);
551 // set R/W permissions on all segments at slide location
552 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
554 seg
->setPermissions(context
, this);
558 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
560 return fAllLibraryChecksumsAndLoadAddressesMatch
;
564 unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth
)
566 // the purpose of this phase is to make the images sortable such that
567 // in a sort list of images, every image that an image depends on
568 // occurs in the list before it.
573 // get depth of dependents
574 unsigned int minDependentDepth
= maxDepth
;
575 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
) {
576 DependentLibrary
& libInfo
= fLibraries
[i
];
577 if ( libInfo
.image
!= NULL
) {
578 unsigned int d
= libInfo
.image
->recursiveUpdateDepth(maxDepth
);
579 if ( d
< minDependentDepth
)
580 minDependentDepth
= d
;
584 // make me less deep then all my dependents
585 fDepth
= minDependentDepth
- 1;
592 void ImageLoader::recursiveLoadLibraries(const LinkContext
& context
, const RPathChain
& loaderRPaths
)
594 if ( fState
< dyld_image_state_dependents_mapped
) {
596 fState
= dyld_image_state_dependents_mapped
;
598 // get list of libraries this image needs
599 fLibrariesCount
= this->doGetDependentLibraryCount();
600 fLibraries
= new DependentLibrary
[fLibrariesCount
];
601 bzero(fLibraries
, sizeof(DependentLibrary
)*fLibrariesCount
);
602 DependentLibraryInfo libraryInfos
[fLibrariesCount
];
603 this->doGetDependentLibraries(libraryInfos
);
605 // get list of rpaths that this image adds
606 std::vector
<const char*> rpathsFromThisImage
;
607 this->getRPaths(context
, rpathsFromThisImage
);
608 const RPathChain
thisRPaths(&loaderRPaths
, &rpathsFromThisImage
);
611 bool canUsePrelinkingInfo
= true;
612 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
613 DependentLibrary
& requiredLib
= fLibraries
[i
];
614 DependentLibraryInfo
& requiredLibInfo
= libraryInfos
[i
];
616 bool depNamespace
= false;
617 requiredLib
.image
= context
.loadLibrary(requiredLibInfo
.name
, true, depNamespace
, this->getPath(), &thisRPaths
);
618 if ( requiredLib
.image
== this ) {
619 // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168
620 requiredLib
.image
= context
.loadLibrary(requiredLibInfo
.name
, false, depNamespace
, NULL
, NULL
);
621 if ( requiredLib
.image
!= this )
622 dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath());
625 requiredLib
.image
->setNeverUnload();
626 requiredLib
.image
->fStaticReferenceCount
+= 1;
627 LibraryInfo actualInfo
= requiredLib
.image
->doGetLibraryInfo();
628 requiredLib
.required
= requiredLibInfo
.required
;
629 requiredLib
.checksumMatches
= ( actualInfo
.checksum
== requiredLibInfo
.info
.checksum
);
630 requiredLib
.isReExported
= requiredLibInfo
.reExported
;
631 if ( ! requiredLib
.isReExported
) {
632 requiredLib
.isSubFramework
= requiredLib
.image
->isSubframeworkOf(context
, this);
633 requiredLib
.isReExported
= requiredLib
.isSubFramework
|| this->hasSubLibrary(context
, requiredLib
.image
);
635 // check found library version is compatible
636 if ( actualInfo
.minVersion
< requiredLibInfo
.info
.minVersion
) {
637 dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
638 this->getShortName(), requiredLibInfo
.info
.minVersion
>> 16, (requiredLibInfo
.info
.minVersion
>> 8) & 0xff, requiredLibInfo
.info
.minVersion
& 0xff,
639 requiredLib
.image
->getShortName(), actualInfo
.minVersion
>> 16, (actualInfo
.minVersion
>> 8) & 0xff, actualInfo
.minVersion
& 0xff);
641 // prebinding for this image disabled if any dependent library changed or slid
642 if ( !requiredLib
.checksumMatches
|| (requiredLib
.image
->getSlide() != 0) )
643 canUsePrelinkingInfo
= false;
644 //if ( context.verbosePrebinding ) {
645 // if ( !requiredLib.checksumMatches )
646 // fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n",
647 // requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(), requiredLib.image->getPath());
648 // if ( requiredLib.image->getSlide() != 0 )
649 // fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), requiredLib.image->getPath());
652 catch (const char* msg
) {
653 //if ( context.verbosePrebinding )
654 // fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), requiredLib.image->getPath());
655 if ( requiredLibInfo
.required
) {
656 fState
= dyld_image_state_mapped
;
657 dyld::throwf("Library not loaded: %s\n Referenced from: %s\n Reason: %s", requiredLibInfo
.name
, this->getPath(), msg
);
659 // ok if weak library not found
660 requiredLib
.image
= NULL
;
661 canUsePrelinkingInfo
= false; // this disables all prebinding, we may want to just slam import vectors for this lib to zero
664 fAllLibraryChecksumsAndLoadAddressesMatch
= canUsePrelinkingInfo
;
666 // tell each to load its dependents
667 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
668 DependentLibrary
& lib
= fLibraries
[i
];
669 if ( lib
.image
!= NULL
) {
670 lib
.image
->recursiveLoadLibraries(context
, thisRPaths
);
674 // do deep prebind check
675 if ( fAllLibraryChecksumsAndLoadAddressesMatch
) {
676 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
677 const DependentLibrary
& libInfo
= fLibraries
[i
];
678 if ( libInfo
.image
!= NULL
) {
679 if ( !libInfo
.image
->allDependentLibrariesAsWhenPreBound() )
680 fAllLibraryChecksumsAndLoadAddressesMatch
= false;
685 // free rpaths (getRPaths() malloc'ed each string)
686 for(std::vector
<const char*>::iterator it
=rpathsFromThisImage
.begin(); it
!= rpathsFromThisImage
.end(); ++it
) {
687 const char* str
= *it
;
694 void ImageLoader::recursiveRebase(const LinkContext
& context
)
696 if ( fState
< dyld_image_state_rebased
) {
698 fState
= dyld_image_state_rebased
;
701 // rebase lower level libraries first
702 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
703 DependentLibrary
& libInfo
= fLibraries
[i
];
704 if ( libInfo
.image
!= NULL
)
705 libInfo
.image
->recursiveRebase(context
);
712 context
.notifySingle(dyld_image_state_rebased
, this->machHeader(), fPath
, fLastModified
);
714 catch (const char* msg
) {
715 // this image is not rebased
716 fState
= dyld_image_state_dependents_mapped
;
725 void ImageLoader::recursiveBind(const LinkContext
& context
, bool forceLazysBound
)
727 // Normally just non-lazy pointers are bound immediately.
728 // The exceptions are:
729 // 1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately
730 // 2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately
731 if ( fState
< dyld_image_state_bound
) {
733 fState
= dyld_image_state_bound
;
736 // bind lower level libraries first
737 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
738 DependentLibrary
& libInfo
= fLibraries
[i
];
739 if ( libInfo
.image
!= NULL
)
740 libInfo
.image
->recursiveBind(context
, forceLazysBound
);
743 this->doBind(context
, forceLazysBound
);
744 this->doUpdateMappingPermissions(context
);
745 // mark if lazys are also bound
746 if ( forceLazysBound
|| this->usablePrebinding(context
) )
747 fAllLazyPointersBound
= true;
749 context
.notifySingle(dyld_image_state_bound
, this->machHeader(), fPath
, fLastModified
);
751 catch (const char* msg
) {
753 fState
= dyld_image_state_rebased
;
760 #if IMAGE_NOTIFY_SUPPORT
761 void ImageLoader::recursiveImageAnnouncement(const LinkContext
& context
, ImageLoader
**& newImages
)
763 if ( ! fAnnounced
) {
767 // announce lower level libraries first
768 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
769 DependentLibrary
& libInfo
= fLibraries
[i
];
770 if ( libInfo
.image
!= NULL
)
771 libInfo
.image
->recursiveImageAnnouncement(context
, newImages
);
774 // add to list of images to notify about
776 //dyld::log("next size = %d\n", newImages.size());
778 // remember that this image wants to be notified about other images
779 if ( this->hasImageNotification() )
780 context
.addImageNeedingNotification(this);
785 void ImageLoader::recursiveGetDOFSections(const LinkContext
& context
, std::vector
<DOFInfo
>& dofs
)
787 if ( ! fRegisteredDOF
) {
789 fRegisteredDOF
= true;
791 // gather lower level libraries first
792 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
793 DependentLibrary
& libInfo
= fLibraries
[i
];
794 if ( libInfo
.image
!= NULL
)
795 libInfo
.image
->recursiveGetDOFSections(context
, dofs
);
797 this->doGetDOFSections(context
, dofs
);
802 void ImageLoader::recursiveSpinLock(recursive_lock
& rlock
)
804 // try to set image's ivar fInitializerRecursiveLock to point to this lock_info
805 // keep trying until success (spin)
806 while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL
, &rlock
, (void**)&fInitializerRecursiveLock
) ) {
807 // if fInitializerRecursiveLock already points to a different lock_info, if it is for
808 // the same thread we are on, the increment the lock count, otherwise continue to spin
809 if ( (fInitializerRecursiveLock
!= NULL
) && (fInitializerRecursiveLock
->thread
== rlock
.thread
) )
812 ++(fInitializerRecursiveLock
->count
);
815 void ImageLoader::recursiveSpinUnLock()
817 if ( --(fInitializerRecursiveLock
->count
) == 0 )
818 fInitializerRecursiveLock
= NULL
;
822 void ImageLoader::recursiveInitialization(const LinkContext
& context
, mach_port_t this_thread
)
824 #if RECURSIVE_INITIALIZER_LOCK
825 recursive_lock
lock_info(this_thread
);
826 recursiveSpinLock(lock_info
);
828 _spin_lock(&fInitializerLock
);
831 if ( fState
< dyld_image_state_dependents_initialized
-1 ) {
832 uint8_t oldState
= fState
;
834 fState
= dyld_image_state_dependents_initialized
-1;
837 // initialize lower level libraries first
838 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
839 DependentLibrary
& libInfo
= fLibraries
[i
];
840 // don't try to initialize stuff "above" me
841 if ( (libInfo
.image
!= NULL
) && (libInfo
.image
->fDepth
>= fDepth
) )
842 libInfo
.image
->recursiveInitialization(context
, this_thread
);
845 // record termination order
846 if ( this->needsTermination() )
847 context
.terminationRecorder(this);
849 // let objc know we are about to initalize this image
850 fState
= dyld_image_state_dependents_initialized
;
852 context
.notifySingle(dyld_image_state_dependents_initialized
, this->machHeader(), fPath
, fLastModified
);
854 // initialize this image
855 this->doInitialization(context
);
856 // let anyone know we finished initalizing this image
857 fState
= dyld_image_state_initialized
;
859 context
.notifySingle(dyld_image_state_initialized
, this->machHeader(), fPath
, fLastModified
);
861 catch (const char* msg
) {
862 // this image is not initialized
864 #if RECURSIVE_INITIALIZER_LOCK
865 recursiveSpinUnLock();
867 _spin_unlock(&fInitializerLock
);
873 #if RECURSIVE_INITIALIZER_LOCK
874 recursiveSpinUnLock();
876 _spin_unlock(&fInitializerLock
);
881 static void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
)
883 static uint64_t sUnitsPerSecond
= 0;
884 if ( sUnitsPerSecond
== 0 ) {
885 struct mach_timebase_info timeBaseInfo
;
886 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS
) {
887 sUnitsPerSecond
= 1000000000ULL * timeBaseInfo
.denom
/ timeBaseInfo
.numer
;
890 if ( partTime
< sUnitsPerSecond
) {
891 uint32_t milliSecondsTimeTen
= (partTime
*10000)/sUnitsPerSecond
;
892 uint32_t milliSeconds
= milliSecondsTimeTen
/10;
893 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
894 uint32_t percent
= percentTimesTen
/10;
895 dyld::log("%s: %u.%u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimeTen
-milliSeconds
*10, percent
, percentTimesTen
-percent
*10);
898 uint32_t secondsTimeTen
= (partTime
*10)/sUnitsPerSecond
;
899 uint32_t seconds
= secondsTimeTen
/10;
900 uint32_t percentTimesTen
= (partTime
*1000)/totalTime
;
901 uint32_t percent
= percentTimesTen
/10;
902 dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10);
906 static char* commatize(uint64_t in
, char* out
)
908 uint64_t div10
= in
/ 10;
909 uint8_t delta
= in
- div10
*10;
913 *(--s
) = '0' + delta
;
916 if ( (digitCount
% 3) == 0 )
919 delta
= in
- div10
*10;
920 *(--s
) = '0' + delta
;
929 void ImageLoader::printStatistics(unsigned int imageCount
)
931 uint64_t totalTime
= fgTotalLoadLibrariesTime
+ fgTotalRebaseTime
+ fgTotalBindTime
+ fgTotalInitTime
;
935 printTime("total time", totalTime
, totalTime
);
936 dyld::log("total images loaded: %d (%u from dyld shared cache, %u needed no fixups)\n", imageCount
, fgImagesUsedFromSharedCache
, fgImagesRequiringNoFixups
);
937 dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped
, fgTotalBytesMapped
/4096, fgTotalBytesPreFetched
/4096);
938 printTime("total images loading time", fgTotalLoadLibrariesTime
, totalTime
);
939 dyld::log("total rebase fixups: %s\n", commatize(fgTotalRebaseFixups
, commaNum1
));
940 printTime("total rebase fixups time", fgTotalRebaseTime
, totalTime
);
941 dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups
, commaNum1
));
942 if ( fgTotalBindSymbolsResolved
!= 0 ) {
943 uint32_t avgTimesTen
= (fgTotalBindImageSearches
* 10) / fgTotalBindSymbolsResolved
;
944 uint32_t avgInt
= fgTotalBindImageSearches
/ fgTotalBindSymbolsResolved
;
945 uint32_t avgTenths
= avgTimesTen
- (avgInt
*10);
946 dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n",
947 commatize(fgTotalBindSymbolsResolved
, commaNum1
), avgInt
, avgTenths
);
949 printTime("total binding fixups time", fgTotalBindTime
, totalTime
);
950 dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups
, commaNum1
), commatize(fgTotalPossibleLazyBindFixups
, commaNum2
));
951 printTime("total init time time", fgTotalInitTime
, totalTime
);
956 // copy path and add suffix to result
958 // /path/foo.dylib _debug => /path/foo_debug.dylib
959 // foo.dylib _debug => foo_debug.dylib
960 // foo _debug => foo_debug
961 // /path/bar _debug => /path/bar_debug
962 // /path/bar.A.dylib _debug => /path/bar.A_debug.dylib
964 void ImageLoader::addSuffix(const char* path
, const char* suffix
, char* result
)
966 strcpy(result
, path
);
968 char* start
= strrchr(result
, '/');
974 char* dot
= strrchr(start
, '.');
977 strcat(&dot
[strlen(suffix
)], &path
[dot
-result
]);
980 strcat(result
, suffix
);
985 void Segment::map(int fd
, uint64_t offsetInFatWrapper
, intptr_t slide
, const ImageLoader
* image
, const ImageLoader::LinkContext
& context
)
987 vm_offset_t fileOffset
= this->getFileOffset() + offsetInFatWrapper
;
988 vm_size_t size
= this->getFileSize();
989 void* requestedLoadAddress
= (void*)(this->getPreferredLoadAddress() + slide
);
991 if ( !this->unaccessible() ) {
992 if ( this->executable() )
993 protection
|= PROT_EXEC
;
994 if ( this->readable() )
995 protection
|= PROT_READ
;
996 if ( this->writeable() )
997 protection
|= PROT_WRITE
;
1000 // initially map __IMPORT segments R/W so dyld can update them
1001 if ( this->readOnlyImportStubs() )
1002 protection
|= PROT_WRITE
;
1004 // wholly zero-fill segments have nothing to mmap() in
1006 void* loadAddress
= mmap(requestedLoadAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
);
1007 if ( loadAddress
== ((void*)(-1)) )
1008 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s", errno
, (uintptr_t)requestedLoadAddress
, (uintptr_t)size
, this->getName(), image
->getPath());
1011 ++ImageLoader::fgTotalSegmentsMapped
;
1012 ImageLoader::fgTotalBytesMapped
+= size
;
1013 if ( context
.verboseMapping
)
1014 dyld::log("%18s at %p->%p with permissions %c%c%c\n", this->getName(), requestedLoadAddress
, (char*)requestedLoadAddress
+this->getFileSize()-1,
1015 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1018 void Segment::map(const void* memoryImage
, intptr_t slide
, const ImageLoader
* image
, const ImageLoader::LinkContext
& context
)
1020 vm_address_t loadAddress
= this->getPreferredLoadAddress() + slide
;
1021 vm_address_t srcAddr
= (uintptr_t)memoryImage
+ this->getFileOffset();
1022 vm_size_t size
= this->getFileSize();
1023 kern_return_t r
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
);
1024 if ( r
!= KERN_SUCCESS
)
1025 throw "can't map segment";
1027 if ( context
.verboseMapping
)
1028 dyld::log("%18s at %p->%p\n", this->getName(), (char*)loadAddress
, (char*)loadAddress
+this->getFileSize()-1);
1031 void Segment::setPermissions(const ImageLoader::LinkContext
& context
, const ImageLoader
* image
)
1033 vm_prot_t protection
= 0;
1034 if ( !this->unaccessible() ) {
1035 if ( this->executable() )
1036 protection
|= VM_PROT_EXECUTE
;
1037 if ( this->readable() )
1038 protection
|= VM_PROT_READ
;
1039 if ( this->writeable() )
1040 protection
|= VM_PROT_WRITE
;
1042 vm_address_t addr
= this->getActualLoadAddress(image
);
1043 vm_size_t size
= this->getSize();
1044 const bool setCurrentPermissions
= false;
1045 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
1046 if ( r
!= KERN_SUCCESS
)
1047 throw "can't set vm permissions for mapped segment";
1048 if ( context
.verboseMapping
) {
1049 dyld::log("%18s at %p->%p altered permissions to %c%c%c\n", this->getName(), (char*)addr
, (char*)addr
+this->getFileSize()-1,
1050 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1054 void Segment::tempWritable(const ImageLoader::LinkContext
& context
, const ImageLoader
* image
)
1056 vm_address_t addr
= this->getActualLoadAddress(image
);
1057 vm_size_t size
= this->getSize();
1058 const bool setCurrentPermissions
= false;
1059 vm_prot_t protection
= VM_PROT_WRITE
| VM_PROT_READ
;
1060 if ( this->executable() )
1061 protection
|= VM_PROT_EXECUTE
;
1062 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
1063 if ( r
!= KERN_SUCCESS
)
1064 throw "can't set vm permissions for mapped segment";
1065 if ( context
.verboseMapping
) {
1066 dyld::log("%18s at %p->%p altered permissions to %c%c%c\n", this->getName(), (char*)addr
, (char*)addr
+this->getFileSize()-1,
1067 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1072 bool Segment::hasTrailingZeroFill()
1074 return ( this->writeable() && (this->getSize() > this->getFileSize()) );
1078 uintptr_t Segment::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
)
1080 vm_address_t addr
= 0;
1081 vm_size_t size
= length
;
1082 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
1083 if ( fgNextPIEDylibAddress
!= 0 ) {
1084 addr
= fgNextPIEDylibAddress
+ (arc4random() & 0x3) * 4096; // add small random padding between dylibs
1085 kern_return_t r
= vm_allocate(mach_task_self(), &addr
, size
, VM_FLAGS_FIXED
);
1086 if ( r
== KERN_SUCCESS
) {
1087 fgNextPIEDylibAddress
= addr
+ size
;
1090 fgNextPIEDylibAddress
= 0;
1092 kern_return_t r
= vm_allocate(mach_task_self(), &addr
, size
, VM_FLAGS_ANYWHERE
);
1093 if ( r
!= KERN_SUCCESS
)
1094 throw "out of address space";
1099 bool Segment::reserveAddressRange(uintptr_t start
, size_t length
)
1101 vm_address_t addr
= start
;
1102 vm_size_t size
= length
;
1103 kern_return_t r
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/);
1104 if ( r
!= KERN_SUCCESS
)