+ //dyld::log("interposedAddress(0x%08llX), tupleCount=%lu\n", (uint64_t)address, fgInterposingTuples.size());
+ for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+ //dyld::log(" interposedAddress: replacee=0x%08llX, replacement=0x%08llX, neverImage=%p, onlyImage=%p, inImage=%p\n",
+ // (uint64_t)it->replacee, (uint64_t)it->replacement, it->neverImage, it->onlyImage, inImage);
+ // replace all references to 'replacee' with 'replacement'
+ if ( (address == it->replacee) && (inImage != it->neverImage) && ((it->onlyImage == NULL) || (inImage == it->onlyImage)) ) {
+ if ( context.verboseInterposing ) {
+ dyld::log("dyld interposing: replace 0x%lX with 0x%lX\n", it->replacee, it->replacement);
+ }
+ return it->replacement;
+ }
+ }
+ return address;
+}
+
+void ImageLoader::applyInterposingToDyldCache(const LinkContext& context) {
+#if USES_CHAINED_BINDS
+ if (!context.dyldCache)
+ return;
+ if (fgInterposingTuples.empty())
+ return;
+ // For each of the interposed addresses, see if any of them are in the shared cache. If so, find
+ // that image and apply its patch table to all uses.
+ uintptr_t cacheStart = (uintptr_t)context.dyldCache;
+ for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+ if ( context.verboseInterposing )
+ dyld::log("dyld: interpose: Trying to interpose address 0x%08llx\n", (uint64_t)it->replacee);
+ uint32_t imageIndex;
+ uint32_t cacheOffsetOfReplacee = (uint32_t)(it->replacee - cacheStart);
+ if (!context.dyldCache->addressInText(cacheOffsetOfReplacee, &imageIndex))
+ continue;
+ dyld3::closure::ImageNum imageInCache = imageIndex+1;
+ if ( context.verboseInterposing )
+ dyld::log("dyld: interpose: Found shared cache image %d for 0x%08llx\n", imageInCache, (uint64_t)it->replacee);
+ const dyld3::closure::Image* image = context.dyldCache->cachedDylibsImageArray()->imageForNum(imageInCache);
+ image->forEachPatchableExport(^(uint32_t cacheOffsetOfImpl, const char* exportName) {
+ // Skip patching anything other than this symbol
+ if (cacheOffsetOfImpl != cacheOffsetOfReplacee)
+ return;
+ if ( context.verboseInterposing )
+ dyld::log("dyld: interpose: Patching uses of symbol %s in shared cache binary at %s\n", exportName, image->path());
+ uintptr_t newLoc = it->replacement;
+ image->forEachPatchableUseOfExport(cacheOffsetOfImpl, ^(dyld3::closure::Image::PatchableExport::PatchLocation patchLocation) {
+ uintptr_t* loc = (uintptr_t*)(cacheStart+patchLocation.cacheOffset);
+#if __has_feature(ptrauth_calls)
+ if ( patchLocation.authenticated ) {
+ dyld3::MachOLoaded::ChainedFixupPointerOnDisk fixupInfo;
+ fixupInfo.authRebase.auth = true;
+ fixupInfo.authRebase.addrDiv = patchLocation.usesAddressDiversity;
+ fixupInfo.authRebase.diversity = patchLocation.discriminator;
+ fixupInfo.authRebase.key = patchLocation.key;
+ *loc = fixupInfo.signPointer(loc, newLoc + patchLocation.getAddend());
+ if ( context.verboseInterposing )
+ dyld::log("dyld: interpose: *%p = %p (JOP: diversity 0x%04X, addr-div=%d, key=%s)\n",
+ loc, (void*)*loc, patchLocation.discriminator, patchLocation.usesAddressDiversity, patchLocation.keyName());
+ return;
+ }
+#endif
+ if ( context.verboseInterposing )
+ dyld::log("dyld: interpose: *%p = 0x%0llX (dyld cache patch) to %s\n", loc, newLoc + patchLocation.getAddend(), exportName);
+ *loc = newLoc + patchLocation.getAddend();
+ });
+ });
+ }
+#endif
+}
+
+void ImageLoader::addDynamicInterposingTuples(const struct dyld_interpose_tuple array[], size_t count)
+{
+ for(size_t i=0; i < count; ++i) {
+ ImageLoader::InterposeTuple tuple;
+ tuple.replacement = (uintptr_t)array[i].replacement;
+ tuple.neverImage = NULL;
+ tuple.onlyImage = this;
+ tuple.replacee = (uintptr_t)array[i].replacee;
+ // chain to any existing interpositions
+ for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+ if ( (it->replacee == tuple.replacee) && (it->onlyImage == this) ) {
+ tuple.replacee = it->replacement;
+ }
+ }
+ ImageLoader::fgInterposingTuples.push_back(tuple);
+ }
+}
+
+// <rdar://problem/29099600> dyld should tell the kernel when it is doing root fix-ups
+void ImageLoader::vmAccountingSetSuspended(const LinkContext& context, bool suspend)
+{
+#if __arm__ || __arm64__
+ static bool sVmAccountingSuspended = false;
+ if ( suspend == sVmAccountingSuspended )
+ return;
+ if ( context.verboseBind )
+ dyld::log("set vm.footprint_suspend=%d\n", suspend);
+ int newValue = suspend ? 1 : 0;
+ int oldValue = 0;
+ size_t newlen = sizeof(newValue);
+ size_t oldlen = sizeof(oldValue);
+ int ret = sysctlbyname("vm.footprint_suspend", &oldValue, &oldlen, &newValue, newlen);
+ if ( context.verboseBind && (ret != 0) )
+ dyld::log("vm.footprint_suspend => %d, errno=%d\n", ret, errno);
+ sVmAccountingSuspended = suspend;
+#endif
+}
+
+
+void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, bool neverUnload, const RPathChain& loaderRPaths, const char* imagePath)
+{
+ //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", imagePath, fDlopenReferenceCount, fNeverUnload);