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