Loading...
dyld3/Loading.cpp dyld-852 dyld-750.5
--- dyld/dyld-852/dyld3/Loading.cpp
+++ dyld/dyld-750.5/dyld3/Loading.cpp
@@ -46,17 +46,14 @@
 //#include <dispatch/dispatch.h>
 #include <mach/vm_page_size.h>
 
-#include "ClosureFileSystemPhysical.h"
 #include "MachOFile.h"
 #include "MachOLoaded.h"
 #include "MachOAnalyzer.h"
 #include "Logging.h"
 #include "Loading.h"
-#include "RootsChecker.h"
 #include "Tracing.h"
 #include "dyld2.h"
 #include "dyld_cache_format.h"
-#include "libdyldEntryVector.h"
 
 #include "objc-shared-cache.h"
 
@@ -106,15 +103,11 @@
 Loader::Loader(const Array<LoadedImage>& existingImages, Array<LoadedImage>& newImagesStorage,
                const void* cacheAddress, const Array<const dyld3::closure::ImageArray*>& imagesArrays,
                const closure::ObjCSelectorOpt* selOpt, const Array<closure::Image::ObjCSelectorImage>& selImages,
-               const RootsChecker& rootsChecker, dyld3::Platform platform,
-               LogFunc logLoads, LogFunc logSegments, LogFunc logFixups, LogFunc logDof,
-               bool allowMissingLazies, dyld3::LaunchErrorInfo* launchErrorInfo)
+               LogFunc logLoads, LogFunc logSegments, LogFunc logFixups, LogFunc logDofs)
        : _existingImages(existingImages), _newImages(newImagesStorage),
          _imagesArrays(imagesArrays), _dyldCacheAddress(cacheAddress), _dyldCacheSelectorOpt(nullptr),
          _closureSelectorOpt(selOpt), _closureSelectorImages(selImages),
-         _rootsChecker(rootsChecker), _allowMissingLazies(allowMissingLazies), _platform(platform),
-         _logLoads(logLoads), _logSegments(logSegments), _logFixups(logFixups), _logDofs(logDof), _launchErrorInfo(launchErrorInfo)
-
+         _logLoads(logLoads), _logSegments(logSegments), _logFixups(logFixups), _logDofs(logDofs)
 {
 #if BUILDING_DYLD
     // This is only needed for dyld and the launch closure, not the dlopen closures
@@ -129,7 +122,7 @@
     _newImages.push_back(li);
 }
 
-LoadedImage* Loader::findImage(closure::ImageNum targetImageNum) const
+LoadedImage* Loader::findImage(closure::ImageNum targetImageNum)
 {
 #if BUILDING_DYLD
     // The launch images are different in dyld vs libdyld.  In dyld, the new images are
@@ -138,7 +131,7 @@
         return info;
     }
 
