if ( li.overrideImageNum != 0 ) {
                 const Image* cacheImage = _dyldImageArray->imageForNum(li.overrideImageNum);
                 STACK_ALLOC_ARRAY(Closure::PatchEntry, patches, cacheImage->patchableExportCount());
+                MachOLoaded::DependentToMachOLoaded reexportFinder = ^(const MachOLoaded* mh, uint32_t depIndex) {
+                    return (const MachOLoaded*)findDependent(mh, depIndex);
+                };
                 //fprintf(stderr, "'%s' overrides '%s'\n", li.loadedFileInfo.path, cacheImage->path());
                 cacheImage->forEachPatchableExport(^(uint32_t cacheOffsetOfImpl, const char* symbolName) {
                     dyld3::MachOAnalyzer::FoundSymbol foundInfo;
                     Closure::PatchEntry               patch;
                     patch.overriddenDylibInCache  = li.overrideImageNum;
                     patch.exportCacheOffset       = cacheOffsetOfImpl;
-                    if ( li.loadAddress()->findExportedSymbol(patchDiag, symbolName, foundInfo, nullptr) ) {
+                    if ( li.loadAddress()->findExportedSymbol(patchDiag, symbolName, foundInfo, reexportFinder) ) {
+                        const MachOAnalyzer* impDylib = (const MachOAnalyzer*)foundInfo.foundInDylib;
                         patch.replacement.image.kind     = Image::ResolvedSymbolTarget::kindImage;
-                        patch.replacement.image.imageNum = li.imageNum;
+                        patch.replacement.image.imageNum = findLoadedImage(impDylib).imageNum;
                         patch.replacement.image.offset   = foundInfo.value;
                     }
                     else {
             if ( (li.overrideImageNum != 0) && (li.imageNum >= _startImageNum) ) {
                 const Image* cacheImage = _dyldImageArray->imageForNum(li.overrideImageNum);
                 STACK_ALLOC_ARRAY(Closure::PatchEntry, patches, cacheImage->patchableExportCount());
+                MachOLoaded::DependentToMachOLoaded reexportFinder = ^(const MachOLoaded* mh, uint32_t depIndex) {
+                    return (const MachOLoaded*)findDependent(mh, depIndex);
+                };
                 //fprintf(stderr, "'%s' overrides '%s'\n", li.loadedFileInfo.path, cacheImage->path());
                 cacheImage->forEachPatchableExport(^(uint32_t cacheOffsetOfImpl, const char* symbolName) {
                     dyld3::MachOAnalyzer::FoundSymbol foundInfo;
                     Closure::PatchEntry               patch;
                     patch.overriddenDylibInCache  = li.overrideImageNum;
                     patch.exportCacheOffset       = cacheOffsetOfImpl;
-                    if ( li.loadAddress()->findExportedSymbol(patchDiag, symbolName, foundInfo, nullptr) ) {
+                    if ( li.loadAddress()->findExportedSymbol(patchDiag, symbolName, foundInfo, reexportFinder) ) {
+                        const MachOAnalyzer* impDylib = (const MachOAnalyzer*)foundInfo.foundInDylib;
                         patch.replacement.image.kind     = Image::ResolvedSymbolTarget::kindImage;
-                        patch.replacement.image.imageNum = li.imageNum;
+                        patch.replacement.image.imageNum = findLoadedImage(impDylib).imageNum;
                         patch.replacement.image.offset   = foundInfo.value;
                     }
                     else {
 
 
 #include "ClosureFileSystem.h"
 
+#include <sys/stat.h>
+
 namespace dyld3 {
 namespace closure {
 
 
     __block Node root;
     root.map["images"] = buildImageArrayNode(closure->images(), imagesArrays, printFixups, printDependentsDetails);
 
+    closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
+        Node patchNode;
+        patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
+        patchNode.map["func-image-num"].value         = hex8(patchEntry.overriddenDylibInCache);
+        patchNode.map["replacement"].value            = printTarget(imagesArrays, patchEntry.replacement);
+        root.map["dyld-cache-fixups"].array.push_back(patchNode);
+    });
+
      Image::ResolvedSymbolTarget entry;
     if ( closure->mainEntry(entry) )
         root.map["main"].value = printTarget(imagesArrays, entry);
 
 
 closure::LoadedFileInfo MachOAnalyzer::load(Diagnostics& diag, const closure::FileSystem& fileSystem, const char* path, const char* reqArchName, Platform reqPlatform)
 {
+    // FIXME: This should probably be an assert, but if we happen to have a diagnostic here then something is wrong
+    // above us and we should quickly return instead of doing unnecessary work.
+    if (diag.hasError())
+        return closure::LoadedFileInfo();
+
     closure::LoadedFileInfo info;
     char realerPath[MAXPATHLEN];
     if (!fileSystem.loadFile(path, info, realerPath, ^(const char *format, ...) {
         return closure::LoadedFileInfo();
     }
 
+    // If we now have an error, but succeeded, then we must have tried multiple paths, one of which errored, but
+    // then succeeded on a later path.  So clear the error.
+    if (diag.hasError())
+        diag.clearError();
+
     // if fat, remap just slice needed
     bool fatButMissingSlice;
     const FatFile*       fh = (FatFile*)info.fileContent;
 {
     // must start with mach-o magic value
     if ( (this->magic != MH_MAGIC) && (this->magic != MH_MAGIC_64) ) {
-        diag.error("could not use '%s' because it is not a mach-o file, 0x%08X", path, this->magic);
+        diag.error("could not use '%s' because it is not a mach-o file: 0x%08X 0x%08X", path, this->magic, this->cputype);
         return false;
     }
 
         case MH_BUNDLE:
             break;
         default:
-            diag.error("could not use '%s' because it is not a dylib, bundle, or executable", path);
+            diag.error("could not use '%s' because it is not a dylib, bundle, or executable, filetype=0x%08X", path, this->filetype);
            return false;
     }
 
             return false;
     }
 
+    // <rdar://problem/45525884> to avoid heap smasher, don't load this dylib
+    if ( strcmp(path, "/usr/lib/libnetsnmp.5.2.1.dylib") == 0 )
+        return false;
+
     // further validations done in validLinkedit()
 
     return true;
         return false;
 
     // <rdar://problem/13622786> ignore code signatures in macOS binaries built with pre-10.9 tools
-    __block bool goodSignature = true;
     if ( (this->cputype == CPU_TYPE_X86_64) || (this->cputype == CPU_TYPE_I386) ) {
+        __block bool foundPlatform = false;
+        __block bool badSignature  = false;
         forEachSupportedPlatform(^(Platform platform, uint32_t minOS, uint32_t sdk) {
+            foundPlatform = true;
             if ( (platform == Platform::macOS) && (sdk < 0x000A0900) )
-                goodSignature = false;
+                badSignature = true;
         });
+        return foundPlatform && !badSignature;
     }
 
-    return goodSignature;
+    return true;
 }
 
 bool MachOAnalyzer::hasInitializer(Diagnostics& diag, bool contentRebased, const void* dyldCache) const
 
     else if ( this->magic == MH_MAGIC )
         startCmds = (load_command*)((char *)this + sizeof(mach_header));
     else {
-        diag.error("file does not start with MH_MAGIC[_64]");
+        const uint32_t* h = (uint32_t*)this;
+        diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
         return;  // not a mach-o file
     }
     const load_command* const cmdsEnd = (load_command*)((char*)startCmds + this->sizeofcmds);
     for (uint32_t i = 0; i < this->ncmds; ++i) {
         const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize);
         if ( cmd->cmdsize < 8 ) {
-            diag.error("malformed load command #%d, size too small %d", i, cmd->cmdsize);
+            diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
             return;
         }
         if ( (nextCmd > cmdsEnd) || (nextCmd < startCmds) ) {
-            diag.error("malformed load command #%d, size too large 0x%X", i, cmd->cmdsize);
+            diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
             return;
         }
         callback(cmd, stop);
 
 
 
 
-static bool addIfMachO(const dyld3::closure::FileSystem& fileSystem, const std::string& runtimePath, const struct stat& statBuf, bool requireSIP, std::vector<MappedMachOsByCategory>& files)
+static bool addIfMachO(const dyld3::closure::FileSystem& fileSystem, const std::string& runtimePath, const struct stat& statBuf, bool requireSIP,
+                       dev_t rootFS, std::vector<MappedMachOsByCategory>& files)
 {
     // don't precompute closure info for any debug or profile dylibs
     if ( endsWith(runtimePath, "_profile.dylib") || endsWith(runtimePath, "_debug.dylib") || endsWith(runtimePath, "_profile") || endsWith(runtimePath, "_debug") )
     if ( startsWith(runtimePath, "/usr/lib/system/introspection/") )
         return false;
 
+    // Only use files on the same volume as the boot volume
+    if (statBuf.st_dev != rootFS) {
+        if ( verbose )
+            fprintf(stderr, "update_dyld_shared_cache: warning: skipping overlay file '%s' which is not on the root volume\n", runtimePath.c_str());
+        return false;
+    }
+
     auto warningHandler = ^(const char* msg) {
         if ( verbose )
             fprintf(stderr, "update_dyld_shared_cache: warning: cannot build dlopen closure for '%s' because %s\n", runtimePath.c_str(), msg);
     return result;
 }
 
-static void findAllFiles(const std::vector<std::string>& pathPrefixes, bool requireSIP, std::vector<MappedMachOsByCategory>& files)
+static void findAllFiles(const std::vector<std::string>& pathPrefixes, bool requireSIP, dev_t rootFS, std::vector<MappedMachOsByCategory>& files)
 {
     std::unordered_set<std::string> skipDirs;
     for (const char* s : sDontUsePrefixes)
                     return;
 
                 // if the file is mach-o, add to list
-                if ( addIfMachO(fileSystem, path, statBuf, requireSIP, files) ) {
+                if ( addIfMachO(fileSystem, path, statBuf, requireSIP, rootFS, files) ) {
                     if ( multiplePrefixes )
                         alreadyUsed.insert(path);
                 }
 }
 
 
-static void findOSFilesViaBOMS(const std::vector<std::string>& pathPrefixes, bool requireSIP, std::vector<MappedMachOsByCategory>& files)
+static void findOSFilesViaBOMS(const std::vector<std::string>& pathPrefixes, bool requireSIP, dev_t rootFS, std::vector<MappedMachOsByCategory>& files)
 {
     __block std::unordered_set<std::string> runtimePathsFound;
     for (const std::string& prefix : pathPrefixes) {
                                     std::string fullPath2 = prefix2 + runPath;
                                     if ( stat(fullPath2.c_str(), &statBuf2) == 0 ) {
                                         dyld3::closure::FileSystemPhysical fileSystem(prefix2.c_str());
-                                        addIfMachO(fileSystem, runPath, statBuf2, requireSIP, files);
-                                        runtimePathsFound.insert(runPath);
-                                        break;
+                                        if ( addIfMachO(fileSystem, runPath, statBuf2, requireSIP, rootFS, files) ) {
+                                            runtimePathsFound.insert(runPath);
+                                            break;
+                                        }
                                     }
                                 }
                             }
         }
     }
 
+    // Find the boot volume so that we can ensure all overlays are on the same volume
+    struct stat rootStatBuf;
+    if ( stat(rootPath == "" ? "/" : rootPath.c_str(), &rootStatBuf) != 0 ) {
+        fprintf(stderr, "update_dyld_shared_cache: error: could not stat root file system because '%s'\n", strerror(errno));
+        return 1;
+    }
+
+    dev_t rootFS = rootStatBuf.st_dev;
+
     //
     // pathPrefixes for three modes:
     //   1) no options: { "" }           // search only boot volume
     //   3) -root:      { root }         // search only -root volume
     //
     std::vector<std::string> pathPrefixes;
-    if ( !overlayPath.empty() )
-        pathPrefixes.push_back(overlayPath);
+    if ( !overlayPath.empty() ) {
+        // Only add the overlay path if it exists, and is the same volume as the root
+        struct stat overlayStatBuf;
+        if ( stat(overlayPath.c_str(), &overlayStatBuf) != 0 ) {
+            fprintf(stderr, "update_dyld_shared_cache: warning: ignoring overlay dir '%s' because '%s'\n", overlayPath.c_str(), strerror(errno));
+            overlayPath.clear();
+        } else if (overlayStatBuf.st_dev != rootFS) {
+            fprintf(stderr, "update_dyld_shared_cache: warning: ignoring overlay dir '%s' because it is not the boot volume\n", overlayPath.c_str());
+            overlayPath.clear();
+        } else {
+            pathPrefixes.push_back(overlayPath);
+        }
+    }
     pathPrefixes.push_back(rootPath);
 
-
     if ( cacheDir.empty() ) {
         // if -cache_dir is not specified, then write() will eventually fail if we are not running as root
         if ( geteuid() != 0 ) {
     if ( archStrs.count("i386") )
         allFileSets.push_back({"i386"});
     if ( searchDisk )
-        findAllFiles(pathPrefixes, requireDylibsBeRootlessProtected, allFileSets);
+        findAllFiles(pathPrefixes, requireDylibsBeRootlessProtected, rootFS, allFileSets);
     else {
         std::unordered_set<std::string> runtimePathsFound;
-        findOSFilesViaBOMS(pathPrefixes, requireDylibsBeRootlessProtected, allFileSets);
+        findOSFilesViaBOMS(pathPrefixes, requireDylibsBeRootlessProtected, rootFS, allFileSets);
     }
 
     // nothing in OS uses i386 dylibs, so only dylibs used by third party apps need to be in cache
 
                     std::vector<MappedMachOsByCategory> mappedFiles;
                     mappedFiles.push_back({fileSet.archName});
-                   if ( addIfMachO(fileSystem, runtimePath, statBuf, requireDylibsBeRootlessProtected, mappedFiles) ) {
+                   if ( addIfMachO(fileSystem, runtimePath, statBuf, requireDylibsBeRootlessProtected, rootFS, mappedFiles) ) {
                         if ( !mappedFiles.back().dylibsForCache.empty() ) {
                             if ( verbose )
                                 fprintf(stderr, "verifySelfContained, add %s\n", mappedFiles.back().dylibsForCache.back().runtimePath.c_str());
 
 
 // BUILD:  mkdir -p $BUILD_DIR/override
+// BUILD:  mkdir -p $BUILD_DIR/re-export-override
 // BUILD:  $CC myzlib.c -dynamiclib -o $BUILD_DIR/override/libz.1.dylib -install_name /usr/lib/libz.1.dylib -compatibility_version 1.0 -framework CoreFoundation
+// BUILD:  $CC reexported-myzlib.c -dynamiclib -o $BUILD_DIR/re-export-override/reexported.dylib -compatibility_version 1.0 -framework CoreFoundation
+// BUILD:  $CC reexporter.c -dynamiclib -o $BUILD_DIR/re-export-override/libz.1.dylib -install_name /usr/lib/libz.1.dylib -compatibility_version 1.0 -Wl,-reexport_library,$BUILD_DIR/re-export-override/reexported.dylib
 // BUILD:  $CC main.c  -o $BUILD_DIR/main.exe -lz
 // BUILD:  $DYLD_ENV_VARS_ENABLE $BUILD_DIR/main.exe
 
 // RUN:  ./main.exe
 // RUN:  DYLD_LIBRARY_PATH=$RUN_DIR/override/ ./main.exe
+// RUN:  DYLD_LIBRARY_PATH=$RUN_DIR/re-export-override/ ./main.exe
 
 #include <stdio.h>
 #include <stdlib.h>
 
--- /dev/null
+const char* zlibVersion()
+{
+    return "my";
+}
 
--- /dev/null
+
+int foo() {
+    return 0;
+}