]> git.saurik.com Git - apple/dyld.git/blob - dyld3/ClosureBuilder.cpp
dyld-733.6.tar.gz
[apple/dyld.git] / dyld3 / ClosureBuilder.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/errno.h>
27 #include <sys/mman.h>
28 #include <sys/mman.h>
29 #include <sys/param.h>
30 #include <ext/__hash>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/sysctl.h>
36
37 #include <mach-o/dyld_priv.h>
38
39 #include "ClosureWriter.h"
40 #include "ClosureBuilder.h"
41 #include "MachOAnalyzer.h"
42 #include "libdyldEntryVector.h"
43 #include "Tracing.h"
44
45 #define CLOSURE_SELOPT_WRITE
46 #include "objc-shared-cache.h"
47
48 namespace dyld3 {
49 namespace closure {
50
51
52 const DlopenClosure* ClosureBuilder::sRetryDlopenClosure = (const DlopenClosure*)(-1);
53
54 ClosureBuilder::ClosureBuilder(uint32_t startImageNum, const FileSystem& fileSystem, const DyldSharedCache* dyldCache, bool dyldCacheIsLive,
55 const GradedArchs& archs, const PathOverrides& pathOverrides, AtPath atPathHandling, bool allowRelativePaths,
56 LaunchErrorInfo* errorInfo, Platform platform, const CacheDylibsBindingHandlers* handlers)
57 : _fileSystem(fileSystem), _dyldCache(dyldCache), _pathOverrides(pathOverrides), _archs(archs), _platform(platform), _startImageNum(startImageNum),
58 _handlers(handlers), _atPathHandling(atPathHandling), _launchErrorInfo(errorInfo), _dyldCacheIsLive(dyldCacheIsLive), _allowRelativePaths(allowRelativePaths)
59 {
60 if ( dyldCache != nullptr ) {
61 _dyldImageArray = dyldCache->cachedDylibsImageArray();
62 if ( (dyldCache->header.otherImageArrayAddr != 0) && (dyldCache->header.progClosuresSize == 0) )
63 _makingClosuresInCache = true;
64 }
65 }
66
67
68 ClosureBuilder::~ClosureBuilder() {
69 if ( _tempPaths != nullptr )
70 PathPool::deallocate(_tempPaths);
71 if ( _mustBeMissingPaths != nullptr )
72 PathPool::deallocate(_mustBeMissingPaths);
73 if ( _objcDuplicateClassWarnings != nullptr )
74 PathPool::deallocate(_objcDuplicateClassWarnings);
75 }
76
77 bool ClosureBuilder::findImage(const char* loadPath, const LoadedImageChain& forImageChain, BuilderLoadedImage*& foundImage, LinkageType linkageType,
78 uint32_t compatVersion, bool canUseSharedCacheClosure)
79 {
80 // There shouldn't be an error here as the callers should stop trying to find more images if they get an error for an image
81 _diag.assertNoError();
82
83 __block bool result = false;
84
85 // record if this is a non-overridable path
86 bool pathIsInDyldCacheWhichCannotBeOverridden = false;
87 bool dylibsExpectedOnDisk = true;
88 if ( _dyldCache != nullptr ) {
89 pathIsInDyldCacheWhichCannotBeOverridden = _dyldCache->hasNonOverridablePath(loadPath);
90 dylibsExpectedOnDisk = _dyldCache->header.dylibsExpectedOnDisk;
91 }
92
93 _pathOverrides.forEachPathVariant(loadPath, pathIsInDyldCacheWhichCannotBeOverridden, ^(const char* possibleVariantPath, bool isFallbackPath, bool& stopPathVariant) {
94
95 // This check is within forEachPathVariant() to let DYLD_LIBRARY_PATH override LC_RPATH
96 bool isRPath = (strncmp(possibleVariantPath, "@rpath/", 7) == 0);
97
98 // passing a leaf name to dlopen() allows rpath searching for it
99 // FIXME: Does this apply to DYLD_INSERT_LIBRARIES too?
100 bool implictRPath = (linkageType == LinkageType::kDynamic) && (loadPath[0] != '/') && (loadPath == possibleVariantPath) && (_atPathHandling != AtPath::none);
101
102 // expand @ paths
103 forEachResolvedPathVar(possibleVariantPath, forImageChain, implictRPath, linkageType,
104 ^(const char* possiblePath, bool& stop) {
105 if ( possibleVariantPath != possiblePath )
106 _atPathUsed = true;
107
108 // look at already loaded images
109 const char* leafName = strrchr(possiblePath, '/');
110 for (BuilderLoadedImage& li: _loadedImages) {
111 if ( strcmp(li.path(), possiblePath) == 0 ) {
112 foundImage = &li;
113 result = true;
114 stop = true;
115 return;
116 }
117 else if ( isRPath ) {
118 // Special case @rpath/ because name in li.fileInfo.path is full path.
119 // Getting installName is expensive, so first see if an already loaded image
120 // has same leaf name and if so see if its installName matches request @rpath
121 if (const char* aLeaf = strrchr(li.path(), '/')) {
122 if ( strcmp(aLeaf, leafName) == 0 ) {
123 if ( li.loadAddress()->isDylib() && (strcmp(loadPath, li.loadAddress()->installName()) == 0) ) {
124 foundImage = &li;
125 result = true;
126 stop = true;
127 return;
128 }
129 }
130 }
131 }
132 }
133
134 // look to see if image already loaded via a different symlink
135 bool fileFound = false;
136 uint64_t fileFoundINode = 0;
137 uint64_t fileFoundMTime = 0;
138 bool inodesMatchRuntime = false;
139 // Note, we only do this check if we even expect to find this on-disk
140 // We can also use the pathIsInDyldCacheWhichCannotBeOverridden result if we are still trying the same path
141 // it was computed from
142 if ( dylibsExpectedOnDisk || !pathIsInDyldCacheWhichCannotBeOverridden || (loadPath != possiblePath) ) {
143 if ( _fileSystem.fileExists(possiblePath, &fileFoundINode, &fileFoundMTime, nullptr, &inodesMatchRuntime) ) {
144 fileFound = true;
145 for (BuilderLoadedImage& li: _loadedImages) {
146 if ( (li.loadedFileInfo.inode == fileFoundINode) && (li.loadedFileInfo.mtime == fileFoundMTime) ) {
147 foundImage = &li;
148 result = true;
149 stop = true;
150 return;
151 }
152 }
153 }
154 }
155
156 bool unmapWhenDone = false;
157 bool contentRebased = false;
158 bool hasInits = false;
159 bool markNeverUnload = false;
160 bool mustBuildClosure = _dyldCacheInvalidFormatVersion;
161 ImageNum overrideImageNum = 0;
162 ImageNum foundImageNum = 0;
163 const MachOAnalyzer* mh = nullptr;
164 const char* filePath = nullptr;
165 LoadedFileInfo loadedFileInfo;
166
167 // look in dyld cache
168 filePath = possiblePath;
169 char realPath[MAXPATHLEN];
170 if ( _dyldImageArray != nullptr ) {
171 uint32_t dyldCacheImageIndex;
172 bool foundInCache = _dyldCache->hasImagePath(possiblePath, dyldCacheImageIndex);
173 if ( !foundInCache && fileFound ) {
174 // see if this is an OS dylib/bundle with a pre-built dlopen closure
175 // We can only use the pre-built closure if we are dynamic linkage (a dlopen) and
176 // there are no roots
177 if ( canUseSharedCacheClosure && (linkageType == LinkageType::kDynamic) ) {
178 if (const dyld3::closure::Image* otherImage = _dyldCache->findDlopenOtherImage(possiblePath) ) {
179 uint64_t expectedInode;
180 uint64_t expectedModTime;
181 if ( !otherImage->isInvalid() ) {
182 bool hasInodeInfo = otherImage->hasFileModTimeAndInode(expectedInode, expectedModTime);
183 // use pre-built Image if it does not have mtime/inode or it does and it has matches current file info
184 if ( !hasInodeInfo || ((expectedInode == fileFoundINode) && (expectedModTime == fileFoundMTime)) ) {
185 loadedFileInfo = MachOAnalyzer::load(_diag, _fileSystem, possiblePath, _archs, _platform, realPath);
186 if ( _diag.noError() ) {
187 mh = (const MachOAnalyzer*)loadedFileInfo.fileContent;
188 foundImageNum = otherImage->imageNum();
189 unmapWhenDone = true;
190 contentRebased = false;
191 hasInits = otherImage->hasInitializers() || otherImage->mayHavePlusLoads();
192 // Use the realpath in the case where we loaded a symlink
193 // The closure must have recordered an alias path
194 if (realPath[0] != '\0')
195 filePath = realPath;
196 }
197 }
198 }
199 }
200 }
201 // if not found in cache, may be a symlink to something in cache
202 if ( mh == nullptr ) {
203 if ( _fileSystem.getRealPath(possiblePath, realPath) ) {
204 foundInCache = _dyldCache->hasImagePath(realPath, dyldCacheImageIndex);
205 if ( foundInCache ) {
206 filePath = realPath;
207 #if BUILDING_LIBDYLD
208 // handle case where OS dylib was updated after this process launched
209 if ( foundInCache ) {
210 for (BuilderLoadedImage& li: _loadedImages) {
211 if ( strcmp(li.path(), realPath) == 0 ) {
212 foundImage = &li;
213 result = true;
214 stop = true;
215 return;
216 }
217 }
218 }
219 #endif
220 }
221 }
222 }
223 }
224
225 // if using a cached dylib, look to see if there is an override
226 if ( foundInCache ) {
227 ImageNum dyldCacheImageNum = dyldCacheImageIndex + 1;
228 bool useCache = true;
229 markNeverUnload = true; // dylibs in cache, or dylibs that override cache should not be unloaded at runtime
230 const Image* image = _dyldImageArray->imageForNum(dyldCacheImageNum);
231 if ( image->overridableDylib() ) {
232 if ( fileFound ) {
233 uint64_t expectedInode;
234 uint64_t expectedModTime;
235 if ( image->hasFileModTimeAndInode(expectedInode, expectedModTime) ) {
236 // macOS where dylibs remain on disk. only use cache if mtime and inode have not changed
237 useCache = ( (fileFoundINode == expectedInode) && (fileFoundMTime == expectedModTime) );
238 }
239 else if ( _makingClosuresInCache ) {
240 // during iOS cache build, don't look at files on disk, use ones in cache
241 useCache = true;
242 }
243 else {
244 // iOS internal build. Any disk on cache overrides cache
245 useCache = false;
246 }
247 }
248 if ( !useCache ) {
249 overrideImageNum = dyldCacheImageNum;
250 _foundDyldCacheRoots = true;
251 }
252 }
253 if ( useCache ) {
254 foundImageNum = dyldCacheImageNum;
255 mh = (MachOAnalyzer*)_dyldCache->getIndexedImageEntry(foundImageNum-1, loadedFileInfo.mtime, loadedFileInfo.inode);
256 unmapWhenDone = false;
257 // if we are building ImageArray in dyld cache, content is not rebased
258 contentRebased = !_makingDyldCacheImages && _dyldCacheIsLive;
259 hasInits = image->hasInitializers() || image->mayHavePlusLoads();
260 // If the cache format is different from dyld/libdyld then we can't use this closure.
261 if ( (_dyldCache->header.formatVersion != dyld3::closure::kFormatVersion) || !canUseSharedCacheClosure ) {
262 mustBuildClosure = true;
263 _foundDyldCacheRoots = true;
264 }
265 }
266 }
267 }
268
269 // If we are building the cache, and don't find an image, then it might be weak so just return
270 if (_makingDyldCacheImages) {
271 addMustBeMissingPath(possiblePath);
272 return;
273 }
274
275 // if not found yet, mmap file
276 if ( mh == nullptr ) {
277 loadedFileInfo = MachOAnalyzer::load(_diag, _fileSystem, filePath, _archs, _platform, realPath);
278 mh = (const MachOAnalyzer*)loadedFileInfo.fileContent;
279 if ( mh == nullptr ) {
280 // Don't add must be missing paths for dlopen as we don't cache dlopen closures
281 if (_isLaunchClosure) {
282 // If we found the file then we want to skip it as its not a valid macho for this platform/arch
283 // We can't record skipped file mtime/inode for caches built on a different machine that it runs on.
284 // In that case, we expect the file to be mastered out, as otherwise we couldn't detect if its
285 // changed or not on the device side
286 if (fileFound && inodesMatchRuntime) {
287 addSkippedFile(possiblePath, fileFoundINode, fileFoundMTime);
288 } else {
289 addMustBeMissingPath(possiblePath);
290 }
291 }
292 return;
293 }
294 if ( linkageType != LinkageType::kDynamic ) {
295 // LC_LOAD_DYLIB can only link with dylibs, and DYLD_INSERT_LIBRARIES can only be dylibs
296 if ( !mh->isDylib() ) {
297 _diag.error("found '%s' which is not a dylib. Needed by '%s'", filePath, forImageChain.image.path());
298 return;
299 }
300 // verify this is compatable dylib version
301 const char* installName;
302 uint32_t foundCompatVers;
303 uint32_t foundCurrentVers;
304 mh->getDylibInstallName(&installName, &foundCompatVers, &foundCurrentVers);
305 if ( (foundCompatVers < compatVersion) && mh->enforceCompatVersion() ) {
306 char foundStr[32];
307 char requiredStr[32];
308 MachOFile::packedVersionToString(foundCompatVers, foundStr);
309 MachOFile::packedVersionToString(compatVersion, requiredStr);
310 _diag.error("found '%s' which has compat version (%s) which is less than required (%s). Needed by '%s'",
311 filePath, foundStr, requiredStr, forImageChain.image.path());
312 return;
313 }
314 }
315 else if ( mh->isMainExecutable() ) {
316 // when dlopen()ing a main executable, it must be dynamic Position Independent Executable
317 if ( !mh->isPIE() || !mh->isDynamicExecutable() ) {
318 _diag.error("not PIE");
319 return;
320 }
321 }
322 // Use the realpath in the case where we loaded a symlink
323 // The closure must have recordered an alias path
324 if (realPath[0] != '\0')
325 filePath = realPath;
326 foundImageNum = _startImageNum + _nextIndex++;
327 _foundNonCachedImage = true;
328 mustBuildClosure = true;
329 unmapWhenDone = true;
330 } else {
331 loadedFileInfo.fileContent = mh;
332 }
333
334 // if path is not original path, or its an inserted path (as forEachInColonList uses a stack temporary)
335 if ( (filePath != loadPath) || (linkageType == LinkageType::kInserted) ) {
336 // possiblePath may be a temporary (stack) string, since we found file at that path, make it permanent
337 filePath = strdup_temp(filePath);
338 // check if this overrides what would have been found in cache
339 // This is the case where we didn't find the image with the path in the shared cache, perhaps as it used library paths
340 // but the path we requested had pointed in to the cache
341 // FIXME: What if load path is via an @rpath and we will override the cache?
342 if ( overrideImageNum == 0 ) {
343 if ( _dyldImageArray != nullptr ) {
344 uint32_t dyldCacheImageIndex;
345 if ( _dyldCache->hasImagePath(loadPath, dyldCacheImageIndex) ) {
346 ImageNum possibleOverrideNum = dyldCacheImageIndex+1;
347 if ( possibleOverrideNum != foundImageNum )
348 overrideImageNum = possibleOverrideNum;
349 }
350 }
351 }
352 }
353
354 if ( !markNeverUnload ) {
355 switch (linkageType) {
356 case LinkageType::kStatic:
357 // Static linkages can only be unloaded if the image loading us can be unloaded
358 markNeverUnload = forImageChain.image.markNeverUnload;
359 break;
360 case LinkageType::kDynamic:
361 markNeverUnload = false;
362 break;
363 case LinkageType::kInserted:
364 // Inserted libraries must never be unloaded
365 markNeverUnload = true;
366 break;
367 };
368 }
369
370 if ( !markNeverUnload ) {
371 // If the parent didn't force us to be never unload, other conditions still may
372 if ( mh->hasThreadLocalVariables() ) {
373 markNeverUnload = true;
374 } else if ( mh->hasObjC() && mh->isDylib() ) {
375 markNeverUnload = true;
376 } else {
377 // record if image has DOF sections
378 __block bool hasDOFs = false;
379 mh->forEachDOFSection(_diag, ^(uint32_t offset) {
380 hasDOFs = true;
381 });
382 if ( hasDOFs )
383 markNeverUnload = true;
384 }
385 }
386
387 // Set the path again just in case it was strdup'ed.
388 loadedFileInfo.path = filePath;
389
390 // add new entry
391 BuilderLoadedImage entry;
392 entry.loadedFileInfo = loadedFileInfo;
393 entry.imageNum = foundImageNum;
394 entry.unmapWhenDone = unmapWhenDone;
395 entry.contentRebased = contentRebased;
396 entry.hasInits = hasInits;
397 entry.markNeverUnload = markNeverUnload;
398 entry.rtldLocal = false;
399 entry.isBadImage = false;
400 entry.mustBuildClosure = mustBuildClosure;
401 entry.hasMissingWeakImports = false;
402 entry.overrideImageNum = overrideImageNum;
403 _loadedImages.push_back(entry);
404 foundImage = &_loadedImages.back();
405 if ( isFallbackPath )
406 _fallbackPathUsed = true;
407 stop = true;
408 result = true;
409 });
410 if (result)
411 stopPathVariant = true;
412 }, _platform);
413
414 // If we found a file, but also had an error, then we must have logged a diagnostic for a file we couldn't use.
415 // Clear that for now.
416 // FIXME: Surface this to the user in case they wanted to see the error
417 if (result && _diag.hasError())
418 _diag.clearError();
419
420 return result;
421 }
422
423 bool ClosureBuilder::expandAtLoaderPath(const char* loadPath, bool fromLCRPATH, const BuilderLoadedImage& loadedImage, char fixedPath[])
424 {
425 switch ( _atPathHandling ) {
426 case AtPath::none:
427 return false;
428 case AtPath::onlyInRPaths:
429 if ( !fromLCRPATH ) {
430 // <rdar://42360708> allow @loader_path in LC_LOAD_DYLIB during dlopen()
431 if ( _isLaunchClosure )
432 return false;
433 }
434 break;
435 case AtPath::all:
436 break;
437 }
438 if ( strncmp(loadPath, "@loader_path/", 13) != 0 )
439 return false;
440
441 strlcpy(fixedPath, loadedImage.path(), PATH_MAX);
442 char* lastSlash = strrchr(fixedPath, '/');
443 if ( lastSlash != nullptr ) {
444 strcpy(lastSlash+1, &loadPath[13]);
445 return true;
446 }
447 return false;
448 }
449
450 bool ClosureBuilder::expandAtExecutablePath(const char* loadPath, bool fromLCRPATH, char fixedPath[])
451 {
452 switch ( _atPathHandling ) {
453 case AtPath::none:
454 return false;
455 case AtPath::onlyInRPaths:
456 if ( !fromLCRPATH )
457 return false;
458 break;
459 case AtPath::all:
460 break;
461 }
462 if ( strncmp(loadPath, "@executable_path/", 17) != 0 )
463 return false;
464
465 if ( _atPathHandling != AtPath::all )
466 return false;
467
468 strlcpy(fixedPath, _mainProgLoadPath, PATH_MAX);
469 char* lastSlash = strrchr(fixedPath, '/');
470 if ( lastSlash != nullptr ) {
471 strcpy(lastSlash+1, &loadPath[17]);
472 return true;
473 }
474 return false;
475 }
476
477 void ClosureBuilder::forEachResolvedPathVar(const char* loadPath, const LoadedImageChain& forImageChain,
478 bool implictRPath, LinkageType linkageType,
479 void (^handler)(const char* possiblePath, bool& stop))
480 {
481 // don't expand @loader_path or @executable_path if disallowed
482 if ( (_atPathHandling == AtPath::none) && (loadPath[0] == '@') && (loadPath[1] != 'r') ) {
483 bool stop = false;
484 handler(loadPath, stop);
485 return;
486 }
487
488 // quick out if not @ path or not implicit rpath
489 if ( !implictRPath && (loadPath[0] != '@') ) {
490 bool stop = false;
491 handler(loadPath, stop);
492 return;
493 }
494
495 // expand @loader_path
496 // Note this isn't supported for DYLD_INSERT_LIBRARIES
497 BLOCK_ACCCESSIBLE_ARRAY(char, tempPath, PATH_MAX); // read as: char tempPath[PATH_MAX];
498 if ( (linkageType != LinkageType::kInserted) && expandAtLoaderPath(loadPath, false, forImageChain.image, tempPath) ) {
499 bool stop = false;
500 handler(tempPath, stop);
501 return;
502 }
503
504 // expand @executable_path
505 // Note this is supported for DYLD_INSERT_LIBRARIES
506 if ( expandAtExecutablePath(loadPath, false, tempPath) ) {
507 bool stop = false;
508 handler(tempPath, stop);
509 return;
510 }
511
512 // expand @rpath
513 // Note this isn't supported for DYLD_INSERT_LIBRARIES
514 const char* rpathTail = nullptr;
515 char implicitRpathBuffer[PATH_MAX];
516 if ( linkageType != LinkageType::kInserted ) {
517 if ( strncmp(loadPath, "@rpath/", 7) == 0 ) {
518 // note: rpathTail starts with '/'
519 rpathTail = &loadPath[6];
520 }
521 else if ( implictRPath ) {
522 // make rpathTail starts with '/'
523 strlcpy(implicitRpathBuffer, "/", PATH_MAX);
524 strlcat(implicitRpathBuffer, loadPath, PATH_MAX);
525 rpathTail = implicitRpathBuffer;
526 }
527 }
528 if ( rpathTail != nullptr ) {
529 // rpath is expansion is technically a stack of rpath dirs built starting with main executable and pushing
530 // LC_RPATHS from each dylib as they are recursively loaded. Our imageChain represents that stack.
531 __block bool done = false;
532 for (const LoadedImageChain* link = &forImageChain; (link != nullptr) && !done; link = link->previous) {
533 link->image.loadAddress()->forEachRPath(^(const char* rPath, bool& stop) {
534 // fprintf(stderr, "LC_RPATH %s from %s\n", rPath, link->image.loadedFileInfo.path);
535 if ( expandAtLoaderPath(rPath, true, link->image, tempPath) || expandAtExecutablePath(rPath, true, tempPath) ) {
536 // @loader_path allowed and expended
537 strlcat(tempPath, rpathTail, PATH_MAX);
538 handler(tempPath, stop);
539 }
540 else if ( rPath[0] == '/' ) {
541 // LC_RPATH is an absolute path, not blocked by AtPath::none
542 strlcpy(tempPath, rPath, PATH_MAX);
543 strlcat(tempPath, rpathTail, PATH_MAX);
544 handler(tempPath, stop);
545 }
546 if (stop)
547 done = true;
548 #if 0
549 if ( _fileSystem.fileExists(tempPath) ) {
550 stop = true;
551 result = strdup_temp(tempPath);
552 }
553 else {
554 // Don't add must be missing paths for dlopen as we don't cache dlopen closures
555 if (_isLaunchClosure) {
556 addMustBeMissingPath(tempPath);
557 }
558 }
559 #endif
560 });
561 }
562 if (done)
563 return;
564 }
565
566 bool stop = false;
567 handler(loadPath, stop);
568 }
569
570 const char* ClosureBuilder::strdup_temp(const char* path)
571 {
572 if ( _tempPaths == nullptr )
573 _tempPaths = PathPool::allocate();
574 return _tempPaths->add(path);
575 }
576
577 void ClosureBuilder::addMustBeMissingPath(const char* path)
578 {
579 //fprintf(stderr, "must be missing: %s\n", path);
580 if ( _mustBeMissingPaths == nullptr )
581 _mustBeMissingPaths = PathPool::allocate();
582 _mustBeMissingPaths->add(path);
583 }
584
585 void ClosureBuilder::addSkippedFile(const char* path, uint64_t inode, uint64_t mtime)
586 {
587 _skippedFiles.push_back({ strdup_temp(path), inode, mtime });
588 }
589
590 ClosureBuilder::BuilderLoadedImage& ClosureBuilder::findLoadedImage(ImageNum imageNum)
591 {
592 for (BuilderLoadedImage& li : _loadedImages) {
593 if ( li.imageNum == imageNum ) {
594 return li;
595 }
596 }
597 for (BuilderLoadedImage& li : _loadedImages) {
598 if ( li.overrideImageNum == imageNum ) {
599 return li;
600 }
601 }
602 assert(0 && "LoadedImage not found");
603 }
604
605 ClosureBuilder::BuilderLoadedImage& ClosureBuilder::findLoadedImage(const MachOAnalyzer* mh)
606 {
607 for (BuilderLoadedImage& li : _loadedImages) {
608 if ( li.loadAddress() == mh ) {
609 return li;
610 }
611 }
612 assert(0 && "LoadedImage not found");
613 }
614
615 const MachOAnalyzer* ClosureBuilder::machOForImageNum(ImageNum imageNum)
616 {
617 return findLoadedImage(imageNum).loadAddress();
618 }
619
620 const MachOAnalyzer* ClosureBuilder::findDependent(const MachOLoaded* mh, uint32_t depIndex)
621 {
622 for (const BuilderLoadedImage& li : _loadedImages) {
623 if ( li.loadAddress() == mh ) {
624 if (li.isBadImage) {
625 // Bad image duting building group 1 closures, so the dependents array
626 // is potentially incomplete.
627 return nullptr;
628 }
629 ImageNum childNum = li.dependents[depIndex].imageNum();
630 // This is typically something like a missing weak-dylib we are re-exporting a weak-import symbol from
631 if (childNum == kMissingWeakLinkedImage)
632 return nullptr;
633 return machOForImageNum(childNum);
634 }
635 }
636 return nullptr;
637 }
638
639 ImageNum ClosureBuilder::imageNumForMachO(const MachOAnalyzer* mh)
640 {
641 for (const BuilderLoadedImage& li : _loadedImages) {
642 if ( li.loadAddress() == mh ) {
643 return li.imageNum;
644 }
645 }
646 assert(0 && "unknown mach-o");
647 return 0;
648 }
649
650 void ClosureBuilder::recursiveLoadDependents(LoadedImageChain& forImageChain, bool canUseSharedCacheClosure)
651 {
652 // if dependents is set, then we have already loaded this
653 if ( forImageChain.image.dependents.begin() != nullptr )
654 return;
655
656 uintptr_t startDepIndex = _dependencies.count();
657 // add dependents
658 __block uint32_t depIndex = 0;
659 forImageChain.image.loadAddress()->forEachDependentDylib(^(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool &stop) {
660 Image::LinkKind kind = Image::LinkKind::regular;
661 if ( isWeak )
662 kind = Image::LinkKind::weak;
663 else if ( isReExport )
664 kind = Image::LinkKind::reExport;
665 else if ( isUpward )
666 kind = Image::LinkKind::upward;
667 BuilderLoadedImage* foundImage;
668 if ( findImage(loadPath, forImageChain, foundImage, LinkageType::kStatic, compatVersion, canUseSharedCacheClosure) ) {
669 ImageNum foundImageNum = foundImage->imageNum;
670 if ( _diag.noError() )
671 _dependencies.push_back(Image::LinkedImage(kind, foundImageNum));
672 }
673 else if ( isWeak ) {
674 _dependencies.push_back(Image::LinkedImage(Image::LinkKind::weak, kMissingWeakLinkedImage));
675 // <rdar://problem/54387345> don't let an error loading weak dylib cause everything to fail
676 // _diag is checked after each dependent load, so if there is an error it was with loading the current dylib.
677 // Since it is a weak load, it is ok to ignore and and go on.
678 _diag.clearError();
679 }
680 else {
681 BLOCK_ACCCESSIBLE_ARRAY(char, extra, 4096);
682 extra[0] = '\0';
683 const char* targetLeaf = strrchr(loadPath, '/');
684 if ( targetLeaf == nullptr )
685 targetLeaf = loadPath;
686 if ( _mustBeMissingPaths != nullptr ) {
687 strcpy(extra, ", tried but didn't find: ");
688 _mustBeMissingPaths->forEachPath(^(const char* aPath) {
689 const char* aLeaf = strrchr(aPath, '/');
690 if ( aLeaf == nullptr )
691 aLeaf = aPath;
692 if ( strcmp(targetLeaf, aLeaf) == 0 ) {
693 strlcat(extra, "'", 4096);
694 strlcat(extra, aPath, 4096);
695 strlcat(extra, "' ", 4096);
696 }
697 });
698 }
699 if ( !_skippedFiles.empty() ) {
700 strcpy(extra, ", tried but invalid: ");
701 for (const SkippedFile& skippedFile : _skippedFiles) {
702 const char* aPath = skippedFile.path;
703 const char* aLeaf = strrchr(aPath, '/');
704 if ( aLeaf == nullptr )
705 aLeaf = aPath;
706 if ( strcmp(targetLeaf, aLeaf) == 0 ) {
707 strlcat(extra, "'", 4096);
708 strlcat(extra, aPath, 4096);
709 strlcat(extra, "' ", 4096);
710 }
711 }
712 }
713 if ( _diag.hasError() ) {
714 #if BUILDING_CACHE_BUILDER
715 std::string errorMessageBuffer = _diag.errorMessage();
716 const char* msg = errorMessageBuffer.c_str();
717 #else
718 const char* msg = _diag.errorMessage();
719 #endif
720 char msgCopy[strlen(msg)+4];
721 strcpy(msgCopy, msg);
722 _diag.error("dependent dylib '%s' not found for '%s'. %s", loadPath, forImageChain.image.path(), msgCopy);
723 }
724 else {
725 _diag.error("dependent dylib '%s' not found for '%s'%s", loadPath, forImageChain.image.path(), extra);
726 }
727 if ( _launchErrorInfo != nullptr ) {
728 _launchErrorInfo->kind = DYLD_EXIT_REASON_DYLIB_MISSING;
729 _launchErrorInfo->clientOfDylibPath = strdup_temp(forImageChain.image.path());
730 _launchErrorInfo->targetDylibPath = strdup_temp(loadPath);
731 _launchErrorInfo->symbol = nullptr;
732 }
733 }
734 ++depIndex;
735 if ( _diag.hasError() )
736 stop = true;
737 });
738 if ( _diag.hasError() )
739 return;
740 forImageChain.image.dependents = _dependencies.subArray(startDepIndex, depIndex);
741
742 // breadth first recurse
743 for (Image::LinkedImage dep : forImageChain.image.dependents) {
744 // don't recurse upwards
745 if ( dep.kind() == Image::LinkKind::upward )
746 continue;
747 // don't recurse down missing weak links
748 if ( (dep.kind() == Image::LinkKind::weak) && (dep.imageNum() == kMissingWeakLinkedImage) )
749 continue;
750 BuilderLoadedImage& depLoadedImage = findLoadedImage(dep.imageNum());
751 LoadedImageChain chain = { &forImageChain, depLoadedImage };
752 recursiveLoadDependents(chain, canUseSharedCacheClosure);
753 if ( _diag.hasError() )
754 break;
755 }
756 }
757
758 void ClosureBuilder::loadDanglingUpwardLinks(bool canUseSharedCacheClosure)
759 {
760 bool danglingFixed;
761 do {
762 danglingFixed = false;
763 for (BuilderLoadedImage& li : _loadedImages) {
764 if ( li.dependents.begin() == nullptr ) {
765 // this image has not have dependents set (probably a dangling upward link or referenced by upward link)
766 LoadedImageChain chain = { nullptr, li };
767 recursiveLoadDependents(chain, canUseSharedCacheClosure);
768 danglingFixed = true;
769 break;
770 }
771 }
772 } while (danglingFixed && _diag.noError());
773 }
774
775 bool ClosureBuilder::overridableDylib(const BuilderLoadedImage& forImage)
776 {
777 // only set on dylibs in the dyld shared cache
778 if ( !_makingDyldCacheImages )
779 return false;
780
781 // on macOS dylibs always override cache
782 if ( _platform == Platform::macOS )
783 return true;
784
785 // on embedded platforms with Internal cache, allow overrides
786 if ( !_makingCustomerCache )
787 return true;
788
789 // embedded platform customer caches, no overrides
790 return false; // FIXME, allow libdispatch.dylib to be overridden
791 }
792
793 void ClosureBuilder::buildImage(ImageWriter& writer, BuilderLoadedImage& forImage)
794 {
795 const MachOAnalyzer* macho = forImage.loadAddress();
796 // set ImageNum
797 writer.setImageNum(forImage.imageNum);
798
799 // set flags
800 writer.setHasWeakDefs(macho->hasWeakDefs());
801 writer.setIsBundle(macho->isBundle());
802 writer.setIsDylib(macho->isDylib());
803 writer.setIs64(macho->is64());
804 writer.setIsExecutable(macho->isMainExecutable());
805 writer.setUses16KPages(macho->uses16KPages());
806 writer.setOverridableDylib(overridableDylib(forImage));
807 writer.setInDyldCache(macho->inDyldCache());
808 if ( macho->hasObjC() ) {
809 writer.setHasObjC(true);
810 bool hasPlusLoads = macho->hasPlusLoadMethod(_diag);
811 writer.setHasPlusLoads(hasPlusLoads);
812 if ( hasPlusLoads )
813 forImage.hasInits = true;
814 }
815 else {
816 writer.setHasObjC(false);
817 writer.setHasPlusLoads(false);
818 }
819
820 if ( forImage.markNeverUnload ) {
821 writer.setNeverUnload(true);
822 }
823
824 #if BUILDING_DYLD || BUILDING_LIBDYLD
825 if ( _foundDyldCacheRoots ) {
826 // If we had roots, then some images are potentially on-disk while others are
827 // being rebuilt for a new initializer order, but do not exist on disk
828 if ( macho->inDyldCache() && !_dyldCache->header.dylibsExpectedOnDisk ) {
829 // don't add file info for shared cache files mastered out of final file system
830 }
831 else {
832 // file is either not in cache or is in cache but not mastered out
833 writer.setFileInfo(forImage.loadedFileInfo.inode, forImage.loadedFileInfo.mtime);
834 }
835 } else {
836 // shared cache not built by dyld or libdyld.dylib, so must be real file
837 writer.setFileInfo(forImage.loadedFileInfo.inode, forImage.loadedFileInfo.mtime);
838 }
839 #else
840 if ( _platform == Platform::macOS || MachOFile::isSimulatorPlatform(_platform) ) {
841 if ( macho->inDyldCache() && !_dyldCache->header.dylibsExpectedOnDisk ) {
842 // don't add file info for shared cache files mastered out of final file system
843 }
844 else {
845 // file is either not in cache or is in cache but not mastered out
846 writer.setFileInfo(forImage.loadedFileInfo.inode, forImage.loadedFileInfo.mtime);
847 }
848 }
849 else {
850 // all other platforms, cache is built off-device, so inodes are not known
851 }
852 #endif
853
854 // add info on how to load image
855 if ( !macho->inDyldCache() ) {
856 writer.setMappingInfo(forImage.loadedFileInfo.sliceOffset, macho->mappedSize());
857 // add code signature, if signed
858 uint32_t codeSigFileOffset;
859 uint32_t codeSigSize;
860 if ( macho->hasCodeSignature(codeSigFileOffset, codeSigSize) ) {
861 writer.setCodeSignatureLocation(codeSigFileOffset, codeSigSize);
862 macho->forEachCDHash(^(const uint8_t *cdHash) {
863 writer.addCDHash(cdHash);
864 });
865 }
866 // add FairPlay encryption range if encrypted
867 uint32_t fairPlayFileOffset;
868 uint32_t fairPlaySize;
869 if ( macho->isFairPlayEncrypted(fairPlayFileOffset, fairPlaySize) ) {
870 writer.setFairPlayEncryptionRange(fairPlayFileOffset, fairPlaySize);
871 }
872 }
873
874 // set path
875 writer.addPath(forImage.path());
876 if ( _aliases != nullptr ) {
877 for (const CachedDylibAlias& alias : *_aliases) {
878 if ( strcmp(alias.realPath, forImage.path()) == 0 )
879 writer.addPath(alias.aliasPath);
880 }
881 }
882
883 // set uuid, if has one
884 uuid_t uuid;
885 if ( macho->getUuid(uuid) )
886 writer.setUUID(uuid);
887
888 // set dependents
889 writer.setDependents(forImage.dependents);
890
891 // set segments
892 addSegments(writer, macho);
893
894 // record if this dylib overrides something in the cache
895 if ( forImage.overrideImageNum != 0 ) {
896 writer.setAsOverrideOf(forImage.overrideImageNum);
897 const char* overridePath = _dyldImageArray->imageForNum(forImage.overrideImageNum)->path();
898 writer.addPath(overridePath);
899 if ( strcmp(overridePath, "/usr/lib/system/libdyld.dylib") == 0 )
900 _libDyldImageNum = forImage.imageNum;
901 else if ( strcmp(overridePath, "/usr/lib/libSystem.B.dylib") == 0 )
902 _libSystemImageNum = forImage.imageNum;
903 }
904
905 // do fix up info for non-cached, and cached if building cache
906 if ( !macho->inDyldCache() || _makingDyldCacheImages ) {
907 if ( macho->hasChainedFixups() ) {
908 addChainedFixupInfo(writer, forImage);
909 }
910 else {
911 if ( _handlers != nullptr ) {
912 reportRebasesAndBinds(writer, forImage);
913 }
914 else {
915 // Note we have to do binds before rebases so that we know if we have missing lazy binds
916 addBindInfo(writer, forImage);
917 if ( _diag.noError() )
918 addRebaseInfo(writer, macho);
919 }
920 }
921 }
922 if ( _diag.hasError() ) {
923 writer.setInvalid();
924 return;
925 }
926
927 // Don't build iOSMac for now. Just add an invalid placeholder
928 if ( _makingDyldCacheImages && strncmp(forImage.path(), "/System/iOSSupport/", 19) == 0 ) {
929 writer.setInvalid();
930 return;
931 }
932
933 // add initializers
934 bool contentRebased = forImage.contentRebased;
935 __block unsigned initCount = 0;
936 Diagnostics initializerDiag;
937 macho->forEachInitializer(initializerDiag, contentRebased, ^(uint32_t offset) {
938 ++initCount;
939 }, _dyldCache);
940 if ( initializerDiag.noError() ) {
941 if ( initCount != 0 ) {
942 BLOCK_ACCCESSIBLE_ARRAY(uint32_t, initOffsets, initCount);
943 __block unsigned index = 0;
944 macho->forEachInitializer(_diag, contentRebased, ^(uint32_t offset) {
945 initOffsets[index++] = offset;
946 }, _dyldCache);
947 writer.setInitOffsets(initOffsets, initCount);
948 forImage.hasInits = true;
949 }
950 }
951 else {
952 // mod_init_func section is malformed, might be self modifying pointers
953 macho->forEachInitializerPointerSection(_diag, ^(uint32_t sectionOffset, uint32_t sectionSize, const uint8_t* content, bool& stop) {
954 writer.setInitSectRange(sectionOffset, sectionSize);
955 forImage.hasInits = true;
956 });
957 }
958
959
960 // add terminators (except for dylibs in the cache because they are never unloaded)
961 if ( !macho->inDyldCache() ) {
962 __block unsigned termCount = 0;
963 macho->forEachTerminator(_diag, contentRebased, ^(uint32_t offset) {
964 ++termCount;
965 });
966 if ( termCount != 0 ) {
967 BLOCK_ACCCESSIBLE_ARRAY(uint32_t, termOffsets, termCount);
968 __block unsigned index = 0;
969 macho->forEachTerminator(_diag, contentRebased, ^(uint32_t offset) {
970 termOffsets[index++] = offset;
971 });
972 writer.setTermOffsets(termOffsets, termCount);
973 }
974 }
975
976 // record if image has DOF sections
977 STACK_ALLOC_ARRAY(uint32_t, dofSectionOffsets, 256);
978 macho->forEachDOFSection(_diag, ^(uint32_t offset) {
979 dofSectionOffsets.push_back(offset);
980 });
981 if ( !dofSectionOffsets.empty() ) {
982 writer.setDofOffsets(dofSectionOffsets);
983 }
984
985 }
986
987 void ClosureBuilder::addSegments(ImageWriter& writer, const MachOAnalyzer* mh)
988 {
989 const uint32_t segCount = mh->segmentCount();
990 if ( mh->inDyldCache() ) {
991 uint64_t cacheUnslideBaseAddress = _dyldCache->unslidLoadAddress();
992 BLOCK_ACCCESSIBLE_ARRAY(Image::DyldCacheSegment, segs, segCount);
993 mh->forEachSegment(^(const MachOAnalyzer::SegmentInfo& info, bool& stop) {
994 segs[info.segIndex] = { (uint32_t)(info.vmAddr-cacheUnslideBaseAddress), (uint32_t)info.vmSize, info.protections };
995 });
996 writer.setCachedSegments(segs, segCount);
997 }
998 else {
999 const uint32_t pageSize = (mh->uses16KPages() ? 0x4000 : 0x1000);
1000 __block uint32_t diskSegIndex = 0;
1001 __block uint32_t totalPageCount = 0;
1002 __block uint32_t lastFileOffsetEnd = 0;
1003 __block uint64_t lastVmAddrEnd = 0;
1004 BLOCK_ACCCESSIBLE_ARRAY(Image::DiskSegment, dsegs, segCount*3); // room for padding
1005 mh->forEachSegment(^(const MachOAnalyzer::SegmentInfo& info, bool& stop) {
1006 if ( (info.fileOffset != 0) && (info.fileOffset != lastFileOffsetEnd) ) {
1007 Image::DiskSegment filePadding;
1008 filePadding.filePageCount = (info.fileOffset - lastFileOffsetEnd)/pageSize;
1009 filePadding.vmPageCount = 0;
1010 filePadding.permissions = 0;
1011 filePadding.paddingNotSeg = 1;
1012 dsegs[diskSegIndex++] = filePadding;
1013 }
1014 if ( (lastVmAddrEnd != 0) && (info.vmAddr != lastVmAddrEnd) ) {
1015 Image::DiskSegment vmPadding;
1016 vmPadding.filePageCount = 0;
1017 vmPadding.vmPageCount = (info.vmAddr - lastVmAddrEnd)/pageSize;
1018 vmPadding.permissions = 0;
1019 vmPadding.paddingNotSeg = 1;
1020 dsegs[diskSegIndex++] = vmPadding;
1021 totalPageCount += vmPadding.vmPageCount;
1022 }
1023 {
1024 Image::DiskSegment segInfo;
1025 segInfo.filePageCount = (info.fileSize+pageSize-1)/pageSize;
1026 segInfo.vmPageCount = (info.vmSize+pageSize-1)/pageSize;
1027 segInfo.permissions = info.protections & 7;
1028 segInfo.paddingNotSeg = 0;
1029 if ( info.readOnlyData )
1030 segInfo.permissions = Image::DiskSegment::kReadOnlyDataPermissions;
1031 dsegs[diskSegIndex++] = segInfo;
1032 totalPageCount += segInfo.vmPageCount;
1033 if ( info.fileSize != 0 )
1034 lastFileOffsetEnd = (uint32_t)(info.fileOffset + info.fileSize);
1035 if ( info.vmSize != 0 )
1036 lastVmAddrEnd = info.vmAddr + info.vmSize;
1037 }
1038 });
1039 writer.setDiskSegments(dsegs, diskSegIndex);
1040 }
1041 }
1042
1043 static bool isTupleFixup(uint64_t tupleSectVmStartOffset, uint64_t tupleSectVmEndOffset, uint64_t imageOffsetOfFixup, uint32_t entrySize, uint32_t& tupleIndex)
1044 {
1045 if ( imageOffsetOfFixup < tupleSectVmStartOffset )
1046 return false;
1047 if ( imageOffsetOfFixup > tupleSectVmEndOffset )
1048 return false;
1049 uint64_t offsetIntoSection = imageOffsetOfFixup - tupleSectVmStartOffset;
1050 tupleIndex = (uint32_t)(offsetIntoSection/entrySize);
1051 return (tupleIndex*entrySize == offsetIntoSection) || ((tupleIndex*entrySize+entrySize/2) == offsetIntoSection);
1052 }
1053
1054 void ClosureBuilder::addInterposingTuples(LaunchClosureWriter& writer, const Image* image, const MachOAnalyzer* mh)
1055 {
1056 const unsigned pointerSize = mh->pointerSize();
1057 const uint64_t baseAddress = mh->preferredLoadAddress();
1058 mh->forEachInterposingSection(_diag, ^(uint64_t sectVmOffset, uint64_t sectVmSize, bool &stop) {
1059 const uint32_t entrySize = 2*pointerSize;
1060 const uint32_t tupleCount = (uint32_t)(sectVmSize/entrySize);
1061 const uint64_t sectVmEndOffset = sectVmOffset + sectVmSize;
1062 BLOCK_ACCCESSIBLE_ARRAY(InterposingTuple, resolvedTuples, tupleCount);
1063 for (uint32_t i=0; i < tupleCount; ++i) {
1064 resolvedTuples[i].stockImplementation.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
1065 resolvedTuples[i].stockImplementation.absolute.value = 0;
1066 resolvedTuples[i].newImplementation.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
1067 resolvedTuples[i].newImplementation.absolute.value = 0;
1068 }
1069 // figure out what the replacement (rebase) and replacement (bind) of the tuple point to
1070 image->forEachFixup(^(uint64_t imageOffsetToRebase, bool& rebaseStop) {
1071 uint32_t tupleIndex;
1072 if ( isTupleFixup(sectVmOffset, sectVmEndOffset, imageOffsetToRebase, entrySize, tupleIndex) ) {
1073 const void* content = (uint8_t*)mh + imageOffsetToRebase;
1074 uint64_t unslidTargetAddress = mh->is64() ? *(uint64_t*)content : *(uint32_t*)content;
1075 resolvedTuples[tupleIndex].newImplementation.image.kind = Image::ResolvedSymbolTarget::kindImage;
1076 resolvedTuples[tupleIndex].newImplementation.image.imageNum = image->imageNum();
1077 resolvedTuples[tupleIndex].newImplementation.image.offset = unslidTargetAddress - mh->preferredLoadAddress();
1078 }
1079 },
1080 ^(uint64_t imageOffsetToBind, Image::ResolvedSymbolTarget bindTarget, bool &bindStop) {
1081 uint32_t tupleIndex;
1082 if ( isTupleFixup(sectVmOffset, sectVmEndOffset, imageOffsetToBind, entrySize, tupleIndex) ) {
1083 resolvedTuples[tupleIndex].stockImplementation = bindTarget;
1084 }
1085 },
1086 ^(uint64_t imageOffsetToStartsInfo, const Array<Image::ResolvedSymbolTarget>& targets, bool& chainStop) {
1087 mh->withChainStarts(_diag, imageOffsetToStartsInfo, ^(const dyld_chained_starts_in_image* startsInfo) {
1088 mh->forEachFixupInAllChains(_diag, startsInfo, false, ^(MachOLoaded::ChainedFixupPointerOnDisk* fixupLoc, const dyld_chained_starts_in_segment* segInfo, bool& fixupsStop) {
1089 uint64_t fixupOffset = (uint8_t*)fixupLoc - (uint8_t*)mh;
1090 uint32_t tupleIndex;
1091 if ( !isTupleFixup(sectVmOffset, sectVmEndOffset, fixupOffset, entrySize, tupleIndex) )
1092 return;
1093 uint32_t bindOrdinal;
1094 uint64_t rebaseTargetOffset;
1095 if ( fixupLoc->isBind(segInfo->pointer_format, bindOrdinal) ) {
1096 if ( bindOrdinal < targets.count() ) {
1097 resolvedTuples[tupleIndex].stockImplementation = targets[bindOrdinal];
1098 }
1099 else {
1100 _diag.error("out of range bind ordinal %d (max %lu)", bindOrdinal, targets.count());
1101 fixupsStop = true;
1102 }
1103 }
1104 else if ( fixupLoc->isRebase(segInfo->pointer_format, baseAddress, rebaseTargetOffset) ) {
1105 resolvedTuples[tupleIndex].newImplementation.image.kind = Image::ResolvedSymbolTarget::kindImage;
1106 resolvedTuples[tupleIndex].newImplementation.image.imageNum = image->imageNum();
1107 resolvedTuples[tupleIndex].newImplementation.image.offset = rebaseTargetOffset;
1108 }
1109 });
1110 });
1111 },
1112 ^(uint64_t imageOffsetToFixup) {
1113 // objc optimisation can't be interposed so nothing to do here.
1114 },
1115 ^(uint64_t imageOffsetToBind, Image::ResolvedSymbolTarget bindTarget, bool &bindStop) {
1116 // objc protocol optimisation fixups can't be interposed so nothing to do here.
1117 },
1118 ^(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool &fixupStop) {
1119 // objc selector optimisation fixups can't be interposed so nothing to do here.
1120 },
1121 ^(uint64_t imageOffsetToFixup, bool &fixupStop) {
1122 // objc stable Swift optimisation fixups can't be interposed so nothing to do here.
1123 },
1124 ^(uint64_t imageOffsetToFixup, bool &fixupStop) {
1125 // objc method list optimisation fixups can't be interposed so nothing to do here.
1126 });
1127
1128 // remove any tuples in which both sides are not set (or target is weak-import NULL)
1129 STACK_ALLOC_ARRAY(InterposingTuple, goodTuples, tupleCount);
1130 for (uint32_t i=0; i < tupleCount; ++i) {
1131 if ( (resolvedTuples[i].stockImplementation.image.kind != Image::ResolvedSymbolTarget::kindAbsolute)
1132 && (resolvedTuples[i].newImplementation.image.kind != Image::ResolvedSymbolTarget::kindAbsolute) )
1133 goodTuples.push_back(resolvedTuples[i]);
1134 }
1135 writer.addInterposingTuples(goodTuples);
1136
1137 // if the target of the interposing is in the dyld shared cache, add a PatchEntry so the cache is fixed up at launch
1138 STACK_ALLOC_ARRAY(Closure::PatchEntry, patches, goodTuples.count());
1139 for (const InterposingTuple& aTuple : goodTuples) {
1140 if ( aTuple.stockImplementation.sharedCache.kind == Image::ResolvedSymbolTarget::kindSharedCache ) {
1141 uint32_t imageIndex;
1142 assert(_dyldCache->addressInText((uint32_t)aTuple.stockImplementation.sharedCache.offset, &imageIndex));
1143 ImageNum imageInCache = imageIndex+1;
1144 Closure::PatchEntry patch;
1145 patch.exportCacheOffset = (uint32_t)aTuple.stockImplementation.sharedCache.offset;
1146 patch.overriddenDylibInCache = imageInCache;
1147 patch.replacement = aTuple.newImplementation;
1148 patches.push_back(patch);
1149 }
1150 }
1151 writer.addCachePatches(patches);
1152 });
1153 }
1154
1155 void ClosureBuilder::addRebaseInfo(ImageWriter& writer, const MachOAnalyzer* mh)
1156 {
1157 const uint64_t ptrSize = mh->pointerSize();
1158 Image::RebasePattern maxLeapPattern = { 0xFFFFF, 0, 0xF };
1159 const uint64_t maxLeapCount = maxLeapPattern.repeatCount * maxLeapPattern.skipCount;
1160 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::RebasePattern, rebaseEntries, 1024);
1161 __block uint64_t lastLocation = -ptrSize;
1162 mh->forEachRebase(_diag, !_foundMissingLazyBinds, ^(uint64_t runtimeOffset, bool& stop) {
1163 const uint64_t delta = runtimeOffset - lastLocation;
1164 const bool aligned = ((delta % ptrSize) == 0);
1165 if ( delta == ptrSize ) {
1166 // this rebase location is contiguous to previous
1167 if ( rebaseEntries.back().contigCount < 255 ) {
1168 // just bump previous's contigCount
1169 rebaseEntries.back().contigCount++;
1170 }
1171 else {
1172 // previous contiguous run already has max 255, so start a new run
1173 rebaseEntries.push_back({ 1, 1, 0 });
1174 }
1175 }
1176 else if ( aligned && (delta <= (ptrSize*15)) ) {
1177 // this rebase is within skip distance of last rebase
1178 rebaseEntries.back().skipCount = (uint8_t)((delta-ptrSize)/ptrSize);
1179 int lastIndex = (int)(rebaseEntries.count() - 1);
1180 if ( lastIndex > 1 ) {
1181 if ( (rebaseEntries[lastIndex].contigCount == rebaseEntries[lastIndex-1].contigCount)
1182 && (rebaseEntries[lastIndex].skipCount == rebaseEntries[lastIndex-1].skipCount) ) {
1183 // this entry as same contig and skip as prev, so remove it and bump repeat count of previous
1184 rebaseEntries.pop_back();
1185 rebaseEntries.back().repeatCount += 1;
1186 }
1187 }
1188 rebaseEntries.push_back({ 1, 1, 0 });
1189 }
1190 else {
1191 uint64_t advanceCount = (delta-ptrSize);
1192 if ( (runtimeOffset < lastLocation) && (lastLocation != -ptrSize) ) {
1193 // out of rebases! handle this be resting rebase offset to zero
1194 rebaseEntries.push_back({ 0, 0, 0 });
1195 advanceCount = runtimeOffset;
1196 }
1197 // if next rebase is too far to reach with one pattern, use series
1198 while ( advanceCount > maxLeapCount ) {
1199 rebaseEntries.push_back(maxLeapPattern);
1200 advanceCount -= maxLeapCount;
1201 }
1202 // if next rebase is not reachable with skipCount==1 or skipCount==15, add intermediate
1203 while ( advanceCount > maxLeapPattern.repeatCount ) {
1204 uint64_t count = advanceCount / maxLeapPattern.skipCount;
1205 rebaseEntries.push_back({ (uint32_t)count, 0, maxLeapPattern.skipCount });
1206 advanceCount -= (count*maxLeapPattern.skipCount);
1207 }
1208 if ( advanceCount != 0 )
1209 rebaseEntries.push_back({ (uint32_t)advanceCount, 0, 1 });
1210 rebaseEntries.push_back({ 1, 1, 0 });
1211 }
1212 lastLocation = runtimeOffset;
1213 });
1214 writer.setRebaseInfo(rebaseEntries);
1215
1216 // i386 programs also use text relocs to rebase stubs
1217 if ( mh->cputype == CPU_TYPE_I386 ) {
1218 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::TextFixupPattern, textRebases, 512);
1219 __block uint64_t lastOffset = -4;
1220 mh->forEachTextRebase(_diag, ^(uint64_t runtimeOffset, bool& stop) {
1221 if ( textRebases.freeCount() < 2 ) {
1222 _diag.error("too many text rebase locations (%ld) in %s", textRebases.maxCount(), writer.currentImage()->path());
1223 stop = true;
1224 }
1225 bool mergedIntoPrevious = false;
1226 if ( (runtimeOffset > lastOffset) && !textRebases.empty() ) {
1227 uint32_t skipAmount = (uint32_t)(runtimeOffset - lastOffset);
1228 if ( (textRebases.back().repeatCount == 1) && (textRebases.back().skipCount == 0) ) {
1229 textRebases.back().repeatCount = 2;
1230 textRebases.back().skipCount = skipAmount;
1231 mergedIntoPrevious = true;
1232 }
1233 else if ( textRebases.back().skipCount == skipAmount ) {
1234 textRebases.back().repeatCount += 1;
1235 mergedIntoPrevious = true;
1236 }
1237 }
1238 if ( !mergedIntoPrevious ) {
1239 Image::TextFixupPattern pattern;
1240 pattern.target.raw = 0;
1241 pattern.startVmOffset = (uint32_t)runtimeOffset;
1242 pattern.repeatCount = 1;
1243 pattern.skipCount = 0;
1244 textRebases.push_back(pattern);
1245 }
1246 lastOffset = runtimeOffset;
1247 });
1248 writer.setTextRebaseInfo(textRebases);
1249 }
1250 }
1251
1252
1253 void ClosureBuilder::forEachBind(BuilderLoadedImage& forImage, void (^handler)(uint64_t runtimeOffset, Image::ResolvedSymbolTarget target, const ResolvedTargetInfo& targetInfo, bool& stop),
1254 void (^strongHandler)(const char* strongSymbolName),
1255 void (^missingLazyBindHandler)())
1256 {
1257 __block int lastLibOrdinal = 256;
1258 __block const char* lastSymbolName = nullptr;
1259 __block uint64_t lastAddend = 0;
1260 __block Image::ResolvedSymbolTarget target;
1261 __block ResolvedTargetInfo targetInfo;
1262 forImage.loadAddress()->forEachBind(_diag, ^(uint64_t runtimeOffset, int libOrdinal, const char* symbolName, bool weakImport, bool lazyBind, uint64_t addend, bool& stop) {
1263 if ( (symbolName == lastSymbolName) && (libOrdinal == lastLibOrdinal) && (addend == lastAddend) ) {
1264 // same symbol lookup as last location
1265 handler(runtimeOffset, target, targetInfo, stop);
1266 }
1267 else if ( findSymbol(forImage, libOrdinal, symbolName, weakImport, lazyBind, addend, target, targetInfo) ) {
1268 if ( !targetInfo.skippableWeakDef ) {
1269 handler(runtimeOffset, target, targetInfo, stop);
1270 lastSymbolName = symbolName;
1271 lastLibOrdinal = libOrdinal;
1272 lastAddend = addend;
1273 }
1274 }
1275 else {
1276 stop = true;
1277 }
1278 }, ^(const char* symbolName) {
1279 strongHandler(symbolName);
1280 }, ^() {
1281 missingLazyBindHandler();
1282 });
1283 }
1284
1285 void ClosureBuilder::addBindInfo(ImageWriter& writer, BuilderLoadedImage& forImage)
1286 {
1287 const uint32_t ptrSize = forImage.loadAddress()->pointerSize();
1288 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::BindPattern, binds, 512);
1289 __block uint64_t lastOffset = -ptrSize;
1290 __block Image::ResolvedSymbolTarget lastTarget = { {0, 0} };
1291 forEachBind(forImage, ^(uint64_t runtimeOffset, Image::ResolvedSymbolTarget target, const ResolvedTargetInfo& targetInfo, bool& stop) {
1292 if ( targetInfo.weakBindCoalese ) {
1293 // may be previous bind to this location
1294 // if so, update that rather create new BindPattern
1295 for (Image::BindPattern& aBind : binds) {
1296 if ( (aBind.startVmOffset == runtimeOffset) && (aBind.repeatCount == 1) && (aBind.skipCount == 0) ) {
1297 aBind.target = target;
1298 return;
1299 }
1300 }
1301 }
1302 bool mergedIntoPrevious = false;
1303 if ( !mergedIntoPrevious && (target == lastTarget) && (runtimeOffset > lastOffset) && !binds.empty() ) {
1304 uint64_t skipAmount = (runtimeOffset - lastOffset - ptrSize)/ptrSize;
1305 if ( skipAmount*ptrSize != (runtimeOffset - lastOffset - ptrSize) ) {
1306 // misaligned pointer means we cannot optimize
1307 }
1308 else {
1309 if ( (binds.back().repeatCount == 1) && (binds.back().skipCount == 0) && (skipAmount <= 255) ) {
1310 binds.back().repeatCount = 2;
1311 binds.back().skipCount = skipAmount;
1312 assert(binds.back().skipCount == skipAmount); // check overflow
1313 mergedIntoPrevious = true;
1314 }
1315 else if ( (binds.back().skipCount == skipAmount) && (binds.back().repeatCount < 0xfff) ) {
1316 uint32_t prevRepeatCount = binds.back().repeatCount;
1317 binds.back().repeatCount += 1;
1318 assert(binds.back().repeatCount > prevRepeatCount); // check overflow
1319 mergedIntoPrevious = true;
1320 }
1321 }
1322 }
1323 if ( (target == lastTarget) && (runtimeOffset == lastOffset) && !binds.empty() ) {
1324 // duplicate bind for same location, ignore this one
1325 mergedIntoPrevious = true;
1326 }
1327 if ( !mergedIntoPrevious ) {
1328 Image::BindPattern pattern;
1329 pattern.target = target;
1330 pattern.startVmOffset = runtimeOffset;
1331 pattern.repeatCount = 1;
1332 pattern.skipCount = 0;
1333 assert(pattern.startVmOffset == runtimeOffset);
1334 binds.push_back(pattern);
1335 }
1336 lastTarget = target;
1337 lastOffset = runtimeOffset;
1338 }, ^(const char* strongSymbolName) {
1339 if ( !_makingDyldCacheImages ) {
1340 // something has a strong symbol definition that may override a weak impl in the dyld cache
1341 Image::ResolvedSymbolTarget strongOverride;
1342 ResolvedTargetInfo strongTargetInfo;
1343 if ( findSymbolInImage(forImage.loadAddress(), strongSymbolName, 0, false, false, strongOverride, strongTargetInfo) ) {
1344 for (const BuilderLoadedImage& li : _loadedImages) {
1345 if ( li.loadAddress()->inDyldCache() && li.loadAddress()->hasWeakDefs() ) {
1346 Image::ResolvedSymbolTarget implInCache;
1347 ResolvedTargetInfo implInCacheInfo;
1348 if ( findSymbolInImage(li.loadAddress(), strongSymbolName, 0, false, false, implInCache, implInCacheInfo) ) {
1349 // found another instance in some dylib in dyld cache, will need to patch it
1350 Closure::PatchEntry patch;
1351 patch.exportCacheOffset = (uint32_t)implInCache.sharedCache.offset;
1352 patch.overriddenDylibInCache = li.imageNum;
1353 patch.replacement = strongOverride;
1354 _weakDefCacheOverrides.push_back(patch);
1355 }
1356 }
1357 }
1358 }
1359 }
1360 }, ^() {
1361 _foundMissingLazyBinds = true;
1362 });
1363
1364 // check for __dyld section in main executable to support licenseware
1365 if ( forImage.loadAddress()->filetype == MH_EXECUTE ) {
1366 forImage.loadAddress()->forEachSection(^(const MachOAnalyzer::SectionInfo& sectInfo, bool malformedSectionRange, bool& stop) {
1367 if ( (strcmp(sectInfo.sectName, "__dyld") == 0) && (strcmp(sectInfo.segInfo.segName, "__DATA") == 0) ) {
1368 // find dyld3::compatFuncLookup in libdyld.dylib
1369 assert(_libDyldImageNum != 0);
1370 Image::ResolvedSymbolTarget lookupFuncTarget;
1371 ResolvedTargetInfo lookupFuncInfo;
1372 if ( findSymbolInImage(findLoadedImage(_libDyldImageNum).loadAddress(), "__ZN5dyld316compatFuncLookupEPKcPPv", 0, false, false, lookupFuncTarget, lookupFuncInfo) ) {
1373 // add bind to set second pointer in __dyld section to be dyld3::compatFuncLookup
1374 uint64_t runtimeOffset = sectInfo.sectAddr - forImage.loadAddress()->preferredLoadAddress() + forImage.loadAddress()->pointerSize();
1375 Image::BindPattern compatFuncPattern;
1376 compatFuncPattern.target = lookupFuncTarget;
1377 compatFuncPattern.startVmOffset = runtimeOffset;
1378 compatFuncPattern.repeatCount = 1;
1379 compatFuncPattern.skipCount = 0;
1380 assert(compatFuncPattern.startVmOffset == runtimeOffset);
1381 binds.push_back(compatFuncPattern);
1382 }
1383 else {
1384 _diag.error("libdyld.dylib is dyld3::compatFuncLookup");
1385 }
1386 }
1387 });
1388 }
1389
1390 writer.setBindInfo(binds);
1391 }
1392
1393 void ClosureBuilder::reportRebasesAndBinds(ImageWriter& writer, BuilderLoadedImage& forImage)
1394 {
1395 // report all rebases
1396 forImage.loadAddress()->forEachRebase(_diag, true, ^(uint64_t runtimeOffset, bool& stop) {
1397 _handlers->rebase(forImage.imageNum, forImage.loadAddress(), (uint32_t)runtimeOffset);
1398 });
1399
1400 // report all binds
1401 forEachBind(forImage, ^(uint64_t runtimeOffset, Image::ResolvedSymbolTarget target, const ResolvedTargetInfo& targetInfo, bool& stop) {
1402 _handlers->bind(forImage.imageNum, forImage.loadAddress(), (uint32_t)runtimeOffset, target, targetInfo);
1403 },
1404 ^(const char* strongSymbolName) {},
1405 ^() { });
1406
1407 // i386 programs also use text relocs to rebase stubs
1408 if ( forImage.loadAddress()->cputype == CPU_TYPE_I386 ) {
1409 // FIX ME
1410 }
1411 }
1412
1413 // These are mangled symbols for all the variants of operator new and delete
1414 // which a main executable can define (non-weak) and override the
1415 // weak-def implementation in the OS.
1416 static const char* const sTreatAsWeak[] = {
1417 "__Znwm", "__ZnwmRKSt9nothrow_t",
1418 "__Znam", "__ZnamRKSt9nothrow_t",
1419 "__ZdlPv", "__ZdlPvRKSt9nothrow_t", "__ZdlPvm",
1420 "__ZdaPv", "__ZdaPvRKSt9nothrow_t", "__ZdaPvm",
1421 "__ZnwmSt11align_val_t", "__ZnwmSt11align_val_tRKSt9nothrow_t",
1422 "__ZnamSt11align_val_t", "__ZnamSt11align_val_tRKSt9nothrow_t",
1423 "__ZdlPvSt11align_val_t", "__ZdlPvSt11align_val_tRKSt9nothrow_t", "__ZdlPvmSt11align_val_t",
1424 "__ZdaPvSt11align_val_t", "__ZdaPvSt11align_val_tRKSt9nothrow_t", "__ZdaPvmSt11align_val_t"
1425 };
1426
1427
1428 void ClosureBuilder::addChainedFixupInfo(ImageWriter& writer, BuilderLoadedImage& forImage)
1429 {
1430 // build array of targets
1431 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::ResolvedSymbolTarget, targets, 1024);
1432 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(ResolvedTargetInfo, targetInfos, 1024);
1433 forImage.loadAddress()->forEachChainedFixupTarget(_diag, ^(int libOrdinal, const char* symbolName, uint64_t addend, bool weakImport, bool& stop) {
1434 Image::ResolvedSymbolTarget target;
1435 ResolvedTargetInfo targetInfo;
1436 if ( !findSymbol(forImage, libOrdinal, symbolName, weakImport, false, addend, target, targetInfo) ) {
1437 const char* expectedInPath = forImage.loadAddress()->dependentDylibLoadPath(libOrdinal-1);
1438 _diag.error("symbol '%s' not found, expected in '%s', needed by '%s'", symbolName, expectedInPath, forImage.path());
1439 stop = true;
1440 return;
1441 }
1442 if ( libOrdinal == BIND_SPECIAL_DYLIB_WEAK_LOOKUP ) {
1443 // add if not already in array
1444 bool alreadyInArray = false;
1445 for (const char* sym : _weakDefsFromChainedBinds) {
1446 if ( strcmp(sym, symbolName) == 0 ) {
1447 alreadyInArray = true;
1448 break;
1449 }
1450 }
1451 if ( !alreadyInArray )
1452 _weakDefsFromChainedBinds.push_back(symbolName);
1453 }
1454 targets.push_back(target);
1455 targetInfos.push_back(targetInfo);
1456 });
1457 if ( _diag.hasError() )
1458 return;
1459
1460 uint64_t chainStartsOffset = forImage.loadAddress()->chainStartsOffset();
1461 if ( _handlers != nullptr ) {
1462 forImage.loadAddress()->withChainStarts(_diag, chainStartsOffset, ^(const dyld_chained_starts_in_image* starts) {
1463 _handlers->chainedBind(forImage.imageNum, forImage.loadAddress(), starts, targets, targetInfos);
1464 });
1465 }
1466 else {
1467 writer.setChainedFixups(chainStartsOffset, targets);
1468 }
1469
1470 // with chained fixups, main executable may define symbol that overrides weak-defs but has no fixup
1471 if ( _isLaunchClosure && forImage.loadAddress()->hasWeakDefs() && forImage.loadAddress()->isMainExecutable() ) {
1472 for (const char* weakSymbolName : sTreatAsWeak) {
1473 Diagnostics exportDiag;
1474 dyld3::MachOAnalyzer::FoundSymbol foundInfo;
1475 if ( forImage.loadAddress()->findExportedSymbol(exportDiag, weakSymbolName, false, foundInfo, nullptr) ) {
1476 _weakDefsFromChainedBinds.push_back(weakSymbolName);
1477 }
1478 }
1479 }
1480 }
1481
1482
1483 bool ClosureBuilder::findSymbolInImage(const MachOAnalyzer* macho, const char* symbolName, uint64_t addend, bool followReExports,
1484 bool weakImport, Image::ResolvedSymbolTarget& target, ResolvedTargetInfo& targetInfo)
1485 {
1486 targetInfo.foundInDylib = nullptr;
1487 targetInfo.requestedSymbolName = symbolName;
1488 targetInfo.addend = addend;
1489 targetInfo.weakBindCoalese = false;
1490 targetInfo.weakBindSameImage = false;
1491 targetInfo.isWeakDef = false;
1492 targetInfo.skippableWeakDef = false;
1493 MachOLoaded::DependentToMachOLoaded reexportFinder = ^(const MachOLoaded* mh, uint32_t depIndex) {
1494 return (const MachOLoaded*)findDependent(mh, depIndex);
1495 };
1496 MachOAnalyzer::DependentToMachOLoaded finder = nullptr;
1497 if ( followReExports )
1498 finder = reexportFinder;
1499
1500 dyld3::MachOAnalyzer::FoundSymbol foundInfo;
1501 if ( macho->findExportedSymbol(_diag, symbolName, weakImport, foundInfo, finder) ) {
1502 const MachOAnalyzer* impDylib = (const MachOAnalyzer*)foundInfo.foundInDylib;
1503 targetInfo.foundInDylib = foundInfo.foundInDylib;
1504 targetInfo.foundSymbolName = foundInfo.foundSymbolName;
1505 if ( foundInfo.isWeakDef )
1506 targetInfo.isWeakDef = true;
1507 if ( foundInfo.kind == MachOAnalyzer::FoundSymbol::Kind::absolute ) {
1508 target.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
1509 target.absolute.value = foundInfo.value + addend;
1510 }
1511 else if ( impDylib->inDyldCache() ) {
1512 uint64_t offsetValue = (uint8_t*)impDylib - (uint8_t*)_dyldCache + foundInfo.value + addend;
1513 target.sharedCache.kind = Image::ResolvedSymbolTarget::kindSharedCache;
1514 target.sharedCache.offset = offsetValue;
1515 assert(target.sharedCache.offset == offsetValue);
1516 }
1517 else {
1518 uint64_t offsetValue = foundInfo.value + addend;
1519 target.image.kind = Image::ResolvedSymbolTarget::kindImage;
1520 target.image.imageNum = findLoadedImage(impDylib).imageNum;
1521 target.image.offset = offsetValue;
1522 assert(target.image.offset == offsetValue);
1523 }
1524 return true;
1525 }
1526 return false;
1527 }
1528
1529 bool ClosureBuilder::findSymbol(BuilderLoadedImage& fromImage, int libOrdinal, const char* symbolName, bool weakImport, bool lazyBind,
1530 uint64_t addend, Image::ResolvedSymbolTarget& target, ResolvedTargetInfo& targetInfo)
1531 {
1532 target.raw = 0;
1533 targetInfo.weakBindCoalese = false;
1534 targetInfo.weakBindSameImage = false;
1535 targetInfo.isWeakDef = false;
1536 targetInfo.skippableWeakDef = false;
1537 targetInfo.requestedSymbolName = symbolName;
1538 targetInfo.libOrdinal = libOrdinal;
1539 if ( libOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) {
1540 for (const BuilderLoadedImage& li : _loadedImages) {
1541 if ( !li.rtldLocal && findSymbolInImage(li.loadAddress(), symbolName, addend, true, weakImport, target, targetInfo) )
1542 return true;
1543 }
1544 if ( weakImport ) {
1545 target.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
1546 target.absolute.value = 0;
1547 // Record that we found a missing weak import so that the objc optimizer doens't have to check
1548 fromImage.hasMissingWeakImports = true;
1549 return true;
1550 }
1551 // <rdar://problem/44315944> closures should bind missing lazy-bind symbols to a missing symbol handler in libdyld in flat namespace
1552 if ( lazyBind && _allowMissingLazies ) {
1553 if ( findMissingSymbolHandler(target, targetInfo) )
1554 return true;
1555 }
1556 _diag.error("symbol '%s' not found, expected in flat namespace by '%s'", symbolName, fromImage.path());
1557 }
1558 else if ( libOrdinal == BIND_SPECIAL_DYLIB_WEAK_LOOKUP ) {
1559 // to resolve weakDef coalesing, we need to search all images in order and use first definition
1560 // but, if first found is a weakDef, a later non-weak def overrides that
1561 bool foundWeakDefImpl = false;
1562 bool foundStrongDefImpl = false;
1563 bool foundImpl = false;
1564
1565 if ( _makingDyldCacheImages ) {
1566 // _loadedImages is all dylibs in the dyld cache, it is not load-order, so need alterate weak-def binding algorithm
1567 // look first in /usr/lib/libc++, most will be here
1568 for (const BuilderLoadedImage& li : _loadedImages) {
1569 if ( li.loadAddress()->hasWeakDefs() && (strncmp(li.path(), "/usr/lib/libc++", 15) == 0) ) {
1570 if ( findSymbolInImage(li.loadAddress(), symbolName, addend, false, weakImport, target, targetInfo) ) {
1571 foundImpl = true;
1572 break;
1573 }
1574 }
1575 }
1576 // if not found, try looking in the images itself, most custom weak-def symbols have a copy in the image itself
1577 if ( !foundImpl ) {
1578 if ( findSymbolInImage(fromImage.loadAddress(), symbolName, addend, false, weakImport, target, targetInfo) ) {
1579 foundImpl = true;
1580 }
1581 }
1582 // if still not found, then this is the rare case of a simple use of a weak-def symbol
1583 if ( !foundImpl ) {
1584 // look in all direct dependents
1585 for (Image::LinkedImage child : fromImage.dependents) {
1586 if (child.imageNum() == kMissingWeakLinkedImage)
1587 continue;
1588 BuilderLoadedImage& childLi = findLoadedImage(child.imageNum());
1589 if ( childLi.loadAddress()->hasWeakDefs() && findSymbolInImage(childLi.loadAddress(), symbolName, addend, false, weakImport, target, targetInfo) ) {
1590 foundImpl = true;
1591 break;
1592 }
1593 }
1594 }
1595 targetInfo.weakBindCoalese = true;
1596 }
1597 else {
1598 // walk images in load-order to find first that implements this symbol
1599 Image::ResolvedSymbolTarget aTarget;
1600 ResolvedTargetInfo aTargetInfo;
1601 STACK_ALLOC_ARRAY(const BuilderLoadedImage*, cachedDylibsUsingSymbol, 1024);
1602 for (const BuilderLoadedImage& li : _loadedImages) {
1603 // only search images with weak-defs that were not loaded with RTLD_LOCAL
1604 if ( li.loadAddress()->hasWeakDefs() && !li.rtldLocal ) {
1605 if ( findSymbolInImage(li.loadAddress(), symbolName, addend, false, weakImport, aTarget, aTargetInfo) ) {
1606 foundImpl = true;
1607 // with non-chained images, weak-defs first have a rebase to their local impl, and a weak-bind which allows earlier impls to override
1608 if ( !li.loadAddress()->hasChainedFixups() && (aTargetInfo.foundInDylib == fromImage.loadAddress()) )
1609 targetInfo.weakBindSameImage = true;
1610 if ( aTargetInfo.isWeakDef ) {
1611 // found a weakDef impl, if this is first found, set target to this
1612 if ( !foundWeakDefImpl && !foundStrongDefImpl ) {
1613 target = aTarget;
1614 targetInfo = aTargetInfo;
1615 }
1616 foundWeakDefImpl = true;
1617 }
1618 else {
1619 // found a non-weak impl, use this (unless early strong found)
1620 if ( !foundStrongDefImpl ) {
1621 target = aTarget;
1622 targetInfo = aTargetInfo;
1623 }
1624 foundStrongDefImpl = true;
1625 }
1626 }
1627 if ( foundImpl && li.loadAddress()->inDyldCache() )
1628 cachedDylibsUsingSymbol.push_back(&li);
1629 }
1630 }
1631
1632 // now that final target found, if any dylib in dyld cache uses that symbol name, redirect it to new target
1633 if ( !cachedDylibsUsingSymbol.empty() ) {
1634 for (const BuilderLoadedImage* li : cachedDylibsUsingSymbol) {
1635 Image::ResolvedSymbolTarget implInCache;
1636 ResolvedTargetInfo implInCacheInfo;
1637 if ( findSymbolInImage(li->loadAddress(), symbolName, addend, false, weakImport, implInCache, implInCacheInfo) ) {
1638 if ( implInCache != target ) {
1639 // found another instance in some dylib in dyld cache, will need to patch it
1640 Closure::PatchEntry patch;
1641 patch.exportCacheOffset = (uint32_t)implInCache.sharedCache.offset;
1642 patch.overriddenDylibInCache = li->imageNum;
1643 patch.replacement = target;
1644 _weakDefCacheOverrides.push_back(patch);
1645 }
1646 }
1647 }
1648 }
1649 targetInfo.weakBindCoalese = true;
1650 }
1651
1652 if ( foundImpl )
1653 return true;
1654 if ( weakImport ) {
1655 target.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
1656 target.absolute.value = 0;
1657 return true;
1658 }
1659 if ( ! fromImage.loadAddress()->hasChainedFixups() ) {
1660 // support old binaries where symbols have been stripped and have weak_bind to itself
1661 targetInfo.skippableWeakDef = true;
1662 return true;
1663 }
1664
1665 _diag.error("symbol '%s' not found, expected to be weak-def coalesced by '%s'", symbolName, fromImage.path());
1666 }
1667 else {
1668 const BuilderLoadedImage* targetLoadedImage = nullptr;
1669 if ( (libOrdinal > 0) && (libOrdinal <= (int)fromImage.dependents.count()) ) {
1670 ImageNum childNum = fromImage.dependents[libOrdinal - 1].imageNum();
1671 if ( childNum != kMissingWeakLinkedImage ) {
1672 targetLoadedImage = &findLoadedImage(childNum);
1673 }
1674 }
1675 else if ( libOrdinal == BIND_SPECIAL_DYLIB_SELF ) {
1676 targetLoadedImage = &fromImage;
1677 }
1678 else if ( libOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
1679 targetLoadedImage = &_loadedImages[_mainProgLoadIndex];
1680 }
1681 else {
1682 _diag.error("unknown special ordinal %d in %s", libOrdinal, fromImage.path());
1683 return false;
1684 }
1685
1686 if ( targetLoadedImage != nullptr ) {
1687 if ( findSymbolInImage(targetLoadedImage->loadAddress(), symbolName, addend, true, weakImport, target, targetInfo) )
1688 return true;
1689 }
1690
1691 if ( weakImport ) {
1692 target.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
1693 target.absolute.value = 0;
1694 // Record that we found a missing weak import so that the objc optimizer doens't have to check
1695 fromImage.hasMissingWeakImports = true;
1696 return true;
1697 }
1698
1699 // <rdar://problem/43315403> closures should bind missing lazy-bind symbols to a missing symbol handler in libdyld
1700 if ( lazyBind && _allowMissingLazies ) {
1701 if ( findMissingSymbolHandler(target, targetInfo) )
1702 return true;
1703 }
1704
1705 // symbol not found and not weak or lazy so error out
1706 const char* expectedInPath = targetLoadedImage ? targetLoadedImage->path() : "unknown";
1707 _diag.error("symbol '%s' not found, expected in '%s', needed by '%s'", symbolName, expectedInPath, fromImage.path());
1708 if ( _launchErrorInfo != nullptr ) {
1709 _launchErrorInfo->kind = DYLD_EXIT_REASON_SYMBOL_MISSING;
1710 _launchErrorInfo->clientOfDylibPath = strdup_temp(fromImage.path());
1711 _launchErrorInfo->targetDylibPath = strdup_temp(expectedInPath);
1712 _launchErrorInfo->symbol = symbolName;
1713 }
1714 }
1715 return false;
1716 }
1717
1718
1719 bool ClosureBuilder::findMissingSymbolHandler(Image::ResolvedSymbolTarget& target, ResolvedTargetInfo& targetInfo)
1720 {
1721 for (BuilderLoadedImage& li : _loadedImages) {
1722 if ( li.loadAddress()->isDylib() && (strcmp(li.loadAddress()->installName(), "/usr/lib/system/libdyld.dylib") == 0) ) {
1723 if ( findSymbolInImage(li.loadAddress(), "__dyld_missing_symbol_abort", 0, false, false, target, targetInfo) ) {
1724 return true;
1725 }
1726 break;
1727 }
1728 }
1729 return false;
1730 }
1731
1732 void ClosureBuilder::depthFirstRecurseSetInitInfo(uint32_t loadIndex, InitInfo initInfos[], uint32_t& initOrder, bool& hasError)
1733 {
1734 if ( initInfos[loadIndex].visited )
1735 return;
1736 initInfos[loadIndex].visited = true;
1737 initInfos[loadIndex].danglingUpward = false;
1738
1739 if (_loadedImages[loadIndex].isBadImage) {
1740 hasError = true;
1741 return;
1742 }
1743
1744 for (const Image::LinkedImage& dep : _loadedImages[loadIndex].dependents) {
1745 if ( dep.imageNum() == kMissingWeakLinkedImage )
1746 continue;
1747 ClosureBuilder::BuilderLoadedImage& depLi = findLoadedImage(dep.imageNum());
1748 uint32_t depLoadIndex = (uint32_t)_loadedImages.index(depLi);
1749 if ( dep.kind() == Image::LinkKind::upward ) {
1750 if ( !initInfos[depLoadIndex].visited )
1751 initInfos[depLoadIndex].danglingUpward = true;
1752 }
1753 else {
1754 depthFirstRecurseSetInitInfo(depLoadIndex, initInfos, initOrder, hasError);
1755 if (hasError)
1756 return;
1757 }
1758 }
1759 initInfos[loadIndex].initOrder = initOrder++;
1760 }
1761
1762 void ClosureBuilder::computeInitOrder(ImageWriter& imageWriter, uint32_t loadIndex)
1763 {
1764 // allocate array to track initializers
1765 InitInfo initInfos[_loadedImages.count()];
1766 bzero(initInfos, sizeof(initInfos));
1767
1768 // recurse all images and build initializer list from bottom up
1769 uint32_t initOrder = 1;
1770 bool hasMissingDependent = false;
1771 depthFirstRecurseSetInitInfo(loadIndex, initInfos, initOrder, hasMissingDependent);
1772 if (hasMissingDependent) {
1773 imageWriter.setInvalid();
1774 return;
1775 }
1776
1777 // any images not visited yet are are danging, force add them to end of init list
1778 for (uint32_t i=0; i < (uint32_t)_loadedImages.count(); ++i) {
1779 if ( !initInfos[i].visited && initInfos[i].danglingUpward ) {
1780 depthFirstRecurseSetInitInfo(i, initInfos, initOrder, hasMissingDependent);
1781 }
1782 }
1783
1784 if (hasMissingDependent) {
1785 imageWriter.setInvalid();
1786 return;
1787 }
1788
1789 // build array of just images with initializer
1790 STACK_ALLOC_ARRAY(uint32_t, indexOfImagesWithInits, _loadedImages.count());
1791 uint32_t index = 0;
1792 for (const BuilderLoadedImage& li : _loadedImages) {
1793 if ( initInfos[index].visited && li.hasInits ) {
1794 indexOfImagesWithInits.push_back(index);
1795 }
1796 ++index;
1797 }
1798
1799 // bubble sort (FIXME)
1800 if ( indexOfImagesWithInits.count() > 1 ) {
1801 for (uint32_t i=0; i < indexOfImagesWithInits.count()-1; ++i) {
1802 for (uint32_t j=0; j < indexOfImagesWithInits.count()-i-1; ++j) {
1803 if ( initInfos[indexOfImagesWithInits[j]].initOrder > initInfos[indexOfImagesWithInits[j+1]].initOrder ) {
1804 uint32_t temp = indexOfImagesWithInits[j];
1805 indexOfImagesWithInits[j] = indexOfImagesWithInits[j+1];
1806 indexOfImagesWithInits[j+1] = temp;
1807 }
1808 }
1809 }
1810 }
1811
1812 // copy ImageNum of each image with initializers into array
1813 ImageNum initNums[indexOfImagesWithInits.count()];
1814 for (uint32_t i=0; i < indexOfImagesWithInits.count(); ++i) {
1815 initNums[i] = _loadedImages[indexOfImagesWithInits[i]].imageNum;
1816 }
1817
1818 // add to closure info
1819 imageWriter.setInitsOrder(initNums, (uint32_t)indexOfImagesWithInits.count());
1820 }
1821
1822 void ClosureBuilder::addClosureInfo(LaunchClosureWriter& closureWriter)
1823 {
1824 // record which is libSystem
1825 assert(_libSystemImageNum != 0);
1826 closureWriter.setLibSystemImageNum(_libSystemImageNum);
1827
1828 // record which is libdyld
1829 assert(_libDyldImageNum != 0);
1830 Image::ResolvedSymbolTarget entryLocation;
1831 ResolvedTargetInfo entryInfo;
1832 if ( findSymbolInImage(findLoadedImage(_libDyldImageNum).loadAddress(), "__ZN5dyld318entryVectorForDyldE", 0, false, false, entryLocation, entryInfo) ) {
1833 const dyld3::LibDyldEntryVector* libDyldEntry = nullptr;
1834 switch ( entryLocation.image.kind ) {
1835 case Image::ResolvedSymbolTarget::kindSharedCache:
1836 libDyldEntry = (dyld3::LibDyldEntryVector*)((uint8_t*)_dyldCache + entryLocation.sharedCache.offset);
1837 break;
1838 case Image::ResolvedSymbolTarget::kindImage:
1839 libDyldEntry = (dyld3::LibDyldEntryVector*)((uint8_t*)findLoadedImage(entryLocation.image.imageNum).loadAddress() + entryLocation.image.offset);
1840 break;
1841 }
1842 if ( (libDyldEntry != nullptr) && ((libDyldEntry->binaryFormatVersion & LibDyldEntryVector::kBinaryFormatVersionMask) == dyld3::closure::kFormatVersion) )
1843 closureWriter.setLibDyldEntry(entryLocation);
1844 else
1845 _diag.error("libdyld.dylib entry vector is incompatible");
1846 }
1847 else {
1848 _diag.error("libdyld.dylib is missing entry vector");
1849 }
1850
1851 // record which is main executable
1852 ImageNum mainProgImageNum = _loadedImages[_mainProgLoadIndex].imageNum;
1853 closureWriter.setTopImageNum(mainProgImageNum);
1854
1855 // add entry
1856 uint32_t entryOffset;
1857 bool usesCRT;
1858 if ( _loadedImages[_mainProgLoadIndex].loadAddress()->getEntry(entryOffset, usesCRT) ) {
1859 Image::ResolvedSymbolTarget location;
1860 location.image.kind = Image::ResolvedSymbolTarget::kindImage;
1861 location.image.imageNum = mainProgImageNum;
1862 location.image.offset = entryOffset;
1863 if ( usesCRT )
1864 closureWriter.setStartEntry(location);
1865 else
1866 closureWriter.setMainEntry(location);
1867 }
1868
1869 // add env vars that must match at launch time
1870 _pathOverrides.forEachEnvVar(^(const char* envVar) {
1871 closureWriter.addEnvVar(envVar);
1872 });
1873
1874 // add list of files which must be missing
1875 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(const char*, paths, 8192);
1876 if ( _mustBeMissingPaths != nullptr ) {
1877 _mustBeMissingPaths->forEachPath(^(const char* aPath) {
1878 paths.push_back(aPath);
1879 });
1880 }
1881 closureWriter.setMustBeMissingFiles(paths);
1882
1883 // add list of files which must be be present with a specific inode/mtime
1884 if (!_skippedFiles.empty())
1885 closureWriter.setMustExistFiles(_skippedFiles);
1886 }
1887 void ClosureBuilder::invalidateInitializerRoots()
1888 {
1889 while (true) {
1890 bool madeChange = false;
1891 for (uintptr_t loadedImageIndex = _alreadyInitedIndex; loadedImageIndex != _loadedImages.count(); ++loadedImageIndex) {
1892 BuilderLoadedImage& li = _loadedImages[loadedImageIndex];
1893 if ( li.mustBuildClosure ) {
1894 // Already invalidated
1895 continue;
1896 }
1897 for (Image::LinkedImage depIndex : li.dependents) {
1898 if ( depIndex.imageNum() == kMissingWeakLinkedImage )
1899 continue;
1900 BuilderLoadedImage& depImage = findLoadedImage(depIndex.imageNum());
1901 // If a dependent is bad, or a new image num, or an override, then we need this image to get a new closure
1902 if ( depImage.mustBuildClosure ) {
1903 li.mustBuildClosure = true; // mark bad
1904 madeChange = true;
1905 }
1906 }
1907 }
1908 if (!madeChange)
1909 break;
1910 // If we made a change, then we detected an existing image with a dependent which needed to be rebuilt.
1911 // This corresponds to a root of the shared cache where the existing image is a shared cache one and the root is the depImage
1912 _foundDyldCacheRoots = true;
1913 }
1914 }
1915
1916 size_t ClosureBuilder::HashCString::hash(const char* v) {
1917 // FIXME: Use hash<string_view> when it has the correct visibility markup
1918 return __gnu_cxx::hash<const char*>{}(v);
1919 }
1920
1921 bool ClosureBuilder::EqualCString::equal(const char* s1, const char* s2) {
1922 return strcmp(s1, s2) == 0;
1923 }
1924
1925
1926 struct HashUInt64 {
1927 static size_t hash(const uint64_t& v) {
1928 return std::hash<uint64_t>{}(v);
1929 }
1930 };
1931
1932 struct EqualUInt64 {
1933 static bool equal(uint64_t s1, uint64_t s2) {
1934 return s1 == s2;
1935 }
1936 };
1937
1938 void ClosureBuilder::writeClassOrProtocolHashTable(bool classes, Array<ObjCOptimizerImage>& objcImages) {
1939 __block MultiMap<const char*, dyld3::closure::Image::ObjCClassImageOffset, HashCString, EqualCString> seenClassesMap;
1940 __block Map<const char*, dyld3::closure::Image::ObjCClassNameImageOffset, HashCString, EqualCString> classNameMap;
1941 __block OverflowSafeArray<const char*> classNames;
1942
1943 // Note we walk the images backwards as we want them in load order to match the order they are registered with objc
1944 for (size_t imageIndex = 0, reverseIndex = (objcImages.count() - 1); imageIndex != objcImages.count(); ++imageIndex, --reverseIndex) {
1945 if (objcImages[reverseIndex].diag.hasError())
1946 continue;
1947 ObjCOptimizerImage& image = objcImages[reverseIndex];
1948 const OverflowSafeArray<ObjCOptimizerImage::SeenClass>& seenClasses = classes ? image.seenClasses : image.seenProtocols;
1949
1950 for (const ObjCOptimizerImage::SeenClass& seenClass : seenClasses) {
1951 closure::Image::ObjCClassNameImageOffset classNameTarget = seenClass.first;
1952 dyld3::closure::Image::ObjCClassImageOffset classDataTarget = seenClass.second;
1953 Image::ObjCClassImage classImage = _objcClassesHashTableImages[classNameTarget.classNameImageIndex];
1954
1955 const BuilderLoadedImage& li = findLoadedImage(classImage.imageNum);
1956 const dyld3::MachOAnalyzer* ma = li.loadAddress();
1957
1958 const char* className = ((const char*)ma) + classImage.offsetOfClassNames + classNameTarget.classNameImageOffset;
1959 //uint64_t nameVMAddr = ma->preferredLoadAddress() + classImage.offsetOfClassNames + classNameTarget.classNameImageOffset;
1960 //printf("%s: 0x%08llx = '%s'\n", li.path(), nameVMAddr, className);
1961 seenClassesMap.insert({ className, classDataTarget });
1962
1963 // Also track the name
1964 auto itAndInserted = classNameMap.insert({ className, dyld3::closure::Image::ObjCClassNameImageOffset() });
1965 if (itAndInserted.second) {
1966 // We inserted the class name so we need to add it to the strings for the closure hash table
1967 classNames.push_back(className);
1968
1969 // We already computed a class name target in a previous loop so use that one
1970 itAndInserted.first->second = seenClass.first;
1971
1972 // If we are processing protocols, and this is the first one we've seen, then track its ISA to be fixed up
1973 if ( !classes ) {
1974 uint64_t protocolVMOffset = classImage.offsetOfClasses + classDataTarget.classData.imageOffset;
1975 image.protocolISAFixups.push_back(protocolVMOffset);
1976 }
1977 }
1978 }
1979 }
1980
1981 __block uint32_t duplicateCount = 0;
1982 seenClassesMap.forEachEntry(^(const char *const &key, const Image::ObjCClassImageOffset **values,
1983 uint64_t valuesCount) {
1984 if (valuesCount != 1)
1985 duplicateCount += valuesCount;
1986 });
1987
1988 // If we have closure class names, we need to make a hash table for them.
1989 OverflowSafeArray<uint8_t>& hashTable = classes ? _objcClassesHashTable : _objcProtocolsHashTable;
1990 if (!classNames.empty()) {
1991 objc_opt::perfect_hash phash;
1992 objc_opt::make_perfect(classNames, phash);
1993 size_t size = ObjCClassOpt::size(phash, duplicateCount);
1994 hashTable.resize(size);
1995 //printf("Class table size: %lld\n", size);
1996 ObjCClassOpt* classesHashTable = (ObjCClassOpt*)hashTable.begin();
1997 classesHashTable->write(phash, classNameMap.array(), seenClassesMap, duplicateCount);
1998 }
1999 }
2000
2001 bool ClosureBuilder::optimizeObjC(Array<ImageWriter>& writers) {
2002 if ( _dyldCache == nullptr )
2003 return false;
2004
2005 // If we have the read only data, make sure it has a valid selector table inside.
2006 const objc_opt::objc_clsopt_t* objcClassOpt = nullptr;
2007 const objc_opt::objc_selopt_t* objcSelOpt = nullptr;
2008 const objc_opt::objc_protocolopt2_t* objcProtocolOpt = nullptr;
2009 if (const objc_opt::objc_opt_t* optObjCHeader = _dyldCache->objcOpt()) {
2010 objcClassOpt = optObjCHeader->clsopt();
2011 objcSelOpt = optObjCHeader->selopt();
2012 objcProtocolOpt = optObjCHeader->protocolopt2();
2013 }
2014
2015 if ( !objcClassOpt || !objcSelOpt || !objcProtocolOpt )
2016 return false;
2017
2018 // We have 24 bits of index in SelectorReferenceFixup so we can't handle a
2019 // shared cache selector table larger than that
2020 if ( objcSelOpt->usedCount() >= (1 << 24) )
2021 return false;
2022
2023 // Make sure we have the pointers section with the pointer to the protocol class
2024 const void* objcOptPtrs = _dyldCache->objcOptPtrs();
2025 if ( objcOptPtrs == nullptr )
2026 return false;
2027
2028 uint32_t pointerSize = _loadedImages.begin()->loadAddress()->pointerSize();
2029 uint64_t classProtocolVMAddr = (pointerSize == 8) ? *(uint64_t*)objcOptPtrs : *(uint32_t*)objcOptPtrs;
2030
2031 Image::ResolvedSymbolTarget objcProtocolClassTarget;
2032 objcProtocolClassTarget.sharedCache.kind = Image::ResolvedSymbolTarget::kindSharedCache;
2033 if ( _dyldCacheIsLive ) {
2034 objcProtocolClassTarget.sharedCache.offset = classProtocolVMAddr - (uint64_t)_dyldCache;
2035 } else {
2036 objcProtocolClassTarget.sharedCache.offset = classProtocolVMAddr - _dyldCache->unslidLoadAddress();
2037 }
2038
2039 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(ObjCOptimizerImage, objcImages, 32);
2040 ArrayFinalizer<ObjCOptimizerImage> scopedCleanup(objcImages,
2041 ^(ObjCOptimizerImage& objcImage) {
2042 objcImage.~ObjCOptimizerImage();
2043 });
2044
2045 // Find all the images with valid objc info
2046 // Also add shared cache images to a map so that we can see them later for looking up classes
2047 Map<const dyld3::MachOAnalyzer*, bool, HashPointer, EqualPointer> sharedCacheImagesMap;
2048 for (size_t imageIndex = 0, writerIndex = 0; imageIndex != _loadedImages.count(); ++imageIndex) {
2049 BuilderLoadedImage& li = _loadedImages[imageIndex];
2050
2051 // Skip shared cache images as even if they need a new closure, the objc runtime can still use
2052 // the optimized shared cache tables.
2053 if ( li.loadAddress()->inDyldCache() ) {
2054 sharedCacheImagesMap.insert({ li.loadAddress(), true });
2055 // Bump the writer index if we have a writer for this image
2056 if ( li.mustBuildClosure )
2057 ++writerIndex;
2058 continue;
2059 }
2060 // Images which don't need a closure can be skipped. They are from the shared cache
2061 if ( !li.mustBuildClosure )
2062 continue;
2063
2064 // If we have a root of libobjc, just give up for now
2065 if ( !strcmp(li.path(), "/usr/lib/libobjc.A.dylib"))
2066 return false;
2067
2068 ImageWriter& writer = writers[writerIndex];
2069 ++writerIndex;
2070
2071 const dyld3::MachOAnalyzer* ma = li.loadAddress();
2072
2073 // Skip images with chained fixups other than arm64e legacy fixups until we can test them
2074 // FIXME: Handle chained fixups
2075 if ( ma->hasChainedFixups() ) {
2076 switch ( ma->chainedPointerFormat() ) {
2077 case DYLD_CHAINED_PTR_ARM64E:
2078 case DYLD_CHAINED_PTR_64:
2079 // We've tested the 64-bit chained fixups.
2080 break;
2081 case DYLD_CHAINED_PTR_32:
2082 case DYLD_CHAINED_PTR_32_CACHE:
2083 case DYLD_CHAINED_PTR_32_FIRMWARE:
2084 // FIXME: Test 32-bit chained fixups then enable this.
2085 continue;
2086 }
2087 }
2088
2089 const MachOAnalyzer::ObjCImageInfo* objcImageInfo = ma->objcImageInfo();
2090 if ( objcImageInfo == nullptr )
2091 continue;
2092
2093 // This image is good so record it for use later.
2094 objcImages.default_constuct_back();
2095 ObjCOptimizerImage& image = objcImages.back();
2096 image.loadedImage = &li;
2097 image.writer = &writer;
2098
2099 // Find FairPlay encryption range if encrypted
2100 uint32_t fairPlayFileOffset;
2101 uint32_t fairPlaySize;
2102 if ( ma->isFairPlayEncrypted(fairPlayFileOffset, fairPlaySize) ) {
2103 image.fairplayFileOffsetStart = fairPlayFileOffset;
2104 image.fairplayFileOffsetEnd = fairPlayFileOffset;
2105 }
2106
2107 // Set the offset to the objc image info
2108 image.objcImageInfoVMOffset = (uint64_t)objcImageInfo - (uint64_t)ma;
2109 }
2110
2111 OverflowSafeArray<const char*> closureSelectorStrings;
2112 Map<const char*, dyld3::closure::Image::ObjCImageOffset, HashCString, EqualCString> closureSelectorMap;
2113 OverflowSafeArray<const char*> closureDuplicateSharedCacheClassNames;
2114 Map<const char*, dyld3::closure::Image::ObjCDuplicateClass, HashCString, EqualCString> closureDuplicateSharedCacheClassMap;
2115 for (ObjCOptimizerImage& image : objcImages) {
2116 optimizeObjCClasses(objcClassOpt, sharedCacheImagesMap, closureDuplicateSharedCacheClassMap, image);
2117 if (image.diag.hasError())
2118 continue;
2119
2120 optimizeObjCProtocols(objcProtocolOpt, sharedCacheImagesMap, image);
2121 if (image.diag.hasError())
2122 continue;
2123
2124 optimizeObjCSelectors(objcSelOpt, closureSelectorMap, image);
2125 if (image.diag.hasError())
2126 continue;
2127
2128 // If this image is still valid, then add its intermediate results to the main tables
2129
2130 // Class results
2131 for (auto nameAndDataVMOffset : image.classesNameAndDataVMOffsets) {
2132 uint64_t nameVMOffset = nameAndDataVMOffset.first;
2133 uint64_t dataVMOffset = nameAndDataVMOffset.second;
2134 _objcClassesHashTableImages.push_back({ image.loadedImage->imageNum, (uint32_t)nameVMOffset, (uint32_t)dataVMOffset });
2135 }
2136 image.classesNameAndDataVMOffsets.clear();
2137
2138 for (const auto& stringAndDuplicate : image.classSharedCacheDuplicates) {
2139 closureDuplicateSharedCacheClassMap[stringAndDuplicate.first] = stringAndDuplicate.second;
2140 closureDuplicateSharedCacheClassNames.push_back(stringAndDuplicate.first);
2141 }
2142
2143 // Selector results
2144 // Note we don't need to add the selector binds here. Its easier just to process them later from each image
2145 for (const auto& stringAndTarget : image.selectorMap) {
2146 closureSelectorMap[stringAndTarget.first] = stringAndTarget.second;
2147 closureSelectorStrings.push_back(stringAndTarget.first);
2148 }
2149 if (image.methodNameVMOffset)
2150 _objcSelectorsHashTableImages.push_back({ image.loadedImage->imageNum, (uint32_t)*image.methodNameVMOffset });
2151 }
2152
2153 // If we successfully analyzed the classes and selectors, we can now emit their data
2154 // Set all the writers to have optimized objc
2155 for (ObjCOptimizerImage& image : objcImages) {
2156 if (image.diag.hasError())
2157 continue;
2158 image.writer->setHasPrecomputedObjC(true);
2159 }
2160
2161 // Write out the class table
2162 writeClassOrProtocolHashTable(true, objcImages);
2163
2164 // Write out the protocol table
2165 writeClassOrProtocolHashTable(false, objcImages);
2166
2167 // If we have closure duplicate classes, we need to make a hash table for them.
2168 closure::ObjCStringTable* duplicateClassesTable = nullptr;
2169 if (!closureDuplicateSharedCacheClassNames.empty()) {
2170 objc_opt::perfect_hash phash;
2171 objc_opt::make_perfect(closureDuplicateSharedCacheClassNames, phash);
2172 size_t size = ObjCStringTable::size(phash);
2173 _objcClassesDuplicatesHashTable.resize(size);
2174 //printf("Duplicate classes table size: %lld\n", size);
2175 duplicateClassesTable = (closure::ObjCClassDuplicatesOpt*)_objcClassesDuplicatesHashTable.begin();
2176 duplicateClassesTable->write(phash, closureDuplicateSharedCacheClassMap.array());
2177 }
2178
2179 // If we have closure selectors, we need to make a hash table for them.
2180 closure::ObjCStringTable* selectorStringTable = nullptr;
2181 if (!closureSelectorStrings.empty()) {
2182 objc_opt::perfect_hash phash;
2183 objc_opt::make_perfect(closureSelectorStrings, phash);
2184 size_t size = ObjCStringTable::size(phash);
2185 _objcSelectorsHashTable.resize(size);
2186 //printf("Selector table size: %lld\n", size);
2187 selectorStringTable = (closure::ObjCStringTable*)_objcSelectorsHashTable.begin();
2188 selectorStringTable->write(phash, closureSelectorMap.array());
2189 }
2190
2191 // Add fixups for the image info, protocol ISAs, and selector refs
2192 for (ObjCOptimizerImage& image : objcImages) {
2193 if (image.diag.hasError())
2194 continue;
2195
2196 // Protocol ISA references
2197 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::ProtocolISAFixup, protocolFixups, 512);
2198 if ( !image.protocolISAFixups.empty() ) {
2199
2200 __block uint64_t lastOffset = -pointerSize;
2201 for (uint64_t runtimeOffset : image.protocolISAFixups) {
2202 bool mergedIntoPrevious = false;
2203 if ( (runtimeOffset > lastOffset) && !protocolFixups.empty() ) {
2204 uint64_t skipAmount = (runtimeOffset - lastOffset - pointerSize)/pointerSize;
2205 if ( skipAmount*pointerSize != (runtimeOffset - lastOffset - pointerSize) ) {
2206 // misaligned pointer means we cannot optimize
2207 }
2208 else {
2209 if ( (protocolFixups.back().repeatCount == 1) && (protocolFixups.back().skipCount == 0) && (skipAmount <= 255) ) {
2210 protocolFixups.back().repeatCount = 2;
2211 protocolFixups.back().skipCount = skipAmount;
2212 assert(protocolFixups.back().skipCount == skipAmount); // check overflow
2213 mergedIntoPrevious = true;
2214 }
2215 else if ( (protocolFixups.back().skipCount == skipAmount) && (protocolFixups.back().repeatCount < 0xfff) ) {
2216 uint32_t prevRepeatCount = protocolFixups.back().repeatCount;
2217 protocolFixups.back().repeatCount += 1;
2218 assert(protocolFixups.back().repeatCount > prevRepeatCount); // check overflow
2219 mergedIntoPrevious = true;
2220 }
2221 }
2222 }
2223 if ( !mergedIntoPrevious ) {
2224 Image::ProtocolISAFixup pattern;
2225 pattern.startVmOffset = runtimeOffset;
2226 pattern.repeatCount = 1;
2227 pattern.skipCount = 0;
2228 assert(pattern.startVmOffset == runtimeOffset);
2229 protocolFixups.push_back(pattern);
2230 }
2231 lastOffset = runtimeOffset;
2232 }
2233 }
2234
2235 // Selector references
2236 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::SelectorReferenceFixup, selRefFixups, 512);
2237 if ( !image.selectorFixups.empty() ) {
2238 uint64_t prevVMOffset = 0;
2239 const uint64_t maxChainOffset = (4 * ((1 << 7) - 1));
2240 for (const ObjCOptimizerImage::SelectorFixup& selectorFixup : image.selectorFixups) {
2241 assert( (selectorFixup.fixupVMOffset & 3) == 0 );
2242 if ( (selectorFixup.fixupVMOffset - prevVMOffset) <= maxChainOffset ) {
2243 // Add this to the previous chain
2244 selRefFixups.back().chainEntry.next = (uint32_t)(selectorFixup.fixupVMOffset - prevVMOffset) / 4;
2245 } else {
2246 // Need to start a new chain as the previous offset can't reach
2247 Image::SelectorReferenceFixup fixup;
2248 fixup.chainStartVMOffset = selectorFixup.fixupVMOffset;
2249 selRefFixups.push_back(fixup);
2250 }
2251
2252 if ( selectorFixup.isSharedCache ) {
2253 // If the entry is in the shared cache then we already have the index for it
2254 Image::SelectorReferenceFixup fixup;
2255 fixup.chainEntry.index = selectorFixup.sharedCache.selectorTableIndex;
2256 fixup.chainEntry.next = 0;
2257 fixup.chainEntry.inSharedCache = 1;
2258 selRefFixups.push_back(fixup);
2259 } else {
2260 // We had to record the string for the closure table entries as we don't know the
2261 // index until now
2262 uint32_t selectorTableIndex = selectorStringTable->getIndex(selectorFixup.image.selectorString);
2263 assert(selectorTableIndex != ObjCSelectorOpt::indexNotFound);
2264 Image::SelectorReferenceFixup fixup;
2265 fixup.chainEntry.index = selectorTableIndex;
2266 fixup.chainEntry.next = 0;
2267 fixup.chainEntry.inSharedCache = 0;
2268 selRefFixups.push_back(fixup);
2269 }
2270
2271 prevVMOffset = selectorFixup.fixupVMOffset;
2272 }
2273 }
2274
2275 // Stable Swift fixups
2276 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::ClassStableSwiftFixup, stableSwiftFixups, 512);
2277 if ( !image.classStableSwiftFixups.empty() ) {
2278
2279 __block uint64_t lastOffset = -pointerSize;
2280 for (uint64_t runtimeOffset : image.classStableSwiftFixups) {
2281 bool mergedIntoPrevious = false;
2282 if ( (runtimeOffset > lastOffset) && !stableSwiftFixups.empty() ) {
2283 uint64_t skipAmount = (runtimeOffset - lastOffset - pointerSize)/pointerSize;
2284 if ( skipAmount*pointerSize != (runtimeOffset - lastOffset - pointerSize) ) {
2285 // misaligned pointer means we cannot optimize
2286 }
2287 else {
2288 if ( (stableSwiftFixups.back().repeatCount == 1) && (stableSwiftFixups.back().skipCount == 0) && (skipAmount <= 255) ) {
2289 stableSwiftFixups.back().repeatCount = 2;
2290 stableSwiftFixups.back().skipCount = skipAmount;
2291 assert(stableSwiftFixups.back().skipCount == skipAmount); // check overflow
2292 mergedIntoPrevious = true;
2293 }
2294 else if ( (stableSwiftFixups.back().skipCount == skipAmount) && (stableSwiftFixups.back().repeatCount < 0xfff) ) {
2295 uint32_t prevRepeatCount = stableSwiftFixups.back().repeatCount;
2296 stableSwiftFixups.back().repeatCount += 1;
2297 assert(stableSwiftFixups.back().repeatCount > prevRepeatCount); // check overflow
2298 mergedIntoPrevious = true;
2299 }
2300 }
2301 }
2302 if ( !mergedIntoPrevious ) {
2303 Image::ClassStableSwiftFixup pattern;
2304 pattern.startVmOffset = runtimeOffset;
2305 pattern.repeatCount = 1;
2306 pattern.skipCount = 0;
2307 assert(pattern.startVmOffset == runtimeOffset);
2308 stableSwiftFixups.push_back(pattern);
2309 }
2310 lastOffset = runtimeOffset;
2311 }
2312 }
2313
2314 // Method list fixups
2315 // TODO: Implement this
2316 STACK_ALLOC_OVERFLOW_SAFE_ARRAY(Image::MethodListFixup, methodListFixups, 512);
2317
2318 image.writer->setObjCFixupInfo(objcProtocolClassTarget, image.objcImageInfoVMOffset, protocolFixups,
2319 selRefFixups, stableSwiftFixups, methodListFixups);
2320 }
2321
2322 return true;
2323 }
2324
2325 void ClosureBuilder::optimizeObjCSelectors(const objc_opt::objc_selopt_t* objcSelOpt,
2326 const Map<const char*, dyld3::closure::Image::ObjCImageOffset, HashCString, EqualCString>& closureSelectorMap,
2327 ObjCOptimizerImage& image) {
2328
2329 BuilderLoadedImage& li = *image.loadedImage;
2330
2331 const dyld3::MachOAnalyzer* ma = li.loadAddress();
2332 uint32_t pointerSize = ma->pointerSize();
2333 const uint64_t loadAddress = ma->preferredLoadAddress();
2334
2335 // The legacy (objc1) codebase uses a bunch of sections we don't want to reason about. If we see them just give up.
2336 __block bool foundBadSection = false;
2337 ma->forEachSection(^(const MachOAnalyzer::SectionInfo &sectInfo, bool malformedSectionRange, bool &stop) {
2338 if ( strcmp(sectInfo.segInfo.segName, "__OBJC") != 0 )
2339 return;
2340 if (strcmp(sectInfo.sectName, "__module_info") == 0) {
2341 foundBadSection = true;
2342 stop = true;
2343 return;
2344 }
2345 if (strcmp(sectInfo.sectName, "__protocol") == 0) {
2346 foundBadSection = true;
2347 stop = true;
2348 return;
2349 }
2350 if (strcmp(sectInfo.sectName, "__message_refs") == 0) {
2351 foundBadSection = true;
2352 stop = true;
2353 return;
2354 }
2355 });
2356 if (foundBadSection) {
2357 image.diag.error("Old objc section");
2358 return;
2359 }
2360
2361 __block MachOAnalyzer::SectionCache selectorStringSectionCache(ma);
2362
2363 uint32_t sharedCacheSentinelIndex = objcSelOpt->getSentinelIndex();
2364
2365 auto visitReferenceToObjCSelector = ^void(uint64_t selectorStringVMAddr, uint64_t selectorReferenceVMAddr) {
2366
2367 uint64_t selectorUseImageOffset = selectorReferenceVMAddr - loadAddress;
2368 if ( (selectorUseImageOffset & 3) != 0 ) {
2369 image.diag.error("Unaligned selector reference fixup");
2370 return;
2371 }
2372
2373 // Image::SelectorReferenceFixup only has a 32-bit reach
2374 if ( selectorUseImageOffset >= (1ULL << 32) ) {
2375 image.diag.error("Selector reference fixup exceeds supported vm offset");
2376 return;
2377 }
2378
2379 // Get the section for the name
2380 const char* selectorString = nullptr;
2381 MachOAnalyzer::PrintableStringResult selectorStringResult = MachOAnalyzer::PrintableStringResult::UnknownSection;
2382 __block uint64_t selectorStringSectionStartVMAddr = 0;
2383 auto selectorStringSectionHandler = ^bool(const MachOAnalyzer::SectionInfo& sectInfo) {
2384
2385 // We only have 24-bits in ObjCClassNameImageOffset to index in to the strings
2386 if (sectInfo.sectSize >= Image::ObjCImageOffset::maximumOffset) {
2387 return false;
2388 }
2389
2390 // We use 32-bit offsets so make sure the section is no larger than that.
2391 uint64_t classNameVMOffset = sectInfo.sectAddr - loadAddress;
2392 if (classNameVMOffset >= (1ULL << 32)) {
2393 return false;
2394 }
2395
2396 selectorStringSectionStartVMAddr = sectInfo.sectAddr;
2397 return true;
2398 };
2399 selectorString = ma->getPrintableString(selectorStringVMAddr, selectorStringResult,
2400 &selectorStringSectionCache, selectorStringSectionHandler);
2401
2402 if ( selectorStringResult != MachOAnalyzer::PrintableStringResult::CanPrint ) {
2403 image.diag.error("Invalid selector string for objc optimisation");
2404 return;
2405 }
2406
2407 uint32_t cacheSelectorIndex = objcSelOpt->getIndexForKey(selectorString);
2408 //printf("selector: %p -> %p %s\n", methodName, cacheSelector, selectorString);
2409
2410 if ( cacheSelectorIndex != sharedCacheSentinelIndex ) {
2411 // We got the selector from the cache so add a fixup to point there.
2412 ObjCOptimizerImage::SelectorFixup fixup;
2413 fixup.isSharedCache = true;
2414 fixup.fixupVMOffset = (uint32_t)selectorUseImageOffset;
2415 fixup.sharedCache.selectorTableIndex = cacheSelectorIndex;
2416
2417 //printf("Overriding fixup at 0x%08llX to cache offset 0x%08llX\n", selectorUseImageOffset, (uint64_t)cacheSelector - (uint64_t)_dyldCache);
2418 image.selectorFixups.push_back(fixup);
2419 return;
2420 }
2421
2422 // See if this selector is already in the closure map from a previous image
2423 auto closureSelectorIt = closureSelectorMap.find(selectorString);
2424 if (closureSelectorIt != closureSelectorMap.end()) {
2425 // This selector was found in a previous image, so use it here.
2426 ObjCOptimizerImage::SelectorFixup fixup;
2427 fixup.isSharedCache = false;
2428 fixup.fixupVMOffset = (uint32_t)selectorUseImageOffset;
2429 fixup.image.selectorString = selectorString;
2430
2431 //printf("Overriding fixup at 0x%08llX to '%s' offset 0x%08llX\n", selectorUseImageOffset, findLoadedImage(target.image.imageNum).path(), target.image.offset);
2432 image.selectorFixups.push_back(fixup);
2433 return;
2434 }
2435
2436 // See if this selector is already in the map for this image
2437 auto itAndInserted = image.selectorMap.insert({ selectorString, dyld3::closure::Image::ObjCImageOffset() });
2438 if (itAndInserted.second) {
2439 // We added the selector so its pointing in to our own image.
2440 // We don't need to add a fixup to our image, but we do need to
2441 // populate the data for other images later to point here.
2442 // First put our image in the list if its not already there.
2443 uint64_t methodNameVMOffset = selectorStringSectionStartVMAddr - loadAddress;
2444 if (!image.methodNameVMOffset) {
2445 if ( _objcSelectorsHashTableImages.count() == Image::ObjCImageOffset::maximumImageIndex ) {
2446 image.diag.error("Out of space for selector hash images");
2447 return;
2448 }
2449 image.methodNameVMOffset = methodNameVMOffset;
2450 } else {
2451 // If we already set the offset to the start of the method names section, double check that
2452 // the section we are in right now is the same as that one. Otherwise we don't have the code
2453 // to handle both right now.
2454 if (*image.methodNameVMOffset != methodNameVMOffset) {
2455 image.diag.error("Cannot handle more than one selector strings section");
2456 return;
2457 }
2458 }
2459
2460 dyld3::closure::Image::ObjCImageOffset target;
2461 target.imageIndex = (uint32_t)_objcSelectorsHashTableImages.count();
2462 target.imageOffset = (uint32_t)(selectorStringVMAddr - selectorStringSectionStartVMAddr);
2463 itAndInserted.first->second = target;
2464 return;
2465 }
2466
2467 // This selector was found elsewhere in our image. If this reference already points to the same
2468 // selector string as we found before (and it should!) then we have nothing to do. Otherwise we
2469 // need to add a fixup here to make sure we point to our chosen definition.
2470 uint32_t imageOffset = (uint32_t)(selectorStringVMAddr - loadAddress);
2471 if ( imageOffset == (*image.methodNameVMOffset + itAndInserted.first->second.imageOffset) )
2472 return;
2473
2474 ObjCOptimizerImage::SelectorFixup fixup;
2475 fixup.isSharedCache = false;
2476 fixup.fixupVMOffset = (uint32_t)selectorUseImageOffset;
2477 fixup.image.selectorString = selectorString;
2478
2479 //printf("Overriding fixup at 0x%08llX to '%s' offset 0x%08llX\n", selectorUseImageOffset, findLoadedImage(target.image.imageNum).path(), target.image.offset);
2480 image.selectorFixups.push_back(fixup);
2481 };
2482
2483 auto visitMethod = ^(uint64_t methodVMAddr, const dyld3::MachOAnalyzer::ObjCMethod& method) {
2484 visitReferenceToObjCSelector(method.nameVMAddr, method.nameLocationVMAddr);
2485 };
2486
2487 auto visitClass = ^(Diagnostics& diag, uint64_t classVMAddr,
2488 uint64_t classSuperclassVMAddr, uint64_t classDataVMAddr,
2489 const dyld3::MachOAnalyzer::ObjCClassInfo& objcClass, bool isMetaClass) {
2490 ma->forEachObjCMethod(objcClass.baseMethodsVMAddr(pointerSize), li.contentRebased,
2491 visitMethod);
2492 };
2493
2494 auto visitCategory = ^(Diagnostics& diag, uint64_t categoryVMAddr,
2495 const dyld3::MachOAnalyzer::ObjCCategory& objcCategory) {
2496 ma->forEachObjCMethod(objcCategory.instanceMethodsVMAddr, li.contentRebased,
2497 visitMethod);
2498 ma->forEachObjCMethod(objcCategory.classMethodsVMAddr, li.contentRebased,
2499 visitMethod);
2500 };
2501 auto visitProtocol = ^(Diagnostics& diag, uint64_t protocolVMAddr,
2502 const dyld3::MachOAnalyzer::ObjCProtocol& objCProtocol) {
2503 ma->forEachObjCMethod(objCProtocol.instanceMethodsVMAddr, li.contentRebased,
2504 visitMethod);
2505 ma->forEachObjCMethod(objCProtocol.classMethodsVMAddr, li.contentRebased,
2506 visitMethod);
2507 ma->forEachObjCMethod(objCProtocol.optionalInstanceMethodsVMAddr, li.contentRebased,
2508 visitMethod);
2509 ma->forEachObjCMethod(objCProtocol.optionalClassMethodsVMAddr, li.contentRebased,
2510 visitMethod);
2511 };
2512
2513 // Walk the class list
2514 ma->forEachObjCClass(image.diag, li.contentRebased, visitClass);
2515 if (image.diag.hasError())
2516 return;
2517
2518 // Walk the category list
2519 ma->forEachObjCCategory(image.diag, li.contentRebased, visitCategory);
2520 if (image.diag.hasError())
2521 return;
2522
2523 // Walk the protocol list
2524 ma->forEachObjCProtocol(image.diag, li.contentRebased, visitProtocol);
2525 if (image.diag.hasError())
2526 return;
2527
2528 // Visit the selector refs
2529 ma->forEachObjCSelectorReference(image.diag, li.contentRebased, ^(uint64_t selRefVMAddr, uint64_t selRefTargetVMAddr) {
2530 visitReferenceToObjCSelector(selRefTargetVMAddr, selRefVMAddr);
2531 });
2532 if (image.diag.hasError())
2533 return;
2534
2535 // Visit the message refs
2536 // Note this isn't actually supported in libobjc any more. Its logic for deciding whether to support it is if this is true:
2537 // #if (defined(__x86_64__) && (TARGET_OS_OSX || TARGET_OS_SIMULATOR))
2538 // So to keep it simple, lets only do this walk if we are x86_64
2539 if ( ma->isArch("x86_64") || ma->isArch("x86_64h") ) {
2540 if (ma->hasObjCMessageReferences()) {
2541 image.diag.error("Cannot handle message refs");
2542 return;
2543 }
2544 }
2545 }
2546
2547 static const dyld3::MachOAnalyzer* getMachHeaderFromObjCHeaderInfo(const void* opaqueHeaderInfo, uint32_t pointerSize) {
2548 if (pointerSize == 8) {
2549 typedef int64_t PtrTy;
2550 struct HeaderInfo {
2551 PtrTy mhdr_offset; // offset to mach_header_64
2552 PtrTy info_offset; // offset to objc_image_info *
2553 };
2554 const HeaderInfo* headerInfo = (const HeaderInfo*)opaqueHeaderInfo;
2555 return (const dyld3::MachOAnalyzer*)(((const uint8_t*)&headerInfo->mhdr_offset) + headerInfo->mhdr_offset);
2556 } else {
2557 typedef int32_t PtrTy;
2558 struct HeaderInfo {
2559 PtrTy mhdr_offset; // offset to mach_header
2560 PtrTy info_offset; // offset to objc_image_info *
2561 };
2562 const HeaderInfo* headerInfo = (const HeaderInfo*)opaqueHeaderInfo;
2563 return (const dyld3::MachOAnalyzer*)(((const uint8_t*)&headerInfo->mhdr_offset) + headerInfo->mhdr_offset);
2564 }
2565 }
2566
2567 void ClosureBuilder::addDuplicateObjCClassWarning(const char* className,
2568 const char* duplicateDefinitionPath,
2569 const char* canonicalDefinitionPath)
2570 {
2571 if ( _objcDuplicateClassWarnings == nullptr )
2572 _objcDuplicateClassWarnings = PathPool::allocate();
2573 // Use a diagnostic to give us a buffer we can safely print to
2574 Diagnostics diag;
2575 diag.error("Class %s is implemented in both %s and %s. One of the two will be used. Which one is undefined.",
2576 className, canonicalDefinitionPath, duplicateDefinitionPath);
2577 #if BUILDING_CACHE_BUILDER
2578 _objcDuplicateClassWarnings->add(diag.errorMessage().c_str());
2579 #else
2580 _objcDuplicateClassWarnings->add(diag.errorMessage());
2581 #endif
2582 }
2583
2584 void ClosureBuilder::optimizeObjCClasses(const objc_opt::objc_clsopt_t* objcClassOpt,
2585 const Map<const dyld3::MachOAnalyzer*, bool, HashPointer, EqualPointer>& sharedCacheImagesMap,
2586 const Map<const char*, dyld3::closure::Image::ObjCDuplicateClass, HashCString, EqualCString>& duplicateSharedCacheClasses,
2587 ObjCOptimizerImage& image) {
2588
2589 BuilderLoadedImage& li = *image.loadedImage;
2590 OverflowSafeArray<ObjCOptimizerImage::SeenClass>& seenClasses = image.seenClasses;
2591
2592 const dyld3::MachOAnalyzer* ma = li.loadAddress();
2593 const uint32_t pointerSize = ma->pointerSize();
2594 const uint64_t loadAddress = ma->preferredLoadAddress();
2595
2596 // Keep track of any missing weak imports so that we can tell if the superclasses are nil
2597 // This is necessary as the shared cache will be marked with 'no missing weak superclasses'
2598 // and so we need to continue to satisfy that constraint
2599 __block Map<uint64_t, bool, HashUInt64, EqualUInt64> missingWeakImportOffets;
2600 if (li.hasMissingWeakImports) {
2601 if (ma->hasChainedFixups()) {
2602 const Image* closureImage = image.writer->currentImage();
2603
2604 const Array<Image::ResolvedSymbolTarget> targets = closureImage->chainedTargets();
2605 if ( !targets.empty() ) {
2606 ma->withChainStarts(_diag, closureImage->chainedStartsOffset(), ^(const dyld_chained_starts_in_image* startsInfo) {
2607 ma->forEachFixupInAllChains(_diag, startsInfo, false, ^(MachOLoaded::ChainedFixupPointerOnDisk* fixupLoc,
2608 const dyld_chained_starts_in_segment* segInfo, bool& fixupsStop) {
2609 uint64_t fixupOffset = (uint8_t*)fixupLoc - (uint8_t*)ma;
2610 uint32_t bindOrdinal;
2611 if ( fixupLoc->isBind(segInfo->pointer_format, bindOrdinal) ) {
2612 if ( bindOrdinal < targets.count() ) {
2613 const Image::ResolvedSymbolTarget& target = targets[bindOrdinal];
2614 if ( (target.absolute.kind == Image::ResolvedSymbolTarget::kindAbsolute) && (target.absolute.value == 0) )
2615 missingWeakImportOffets[fixupOffset] = true;
2616 }
2617 else {
2618 image.diag.error("out of range bind ordinal %d (max %lu)", bindOrdinal, targets.count());
2619 fixupsStop = true;
2620 }
2621 }
2622 });
2623 });
2624 if (image.diag.hasError())
2625 return;
2626 }
2627 } else {
2628 forEachBind(li, ^(uint64_t runtimeOffset, Image::ResolvedSymbolTarget target, const ResolvedTargetInfo& targetInfo, bool& stop) {
2629 if ( (target.absolute.kind == Image::ResolvedSymbolTarget::kindAbsolute) && (target.absolute.value == 0) )
2630 missingWeakImportOffets[runtimeOffset] = true;
2631 }, ^(const char *strongSymbolName) {
2632 }, ^() { });
2633 }
2634 }
2635
2636 // Class names and data may be in different sections depending on swift vs objc so handle multiple sections
2637 __block MachOAnalyzer::SectionCache classNameSectionCache(ma);
2638 __block MachOAnalyzer::SectionCache classSectionCache(ma);
2639
2640 ma->forEachObjCClass(image.diag, li.contentRebased, ^(Diagnostics &diag, uint64_t classVMAddr,
2641 uint64_t classSuperclassVMAddr, uint64_t classDataVMAddr,
2642 const MachOAnalyzer::ObjCClassInfo &objcClass, bool isMetaClass) {
2643 if (isMetaClass) return;
2644
2645 // Make sure the superclass pointer is not nil
2646 uint64_t superclassRuntimeOffset = classSuperclassVMAddr - loadAddress;
2647 if (missingWeakImportOffets.find(superclassRuntimeOffset) != missingWeakImportOffets.end()) {
2648 diag.error("Missing weak superclass");
2649 return;
2650 }
2651
2652 // Does this class need to be fixed up for stable Swift ABI.
2653 // Note the order matches the objc runtime in that we always do this fix before checking for dupes,
2654 // but after excluding classes with missing weak superclasses.
2655 if (objcClass.isUnfixedBackwardDeployingStableSwift()) {
2656 // Class really is stable Swift, pretending to be pre-stable.
2657 // Fix its lie. This involves fixing the FAST bits on the class data value, so record that vmaddr
2658 image.classStableSwiftFixups.push_back(classDataVMAddr - loadAddress);
2659 }
2660
2661 // Get the section for the name
2662 const char* className = nullptr;
2663 MachOAnalyzer::PrintableStringResult classNameResult = MachOAnalyzer::PrintableStringResult::UnknownSection;
2664 __block uint64_t classNameSectionStartVMAddr = 0;
2665 auto classNameSectionHandler = ^bool(const MachOAnalyzer::SectionInfo& sectInfo) {
2666 // We only have 24-bits in ObjCClassNameImageOffset to index in to the strings
2667 if (sectInfo.sectSize >= Image::ObjCClassNameImageOffset::maximumOffset) {
2668 return false;
2669 }
2670
2671 // We use 32-bit offsets so make sure the section is no larger than that.
2672 uint64_t classNameVMOffset = sectInfo.sectAddr - loadAddress;
2673 if (classNameVMOffset >= (1ULL << 32)) {
2674 return false;
2675 }
2676
2677 classNameSectionStartVMAddr = sectInfo.sectAddr;
2678 return true;
2679 };
2680 uint64_t classNameVMAddr = objcClass.nameVMAddr(pointerSize);
2681 className = ma->getPrintableString(classNameVMAddr, classNameResult,
2682 &classNameSectionCache, classNameSectionHandler);
2683
2684 if ( classNameResult != MachOAnalyzer::PrintableStringResult::CanPrint ) {
2685 diag.error("Invalid class name for objc optimisation");
2686 return;
2687 }
2688
2689 // If the class also exists in a shared cache image which is loaded, then objc
2690 // would have found that one, regardless of load order. So we can just skip this one.
2691 {
2692 void *cls;
2693 void *hi;
2694 uint32_t index;
2695 uint32_t count = objcClassOpt->getClassHeaderAndIndex(className, cls, hi, index);
2696 if (count == 1) {
2697 // exactly one matching class. Check if its loaded
2698 const dyld3::MachOAnalyzer* sharedCacheMA = getMachHeaderFromObjCHeaderInfo(hi, pointerSize);
2699 if (sharedCacheImagesMap.find(sharedCacheMA) != sharedCacheImagesMap.end()) {
2700 addDuplicateObjCClassWarning(className, li.path(), sharedCacheMA->installName());
2701
2702 // We have a duplicate class, so check if we've already got it in our map.
2703 if ( duplicateSharedCacheClasses.find(className) == duplicateSharedCacheClasses.end() ) {
2704 // We haven't seen this one yet
2705 Image::ObjCDuplicateClass duplicateClass;
2706 duplicateClass.sharedCacheClassOptIndex = index;
2707 duplicateClass.sharedCacheClassDuplicateIndex = 0;
2708 image.classSharedCacheDuplicates.insert({ className, duplicateClass });
2709 }
2710 }
2711 }
2712 else if (count > 1) {
2713 // more than one matching class - find one that is loaded
2714 void *clslist[count];
2715 void *hilist[count];
2716 objcClassOpt->getClassesAndHeaders(className, clslist, hilist);
2717 for (uint32_t i = 0; i < count; i++) {
2718 const dyld3::MachOAnalyzer* sharedCacheMA = getMachHeaderFromObjCHeaderInfo(hilist[i], pointerSize);
2719 if (sharedCacheImagesMap.find(sharedCacheMA) != sharedCacheImagesMap.end()) {
2720 addDuplicateObjCClassWarning(className, li.path(), sharedCacheMA->installName());
2721
2722 // We have a duplicate class, so check if we've already got it in our map.
2723 if ( duplicateSharedCacheClasses.find(className) == duplicateSharedCacheClasses.end() ) {
2724 // We haven't seen this one yet
2725 Image::ObjCDuplicateClass duplicateClass;
2726 duplicateClass.sharedCacheClassOptIndex = index;
2727 duplicateClass.sharedCacheClassDuplicateIndex = i;
2728 image.classSharedCacheDuplicates.insert({ className, duplicateClass });
2729 }
2730
2731 break;
2732 }
2733 }
2734 }
2735 }
2736
2737 // Get the section for the class itself
2738 __block uint64_t classSectionStartVMAddr = 0;
2739 auto classSectionHandler = ^bool(const MachOAnalyzer::SectionInfo& sectInfo) {
2740 // We only have 23-bits in ObjCClassImageOffset to index in to the classes
2741 if (sectInfo.sectSize > Image::ObjCClassImageOffset::maximumOffset) {
2742 return false;
2743 }
2744
2745 // We use 32-bit offsets so make sure the section is no larger than that.
2746 uint64_t classDatasVMOffset = sectInfo.sectAddr - loadAddress;
2747 if (classDatasVMOffset >= (1ULL << 32)) {
2748 return false;
2749 }
2750
2751 classSectionStartVMAddr = sectInfo.sectAddr;
2752 return true;
2753 };
2754 if (!classSectionCache.findSectionForVMAddr(classVMAddr, classSectionHandler)) {
2755 diag.error("Invalid class for objc optimisation");
2756 return;
2757 }
2758
2759 // Make sure we have an entry for our images offsets for later
2760 uint64_t classNameSectionVMOffset = classNameSectionStartVMAddr - loadAddress;
2761 uint64_t classSectionVMOffset = classSectionStartVMAddr - loadAddress;
2762 uint64_t hashTableVMOffsetsIndex = 0;
2763 for (auto nameAndDataVMOffset : image.classesNameAndDataVMOffsets) {
2764 if ( (nameAndDataVMOffset.first == classNameSectionVMOffset) && (nameAndDataVMOffset.second == classSectionVMOffset) )
2765 break;
2766 ++hashTableVMOffsetsIndex;
2767 }
2768
2769 if (hashTableVMOffsetsIndex == image.classesNameAndDataVMOffsets.count()) {
2770 // Didn't find an image entry with this offset. Add one if we have space
2771 uint64_t totalHashTableImages = image.classesNameAndDataVMOffsets.count() + _objcClassesHashTableImages.count();
2772 if ( totalHashTableImages == Image::ObjCClassNameImageOffset::maximumImageIndex ) {
2773 // No more space. We need to give up
2774 diag.error("No more space for class hash table image");
2775 return;
2776 }
2777 image.classesNameAndDataVMOffsets.push_back({ classNameSectionVMOffset, classSectionVMOffset });
2778 }
2779
2780 hashTableVMOffsetsIndex += _objcClassesHashTableImages.count();
2781
2782 uint64_t classNameOffset = classNameVMAddr - classNameSectionStartVMAddr;
2783 uint64_t classDataOffset = classVMAddr - classSectionStartVMAddr;
2784
2785 closure::Image::ObjCClassNameImageOffset classNameTarget;
2786 classNameTarget.classNameImageIndex = (uint32_t)hashTableVMOffsetsIndex;
2787 classNameTarget.classNameImageOffset = (uint32_t)classNameOffset;
2788
2789 dyld3::closure::Image::ObjCClassImageOffset classDataTarget;
2790 classDataTarget.classData.imageIndex = (uint32_t)hashTableVMOffsetsIndex;
2791 classDataTarget.classData.imageOffset = (uint32_t)classDataOffset;
2792 classDataTarget.classData.isDuplicate = 0;
2793
2794 seenClasses.push_back({ classNameTarget, classDataTarget });
2795 });
2796 }
2797
2798 void ClosureBuilder::optimizeObjCProtocols(const objc_opt::objc_protocolopt2_t* objcProtocolOpt,
2799 const Map<const dyld3::MachOAnalyzer*, bool, HashPointer, EqualPointer>& sharedCacheImagesMap,
2800 ObjCOptimizerImage& image) {
2801
2802 BuilderLoadedImage& li = *image.loadedImage;
2803 OverflowSafeArray<ObjCOptimizerImage::SeenClass>& seenProtocols = image.seenProtocols;
2804
2805 const dyld3::MachOAnalyzer* ma = li.loadAddress();
2806 const uint32_t pointerSize = ma->pointerSize();
2807 const uint64_t loadAddress = ma->preferredLoadAddress();
2808
2809 // Protocol names and data may be in different sections depending on swift vs objc so handle multiple sections
2810 __block MachOAnalyzer::SectionCache protocolNameSectionCache(ma);
2811 __block MachOAnalyzer::SectionCache protocolSectionCache(ma);
2812
2813 ma->forEachObjCProtocol(image.diag, li.contentRebased, ^(Diagnostics &diag, uint64_t protocolVMAddr,
2814 const dyld3::MachOAnalyzer::ObjCProtocol &objCProtocol) {
2815 if ( objCProtocol.requiresObjCReallocation ) {
2816 // We can't optimize this protocol as the runtime needs all fields to be present
2817 diag.error("Protocol is too small to be optimized");
2818 return;
2819 }
2820 if ( objCProtocol.isaVMAddr != 0 ) {
2821 // We can't optimize this protocol if it has an ISA as we want to override it
2822 diag.error("Protocol ISA cannot be non-zero");
2823 return;
2824 }
2825
2826 // Get the section for the name
2827 const char* protocolName = nullptr;
2828 MachOAnalyzer::PrintableStringResult protocolNameResult = MachOAnalyzer::PrintableStringResult::UnknownSection;
2829 __block uint64_t protocolNameSectionStartVMAddr = 0;
2830 auto protocolNameSectionHandler = ^bool(const MachOAnalyzer::SectionInfo& sectInfo) {
2831 // We only have 24-bits in ObjCClassNameImageOffset to index in to the strings
2832 if (sectInfo.sectSize >= Image::ObjCClassNameImageOffset::maximumOffset) {
2833 return false;
2834 }
2835
2836 // We use 32-bit offsets so make sure the section is no larger than that.
2837 uint64_t protocolNameVMOffset = sectInfo.sectAddr - loadAddress;
2838 if (protocolNameVMOffset >= (1ULL << 32)) {
2839 return false;
2840 }
2841
2842 protocolNameSectionStartVMAddr = sectInfo.sectAddr;
2843 return true;
2844 };
2845 uint64_t protocolNameVMAddr = objCProtocol.nameVMAddr;
2846 protocolName = ma->getPrintableString(protocolNameVMAddr, protocolNameResult,
2847 &protocolNameSectionCache, protocolNameSectionHandler);
2848
2849 if ( protocolNameResult != MachOAnalyzer::PrintableStringResult::CanPrint ) {
2850 diag.error("Invalid protocol name for objc optimisation");
2851 return;
2852 }
2853
2854 // If the protocol also exists in a shared cache image which is loaded, then objc
2855 // would have found that one, regardless of load order. So we can just skip this one.
2856 {
2857 void *cls;
2858 void *hi;
2859 uint32_t count = objcProtocolOpt->getClassAndHeader(protocolName, cls, hi);
2860 if (count == 1) {
2861 // exactly one matching protocol. Check if its loaded
2862 if (sharedCacheImagesMap.find(getMachHeaderFromObjCHeaderInfo(hi, pointerSize)) != sharedCacheImagesMap.end())
2863 return;
2864 }
2865 else if (count > 1) {
2866 // more than one matching protocol - find one that is loaded
2867 void *clslist[count];
2868 void *hilist[count];
2869 objcProtocolOpt->getClassesAndHeaders(protocolName, clslist, hilist);
2870 for (uint32_t i = 0; i < count; i++) {
2871 if (sharedCacheImagesMap.find(getMachHeaderFromObjCHeaderInfo(hilist[i], pointerSize)) != sharedCacheImagesMap.end())
2872 return;
2873 }
2874 }
2875 }
2876
2877 // Get the section for the protocol itself
2878 __block uint64_t protocolSectionStartVMAddr = 0;
2879 auto protocolSectionHandler = ^bool(const MachOAnalyzer::SectionInfo& sectInfo) {
2880 // We only have 23-bits in ObjCClassImageOffset to index in to the protocols
2881 if (sectInfo.sectSize > Image::ObjCClassImageOffset::maximumOffset) {
2882 return false;
2883 }
2884
2885 // We use 32-bit offsets so make sure the section is no larger than that.
2886 uint64_t protocolDatasVMOffset = sectInfo.sectAddr - loadAddress;
2887 if (protocolDatasVMOffset >= (1ULL << 32)) {
2888 return false;
2889 }
2890
2891 protocolSectionStartVMAddr = sectInfo.sectAddr;
2892 return true;
2893 };
2894 if (!protocolSectionCache.findSectionForVMAddr(protocolVMAddr, protocolSectionHandler)) {
2895 diag.error("Invalid protocol for objc optimisation");
2896 return;
2897 }
2898
2899 // Make sure we have an entry for our images offsets for later
2900 uint64_t protocolNameSectionVMOffset = protocolNameSectionStartVMAddr - loadAddress;
2901 uint64_t protocolSectionVMOffset = protocolSectionStartVMAddr - loadAddress;
2902 uint64_t hashTableVMOffsetsIndex = 0;
2903 for (auto nameAndDataVMOffset : image.classesNameAndDataVMOffsets) {
2904 if ( (nameAndDataVMOffset.first == protocolNameSectionVMOffset) && (nameAndDataVMOffset.second == protocolSectionVMOffset) )
2905 break;
2906 ++hashTableVMOffsetsIndex;
2907 }
2908
2909 if (hashTableVMOffsetsIndex == image.classesNameAndDataVMOffsets.count()) {
2910 // Didn't find an image entry with this offset. Add one if we have space
2911 uint64_t totalHashTableImages = image.classesNameAndDataVMOffsets.count() + _objcClassesHashTableImages.count();
2912 if ( totalHashTableImages == Image::ObjCClassNameImageOffset::maximumImageIndex ) {
2913 // No more space. We need to give up
2914 diag.error("No more space for protocol hash table image");
2915 return;
2916 }
2917 image.classesNameAndDataVMOffsets.push_back({ protocolNameSectionVMOffset, protocolSectionVMOffset });
2918 }
2919
2920 hashTableVMOffsetsIndex += _objcClassesHashTableImages.count();
2921
2922 uint64_t protocolNameOffset = protocolNameVMAddr - protocolNameSectionStartVMAddr;
2923 uint64_t protocolDataOffset = protocolVMAddr - protocolSectionStartVMAddr;
2924
2925 closure::Image::ObjCClassNameImageOffset protocolNameTarget;
2926 protocolNameTarget.classNameImageIndex = (uint32_t)hashTableVMOffsetsIndex;
2927 protocolNameTarget.classNameImageOffset = (uint32_t)protocolNameOffset;
2928
2929 dyld3::closure::Image::ObjCClassImageOffset protocolDataTarget;
2930 protocolDataTarget.classData.imageIndex = (uint32_t)hashTableVMOffsetsIndex;
2931 protocolDataTarget.classData.imageOffset = (uint32_t)protocolDataOffset;
2932 protocolDataTarget.classData.isDuplicate = 0;
2933
2934 seenProtocols.push_back({ protocolNameTarget, protocolDataTarget });
2935 });
2936 }
2937
2938 // used at launch by dyld when kernel has already mapped main executable
2939 const LaunchClosure* ClosureBuilder::makeLaunchClosure(const LoadedFileInfo& fileInfo, bool allowInsertFailures)
2940 {
2941 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_BUILD_CLOSURE, 0, 0, 0);
2942 const mach_header* mainMH = (const mach_header*)fileInfo.fileContent;
2943 // set up stack based storage for all arrays
2944 BuilderLoadedImage loadImagesStorage[512];
2945 Image::LinkedImage dependenciesStorage[512*8];
2946 InterposingTuple tuplesStorage[64];
2947 Closure::PatchEntry cachePatchStorage[64];
2948 const char* weakDefNameStorage[64];
2949 _loadedImages.setInitialStorage(loadImagesStorage, 512);
2950 _dependencies.setInitialStorage(dependenciesStorage, 512*8);
2951 _interposingTuples.setInitialStorage(tuplesStorage, 64);
2952 _weakDefCacheOverrides.setInitialStorage(cachePatchStorage, 64);
2953 _weakDefsFromChainedBinds.setInitialStorage(weakDefNameStorage, 64);
2954 ArrayFinalizer<BuilderLoadedImage> scopedCleanup(_loadedImages, ^(BuilderLoadedImage& li) { if (li.unmapWhenDone) {_fileSystem.unloadFile(li.loadedFileInfo); li.unmapWhenDone=false;} });
2955
2956 const MachOAnalyzer* mainExecutable = MachOAnalyzer::validMainExecutable(_diag, mainMH, fileInfo.path, fileInfo.sliceLen, _archs, _platform);
2957 if ( mainExecutable == nullptr )
2958 return nullptr;
2959 if ( !mainExecutable->isDynamicExecutable() ) {
2960 _diag.error("not a main executable");
2961 return nullptr;
2962 }
2963 _isLaunchClosure = true;
2964 _allowMissingLazies = true;
2965
2966 _nextIndex = 0;
2967
2968 // add main executable
2969 __block BuilderLoadedImage mainEntry;
2970 mainEntry.loadedFileInfo = fileInfo;
2971 mainEntry.imageNum = 0; // We can't fill this in until we've done inserted dylibs
2972 mainEntry.unmapWhenDone = false;
2973 mainEntry.contentRebased = false;
2974 mainEntry.hasInits = false;
2975 mainEntry.markNeverUnload = true;
2976 mainEntry.rtldLocal = false;
2977 mainEntry.isBadImage = false;
2978 mainEntry.mustBuildClosure = true;
2979 mainEntry.hasMissingWeakImports = false;
2980 mainEntry.overrideImageNum = 0;
2981
2982 // Set the executable load path so that @executable_path can use it later
2983 _mainProgLoadPath = fileInfo.path;
2984
2985 // add any DYLD_INSERT_LIBRARIES
2986 _pathOverrides.forEachInsertedDylib(^(const char* dylibPath, bool &stop) {
2987 LoadedImageChain chainMain = { nullptr, mainEntry };
2988 BuilderLoadedImage* foundTopImage;
2989 if ( !findImage(dylibPath, chainMain, foundTopImage, LinkageType::kInserted, 0, true) ) {
2990 if ( !allowInsertFailures ) {
2991 if ( _diag.noError() )
2992 _diag.error("could not load inserted dylib %s", dylibPath);
2993 stop = true;
2994 return;
2995 }
2996 _diag.clearError(); // FIXME add way to plumb back warning
2997 }
2998 });
2999
3000 if ( _diag.hasError() )
3001 return nullptr;
3002
3003 _mainProgLoadIndex = (uint32_t)_loadedImages.count();
3004 mainEntry.imageNum = _startImageNum + _nextIndex++;
3005 _loadedImages.push_back(mainEntry);
3006
3007 // get mach_headers for all images needed to launch this main executable
3008 LoadedImageChain chainStart = { nullptr, _loadedImages[_mainProgLoadIndex] };
3009 recursiveLoadDependents(chainStart);
3010 if ( _diag.hasError() )
3011 return nullptr;
3012 for (uint32_t i=0; i < _mainProgLoadIndex; ++i) {
3013 LoadedImageChain insertChainStart = { nullptr, _loadedImages[i] };
3014 recursiveLoadDependents(insertChainStart);
3015 if ( _diag.hasError() )
3016 return nullptr;
3017 }
3018 loadDanglingUpwardLinks();
3019
3020 // If we have an on-disk image then we need all images which are dependent on the disk image to get a new
3021 // initializer order. Its not enough to just do the top level image as we may dlopen while in dlopen
3022 invalidateInitializerRoots();
3023
3024 // now that everything loaded, set _libDyldImageNum and _libSystemImageNum
3025 for (BuilderLoadedImage& li : _loadedImages) {
3026 if ( li.loadAddress()->isDylib() && (strcmp(li.loadAddress()->installName(), "/usr/lib/system/libdyld.dylib") == 0) )
3027 _libDyldImageNum = li.imageNum;
3028 else if ( strcmp(li.path(), "/usr/lib/libSystem.B.dylib") == 0 )
3029 _libSystemImageNum = li.imageNum;
3030 }
3031
3032 // only some images need to go into closure (non-rooted ones from dyld cache do not)
3033 STACK_ALLOC_ARRAY(ImageWriter, writers, _loadedImages.count());
3034 for (BuilderLoadedImage& li : _loadedImages) {
3035 if ( li.mustBuildClosure ) {
3036 writers.push_back(ImageWriter());
3037 buildImage(writers.back(), li);
3038 if ( _diag.hasError() )
3039 return nullptr;
3040 }
3041 }
3042
3043 bool optimizedObjC = optimizeObjC(writers);
3044
3045 // Note we have to compute the init order after buildImage as buildImage may set hasInits to true
3046 for (uintptr_t imageIndex = 0, writerIndex = 0; imageIndex != _loadedImages.count(); ++imageIndex) {
3047 BuilderLoadedImage& li = _loadedImages[imageIndex];
3048 if ( li.mustBuildClosure ) {
3049 computeInitOrder(writers[writerIndex], (uint32_t)imageIndex);
3050 writerIndex++;
3051 }
3052 }
3053
3054 // combine all Image objects into one ImageArray
3055 ImageArrayWriter imageArrayWriter(_startImageNum, (uint32_t)writers.count(), _foundDyldCacheRoots);
3056 for (ImageWriter& writer : writers) {
3057 imageArrayWriter.appendImage(writer.finalize());
3058 writer.deallocate();
3059 }
3060 const ImageArray* imageArray = imageArrayWriter.finalize();
3061
3062 // merge ImageArray object into LaunchClosure object
3063 __block LaunchClosureWriter closureWriter(imageArray);
3064
3065 if (optimizedObjC) {
3066 if (!_objcSelectorsHashTable.empty())
3067 closureWriter.setObjCSelectorInfo(_objcSelectorsHashTable, _objcSelectorsHashTableImages);
3068
3069 if (!_objcClassesHashTableImages.empty()) {
3070 closureWriter.setObjCClassAndProtocolInfo(_objcClassesHashTable, _objcProtocolsHashTable,
3071 _objcClassesHashTableImages);
3072 }
3073
3074 if ( _objcDuplicateClassWarnings != nullptr ) {
3075 _objcDuplicateClassWarnings->forEachPath(^(const char* warning) {
3076 closureWriter.addWarning(Closure::Warning::duplicateObjCClass, warning);
3077 });
3078 }
3079
3080 if (!_objcClassesDuplicatesHashTable.empty())
3081 closureWriter.setObjCDuplicateClassesInfo(_objcClassesDuplicatesHashTable);
3082 }
3083
3084 // record shared cache info
3085 if ( _dyldCache != nullptr ) {
3086 // record cache UUID
3087 uuid_t cacheUUID;
3088 _dyldCache->getUUID(cacheUUID);
3089 closureWriter.setDyldCacheUUID(cacheUUID);
3090
3091 // record any cache patching needed because of dylib overriding cache
3092 for (const BuilderLoadedImage& li : _loadedImages) {
3093 if ( li.overrideImageNum != 0 ) {
3094 uint32_t imageIndex = li.overrideImageNum - (uint32_t)_dyldImageArray->startImageNum();
3095 STACK_ALLOC_ARRAY(Closure::PatchEntry, patches, _dyldCache->patchableExportCount(imageIndex));
3096 MachOLoaded::DependentToMachOLoaded reexportFinder = ^(const MachOLoaded* mh, uint32_t depIndex) {
3097 return (const MachOLoaded*)findDependent(mh, depIndex);
3098 };
3099 //fprintf(stderr, "'%s' overrides '%s'\n", li.loadedFileInfo.path, cacheImage->path());
3100 _dyldCache->forEachPatchableExport(imageIndex, ^(uint32_t cacheOffsetOfImpl, const char* symbolName) {
3101 dyld3::MachOAnalyzer::FoundSymbol foundInfo;
3102 Diagnostics patchDiag;
3103 Closure::PatchEntry patch;
3104 patch.overriddenDylibInCache = li.overrideImageNum;
3105 patch.exportCacheOffset = cacheOffsetOfImpl;
3106 if ( li.loadAddress()->findExportedSymbol(patchDiag, symbolName, false, foundInfo, reexportFinder) ) {
3107 const MachOAnalyzer* impDylib = (const MachOAnalyzer*)foundInfo.foundInDylib;
3108 patch.replacement.image.kind = Image::ResolvedSymbolTarget::kindImage;
3109 patch.replacement.image.imageNum = findLoadedImage(impDylib).imageNum;
3110 patch.replacement.image.offset = foundInfo.value;
3111 }
3112 else {
3113 // this means the symbol is missing in the cache override dylib, so set any uses to NULL
3114 patch.replacement.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
3115 patch.replacement.absolute.value = 0;
3116 }
3117 patches.push_back(patch);
3118 });
3119 closureWriter.addCachePatches(patches);
3120 }
3121 }
3122
3123 // handle any extra weak-def coalescing needed by chained fixups
3124 if ( !_weakDefsFromChainedBinds.empty() ) {
3125 for (const char* symbolName : _weakDefsFromChainedBinds) {
3126 Image::ResolvedSymbolTarget cacheOverrideTarget;
3127 bool haveCacheOverride = false;
3128 bool foundCachOverrideIsWeakDef = false;
3129 for (const BuilderLoadedImage& li : _loadedImages) {
3130 if ( !li.loadAddress()->hasWeakDefs() )
3131 continue;
3132 Image::ResolvedSymbolTarget target;
3133 ResolvedTargetInfo targetInfo;
3134 if ( findSymbolInImage(li.loadAddress(), symbolName, 0, false, false, target, targetInfo) ) {
3135 if ( li.loadAddress()->inDyldCache() ) {
3136 if ( haveCacheOverride ) {
3137 Closure::PatchEntry patch;
3138 patch.exportCacheOffset = (uint32_t)target.sharedCache.offset;
3139 patch.overriddenDylibInCache = li.imageNum;
3140 patch.replacement = cacheOverrideTarget;
3141 _weakDefCacheOverrides.push_back(patch);
3142 }
3143 else {
3144 // found first in cached dylib, so no need to patch cache for this symbol
3145 break;
3146 }
3147 }
3148 else {
3149 // found image that exports this symbol and is not in cache
3150 if ( !haveCacheOverride || (foundCachOverrideIsWeakDef && !targetInfo.isWeakDef) ) {
3151 // update cache to use this symbol if it if first found or it is first non-weak found
3152 cacheOverrideTarget = target;
3153 foundCachOverrideIsWeakDef = targetInfo.isWeakDef;
3154 haveCacheOverride = true;
3155 }
3156 }
3157 }
3158 }
3159 }
3160 }
3161
3162 // record any cache patching needed because weak-def C++ symbols override dyld cache
3163 if ( !_weakDefCacheOverrides.empty() )
3164 closureWriter.addCachePatches(_weakDefCacheOverrides);
3165
3166 }
3167
3168 #if __IPHONE_OS_VERSION_MIN_REQUIRED
3169 // if closure is built on-device for iOS, then record boot UUID
3170 char bootSessionUUID[256] = { 0 };
3171 size_t bootSize = sizeof(bootSessionUUID);
3172 if ( sysctlbyname("kern.bootsessionuuid", bootSessionUUID, &bootSize, NULL, 0) == 0 )
3173 closureWriter.setBootUUID(bootSessionUUID);
3174 #endif
3175
3176 // record any interposing info
3177 imageArray->forEachImage(^(const Image* image, bool &stop) {
3178 if ( !image->inDyldCache() )
3179 addInterposingTuples(closureWriter, image, findLoadedImage(image->imageNum()).loadAddress());
3180 });
3181
3182 // modify fixups in contained Images by applying interposing tuples
3183 closureWriter.applyInterposing((const LaunchClosure*)closureWriter.currentTypedBytes());
3184
3185 // set flags
3186 closureWriter.setUsedAtPaths(_atPathUsed);
3187 closureWriter.setUsedFallbackPaths(_fallbackPathUsed);
3188 closureWriter.setHasInsertedLibraries(_mainProgLoadIndex > 0);
3189 closureWriter.setInitImageCount((uint32_t)_loadedImages.count());
3190
3191 // add other closure attributes
3192 addClosureInfo(closureWriter);
3193
3194 // make result
3195 const LaunchClosure* result = closureWriter.finalize();
3196 imageArrayWriter.deallocate();
3197
3198 timer.setData4(dyld3::DyldTimingBuildClosure::LaunchClosure_Built);
3199
3200 return result;
3201 }
3202
3203 // used by libdyld for dlopen()
3204 const DlopenClosure* ClosureBuilder::makeDlopenClosure(const char* path, const LaunchClosure* mainClosure, const Array<LoadedImage>& alreadyLoadedList,
3205 closure::ImageNum callerImageNum, bool noLoad, bool forceBindLazies, bool canUseSharedCacheClosure, closure::ImageNum* topImageNum)
3206 {
3207 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_BUILD_CLOSURE, 0, 0, 0);
3208 // set up stack based storage for all arrays
3209 BuilderLoadedImage loadImagesStorage[300];
3210 Image::LinkedImage dependenciesStorage[128];
3211 Closure::PatchEntry cachePatchStorage[64];
3212 _loadedImages.setInitialStorage(loadImagesStorage, 300);
3213 _dependencies.setInitialStorage(dependenciesStorage, 128);
3214 _weakDefCacheOverrides.setInitialStorage(cachePatchStorage, 64);
3215 ArrayFinalizer<BuilderLoadedImage> scopedCleanup(_loadedImages, ^(BuilderLoadedImage& li) { if (li.unmapWhenDone) {_fileSystem.unloadFile(li.loadedFileInfo); li.unmapWhenDone=false;} });
3216
3217 // fill in builder array from already loaded images
3218 bool cachedDylibsExpectedOnDisk = _dyldCache ? _dyldCache->header.dylibsExpectedOnDisk : true;
3219 uintptr_t callerImageIndex = UINTPTR_MAX;
3220 for (const LoadedImage& ali : alreadyLoadedList) {
3221 const Image* image = ali.image();
3222 const MachOAnalyzer* ma = (MachOAnalyzer*)(ali.loadedAddress());
3223 bool inDyldCache = ma->inDyldCache();
3224 BuilderLoadedImage entry;
3225 ImageNum overrideImageNum;
3226 entry.loadedFileInfo.path = image->path();
3227 entry.loadedFileInfo.fileContent = ma;
3228 entry.loadedFileInfo.sliceOffset = 0;
3229 entry.loadedFileInfo.inode = 0;
3230 entry.loadedFileInfo.mtime = 0;
3231 entry.imageNum = image->imageNum();
3232 entry.dependents = image->dependentsArray();
3233 entry.unmapWhenDone = false;
3234 entry.contentRebased = inDyldCache;
3235 entry.hasInits = false;
3236 entry.markNeverUnload = image->neverUnload();
3237 entry.rtldLocal = ali.hideFromFlatSearch();
3238 entry.isBadImage = false;
3239 entry.mustBuildClosure = false;
3240 entry.hasMissingWeakImports = false;
3241 entry.overrideImageNum = 0;
3242 if ( !inDyldCache && image->isOverrideOfDyldCacheImage(overrideImageNum) ) {
3243 entry.overrideImageNum = overrideImageNum;
3244 canUseSharedCacheClosure = false;
3245 }
3246 if ( !inDyldCache || cachedDylibsExpectedOnDisk )
3247 image->hasFileModTimeAndInode(entry.loadedFileInfo.inode, entry.loadedFileInfo.mtime);
3248 if ( entry.imageNum == callerImageNum )
3249 callerImageIndex = _loadedImages.count();
3250 _loadedImages.push_back(entry);
3251 }
3252 _alreadyInitedIndex = (uint32_t)_loadedImages.count();
3253
3254 // find main executable (may be needed for @executable_path)
3255 _isLaunchClosure = false;
3256 for (uint32_t i=0; i < alreadyLoadedList.count(); ++i) {
3257 if ( _loadedImages[i].loadAddress()->isMainExecutable() ) {
3258 _mainProgLoadIndex = i;
3259 _mainProgLoadPath = _loadedImages[i].path();
3260 break;
3261 }
3262 }
3263
3264 // We can't use an existing dlopen closure if the main closure had interposing tuples
3265 if (canUseSharedCacheClosure) {
3266 if (mainClosure->hasInterposings())
3267 canUseSharedCacheClosure = false;
3268 }
3269
3270 // add top level dylib being dlopen()ed
3271 BuilderLoadedImage* foundTopImage;
3272 _nextIndex = 0;
3273 // @rpath has caller's LC_PRATH, then main executable's LC_RPATH
3274 BuilderLoadedImage& callerImage = (callerImageIndex != UINTPTR_MAX) ? _loadedImages[callerImageIndex] : _loadedImages[_mainProgLoadIndex];
3275 LoadedImageChain chainCaller = { nullptr, callerImage };
3276 LoadedImageChain chainMain = { &chainCaller, _loadedImages[_mainProgLoadIndex] };
3277 if ( !findImage(path, chainMain, foundTopImage, LinkageType::kDynamic, 0, canUseSharedCacheClosure) ) {
3278 // If we didn't find the image, it might be a symlink to something in the dyld cache that is not on disk
3279 if ( (_dyldCache != nullptr) && !_dyldCache->header.dylibsExpectedOnDisk ) {
3280 char resolvedPath[PATH_MAX];
3281 if ( _fileSystem.getRealPath(path, resolvedPath) ) {
3282 _diag.clearError();
3283 if ( !findImage(resolvedPath, chainMain, foundTopImage, LinkageType::kDynamic, 0, canUseSharedCacheClosure) ) {
3284 return nullptr;
3285 }
3286 } else {
3287 // We didn't find a new path from realpath
3288 return nullptr;
3289 }
3290 } else {
3291 // cached dylibs on disk, so don't call realpath() again, it would have been found first call to findImage()
3292 return nullptr;
3293 }
3294 }
3295
3296 // exit early in RTLD_NOLOAD mode
3297 if ( noLoad ) {
3298 timer.setData4(dyld3::DyldTimingBuildClosure::DlopenClosure_NoLoad);
3299 // if no new images added to _loadedImages, then requested path was already loaded
3300 if ( (uint32_t)_loadedImages.count() == _alreadyInitedIndex )
3301 *topImageNum = foundTopImage->imageNum;
3302 else
3303 *topImageNum = 0;
3304 return nullptr;
3305 }
3306
3307 // fast path if roots are not allowed and target is in dyld cache or is other
3308 if ( (_dyldCache != nullptr) && (_dyldCache->header.cacheType == kDyldSharedCacheTypeProduction) ) {
3309 if ( foundTopImage->imageNum < closure::kFirstLaunchClosureImageNum ) {
3310 if (foundTopImage->imageNum < closure::kLastDyldCacheImageNum)
3311 timer.setData4(dyld3::DyldTimingBuildClosure::DlopenClosure_UsedSharedCacheDylib);
3312 else
3313 timer.setData4(dyld3::DyldTimingBuildClosure::DlopenClosure_UsedSharedCacheOther);
3314 *topImageNum = foundTopImage->imageNum;
3315 return nullptr;
3316 }
3317 }
3318
3319 // recursive load dependents
3320 // @rpath for stuff top dylib depends on uses LC_RPATH from caller, main exe, and dylib being dlopen()ed
3321 LoadedImageChain chainTopDylib = { &chainMain, *foundTopImage };
3322 recursiveLoadDependents(chainTopDylib, canUseSharedCacheClosure);
3323 if ( _diag.hasError() )
3324 return nullptr;
3325 loadDanglingUpwardLinks(canUseSharedCacheClosure);
3326 if ( _diag.hasError() )
3327 return nullptr;
3328
3329 // RTLD_NOW means fail the dlopen() if a symbol cannot be bound
3330 _allowMissingLazies = !forceBindLazies;
3331
3332 // only some images need to go into closure (ones from dyld cache do not, unless the cache format changed)
3333 STACK_ALLOC_ARRAY(ImageWriter, writers, _loadedImages.count());
3334 if ( _foundNonCachedImage || _foundDyldCacheRoots ) {
3335 // If we have an on-disk image then we need all images which are dependent on the disk image to get a new
3336 // initializer order. Its not enough to just do the top level image as we may dlopen while in dlopen
3337 invalidateInitializerRoots();
3338
3339 for (uintptr_t loadedImageIndex = 0; loadedImageIndex != _loadedImages.count(); ++loadedImageIndex) {
3340 BuilderLoadedImage& li = _loadedImages[loadedImageIndex];
3341 if ( li.mustBuildClosure ) {
3342 writers.push_back(ImageWriter());
3343 buildImage(writers.back(), li);
3344 if ( _diag.hasError() )
3345 return nullptr;
3346 }
3347 }
3348
3349 // Note we have to compute the init order after buildImage as buildImage may set hasInits to true
3350 for (uintptr_t imageIndex = 0, writerIndex = 0; imageIndex != _loadedImages.count(); ++imageIndex) {
3351 BuilderLoadedImage& li = _loadedImages[imageIndex];
3352 if ( li.mustBuildClosure ) {
3353 computeInitOrder(writers[writerIndex], (uint32_t)imageIndex);
3354 writerIndex++;
3355 }
3356 }
3357 }
3358 if ( _diag.hasError() )
3359 return nullptr;
3360
3361 // check if top image loaded is in shared cache along with everything it depends on
3362 *topImageNum = foundTopImage->imageNum;
3363 if ( _foundNonCachedImage || _foundDyldCacheRoots ) {
3364 if ( canUseSharedCacheClosure && ( foundTopImage->imageNum < closure::kFirstLaunchClosureImageNum ) ) {
3365 // We used a shared cache built closure, but now discovered roots. We need to try again
3366 topImageNum = 0;
3367 return sRetryDlopenClosure;
3368 }
3369 } else {
3370 if (foundTopImage->imageNum < closure::kLastDyldCacheImageNum)
3371 timer.setData4(dyld3::DyldTimingBuildClosure::DlopenClosure_UsedSharedCacheDylib);
3372 else
3373 timer.setData4(dyld3::DyldTimingBuildClosure::DlopenClosure_UsedSharedCacheOther);
3374 return nullptr;
3375 }
3376
3377 // combine all Image objects into one ImageArray
3378 ImageArrayWriter imageArrayWriter(_startImageNum, (uint32_t)writers.count(), _foundDyldCacheRoots);
3379 for (ImageWriter& writer : writers) {
3380 imageArrayWriter.appendImage(writer.finalize());
3381 writer.deallocate();
3382 }
3383 const ImageArray* imageArray = imageArrayWriter.finalize();
3384
3385 // merge ImageArray object into LaunchClosure object
3386 DlopenClosureWriter closureWriter(imageArray);
3387
3388 // add other closure attributes
3389 closureWriter.setTopImageNum(foundTopImage->imageNum);
3390
3391 // record any cache patching needed because of dylib overriding cache
3392 if ( _dyldCache != nullptr ) {
3393 for (const BuilderLoadedImage& li : _loadedImages) {
3394 if ( (li.overrideImageNum != 0) && (li.imageNum >= _startImageNum) ) {
3395 const Image* cacheImage = _dyldImageArray->imageForNum(li.overrideImageNum);
3396 uint32_t imageIndex = cacheImage->imageNum() - (uint32_t)_dyldCache->cachedDylibsImageArray()->startImageNum();
3397 STACK_ALLOC_ARRAY(Closure::PatchEntry, patches, _dyldCache->patchableExportCount(imageIndex));
3398 MachOLoaded::DependentToMachOLoaded reexportFinder = ^(const MachOLoaded* mh, uint32_t depIndex) {
3399 return (const MachOLoaded*)findDependent(mh, depIndex);
3400 };
3401 //fprintf(stderr, "'%s' overrides '%s'\n", li.loadedFileInfo.path, cacheImage->path());
3402 _dyldCache->forEachPatchableExport(imageIndex,
3403 ^(uint32_t cacheOffsetOfImpl, const char* symbolName) {
3404 dyld3::MachOAnalyzer::FoundSymbol foundInfo;
3405 Diagnostics patchDiag;
3406 Closure::PatchEntry patch;
3407 patch.overriddenDylibInCache = li.overrideImageNum;
3408 patch.exportCacheOffset = cacheOffsetOfImpl;
3409 if ( li.loadAddress()->findExportedSymbol(patchDiag, symbolName, false, foundInfo, reexportFinder) ) {
3410 const MachOAnalyzer* impDylib = (const MachOAnalyzer*)foundInfo.foundInDylib;
3411 patch.replacement.image.kind = Image::ResolvedSymbolTarget::kindImage;
3412 patch.replacement.image.imageNum = findLoadedImage(impDylib).imageNum;
3413 patch.replacement.image.offset = foundInfo.value;
3414 }
3415 else {
3416 patch.replacement.absolute.kind = Image::ResolvedSymbolTarget::kindAbsolute;
3417 patch.replacement.absolute.value = 0;
3418 }
3419 patches.push_back(patch);
3420 });
3421 closureWriter.addCachePatches(patches);
3422 }
3423 }
3424 }
3425
3426 // modify fixups in contained Images by applying interposing tuples
3427 closureWriter.applyInterposing(mainClosure);
3428
3429 // Dlopen's should never keep track of missing paths as we don't cache these closures.
3430 assert(_mustBeMissingPaths == nullptr);
3431
3432 // make final DlopenClosure object
3433 const DlopenClosure* result = closureWriter.finalize();
3434 imageArrayWriter.deallocate();
3435 timer.setData4(dyld3::DyldTimingBuildClosure::DlopenClosure_Built);
3436 return result;
3437 }
3438
3439
3440 // used by dyld_closure_util
3441 const LaunchClosure* ClosureBuilder::makeLaunchClosure(const char* mainPath, bool allowInsertFailures)
3442 {
3443 char realerPath[MAXPATHLEN];
3444 closure::LoadedFileInfo loadedFileInfo = MachOAnalyzer::load(_diag, _fileSystem, mainPath, _archs, _platform, realerPath);
3445 const MachOAnalyzer* mh = (const MachOAnalyzer*)loadedFileInfo.fileContent;
3446 loadedFileInfo.path = mainPath;
3447 if (_diag.hasError())
3448 return nullptr;
3449 if (mh == nullptr) {
3450 _diag.error("could not load file");
3451 return nullptr;
3452 }
3453 if (!mh->isDynamicExecutable()) {
3454 _diag.error("file is not an executable");
3455 return nullptr;
3456 }
3457 const_cast<PathOverrides*>(&_pathOverrides)->setMainExecutable(mh, mainPath);
3458 const LaunchClosure* launchClosure = makeLaunchClosure(loadedFileInfo, allowInsertFailures);
3459 loadedFileInfo.unload(loadedFileInfo);
3460 return launchClosure;
3461 }
3462
3463 void ClosureBuilder::setDyldCacheInvalidFormatVersion() {
3464 _dyldCacheInvalidFormatVersion = true;
3465 }
3466
3467
3468 // used by dyld shared cache builder
3469 const ImageArray* ClosureBuilder::makeDyldCacheImageArray(bool customerCache, const Array<CachedDylibInfo>& dylibs, const Array<CachedDylibAlias>& aliases)
3470 {
3471 // because this is run in cache builder using dispatch_apply() there is minimal stack space
3472 // so set up storage for all arrays to be vm_allocated
3473 uintptr_t maxImageCount = dylibs.count() + 16;
3474 _loadedImages.reserve(maxImageCount);
3475 _dependencies.reserve(maxImageCount*16);
3476
3477 _makingDyldCacheImages = true;
3478 _allowMissingLazies = false;
3479 _makingCustomerCache = customerCache;
3480 _aliases = &aliases;
3481
3482 // build _loadedImages[] with every dylib in cache
3483 __block ImageNum imageNum = _startImageNum;
3484 for (const CachedDylibInfo& aDylibInfo : dylibs) {
3485 BuilderLoadedImage entry;
3486 entry.loadedFileInfo = aDylibInfo.fileInfo;
3487 entry.imageNum = imageNum++;
3488 entry.unmapWhenDone = false;
3489 entry.contentRebased = false;
3490 entry.hasInits = false;
3491 entry.markNeverUnload = true;
3492 entry.rtldLocal = false;
3493 entry.isBadImage = false;
3494 entry.mustBuildClosure = false;
3495 entry.hasMissingWeakImports = false;
3496 entry.overrideImageNum = 0;
3497 _loadedImages.push_back(entry);
3498 }
3499
3500 // wire up dependencies between cached dylibs
3501 for (BuilderLoadedImage& li : _loadedImages) {
3502 LoadedImageChain chainStart = { nullptr, li };
3503 recursiveLoadDependents(chainStart);
3504 if ( _diag.hasError() )
3505 break;
3506 }
3507 assert(_loadedImages.count() == dylibs.count());
3508
3509 // create an ImageWriter for each cached dylib
3510 STACK_ALLOC_ARRAY(ImageWriter, writers, _loadedImages.count());
3511 for (BuilderLoadedImage& li : _loadedImages) {
3512 writers.push_back(ImageWriter());
3513 buildImage(writers.back(), li);
3514 }
3515
3516 // add initializer order into each dylib
3517 // Note we have to compute the init order after buildImage as buildImage may set hasInits to true
3518 for (const BuilderLoadedImage& li : _loadedImages) {
3519 uint32_t index = li.imageNum - _startImageNum;
3520 computeInitOrder(writers[index], index);
3521 }
3522
3523 // combine all Image objects into one ImageArray
3524 ImageArrayWriter imageArrayWriter(_startImageNum, (uint32_t)writers.count(), _foundDyldCacheRoots);
3525 for (ImageWriter& writer : writers) {
3526 imageArrayWriter.appendImage(writer.finalize());
3527 writer.deallocate();
3528 }
3529 const ImageArray* imageArray = imageArrayWriter.finalize();
3530
3531 return imageArray;
3532 }
3533
3534
3535 #if BUILDING_CACHE_BUILDER
3536 const ImageArray* ClosureBuilder::makeOtherDylibsImageArray(const Array<LoadedFileInfo>& otherDylibs, uint32_t cachedDylibsCount)
3537 {
3538 // because this is run in cache builder using dispatch_apply() there is minimal stack space
3539 // so set up storage for all arrays to be vm_allocated
3540 uintptr_t maxImageCount = otherDylibs.count() + cachedDylibsCount + 128;
3541 _loadedImages.reserve(maxImageCount);
3542 _dependencies.reserve(maxImageCount*16);
3543
3544 // build _loadedImages[] with every dylib in cache, followed by others
3545 _nextIndex = 0;
3546 for (const LoadedFileInfo& aDylibInfo : otherDylibs) {
3547 BuilderLoadedImage entry;
3548 entry.loadedFileInfo = aDylibInfo;
3549 entry.imageNum = _startImageNum + _nextIndex++;
3550 entry.unmapWhenDone = false;
3551 entry.contentRebased = false;
3552 entry.hasInits = false;
3553 entry.markNeverUnload = false;
3554 entry.rtldLocal = false;
3555 entry.isBadImage = false;
3556 entry.mustBuildClosure = false;
3557 entry.hasMissingWeakImports = false;
3558 entry.overrideImageNum = 0;
3559 _loadedImages.push_back(entry);
3560 }
3561
3562 // wire up dependencies between cached dylibs
3563 // Note, _loadedImages can grow when we call recursiveLoadDependents so we need
3564 // to check the count on each iteration.
3565 for (uint64_t index = 0; index != _loadedImages.count(); ++index) {
3566 BuilderLoadedImage& li = _loadedImages[index];
3567 LoadedImageChain chainStart = { nullptr, li };
3568 recursiveLoadDependents(chainStart);
3569 if ( _diag.hasError() ) {
3570 _diag.warning("while building dlopen closure for %s: %s", li.loadedFileInfo.path, _diag.errorMessage().c_str());
3571 //fprintf(stderr, "while building dlopen closure for %s: %s\n", li.loadedFileInfo.path, _diag.errorMessage().c_str());
3572 _diag.clearError();
3573 li.isBadImage = true; // mark bad
3574 }
3575 }
3576
3577 auto invalidateBadImages = [&]() {
3578 // Invalidate images with bad dependencies
3579 while (true) {
3580 bool madeChange = false;
3581 for (BuilderLoadedImage& li : _loadedImages) {
3582 if (li.isBadImage) {
3583 // Already invalidated
3584 continue;
3585 }
3586 for (Image::LinkedImage depIndex : li.dependents) {
3587 if ( depIndex.imageNum() == kMissingWeakLinkedImage )
3588 continue;
3589 if ( depIndex.imageNum() >= dyld3::closure::kLastDyldCacheImageNum ) {
3590 // dlopen closures can only depend on the shared cache. This is because if foo.dylib links bar.dylib
3591 // and bar.dylib is loaded in to the launch closure, then the dlopen closure for foo.dylib wouldn't see
3592 // bar.dylib at the image num in the launch closure
3593 _diag.warning("while building dlopen closure for %s: dependent dylib is not from shared cache", li.loadedFileInfo.path);
3594 li.isBadImage = true; // mark bad
3595 madeChange = true;
3596 continue;
3597 }
3598 BuilderLoadedImage& depImage = findLoadedImage(depIndex.imageNum());
3599 if (depImage.isBadImage) {
3600 _diag.warning("while building dlopen closure for %s: dependent dylib had error", li.loadedFileInfo.path);
3601 li.isBadImage = true; // mark bad
3602 madeChange = true;
3603 }
3604 }
3605 }
3606 if (!madeChange)
3607 break;
3608 }
3609 };
3610
3611 invalidateBadImages();
3612
3613 // create an ImageWriter for each cached dylib
3614 STACK_ALLOC_ARRAY(ImageWriter, writers, _loadedImages.count());
3615 for (BuilderLoadedImage& li : _loadedImages) {
3616 if ( li.isBadImage ) {
3617 writers.push_back(ImageWriter());
3618 writers.back().setInvalid();
3619 continue;
3620 }
3621 if ( li.imageNum < dyld3::closure::kLastDyldCacheImageNum )
3622 continue;
3623 writers.push_back(ImageWriter());
3624 buildImage(writers.back(), li);
3625 if ( _diag.hasError() ) {
3626 _diag.warning("while building dlopen closure for %s: %s", li.loadedFileInfo.path, _diag.errorMessage().c_str());
3627 //fprintf(stderr, "while building dlopen closure for %s: %s\n", li.loadedFileInfo.path, _diag.errorMessage().c_str());
3628 _diag.clearError();
3629 li.isBadImage = true; // mark bad
3630 writers.back().setInvalid();
3631 }
3632 }
3633
3634 invalidateBadImages();
3635
3636 // add initializer order into each dylib
3637 // Note we have to compute the init order after buildImage as buildImage may set hasInits to true
3638 for (const BuilderLoadedImage& li : _loadedImages) {
3639 if ( li.imageNum < dyld3::closure::kLastDyldCacheImageNum )
3640 continue;
3641 if (li.isBadImage)
3642 continue;
3643 uint32_t index = li.imageNum - _startImageNum;
3644 computeInitOrder(writers[index], index);
3645 }
3646
3647 // combine all Image objects into one ImageArray
3648 ImageArrayWriter imageArrayWriter(_startImageNum, (uint32_t)writers.count(), _foundDyldCacheRoots);
3649 for (ImageWriter& writer : writers) {
3650 imageArrayWriter.appendImage(writer.finalize());
3651 writer.deallocate();
3652 }
3653 const ImageArray* imageArray = imageArrayWriter.finalize();
3654
3655 return imageArray;
3656 }
3657 #endif
3658
3659
3660 bool ClosureBuilder::inLoadedImageArray(const Array<LoadedImage>& loadedList, ImageNum imageNum)
3661 {
3662 for (const LoadedImage& ali : loadedList) {
3663 if ( ali.image()->representsImageNum(imageNum) )
3664 return true;
3665 }
3666 return false;
3667 }
3668
3669 void ClosureBuilder::buildLoadOrderRecurse(Array<LoadedImage>& loadedList, const Array<const ImageArray*>& imagesArrays, const Image* image)
3670 {
3671 // breadth first load
3672 STACK_ALLOC_ARRAY(const Image*, needToRecurse, 256);
3673 image->forEachDependentImage(^(uint32_t dependentIndex, dyld3::closure::Image::LinkKind kind, ImageNum depImageNum, bool &stop) {
3674 if ( !inLoadedImageArray(loadedList, depImageNum) ) {
3675 const Image* depImage = ImageArray::findImage(imagesArrays, depImageNum);
3676 loadedList.push_back(LoadedImage::make(depImage));
3677 needToRecurse.push_back(depImage);
3678 }
3679 });
3680
3681 // recurse load
3682 for (const Image* img : needToRecurse) {
3683 buildLoadOrderRecurse(loadedList, imagesArrays, img);
3684 }
3685 }
3686
3687 void ClosureBuilder::buildLoadOrder(Array<LoadedImage>& loadedList, const Array<const ImageArray*>& imagesArrays, const Closure* toAdd)
3688 {
3689 const dyld3::closure::Image* topImage = ImageArray::findImage(imagesArrays, toAdd->topImage());
3690 loadedList.push_back(LoadedImage::make(topImage));
3691 buildLoadOrderRecurse(loadedList, imagesArrays, topImage);
3692 }
3693
3694
3695
3696 //////////////////////////// ObjCStringTable ////////////////////////////////////////
3697
3698 template<typename PerfectHashT, typename ImageOffsetT>
3699 void ObjCStringTable::write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings)
3700 {
3701 ObjCSelectorOpt::StringTarget sentinel = (ObjCSelectorOpt::StringTarget)ImageOffsetT::sentinelValue;
3702 // Set header
3703 capacity = phash.capacity;
3704 occupied = phash.occupied;
3705 shift = phash.shift;
3706 mask = phash.mask;
3707 sentinelTarget = sentinel;
3708 roundedTabSize = std::max(phash.mask+1, 4U);
3709 salt = phash.salt;
3710
3711 // Set hash data
3712 for (uint32_t i = 0; i < 256; i++) {
3713 scramble[i] = phash.scramble[i];
3714 }
3715 for (uint32_t i = 0; i < phash.mask+1; i++) {
3716 tab[i] = phash.tab[i];
3717 }
3718
3719 dyld3::Array<StringTarget> targetsArray = targets();
3720 dyld3::Array<StringHashCheckByte> checkBytesArray = checkBytes();
3721
3722 // Set offsets to the sentinel
3723 for (uint32_t i = 0; i < phash.capacity; i++) {
3724 targetsArray[i] = sentinel;
3725 }
3726 // Set checkbytes to 0
3727 for (uint32_t i = 0; i < phash.capacity; i++) {
3728 checkBytesArray[i] = 0;
3729 }
3730
3731 // Set real string offsets and checkbytes
3732 for (const auto& s : strings) {
3733 assert(s.second.raw != sentinelTarget);
3734 uint32_t h = hash(s.first);
3735 targetsArray[h] = s.second.raw;
3736 checkBytesArray[h] = checkbyte(s.first);
3737 }
3738 }
3739
3740 //////////////////////////// ObjCClassOpt ////////////////////////////////////////
3741
3742
3743 template<typename PerfectHashT, typename ImageOffsetT, typename ClassesMapT>
3744 void ObjCClassOpt::write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings,
3745 const ClassesMapT& classes, uint32_t preCalculatedDuplicateCount)
3746 {
3747 ObjCStringTable::write(phash, strings);
3748
3749 __block dyld3::Array<ClassTarget> classOffsetsArray = classOffsets();
3750 __block dyld3::Array<ClassTarget> duplicateOffsetsArray = duplicateOffsets(preCalculatedDuplicateCount);
3751
3752 // Set class offsets to 0
3753 for (uint32_t i = 0; i < capacity; i++) {
3754 classOffsetsArray[i].raw = dyld3::closure::Image::ObjCImageOffset::sentinelValue;
3755 }
3756
3757 classes.forEachEntry(^(const char *const &key, const Image::ObjCClassImageOffset **values, uint64_t valuesCount) {
3758 uint32_t keyIndex = getIndex(key);
3759 assert(keyIndex != indexNotFound);
3760 assert(classOffsetsArray[keyIndex].raw == dyld3::closure::Image::ObjCImageOffset::sentinelValue);
3761
3762 if (valuesCount == 1) {
3763 // Only one entry so write it in to the class offsets directly
3764 Image::ObjCClassImageOffset classImageOffset = *(values[0]);
3765 assert(classImageOffset.classData.isDuplicate == 0);
3766 classOffsetsArray[keyIndex] = classImageOffset;
3767 return;
3768 }
3769
3770 // We have more than one value. We add a placeholder to the class offsets which tells us the head
3771 // of the linked list of classes in the duplicates array
3772 uint32_t dest = duplicateCount();
3773 duplicateCount() += valuesCount;
3774
3775 Image::ObjCClassImageOffset classImagePlaceholder;
3776 assert(valuesCount < (1 << 8));
3777 classImagePlaceholder.duplicateData.count = (uint32_t)valuesCount;
3778 classImagePlaceholder.duplicateData.index = dest;
3779 classImagePlaceholder.duplicateData.isDuplicate = 1;
3780 classOffsetsArray[keyIndex] = classImagePlaceholder;
3781
3782 for (uint64_t i = 0; i != valuesCount; ++i) {
3783 Image::ObjCClassImageOffset classImageOffset = *(values[i]);
3784 assert(classImageOffset.classData.isDuplicate == 0);
3785 duplicateOffsetsArray.push_back(classImageOffset);
3786 }
3787 });
3788 }
3789
3790 } // namespace closure
3791 } // namespace dyld3