-    for (uintptr_t index = 0; index != _newImages.count(); ++index) {
+    for (uint64_t index = 0; index != _newImages.count(); ++index) {
         LoadedImage& info = _newImages[index];
         if ( info.image()->representsImageNum(targetImageNum) ) {
             // Try cache this entry for next time
@@ -187,16 +180,11 @@
 
 void Loader::completeAllDependents(Diagnostics& diag, bool& someCacheImageOverridden)
 {
-    bool iOSonMac = (_platform == Platform::iOSMac);
-#if (TARGET_OS_OSX && TARGET_CPU_ARM64)
-    if ( _platform == Platform::iOS )
-        iOSonMac = true;
-#endif
-    // accumulate all image overrides (512 is placeholder for max unzippered twins in dyld cache)
-    STACK_ALLOC_ARRAY(ImageOverride, overrides, _existingImages.maxCount() + _newImages.maxCount() + 512);
+    // accumulate all image overrides
+    STACK_ALLOC_ARRAY(ImageOverride, overrides, _existingImages.maxCount() + _newImages.maxCount());
     for (const auto anArray : _imagesArrays) {
-        // ignore prebuilt Image* in dyld cache, except for MacCatalyst apps where unzipped twins can override each other
-        if ( (anArray->startImageNum() < dyld3::closure::kFirstLaunchClosureImageNum) && !iOSonMac )
+        // ignore prebuilt Image* in dyld cache
+        if ( anArray->startImageNum() < dyld3::closure::kFirstLaunchClosureImageNum )
             continue;
         anArray->forEachImage(^(const dyld3::closure::Image* image, bool& stop) {
             ImageOverride overrideEntry;
@@ -219,7 +207,7 @@
     uintptr_t index = 0;
     while ( (index < _newImages.count()) && diag.noError() ) {
         const closure::Image* image = _newImages[index].image();
-        //dyld::log("completeAllDependents(): looking at dependents of %s\n", image->path());
+        //fprintf(stderr, "completeAllDependents(): looking at dependents of %s\n", image->path());
         image->forEachDependentImage(^(uint32_t depIndex, closure::Image::LinkKind kind, closure::ImageNum depImageNum, bool& stop) {
             // check if imageNum needs to be changed to an override
             for (const ImageOverride& entry : overrides) {
@@ -233,7 +221,7 @@
                 // if not, look in imagesArrays
                 const closure::Image* depImage = closure::ImageArray::findImage(_imagesArrays, depImageNum);
                 if ( depImage != nullptr ) {
-                     //dyld::log("  load imageNum=0x%05X, image path=%s\n", depImageNum, depImage->path());
+                    //dyld::log("  load imageNum=0x%05X, image path=%s\n", depImageNum, depImage->path());
                      if ( _newImages.freeCount() == 0 ) {
                          diag.error("too many initial images");
                          stop = true;
@@ -253,11 +241,8 @@
     }
 }
 
-void Loader::mapAndFixupAllImages(Diagnostics& diag, bool processDOFs, bool fromOFI, bool* closureOutOfDate, bool* recoverable)
-{
-    *closureOutOfDate = false;
-    *recoverable      = true;
-
+void Loader::mapAndFixupAllImages(Diagnostics& diag, bool processDOFs, bool fromOFI)
+{
     // scan array and map images not already loaded
     for (LoadedImage& info : _newImages) {
         if ( info.loadedAddress() != nullptr ) {
@@ -282,21 +267,21 @@
         if ( info.image()->inDyldCache() ) {
             if ( info.image()->overridableDylib() ) {
                 struct stat statBuf;
-                if ( dyld3::stat(info.image()->path(), &statBuf) == 0 ) {
-                    dyld3::closure::FileSystemPhysical fileSystem;
-                    if ( _rootsChecker.onDiskFileIsRoot(info.image()->path(), (const DyldSharedCache*)_dyldCacheAddress, info.image(),
-                                                        &fileSystem, statBuf.st_ino, statBuf.st_mtime) ) {
-                        if ( ((const DyldSharedCache*)_dyldCacheAddress)->header.dylibsExpectedOnDisk ) {
+                if ( stat(info.image()->path(), &statBuf) == 0 ) {
+                    // verify file has not changed since closure was built
+                    uint64_t inode;
+                    uint64_t mtime;
+                    if ( info.image()->hasFileModTimeAndInode(inode, mtime) ) {
+                        if ( (statBuf.st_mtime != mtime) || (statBuf.st_ino != inode) ) {
                             diag.error("dylib file mtime/inode changed since closure was built for '%s'", info.image()->path());
-                        } else {
-                            diag.error("dylib file not expected on disk, must be a root '%s'", info.image()->path());
                         }
-                        *closureOutOfDate = true;
+                    }
+                    else {
+                        diag.error("dylib file not expected on disk, must be a root '%s'", info.image()->path());
                     }
                 }
                 else if ( (_dyldCacheAddress != nullptr) && ((dyld_cache_header*)_dyldCacheAddress)->dylibsExpectedOnDisk ) {
                     diag.error("dylib file missing, was in dyld shared cache '%s'", info.image()->path());
-                    *closureOutOfDate = true;
                 }
             }
             if ( diag.noError() ) {
@@ -312,28 +297,28 @@
             }
         }
         else {
-            mapImage(diag, info, fromOFI, closureOutOfDate);
+            mapImage(diag, info, fromOFI);
             if ( diag.hasError() )
                 break; // out of for loop
         }
 
     }
-    if ( diag.hasError() ) {
-        // need to clean up by unmapping any images just mapped
-        unmapAllImages();
+    if ( diag.hasError() )  {
+        // bummer, need to clean up by unmapping any images just mapped
+        for (LoadedImage& info : _newImages) {
+            if ( (info.state() == LoadedImage::State::mapped) && !info.image()->inDyldCache() && !info.leaveMapped() ) {
+                _logSegments("dyld: unmapping %s\n", info.image()->path());
+                unmapImage(info);
+            }
+        }
         return;
     }
 
-    // apply fixups to all but main executable
-    LoadedImage* mainInfo = nullptr;
+    // apply fixups
     for (LoadedImage& info : _newImages) {
         // images in shared cache do not need fixups applied
         if ( info.image()->inDyldCache() )
             continue;
-        if ( info.loadedAddress()->filetype == MH_EXECUTE ) {
-            mainInfo = &info;
-            continue;
-        }
         // previously loaded images were previously fixed up
         if ( info.state() < LoadedImage::State::fixedUp ) {
             applyFixupsToImage(diag, info);
@@ -341,26 +326,6 @@
                 break;
             info.setState(LoadedImage::State::fixedUp);
         }
-    }
-    if ( diag.hasError() ) {
-        // need to clean up by unmapping any images just mapped
-        unmapAllImages();
-        return;
-    }
-
-    if ( mainInfo != nullptr ) {
-        // now apply fixups to main executable
-        // we do it in this order so that if there is a problem with the dylibs in the closure
-        // the main executable is left untouched so the closure can be rebuilt
-        applyFixupsToImage(diag, *mainInfo);
-        if ( diag.hasError() ) {
-            // need to clean up by unmapping any images just mapped
-            unmapAllImages();
-            // we have already started fixing up the main executable, so we cannot retry the launch again
-            *recoverable = false;
-            return;
-        }
-        mainInfo->setState(LoadedImage::State::fixedUp);
     }
 
     // find and register dtrace DOFs
@@ -379,18 +344,6 @@
     }
 }
 
-void Loader::unmapAllImages()
-{
-    for (LoadedImage& info : _newImages) {
-        if ( !info.image()->inDyldCache() && !info.leaveMapped() ) {
-            if ( (info.state() == LoadedImage::State::mapped) || (info.state() == LoadedImage::State::fixedUp) ) {
-                _logSegments("dyld: unmapping %s\n", info.image()->path());
-                unmapImage(info);
-            }
-        }
-    }
-}
-
 bool Loader::sandboxBlocked(const char* path, const char* kind)
 {
 #if TARGET_OS_SIMULATOR || TARGET_OS_DRIVERKIT
@@ -417,7 +370,7 @@
     return sandboxBlocked(path, "file-read-metadata");
 }
 
-void Loader::mapImage(Diagnostics& diag, LoadedImage& info, bool fromOFI, bool* closureOutOfDate)
+void Loader::mapImage(Diagnostics& diag, LoadedImage& info, bool fromOFI)
 {
     dyld3::ScopedTimer timer(DBG_DYLD_TIMING_MAP_IMAGE, info.image()->path(), 0, 0);
 
@@ -429,7 +382,11 @@
     bool                    isCodeSigned  = image->hasCodeSignature(codeSignFileOffset, codeSignFileSize);
 
     // open file
-    int fd = dyld3::open(info.image()->path(), O_RDONLY, 0);
+#if BUILDING_DYLD
+    int fd = dyld::my_open(info.image()->path(), O_RDONLY, 0);
+#else
+    int fd = ::open(info.image()->path(), O_RDONLY, 0);
+#endif
     if ( fd == -1 ) {
         int openErr = errno;
         if ( (openErr == EPERM) && sandboxBlockedOpen(image->path()) )
@@ -442,7 +399,7 @@
     // get file info
     struct stat statBuf;
 #if TARGET_OS_SIMULATOR
-    if ( dyld3::stat(image->path(), &statBuf) != 0 ) {
+    if ( stat(image->path(), &statBuf) != 0 ) {
 #else
     if ( fstat(fd, &statBuf) != 0 ) {
 #endif
@@ -461,7 +418,6 @@
     if ( image->hasFileModTimeAndInode(inode, mtime) ) {
         if ( (statBuf.st_mtime != mtime) || (statBuf.st_ino != inode) ) {
             diag.error("file mtime/inode changed since closure was built for '%s'", image->path());
-            *closureOutOfDate = true;
             close(fd);
             return;
         }
@@ -474,23 +430,6 @@
                 // file is now thin
                 sliceOffset = 0;
             }
-        }
-    }
-
-    if ( isCodeSigned && (sliceOffset == 0) ) {
-        uint64_t expectedFileSize = round_page_kernel(codeSignFileOffset+codeSignFileSize);
-        uint64_t actualFileSize = round_page_kernel(statBuf.st_size);
-        if ( actualFileSize < expectedFileSize ) {
-            diag.error("File size too small for code signature");
-            *closureOutOfDate = true;
-            close(fd);
-            return;
-        }
-        if ( actualFileSize != expectedFileSize ) {
-            diag.error("File size doesn't match code signature");
-            *closureOutOfDate = true;
-            close(fd);
-            return;
         }
     }
 
@@ -508,13 +447,6 @@
             if ( (errnoCopy == EPERM) || (errnoCopy == EBADEXEC) ) {
                 diag.error("code signature invalid (errno=%d) sliceOffset=0x%08llX, codeBlobOffset=0x%08X, codeBlobSize=0x%08X for '%s'",
                             errnoCopy, sliceOffset, codeSignFileOffset, codeSignFileSize, image->path());
-#if BUILDING_LIBDYLD
-                if ( errnoCopy == EBADEXEC ) {
-                    // dlopen closures many be prebuilt in to the shared cache with a code signature, but the dylib is replaced
-                    // with one without a code signature.  In that case, lets build a new closure
-                    *closureOutOfDate = true;
-                }
-#endif
             }
             else {
                 diag.error("fcntl(fd, F_ADDFILESIGS_RETURN) failed with errno=%d, sliceOffset=0x%08llX, codeBlobOffset=0x%08X, codeBlobSize=0x%08X for '%s'",
@@ -671,7 +603,6 @@
             }
         }
         if ( diag.hasError() ) {
-            *closureOutOfDate = true;
             ::vm_deallocate(mach_task_self(), loadAddress, (vm_size_t)totalVMSize);
             return;
         }
@@ -679,7 +610,7 @@
 
 #endif
 
-#if (__arm__ || __arm64__) && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
     // tell kernel about fairplay encrypted regions
     uint32_t fpTextOffset;
     uint32_t fpSize;
@@ -713,7 +644,7 @@
     if ( dofs.empty() )
         return;
 
-    int fd = ::open("/dev/" DTRACEMNR_HELPER, O_RDWR);
+    int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
     if ( fd < 0 ) {
         _logDofs("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
     }
@@ -751,18 +682,14 @@
 
 bool Loader::dtraceUserProbesEnabled()
 {
-#if !TARGET_OS_SIMULATOR
     uint8_t dofEnabled = *((uint8_t*)_COMM_PAGE_DTRACE_DOF_ENABLED);
     return ( (dofEnabled & 1) );
-#else
-    return false;
-#endif
 }
 
 
 void Loader::vmAccountingSetSuspended(bool suspend, LogFunc logger)
 {
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __arm__ || __arm64__
     // <rdar://problem/29099600> dyld should tell the kernel when it is doing fix-ups caused by roots
     logger("vm.footprint_suspend=%d\n", suspend);
     int newValue = suspend ? 1 : 0;
@@ -771,21 +698,6 @@
     size_t oldlen = sizeof(oldValue);
     sysctlbyname("vm.footprint_suspend", &oldValue, &oldlen, &newValue, newlen);
 #endif
-}
-
-static const char* targetString(const MachOAnalyzerSet::FixupTarget& target)
-{
-    switch (target.kind ) {
-        case MachOAnalyzerSet::FixupTarget::Kind::rebase:
-            return "rebase";
-        case MachOAnalyzerSet::FixupTarget::Kind::bindAbsolute:
-            return "abolute";
-        case MachOAnalyzerSet::FixupTarget::Kind::bindToImage:
-            return target.foundSymbolName;
-        case MachOAnalyzerSet::FixupTarget::Kind::bindMissingSymbol:
-            return "missing";
-    }
-    return "";
 }
 
 void Loader::applyFixupsToImage(Diagnostics& diag, LoadedImage& info)
@@ -800,192 +712,93 @@
     
     if ( overrideOfCache )
         vmAccountingSetSuspended(true, _logFixups);
-    if ( image->fixupsNotEncoded() ) {
-        // make the cache writable for this block
-        // We do this lazily, only if we find a symbol which needs to be overridden
-        DyldSharedCache::DataConstLazyScopedWriter patcher((const DyldSharedCache*)_dyldCacheAddress, mach_task_self(), (DyldSharedCache::DataConstLogFunc)_logSegments);
-        auto* patcherPtr = &patcher;
-
-        WrappedMachO wmo((MachOAnalyzer*)info.loadedAddress(), this, (void*)info.image());
-        wmo.forEachFixup(diag,
-        ^(uint64_t fixupLocRuntimeOffset, PointerMetaData pmd, const FixupTarget& target, bool& stop) {
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + fixupLocRuntimeOffset);
-            uintptr_t value;
-            switch ( target.kind ) {
-                case MachOAnalyzerSet::FixupTarget::Kind::rebase:
-                case MachOAnalyzerSet::FixupTarget::Kind::bindToImage:
-                    value = (uintptr_t)(target.foundInImage._mh) + target.offsetInImage;
-                    break;
-                case MachOAnalyzerSet::FixupTarget::Kind::bindAbsolute:
-                    value = (uintptr_t)target.offsetInImage;
-                    break;
-                case MachOAnalyzerSet::FixupTarget::Kind::bindMissingSymbol:
-                    if ( _launchErrorInfo ) {
-                        _launchErrorInfo->kind              = DYLD_EXIT_REASON_SYMBOL_MISSING;
-                        _launchErrorInfo->clientOfDylibPath = info.image()->path();
-                        _launchErrorInfo->targetDylibPath   = target.foundInImage.path();
-                        _launchErrorInfo->symbol            = target.requestedSymbolName;
-                    }
-                    // we have no value to set, and forEachFixup() is about to finish
-                    return;
-            }
-    #if __has_feature(ptrauth_calls)
-            if ( pmd.authenticated )
-                value = MachOLoaded::ChainedFixupPointerOnDisk::Arm64e::signPointer(value, fixUpLoc, pmd.usesAddrDiversity, pmd.diversity, pmd.key);
-    #endif
-            if ( pmd.high8 )
-                value |= ((uint64_t)pmd.high8 << 56);
-            _logFixups("dyld: fixup: %s:%p = %p (%s)\n", leafName, fixUpLoc, (void*)value, targetString(target));
-            *fixUpLoc = value;
-        },
-        ^(uint32_t cachedDylibIndex, uint32_t exportCacheOffset, const FixupTarget& target) {
-#if BUILDING_LIBDYLD && __x86_64__
-            // Full dlopen closures don't patch weak defs.  Bail out early if we are libdyld to match this behaviour
-            return;
-#endif
-            patcherPtr->makeWriteable();
-            ((const DyldSharedCache*)_dyldCacheAddress)->forEachPatchableUseOfExport(cachedDylibIndex, exportCacheOffset, ^(dyld_cache_patchable_location patchLoc) {
-                uintptr_t* loc     = (uintptr_t*)(((uint8_t*)_dyldCacheAddress)+patchLoc.cacheOffset);
-                uintptr_t  newImpl = (uintptr_t)(target.foundInImage._mh) + target.offsetInImage + DyldSharedCache::getAddend(patchLoc);
-    #if __has_feature(ptrauth_calls)
-                if ( patchLoc.authenticated )
-                    newImpl = MachOLoaded::ChainedFixupPointerOnDisk::Arm64e::signPointer(newImpl, loc, patchLoc.usesAddressDiversity, patchLoc.discriminator, patchLoc.key);
-    #endif
-                // ignore duplicate patch entries
-                if ( *loc != newImpl ) {
-                    _logFixups("dyld: cache patch: %p = 0x%0lX\n", loc, newImpl);
-                    *loc = newImpl;
-                }
+    image->forEachFixup(^(uint64_t imageOffsetToRebase, bool& stop) {
+        // this is a rebase, add slide
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
+        *fixUpLoc += slide;
+        _logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
+    },
+    ^(uint64_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
+        // this is a bind, set to target
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToBind);
+        uintptr_t value = resolveTarget(bindTarget);
+        _logFixups("dyld: fixup: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
+        *fixUpLoc = value;
+    },
+    ^(uint64_t imageOffsetToStartsInfo, const Array<closure::Image::ResolvedSymbolTarget>& targets, bool& stop) {
+        // this is a chain of fixups, fix up all
+        STACK_ALLOC_OVERFLOW_SAFE_ARRAY(const void*, targetAddrs, 128);
+        targetAddrs.reserve(targets.count());
+        for (uint32_t i=0; i < targets.count(); ++i)
+            targetAddrs.push_back((void*)resolveTarget(targets[i]));
+        ((dyld3::MachOAnalyzer*)(info.loadedAddress()))->withChainStarts(diag, imageOffsetToStartsInfo, ^(const dyld_chained_starts_in_image* starts) {
+            info.loadedAddress()->fixupAllChainedFixups(diag, starts, slide, targetAddrs, ^(void* loc, void* newValue) {
+                _logFixups("dyld: fixup: %s:%p = %p\n", leafName, loc, newValue);
             });
         });
-#if BUILDING_LIBDYLD && TARGET_OS_OSX
-        // <rdar://problem/59265987> support old licenseware plugins on macOS using minimal closures
-        __block bool oldBinary = true;
-        info.loadedAddress()->forEachSupportedPlatform(^(Platform platform, uint32_t minOS, uint32_t sdk) {
-            if ( (platform == Platform::macOS) && (sdk >= 0x000A0F00) )
-                oldBinary = false;
-        });
-        if ( oldBinary ) {
-            // look for __DATA,__dyld section
-            info.loadedAddress()->forEachSection(^(const MachOAnalyzer::SectionInfo& sectInfo, bool malformedSectionRange, bool& stop) {
-                if ( (strcmp(sectInfo.sectName, "__dyld") == 0) && (strcmp(sectInfo.segInfo.segName, "__DATA") == 0) ) {
-                    // dyld_func_lookup is second pointer in __dyld section
-                    uintptr_t* dyldSection = (uintptr_t*)(sectInfo.sectAddr + (uintptr_t)info.loadedAddress());
-                    _logFixups("dyld: __dyld section: %p = %p\n", &dyldSection[1], &dyld3::compatFuncLookup);
-                    dyldSection[1] = (uintptr_t)&dyld3::compatFuncLookup;
-                 }
-            });
-        }
-#endif
-    }
-    else {
-        if ( image->rebasesNotEncoded() ) {
-            // <rdar://problem/56172089> some apps have so many rebases the closure file is too big, instead we go back to rebase opcodes
-            ((MachOAnalyzer*)imageLoadAddress)->forEachRebase(diag, true, ^(uint64_t imageOffsetToRebase, bool& stop) {
-                // this is a rebase, add slide
-                uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
-                *fixUpLoc += slide;
-                _logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
-            });
-        }
-        image->forEachFixup(^(uint64_t imageOffsetToRebase, bool& stop) {
-            // this is a rebase, add slide
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
-            *fixUpLoc += slide;
-            _logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
-        },
-        ^(uint64_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
-            // this is a bind, set to target
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToBind);
-            uintptr_t value = resolveTarget(bindTarget);
-            _logFixups("dyld: fixup: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
-            *fixUpLoc = value;
-        },
-        ^(uint64_t imageOffsetToStartsInfo, const Array<closure::Image::ResolvedSymbolTarget>& targets, bool& stop) {
-            // this is a chain of fixups, fix up all
-            STACK_ALLOC_OVERFLOW_SAFE_ARRAY(const void*, targetAddrs, 128);
-            targetAddrs.reserve(targets.count());
-            for (uint32_t i=0; i < targets.count(); ++i)
-                targetAddrs.push_back((void*)resolveTarget(targets[i]));
-            ((dyld3::MachOAnalyzer*)(info.loadedAddress()))->withChainStarts(diag, imageOffsetToStartsInfo, ^(const dyld_chained_starts_in_image* starts) {
-                info.loadedAddress()->fixupAllChainedFixups(diag, starts, slide, targetAddrs, ^(void* loc, void* newValue) {
-                    _logFixups("dyld: fixup: %s:%p = %p\n", leafName, loc, newValue);
-                });
-            });
-        },
-        ^(uint64_t imageOffsetToFixup) {
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
-            _logFixups("dyld: fixup objc image info: %s Setting objc image info for precomputed objc\n", leafName);
-
-            MachOAnalyzer::ObjCImageInfo *imageInfo = (MachOAnalyzer::ObjCImageInfo *)fixUpLoc;
-            ((MachOAnalyzer::ObjCImageInfo *)imageInfo)->flags |= MachOAnalyzer::ObjCImageInfo::dyldPreoptimized;
-        },
-        ^(uint64_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
-            // this is a bind, set to target
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToBind);
-            uintptr_t value = resolveTarget(bindTarget);
-#if __has_feature(ptrauth_calls)
-            // Sign the ISA on arm64e.
-            // Unfortunately a hard coded value here is not ideal, but this is ABI so we aren't going to change it
-            // This matches the value in libobjc __objc_opt_ptrs: .quad x@AUTH(da, 27361, addr)
-            value = MachOLoaded::ChainedFixupPointerOnDisk::Arm64e::signPointer(value, fixUpLoc, true, 27361, 2);
-#endif
-            _logFixups("dyld: fixup objc protocol: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
-            *fixUpLoc = value;
-        },
-        ^(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool &stop) {
-            // fixupObjCSelRefs
-            closure::Image::ResolvedSymbolTarget fixupTarget;
-            if ( inSharedCache ) {
-                const char* selectorString = _dyldCacheSelectorOpt->getEntryForIndex(selectorIndex);
-                fixupTarget.sharedCache.kind     = closure::Image::ResolvedSymbolTarget::kindSharedCache;
-                fixupTarget.sharedCache.offset   = (uint64_t)selectorString - (uint64_t)_dyldCacheAddress;
-            } else {
-                closure::ImageNum imageNum;
-                uint64_t vmOffset;
-                bool gotLocation = _closureSelectorOpt->getStringLocation(selectorIndex, _closureSelectorImages, imageNum, vmOffset);
-                assert(gotLocation);
-                fixupTarget.image.kind = closure::Image::ResolvedSymbolTarget::kindImage;
-                fixupTarget.image.imageNum = imageNum;
-                fixupTarget.image.offset = vmOffset;
-            }
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
-            uintptr_t value = resolveTarget(fixupTarget);
-            _logFixups("dyld: fixup objc selector: %s:%p(was '%s') = %p(now '%s')\n", leafName, fixUpLoc, (const char*)*fixUpLoc, (void*)value, (const char*)value);
-            *fixUpLoc = value;
-        }, ^(uint64_t imageOffsetToFixup, bool &stop) {
-            // fixupObjCStableSwift
-            // Class really is stable Swift, pretending to be pre-stable.
-            // Fix its lie.
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
-            uintptr_t value = ((*fixUpLoc) | MachOAnalyzer::ObjCClassInfo::FAST_IS_SWIFT_STABLE) & ~MachOAnalyzer::ObjCClassInfo::FAST_IS_SWIFT_LEGACY;
-            _logFixups("dyld: fixup objc stable Swift: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
-            *fixUpLoc = value;
-        }, ^(uint64_t imageOffsetToFixup, bool &stop) {
-            // fixupObjCMethodList
-            // Set the method list to have the uniqued bit set
-            uint32_t* fixUpLoc = (uint32_t*)(imageLoadAddress + imageOffsetToFixup);
-            uint32_t value = (*fixUpLoc) | MachOAnalyzer::ObjCMethodList::methodListIsUniqued;
-            _logFixups("dyld: fixup objc method list: %s:%p = 0x%08x\n", leafName, fixUpLoc, value);
-            *fixUpLoc = value;
-        });
+    },
+    ^(uint64_t imageOffsetToFixup) {
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
+        _logFixups("dyld: fixup objc image info: %s Setting objc image info for precomputed objc\n", leafName);
+
+        MachOAnalyzer::ObjCImageInfo *imageInfo = (MachOAnalyzer::ObjCImageInfo *)fixUpLoc;
+        ((MachOAnalyzer::ObjCImageInfo *)imageInfo)->flags |= MachOAnalyzer::ObjCImageInfo::dyldPreoptimized;
+    },
+    ^(uint64_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
+        // this is a bind, set to target
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToBind);
+        uintptr_t value = resolveTarget(bindTarget);
+        _logFixups("dyld: fixup objc protocol: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
+        *fixUpLoc = value;
+    },
+    ^(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool &stop) {
+        // fixupObjCSelRefs
+        closure::Image::ResolvedSymbolTarget fixupTarget;
+        if ( inSharedCache ) {
+            const char* selectorString = _dyldCacheSelectorOpt->getEntryForIndex(selectorIndex);
+            fixupTarget.sharedCache.kind     = closure::Image::ResolvedSymbolTarget::kindSharedCache;
+            fixupTarget.sharedCache.offset   = (uint64_t)selectorString - (uint64_t)_dyldCacheAddress;
+        } else {
+            closure::ImageNum imageNum;
+            uint64_t vmOffset;
+            bool gotLocation = _closureSelectorOpt->getStringLocation(selectorIndex, _closureSelectorImages, imageNum, vmOffset);
+            assert(gotLocation);
+            fixupTarget.image.kind = closure::Image::ResolvedSymbolTarget::kindImage;
+            fixupTarget.image.imageNum = imageNum;
+            fixupTarget.image.offset = vmOffset;
+        }
+
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
+        uintptr_t value = resolveTarget(fixupTarget);
+        _logFixups("dyld: fixup objc selector: %s:%p(was '%s') = %p(now '%s')\n", leafName, fixUpLoc, (const char*)*fixUpLoc, (void*)value, (const char*)value);
+        *fixUpLoc = value;
+    }, ^(uint64_t imageOffsetToFixup, bool &stop) {
+        // fixupObjCStableSwift
+        // Class really is stable Swift, pretending to be pre-stable.
+        // Fix its lie.
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
+        uintptr_t value = ((*fixUpLoc) | MachOAnalyzer::ObjCClassInfo::FAST_IS_SWIFT_STABLE) & ~MachOAnalyzer::ObjCClassInfo::FAST_IS_SWIFT_LEGACY;
+        _logFixups("dyld: fixup objc stable Swift: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
+        *fixUpLoc = value;
+    }, ^(uint64_t imageOffsetToFixup, bool &stop) {
+        // TODO: Implement this
+    });
 
 #if __i386__
-        __block bool segmentsMadeWritable = false;
-        image->forEachTextReloc(^(uint32_t imageOffsetToRebase, bool& stop) {
-            if ( !segmentsMadeWritable )
-                setSegmentProtects(info, true);
-            uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
-            *fixUpLoc += slide;
-            _logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
-         },
-        ^(uint32_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
-            // FIXME
-        });
-        if ( segmentsMadeWritable )
-            setSegmentProtects(info, false);
-#endif
-    }
+    __block bool segmentsMadeWritable = false;
+    image->forEachTextReloc(^(uint32_t imageOffsetToRebase, bool& stop) {
+        if ( !segmentsMadeWritable )
+            setSegmentProtects(info, true);
+        uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
+        *fixUpLoc += slide;
+        _logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
+     },
+    ^(uint32_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
+        // FIXME
+    });
+    if ( segmentsMadeWritable )
+        setSegmentProtects(info, false);
+#endif
 
     // make any read-only data segments read-only
     if ( image->hasReadOnlyData() && !image->inDyldCache() ) {
@@ -1015,112 +828,13 @@
 }
 #endif
 
-
-void Loader::forEachImage(void (^handler)(const LoadedImage& li, bool& stop)) const
-{
-    bool stop = false;
-    for (const LoadedImage& li : _existingImages) {
-        handler(li, stop);
-        if ( stop )
-            return;
-    }
-    for (const LoadedImage& li : _newImages) {
-        handler(li, stop);
-        if ( stop )
-            return;
-    }
-}
-
-void Loader::mas_forEachImage(void (^handler)(const WrappedMachO& wmo, bool hidden, bool& stop)) const
-{
-    forEachImage(^(const LoadedImage& li, bool& stop) {
-        WrappedMachO wmo((MachOAnalyzer*)li.loadedAddress(), this, (void*)li.image());
-        handler(wmo, li.hideFromFlatSearch(), stop);
-    });
-}
-
-
-bool Loader::wmo_missingSymbolResolver(const WrappedMachO* fromWmo, bool weakImport, bool lazyBind, const char* symbolName, const char* expectedInDylibPath, const char* clientPath, FixupTarget& target) const
-{
-    if ( weakImport ) {
-        target.offsetInImage = 0;
-        target.kind  = FixupTarget::Kind::bindAbsolute;
-        return true;
-    }
-
-    if ( lazyBind && _allowMissingLazies ) {
-        __block bool result = false;
-        forEachImage(^(const LoadedImage& li, bool& stop) {
-            if ( li.loadedAddress()->isDylib() && (strcmp(li.loadedAddress()->installName(), "/usr/lib/system/libdyld.dylib") == 0) ) {
-                WrappedMachO libdyldWmo((MachOAnalyzer*)li.loadedAddress(), this, (void*)li.image());
-                Diagnostics  diag;
-                if ( libdyldWmo.findSymbolIn(diag, "__dyld_missing_symbol_abort", 0, target) ) {
-                     // <rdar://problem/44315944> closures should bind missing lazy-bind symbols to a missing symbol handler in libdyld in flat namespace
-                     result = true;
-                }
-                stop = true;
-            }
-        });
-        return result;
-    }
-
-    // FIXME
-    return false;
-}
-
-
-void Loader::mas_mainExecutable(WrappedMachO& mainWmo) const
-{
-    forEachImage(^(const LoadedImage& li, bool& stop) {
-        if ( li.loadedAddress()->isMainExecutable() ) {
-            WrappedMachO wmo((MachOAnalyzer*)li.loadedAddress(), this, (void*)li.image());
-            mainWmo = wmo;
-            stop = true;
-        }
-    });
-}
-
-void* Loader::mas_dyldCache() const
-{
-    return (void*)_dyldCacheAddress;
-}
-
-
-bool Loader::wmo_dependent(const WrappedMachO* wmo, uint32_t depIndex, WrappedMachO& childWmo, bool& missingWeakDylib) const
-{
-    const closure::Image* image = (closure::Image*)(wmo->_other);
-    closure::ImageNum depImageNum = image->dependentImageNum(depIndex);
-    if ( depImageNum == closure::kMissingWeakLinkedImage ) {
-        missingWeakDylib = true;
-        return true;
-    }
-    else {
-        if ( LoadedImage* li = findImage(depImageNum) ) {
-            WrappedMachO foundWmo((MachOAnalyzer*)li->loadedAddress(), this, (void*)li->image());
-            missingWeakDylib = false;
-            childWmo = foundWmo;
-            return true;
-        }
-    }
-    return false;
-}
-
-
-const char* Loader::wmo_path(const WrappedMachO* wmo) const
-{
-    const closure::Image* image = (closure::Image*)(wmo->_other);
-    return image->path();
-}
-
-
-
 #if BUILDING_DYLD
 LoadedImage* Loader::LaunchImagesCache::findImage(closure::ImageNum imageNum,
                                                   Array<LoadedImage>& images) const {
     if ( (imageNum < _firstImageNum) || (imageNum >= _lastImageNum) )
         return nullptr;
 
-    unsigned int cacheIndex = imageNum - _firstImageNum;
+    uint64_t cacheIndex = imageNum - _firstImageNum;
     uint32_t imagesIndex = _imageIndices[cacheIndex];
     if ( imagesIndex == 0 )
         return nullptr;
@@ -1129,17 +843,16 @@
     return &images[imagesIndex - 1];
 }
 
-void Loader::LaunchImagesCache::tryAddImage(closure::ImageNum imageNum, uint64_t allImagesIndex) const {
+void Loader::LaunchImagesCache::tryAddImage(closure::ImageNum imageNum,
+                                            uint64_t allImagesIndex) {
     if ( (imageNum < _firstImageNum) || (imageNum >= _lastImageNum) )
         return;
 
-    unsigned int cacheIndex = imageNum - _firstImageNum;
+    uint64_t cacheIndex = imageNum - _firstImageNum;
 
     // Note the index is offset by 1 so that 0's are not yet set
     _imageIndices[cacheIndex] = (uint32_t)allImagesIndex + 1;
 }
- #endif
-
 
 void forEachLineInFile(const char* buffer, size_t bufferLen, void (^lineHandler)(const char* line, bool& stop))
 {
@@ -1163,7 +876,7 @@
 
 void forEachLineInFile(const char* path, void (^lineHandler)(const char* line, bool& stop))
 {
-    int fd = dyld3::open(path, O_RDONLY, 0);
+    int fd = dyld::my_open(path, O_RDONLY, 0);
     if ( fd != -1 ) {
         struct stat statBuf;
         if ( fstat(fd, &statBuf) == 0 ) {
@@ -1177,13 +890,14 @@
     }
 }
 
+#endif
 
 #if (BUILDING_LIBDYLD || BUILDING_DYLD)
     bool internalInstall()
     {
 #if TARGET_OS_SIMULATOR
         return false;
-#elif TARGET_OS_IPHONE
+#elif __IPHONE_OS_VERSION_MIN_REQUIRED
         uint32_t devFlags = *((uint32_t*)_COMM_PAGE_DEV_FIRM);
         return ( (devFlags & 1) == 1 );
 #else