+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
+}
+