]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoader.cpp
7a84b13b773fa3b69330bd986b81ba71c2d2025c
[apple/dyld.git] / src / ImageLoader.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #define __STDC_LIMIT_MACROS
26 #include <stdint.h>
27 #include <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>
37
38 #include "ImageLoader.h"
39
40 // in libc.a
41 extern "C" void _spin_lock(uint32_t*);
42 extern "C" void _spin_unlock(uint32_t*);
43
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;
63
64
65 void ImageLoader::init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate)
66 {
67 fPathHash = 0;
68 fPath = path;
69 fLogicalPath = NULL;
70 fDevice = device;
71 fInode = inode;
72 fLastModified = modDate;
73 fOffsetInFatFile = offsetInFat;
74 fLibraries = NULL;
75 fLibrariesCount = 0;
76 fDlopenReferenceCount = 0;
77 fStaticReferenceCount = 0;
78 fDynamicReferenceCount = 0;
79 fDynamicReferences = NULL;
80 fDepth = 0;
81 fLoadOrder = fgLoadOrdinal++;
82 fState = 0;
83 fAllLibraryChecksumsAndLoadAddressesMatch = false;
84 fLeaveMapped = false;
85 fNeverUnload = false;
86 fHideSymbols = false;
87 fMatchByInstallName = false;
88 fRegisteredDOF = false;
89 #if IMAGE_NOTIFY_SUPPORT
90 fAnnounced = false;
91 #endif
92 fAllLazyPointersBound = false;
93 fBeingRemoved = false;
94 fPathOwnedByImage = false;
95 #if RECURSIVE_INITIALIZER_LOCK
96 fInitializerRecursiveLock = NULL;
97 #else
98 fInitializerLock = 0;
99 #endif
100 if ( fPath != NULL )
101 fPathHash = hash(fPath);
102 }
103
104
105 ImageLoader::ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info)
106 {
107 init(path, offsetInFat, info.st_dev, info.st_ino, info.st_mtime);
108 }
109
110 ImageLoader::ImageLoader(const char* moduleName)
111 {
112 init(moduleName, 0, 0, 0, 0);
113 }
114
115
116 ImageLoader::~ImageLoader()
117 {
118 if ( fPathOwnedByImage && (fPath != NULL) )
119 delete [] fPath;
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--;
126 }
127 delete [] fLibraries;
128 }
129 if ( fDynamicReferences != NULL ) {
130 for (std::set<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
131 const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
132 }
133 delete fDynamicReferences;
134 }
135 }
136
137 void ImageLoader::setMapped(const LinkContext& context)
138 {
139 fState = dyld_image_state_mapped;
140 context.notifySingle(dyld_image_state_mapped, this->machHeader(), fPath, fLastModified);
141 }
142
143 void ImageLoader::addDynamicReference(const ImageLoader* target)
144 {
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++;
150 }
151 //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
152 }
153
154 int ImageLoader::compare(const ImageLoader* right) const
155 {
156 if ( this->fDepth == right->fDepth ) {
157 if ( this->fLoadOrder == right->fLoadOrder )
158 return 0;
159 else if ( this->fLoadOrder < right->fLoadOrder )
160 return -1;
161 else
162 return 1;
163 }
164 else {
165 if ( this->fDepth < right->fDepth )
166 return -1;
167 else
168 return 1;
169 }
170 }
171
172 void ImageLoader::setPath(const char* path)
173 {
174 if ( fPathOwnedByImage && (fPath != NULL) )
175 delete [] fPath;
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);
180 }
181
182 void ImageLoader::setPathUnowned(const char* path)
183 {
184 if ( fPathOwnedByImage && (fPath != NULL) ) {
185 delete [] fPath;
186 }
187 fPath = path;
188 fPathOwnedByImage = false;
189 fPathHash = hash(fPath);
190 }
191
192 void ImageLoader::setLogicalPath(const char* path)
193 {
194 if ( fPath == NULL ) {
195 // no physical path set yet, so use this path as physical
196 this->setPath(path);
197 }
198 else if ( strcmp(path, fPath) == 0 ) {
199 // do not set logical path because it is the same as the physical path
200 fLogicalPath = NULL;
201 }
202 else {
203 fLogicalPath = new char[strlen(path)+1];
204 strcpy((char*)fLogicalPath, path);
205 }
206 }
207
208 const char* ImageLoader::getLogicalPath() const
209 {
210 if ( fLogicalPath != NULL )
211 return fLogicalPath;
212 else
213 return fPath;
214 }
215
216 uint32_t ImageLoader::hash(const char* path)
217 {
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
221 uint32_t h = 0;
222 for (const char* s=path; *s != '\0'; ++s)
223 h = h*5 + *s;
224 return h;
225 }
226
227 bool ImageLoader::matchInstallPath() const
228 {
229 return fMatchByInstallName;
230 }
231
232 void ImageLoader::setMatchInstallPath(bool match)
233 {
234 fMatchByInstallName = match;
235 }
236
237 bool ImageLoader::statMatch(const struct stat& stat_buf) const
238 {
239 return ( (this->fDevice == stat_buf.st_dev) && (this->fInode == stat_buf.st_ino) );
240 }
241
242 const char* ImageLoader::getShortName() const
243 {
244 // try to return leaf name
245 if ( fPath != NULL ) {
246 const char* s = strrchr(fPath, '/');
247 if ( s != NULL )
248 return &s[1];
249 }
250 return fPath;
251 }
252
253 uint64_t ImageLoader::getOffsetInFatFile() const
254 {
255 return fOffsetInFatFile;
256 }
257
258 void ImageLoader::setLeaveMapped()
259 {
260 fLeaveMapped = true;
261 }
262
263 void ImageLoader::setHideExports(bool hide)
264 {
265 fHideSymbols = hide;
266 }
267
268 bool ImageLoader::hasHiddenExports() const
269 {
270 return fHideSymbols;
271 }
272
273 bool ImageLoader::isLinked() const
274 {
275 return (fState >= dyld_image_state_bound);
276 }
277
278 time_t ImageLoader::lastModified() const
279 {
280 return fLastModified;
281 }
282
283 bool ImageLoader::containsAddress(const void* addr) const
284 {
285 if ( ! this->isLinked() )
286 return false;
287 for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
288 Segment* seg = *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() )
292 return true;
293 }
294 return false;
295 }
296
297 bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) const
298 {
299 for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
300 Segment* seg = *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) )
304 return true;
305 if ( (start <= segEnd) && (segEnd < end) )
306 return true;
307 if ( (segStart < start) && (end < segEnd) )
308 return true;
309 }
310 return false;
311 }
312
313 void ImageLoader::getMappedRegions(MappedRegion*& regions) const
314 {
315 for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
316 Segment* seg = *it;
317 MappedRegion region;
318 region.address = seg->getActualLoadAddress(this);
319 region.size = seg->getSize();
320 *regions++ = region;
321 }
322 }
323
324
325 static bool notInImgageList(const ImageLoader* image, const ImageLoader** dsiStart, const ImageLoader** dsiCur)
326 {
327 for (const ImageLoader** p = dsiStart; p < dsiCur; ++p)
328 if ( *p == image )
329 return false;
330 return true;
331 }
332
333
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
337 {
338 const ImageLoader::Symbol* sym;
339
340 // search self
341 if ( notInImgageList(this, dsiStart, dsiCur) ) {
342 sym = this->findExportedSymbol(name, NULL, false, foundIn);
343 if ( sym != NULL )
344 return sym;
345 *dsiCur++ = this;
346 }
347
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);
353 if ( sym != NULL )
354 return sym;
355 }
356 }
357
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);
364 if ( sym != NULL )
365 return sym;
366 }
367 }
368
369 return NULL;
370 }
371
372
373 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
374 {
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);
380 }
381
382 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
383 {
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);
388 }
389
390
391 void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
392 {
393 //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
394
395 uint64_t t0 = mach_absolute_time();
396 this->recursiveLoadLibraries(context,loaderRPaths);
397 context.notifyBatch(dyld_image_state_dependents_mapped);
398
399 // we only do the loading step for preflights
400 if ( preflightOnly )
401 return;
402
403 uint64_t t1 = mach_absolute_time();
404 context.clearAllDepths();
405 this->recursiveUpdateDepth(context.imageCount());
406
407 uint64_t t2 = mach_absolute_time();
408 this->recursiveRebase(context);
409 context.notifyBatch(dyld_image_state_rebased);
410
411 uint64_t t3 = mach_absolute_time();
412 this->recursiveBind(context, forceLazysBound);
413 context.notifyBatch(dyld_image_state_bound);
414
415 uint64_t t4 = mach_absolute_time();
416 std::vector<DOFInfo> dofs;
417 this->recursiveGetDOFSections(context, dofs);
418 context.registerDOFs(dofs);
419
420
421 fgTotalLoadLibrariesTime += t1 - t0;
422 fgTotalRebaseTime += t3 - t2;
423 fgTotalBindTime += t4 - t3;
424
425 // done with initial dylib loads
426 Segment::fgNextPIEDylibAddress = 0;
427 }
428
429
430 void ImageLoader::printReferenceCounts()
431 {
432 dyld::log(" dlopen=%d, static=%d, dynamic=%d for %s\n",
433 fDlopenReferenceCount, fStaticReferenceCount, fDynamicReferenceCount, getPath() );
434 }
435
436
437 bool ImageLoader::decrementDlopenReferenceCount()
438 {
439 if ( fDlopenReferenceCount == 0 )
440 return true;
441 --fDlopenReferenceCount;
442 return false;
443 }
444
445 void ImageLoader::runInitializers(const LinkContext& context)
446 {
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
452 #endif
453
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);
459 }
460
461
462 void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive)
463 {
464 if ( ! fAllLazyPointersBound ) {
465 fAllLazyPointersBound = true;
466
467 if ( recursive ) {
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);
473 }
474 }
475 // bind lazys in this image
476 this->doBind(context, true);
477 }
478 }
479
480
481 intptr_t ImageLoader::assignSegmentAddresses(const LinkContext& context)
482 {
483 // preflight and calculate slide if needed
484 intptr_t slide = 0;
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 ) {
490 Segment* seg = *it;
491 const uintptr_t segLow = seg->getPreferredLoadAddress();
492 const uintptr_t segHigh = (segLow + seg->getSize() + 4095) & -4096;
493 if ( segLow < lowAddr )
494 lowAddr = segLow;
495 if ( segHigh > highAddr )
496 highAddr = segHigh;
497
498 if ( !seg->hasPreferredLoadAddress() || !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) )
499 needsToSlide = true;
500 }
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;
505 }
506 }
507 else if ( ! this->segmentsCanSlide() ) {
508 for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
509 Segment* seg = *it;
510 if ( strcmp(seg->getName(), "__PAGEZERO") == 0 )
511 continue;
512 if ( !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) )
513 throw "can't map";
514 }
515 }
516 else {
517 // mach-o does not support independently sliding segments
518 }
519 return slide;
520 }
521
522
523 void ImageLoader::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
524 {
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 ) {
531 Segment* seg = *it;
532 seg->map(fd, offsetInFat, slide, this, context);
533 }
534 // update slide to reflect load location
535 this->setSlide(slide);
536 }
537
538 void ImageLoader::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
539 {
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 ) {
546 Segment* seg = *it;
547 seg->map(memoryImage, slide, this, context);
548 }
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 ) {
553 Segment* seg = *it;
554 seg->setPermissions(context, this);
555 }
556 }
557
558 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
559 {
560 return fAllLibraryChecksumsAndLoadAddressesMatch;
561 }
562
563
564 unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
565 {
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.
569 if ( fDepth == 0 ) {
570 // break cycles
571 fDepth = maxDepth;
572
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;
581 }
582 }
583
584 // make me less deep then all my dependents
585 fDepth = minDependentDepth - 1;
586 }
587
588 return fDepth;
589 }
590
591
592 void ImageLoader::recursiveLoadLibraries(const LinkContext& context, const RPathChain& loaderRPaths)
593 {
594 if ( fState < dyld_image_state_dependents_mapped ) {
595 // break cycles
596 fState = dyld_image_state_dependents_mapped;
597
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);
604
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);
609
610 // try to load each
611 bool canUsePrelinkingInfo = true;
612 for(unsigned int i=0; i < fLibrariesCount; ++i){
613 DependentLibrary& requiredLib = fLibraries[i];
614 DependentLibraryInfo& requiredLibInfo = libraryInfos[i];
615 try {
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());
623 }
624 if ( fNeverUnload )
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);
634 }
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);
640 }
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());
650 //}
651 }
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);
658 }
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
662 }
663 }
664 fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo;
665
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);
671 }
672 }
673
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;
681 }
682 }
683 }
684
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;
688 free((void*)str);
689 }
690
691 }
692 }
693
694 void ImageLoader::recursiveRebase(const LinkContext& context)
695 {
696 if ( fState < dyld_image_state_rebased ) {
697 // break cycles
698 fState = dyld_image_state_rebased;
699
700 try {
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);
706 }
707
708 // rebase this image
709 doRebase(context);
710
711 // notify
712 context.notifySingle(dyld_image_state_rebased, this->machHeader(), fPath, fLastModified);
713 }
714 catch (const char* msg) {
715 // this image is not rebased
716 fState = dyld_image_state_dependents_mapped;
717 throw;
718 }
719 }
720 }
721
722
723
724
725 void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound)
726 {
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 ) {
732 // break cycles
733 fState = dyld_image_state_bound;
734
735 try {
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);
741 }
742 // bind this image
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;
748
749 context.notifySingle(dyld_image_state_bound, this->machHeader(), fPath, fLastModified);
750 }
751 catch (const char* msg) {
752 // restore state
753 fState = dyld_image_state_rebased;
754 throw;
755 }
756 }
757 }
758
759
760 #if IMAGE_NOTIFY_SUPPORT
761 void ImageLoader::recursiveImageAnnouncement(const LinkContext& context, ImageLoader**& newImages)
762 {
763 if ( ! fAnnounced ) {
764 // break cycles
765 fAnnounced = true;
766
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);
772 }
773
774 // add to list of images to notify about
775 *newImages++ = this;
776 //dyld::log("next size = %d\n", newImages.size());
777
778 // remember that this image wants to be notified about other images
779 if ( this->hasImageNotification() )
780 context.addImageNeedingNotification(this);
781 }
782 }
783 #endif
784
785 void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs)
786 {
787 if ( ! fRegisteredDOF ) {
788 // break cycles
789 fRegisteredDOF = true;
790
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);
796 }
797 this->doGetDOFSections(context, dofs);
798 }
799 }
800
801
802 void ImageLoader::recursiveSpinLock(recursive_lock& rlock)
803 {
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) )
810 break;
811 }
812 ++(fInitializerRecursiveLock->count);
813 }
814
815 void ImageLoader::recursiveSpinUnLock()
816 {
817 if ( --(fInitializerRecursiveLock->count) == 0 )
818 fInitializerRecursiveLock = NULL;
819 }
820
821
822 void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread)
823 {
824 #if RECURSIVE_INITIALIZER_LOCK
825 recursive_lock lock_info(this_thread);
826 recursiveSpinLock(lock_info);
827 #else
828 _spin_lock(&fInitializerLock);
829 #endif
830
831 if ( fState < dyld_image_state_dependents_initialized-1 ) {
832 uint8_t oldState = fState;
833 // break cycles
834 fState = dyld_image_state_dependents_initialized-1;
835
836 try {
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);
843 }
844
845 // record termination order
846 if ( this->needsTermination() )
847 context.terminationRecorder(this);
848
849 // let objc know we are about to initalize this image
850 fState = dyld_image_state_dependents_initialized;
851 oldState = fState;
852 context.notifySingle(dyld_image_state_dependents_initialized, this->machHeader(), fPath, fLastModified);
853
854 // initialize this image
855 this->doInitialization(context);
856 // let anyone know we finished initalizing this image
857 fState = dyld_image_state_initialized;
858 oldState = fState;
859 context.notifySingle(dyld_image_state_initialized, this->machHeader(), fPath, fLastModified);
860 }
861 catch (const char* msg) {
862 // this image is not initialized
863 fState = oldState;
864 #if RECURSIVE_INITIALIZER_LOCK
865 recursiveSpinUnLock();
866 #else
867 _spin_unlock(&fInitializerLock);
868 #endif
869 throw;
870 }
871 }
872
873 #if RECURSIVE_INITIALIZER_LOCK
874 recursiveSpinUnLock();
875 #else
876 _spin_unlock(&fInitializerLock);
877 #endif
878 }
879
880
881 static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
882 {
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;
888 }
889 }
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);
896 }
897 else {
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);
903 }
904 }
905
906 static char* commatize(uint64_t in, char* out)
907 {
908 uint64_t div10 = in / 10;
909 uint8_t delta = in - div10*10;
910 char* s = &out[32];
911 int digitCount = 1;
912 *s = '\0';
913 *(--s) = '0' + delta;
914 in = div10;
915 while ( in != 0 ) {
916 if ( (digitCount % 3) == 0 )
917 *(--s) = ',';
918 div10 = in / 10;
919 delta = in - div10*10;
920 *(--s) = '0' + delta;
921 in = div10;
922 ++digitCount;
923 }
924 return s;
925 }
926
927
928
929 void ImageLoader::printStatistics(unsigned int imageCount)
930 {
931 uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalInitTime;
932 char commaNum1[40];
933 char commaNum2[40];
934
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);
948 }
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);
952 }
953
954
955 //
956 // copy path and add suffix to result
957 //
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
963 //
964 void ImageLoader::addSuffix(const char* path, const char* suffix, char* result)
965 {
966 strcpy(result, path);
967
968 char* start = strrchr(result, '/');
969 if ( start != NULL )
970 start++;
971 else
972 start = result;
973
974 char* dot = strrchr(start, '.');
975 if ( dot != NULL ) {
976 strcpy(dot, suffix);
977 strcat(&dot[strlen(suffix)], &path[dot-result]);
978 }
979 else {
980 strcat(result, suffix);
981 }
982 }
983
984
985 void Segment::map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context)
986 {
987 vm_offset_t fileOffset = this->getFileOffset() + offsetInFatWrapper;
988 vm_size_t size = this->getFileSize();
989 void* requestedLoadAddress = (void*)(this->getPreferredLoadAddress() + slide);
990 int protection = 0;
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;
998 }
999 #if __i386__
1000 // initially map __IMPORT segments R/W so dyld can update them
1001 if ( this->readOnlyImportStubs() )
1002 protection |= PROT_WRITE;
1003 #endif
1004 // wholly zero-fill segments have nothing to mmap() in
1005 if ( size > 0 ) {
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());
1009 }
1010 // update stats
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' : '.' );
1016 }
1017
1018 void Segment::map(const void* memoryImage, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context)
1019 {
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";
1026
1027 if ( context.verboseMapping )
1028 dyld::log("%18s at %p->%p\n", this->getName(), (char*)loadAddress, (char*)loadAddress+this->getFileSize()-1);
1029 }
1030
1031 void Segment::setPermissions(const ImageLoader::LinkContext& context, const ImageLoader* image)
1032 {
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;
1041 }
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' : '.' );
1051 }
1052 }
1053
1054 void Segment::tempWritable(const ImageLoader::LinkContext& context, const ImageLoader* image)
1055 {
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' : '.' );
1068 }
1069 }
1070
1071
1072 bool Segment::hasTrailingZeroFill()
1073 {
1074 return ( this->writeable() && (this->getSize() > this->getFileSize()) );
1075 }
1076
1077
1078 uintptr_t Segment::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
1079 {
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;
1088 return addr;
1089 }
1090 fgNextPIEDylibAddress = 0;
1091 }
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";
1095
1096 return addr;
1097 }
1098
1099 bool Segment::reserveAddressRange(uintptr_t start, size_t length)
1100 {
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 )
1105 return false;
1106 return true;
1107 }
1108
1109
1110