Loading...
cache-builder/AppCacheBuilder.cpp dyld-1066.8 dyld-1284.13
--- dyld/dyld-1066.8/cache-builder/AppCacheBuilder.cpp
+++ dyld/dyld-1284.13/cache-builder/AppCacheBuilder.cpp
@@ -36,6 +36,10 @@
 #include <CommonCrypto/CommonDigest.h>
 #include <CommonCrypto/CommonDigestSPI.h>
 
+#include "Header.h"
+
+using mach_o::Header;
+
 AppCacheBuilder::AppCacheBuilder(const DyldSharedCache::CreateOptions& options,
                                  const Options& appCacheOptions,
                                  const dyld3::closure::FileSystem& fileSystem)
@@ -105,7 +109,7 @@
     bool stop = false;
     for (const AppCacheDylibInfo& dylib : sortedDylibs) {
         for (const SegmentMappingInfo& loc : dylib.cacheLocation) {
-            if (!strcmp(loc.segName, "__TEXT")) {
+            if ( loc.segName == "__TEXT" ) {
                 // Assume __TEXT contains the mach header
                 callback((const dyld3::MachOAnalyzer*)loc.dstSegment, dylib.dylibID, dylib.stripMode,
                          dylib.dependencies, *dylib.errors, stop);
@@ -159,6 +163,10 @@
     // readOnlyTextRegion
     callback(readOnlyTextRegion);
 
+    // -sectcreate
+    for (const Region& region : customDataRegions)
+        callback(region);
+
     // readExecuteRegion
     if ( readExecuteRegion.sizeInUse != 0 )
         callback(readExecuteRegion);
@@ -175,6 +183,14 @@
     if ( dataConstRegion.sizeInUse != 0 )
         callback(dataConstRegion);
 
+    // lateConstRegion
+    if ( lateConstRegion.sizeInUse != 0 )
+        callback(lateConstRegion);
+
+    // dataSptmRegion
+    if ( dataSptmRegion.sizeInUse != 0 )
+        callback(dataSptmRegion);
+
     // branchGOTsRegion
     if ( branchGOTsRegion.bufferSize != 0 )
         callback(branchGOTsRegion);
@@ -186,10 +202,6 @@
     // hibernateRegion
     if ( hibernateRegion.sizeInUse != 0 )
         callback(hibernateRegion);
-
-    // -sectcreate
-    for (const Region& region : customDataRegions)
-        callback(region);
 
     // prelinkInfoRegion
     if ( prelinkInfoDict != nullptr )
@@ -287,6 +299,17 @@
     return totalTargets;
 }
 
+bool AppCacheBuilder::hasSancovGateSection() const
+{
+    for ( const AppCacheDylibInfo& dylib : sortedDylibs ) {
+        const dyld3::MachOAnalyzer* ma = dylib.input->mappedFile.mh;
+        if ( ma->hasSection("__DATA", "__sancov_gate") )
+            return true;
+    }
+
+    return false;
+}
+
 bool AppCacheBuilder::removeStubs()
 {
     // Only eliminate stubs in the base kernel collection.  We could eliminate stubs
@@ -297,6 +320,9 @@
     if ( _options.archs != &dyld3::GradedArchs::arm64e )
         return false;
 
+    if ( hasSancovGateSection() )
+        return false;
+
     return true;
 }
 
@@ -320,13 +346,13 @@
 
         // Find __TEXT_EXEC __auth_stubs, and remove it if we have it
         __block bool lastSectionWasAuthStubs = false;
-        ma->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo& sectInfo, bool malformedSectionRange, bool& stop) {
-            if ( strcmp(sectInfo.segInfo.segName, "__TEXT_EXEC") != 0 )
+        ((const Header*)ma)->forEachSection(^(const Header::SectionInfo& sectInfo, bool& stop) {
+            if ( sectInfo.segmentName != "__TEXT_EXEC" )
                 return;
             lastSectionWasAuthStubs = false;
-            if ( strcmp(sectInfo.sectName, "__auth_stubs") == 0 ) {
+            if ( sectInfo.sectionName == "__auth_stubs" ) {
                 // The auth stubs are only valid if the sections is 16-byte stubs
-                if ( ((sectInfo.sectFlags & SECTION_TYPE) == S_SYMBOL_STUBS) && (sectInfo.reserved2 == 16) )
+                if ( ((sectInfo.flags & SECTION_TYPE) == S_SYMBOL_STUBS) && (sectInfo.reserved2 == 16) )
                     lastSectionWasAuthStubs = true;
             }
         });
@@ -342,25 +368,25 @@
     // so first make space for all the cache location objects so that we get the order the same
     // as the LC_SEGMENTs
     for (DylibInfo& dylib : sortedDylibs) {
-        dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+        ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, bool& stop) {
             dylib.cacheLocation.push_back({});
         });
     }
 
     // If we are building the kernel collection, then inherit the base address of the statically linked kernel
-    const dyld3::MachOAnalyzer* kernelMA = nullptr;
+    const Header* kernelHdr = nullptr;
     if ( appCacheOptions.cacheKind == Options::AppCacheKind::kernel ) {
         for (DylibInfo& dylib : sortedDylibs) {
             if ( dylib.input->mappedFile.mh->isStaticExecutable() ) {
-                kernelMA = dylib.input->mappedFile.mh;
+                kernelHdr = (const Header*)dylib.input->mappedFile.mh;
                 break;
             }
         }
-        if ( kernelMA == nullptr ) {
+        if ( kernelHdr == nullptr ) {
             _diagnostics.error("Could not find kernel image");
             return;
         }
-        cacheBaseAddress = kernelMA->preferredLoadAddress();
+        cacheBaseAddress = kernelHdr->preferredLoadAddress();
     }
 
     // x86_64 doesn't have stubs for kext branches.  So work out how many potential targets
@@ -372,10 +398,10 @@
         minimumSegmentAlignmentP2 = 12;
     }
 
-    auto getMinAlignment = ^(const dyld3::MachOAnalyzer* ma) {
+    auto getMinAlignment = ^(const Header* hdr) {
         // The kernel wants to be able to unmap its own segments so always align it.
         // And align the pageable KC as each kext can be mapped individually
-        if ( ma == kernelMA )
+        if ( hdr == kernelHdr )
             return minimumSegmentAlignmentP2;
         if ( fixupsArePerKext() )
             return minimumSegmentAlignmentP2;
@@ -391,26 +417,27 @@
                 continue;
 
             __block uint64_t textSegVmAddr = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( segInfo.protections != (VM_PROT_READ) )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( segInfo.initProt != (VM_PROT_READ) )
                     return;
-                if ( (strcmp(segInfo.segName, "__DATA_CONST") == 0)
-                    || (strcmp(segInfo.segName, "__PPLDATA_CONST") == 0)
-                    || (strcmp(segInfo.segName, "__LASTDATA_CONST") == 0) )
+                if (   ( segInfo.segmentName == "__DATA_CONST"     )
+                    || ( segInfo.segmentName == "__PPLDATA_CONST"  )
+                    || ( segInfo.segmentName == "__LASTDATA_CONST" )
+                    || ( segInfo.segmentName == "__LATE_CONST"     ) )
                     return;
-                if ( strcmp(segInfo.segName, "__LINKEDIT") == 0 )
+                if ( segInfo.segmentName == "__LINKEDIT" )
                     return;
-                if ( strcmp(segInfo.segName, "__LINKINFO") == 0 )
+                if ( segInfo.segmentName == "__LINKINFO" )
                     return;
 
-                uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
-                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
-                uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+                uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
 
                 // __CTF is not mapped in to the kernel, so remove it from the final binary.
-                if ( strcmp(segInfo.segName, "__CTF") == 0 ) {
+                if ( segInfo.segmentName == "__CTF" ) {
                     copySize = 0;
                     dstCacheSegmentSize = 0;
                 }
@@ -418,20 +445,20 @@
                 // kxld packs __TEXT so we will do
                 // Note we align to at least 16-bytes as LDR's can scale up to 16 from their address
                 // and aligning them less than 16 would break that
-                offsetInRegion = align(offsetInRegion, std::max(segInfo.p2align, 4U));
+                offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 4U));
                 offsetInRegion = align(offsetInRegion, minAlignmentP2);
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
                 loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
                 loc.dstCacheFileSize       = (uint32_t)copySize;
                 loc.copySegmentSize        = (uint32_t)copySize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &readOnlyTextRegion;
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += dstCacheSegmentSize;
             });
         }
@@ -454,51 +481,51 @@
                 continue;
 
             __block uint64_t textSegVmAddr = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( strcmp(segInfo.segName, "__HIB") == 0 )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t segSizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( segInfo.segmentName == "__HIB" )
                     return;
-                if ( (strcmp(segInfo.segName, "__TEXT_BOOT_EXEC") == 0) && dylib.input->mappedFile.mh->isStaticExecutable() )
+                if ( (segInfo.segmentName == "__TEXT_BOOT_EXEC" ) && dylib.input->mappedFile.mh->isStaticExecutable() )
                     return;
-                if ( segInfo.protections != (VM_PROT_READ | VM_PROT_EXECUTE) )
+                if ( segInfo.initProt != (VM_PROT_READ | VM_PROT_EXECUTE) )
                    return;
 
                 // We may have coalesced the sections at the end of this segment.  In that case, shrink the segment to remove them.
                 __block size_t sizeOfSections = 0;
                 __block bool foundRemovedSection = false;
-                dylib.input->mappedFile.mh->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo &sectInfo, bool malformedSectionRange, bool &stopSection) {
-                    if (strcmp(sectInfo.segInfo.segName, segInfo.segName) != 0)
+                ((const Header*)dylib.input->mappedFile.mh)->forEachSection(^(const Header::SectionInfo &sectInfo, bool &stopSection) {
+                    if ( sectInfo.segmentName != segInfo.segmentName )
                         return;
-                    if ( dylib._coalescer.sectionWasObliterated(segInfo.segName, sectInfo.sectName)) {
+                    if ( dylib._coalescer.sectionWasObliterated(segInfo.segmentName, sectInfo.sectionName) ) {
                         foundRemovedSection = true;
                     } else {
-                        sizeOfSections = sectInfo.sectAddr + sectInfo.sectSize - segInfo.vmAddr;
+                        sizeOfSections = sectInfo.address + sectInfo.size - segInfo.vmaddr;
                     }
                 });
                 if ( !foundRemovedSection )
-                    sizeOfSections = segInfo.sizeOfSections;
+                    sizeOfSections = segSizeOfSections;
 
                 // kxld packs __TEXT_EXEC so we will do
                 // Note we align to at least 16-bytes as LDR's can scale up to 16 from their address
                 // and aligning them less than 16 would break that
-                uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
-                offsetInRegion = align(offsetInRegion, std::max(segInfo.p2align, 4U));
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 4U));
                 offsetInRegion = align(offsetInRegion, minAlignmentP2);
                 size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
                 uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
                 loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
                 loc.dstCacheFileSize       = (uint32_t)copySize;
                 loc.copySegmentSize        = (uint32_t)copySize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &readExecuteRegion;
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += loc.dstCacheSegmentSize;
             });
         }
@@ -533,49 +560,49 @@
                 continue;
 
             __block uint64_t textSegVmAddr = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( strcmp(segInfo.segName, "__TEXT_BOOT_EXEC") != 0 )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t segSizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( segInfo.segmentName != "__TEXT_BOOT_EXEC" )
                     return;
-                if ( segInfo.protections != (VM_PROT_READ | VM_PROT_EXECUTE) )
+                if ( segInfo.initProt != (VM_PROT_READ | VM_PROT_EXECUTE) )
                     return;
 
                 // We may have coalesced the sections at the end of this segment.  In that case, shrink the segment to remove them.
                 __block size_t sizeOfSections = 0;
                 __block bool foundRemovedSection = false;
-                dylib.input->mappedFile.mh->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo &sectInfo, bool malformedSectionRange, bool &stopSection) {
-                    if (strcmp(sectInfo.segInfo.segName, segInfo.segName) != 0)
+                ((const Header*)dylib.input->mappedFile.mh)->forEachSection(^(const Header::SectionInfo &sectInfo, bool &stopSection) {
+                    if ( sectInfo.segmentName != segInfo.segmentName )
                         return;
-                    if ( dylib._coalescer.sectionWasObliterated(segInfo.segName, sectInfo.sectName)) {
+                    if ( dylib._coalescer.sectionWasObliterated(segInfo.segmentName, sectInfo.sectionName)) {
                         foundRemovedSection = true;
                     } else {
-                        sizeOfSections = sectInfo.sectAddr + sectInfo.sectSize - segInfo.vmAddr;
+                        sizeOfSections = sectInfo.address + sectInfo.size - segInfo.vmaddr;
                     }
                 });
                 if ( !foundRemovedSection )
-                    sizeOfSections = segInfo.sizeOfSections;
+                    sizeOfSections = segSizeOfSections;
 
                 // kxld packs __TEXT_EXEC so we will do
                 // Note we align to at least 16-bytes as LDR's can scale up to 16 from their address
                 // and aligning them less than 16 would break that
-                uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
-                offsetInRegion = align(offsetInRegion, std::max(segInfo.p2align, 4U));
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 4U));
                 offsetInRegion = align(offsetInRegion, minAlignmentP2);
                 size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
                 uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
                 loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
                 loc.dstCacheFileSize       = (uint32_t)copySize;
                 loc.copySegmentSize        = (uint32_t)copySize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &textBootExecRegion;
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += loc.dstCacheSegmentSize;
             });
         }
@@ -596,33 +623,35 @@
                 continue;
 
             __block uint64_t textSegVmAddr = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( (segInfo.protections & VM_PROT_EXECUTE) != 0 )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( (segInfo.initProt & VM_PROT_EXECUTE) != 0 )
                     return;
-                if ( (strcmp(segInfo.segName, "__DATA_CONST") != 0)
-                    && (strcmp(segInfo.segName, "__PPLDATA_CONST") != 0)
-                    && (strcmp(segInfo.segName, "__LASTDATA_CONST") != 0)  )
+                if (   ( segInfo.segmentName != "__DATA_CONST"    )
+                    && ( segInfo.segmentName != "__PPLDATA_CONST" )
+                    && ( segInfo.segmentName != "__LASTDATA_CONST") )
+                    return;
+                if ( segInfo.segmentName == "__LATE_CONST" )
                     return;
                 // kxld packs __DATA_CONST so we will do
-                uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
-                offsetInRegion = align(offsetInRegion, segInfo.p2align);
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                offsetInRegion = align(offsetInRegion, maxAlignOfSections);
                 offsetInRegion = align(offsetInRegion, minAlignmentP2);
-                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
-                uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
+                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+                uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
                 loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
                 loc.dstCacheFileSize       = (uint32_t)copySize;
                 loc.copySegmentSize        = (uint32_t)copySize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &dataConstRegion;
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += loc.dstCacheSegmentSize;
             });
         }
@@ -634,6 +663,96 @@
         dataConstRegion.maxProt     = VM_PROT_READ;
         dataConstRegion.name        = "__DATA_CONST";
     }
+
+    // __LATE_CONST segments
+    {
+        __block uint64_t offsetInRegion = 0;
+        for (DylibInfo& dylib : sortedDylibs) {
+            if (!dylib.input->mappedFile.mh->hasSplitSeg())
+                continue;
+
+            __block uint64_t textSegVmAddr = 0;
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( (segInfo.initProt & VM_PROT_EXECUTE) != 0 )
+                    return;
+                if ( segInfo.segmentName != "__LATE_CONST" )
+                    return;
+                // pack __LATE_CONST
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                offsetInRegion = align(offsetInRegion, maxAlignOfSections);
+                offsetInRegion = align(offsetInRegion, minAlignmentP2);
+                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+                uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
+                SegmentMappingInfo loc;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
+                loc.dstSegment             = nullptr;
+                loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
+                loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
+                loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
+                loc.dstCacheFileSize       = (uint32_t)copySize;
+                loc.copySegmentSize        = (uint32_t)copySize;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
+                loc.parentRegion           = &lateConstRegion;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
+                offsetInRegion += loc.dstCacheSegmentSize;
+            });
+        }
+
+        // align r/o region end
+        lateConstRegion.bufferSize  = align(offsetInRegion, 14);
+        lateConstRegion.sizeInUse   = lateConstRegion.bufferSize;
+        lateConstRegion.initProt    = VM_PROT_READ;
+        lateConstRegion.maxProt     = VM_PROT_READ;
+        lateConstRegion.name        = "__LATE_CONST";
+    }
+
+    // __DATA_SPTM segments
+    {
+        __block uint64_t offsetInRegion = 0;
+        for (DylibInfo& dylib : sortedDylibs) {
+            if (!dylib.input->mappedFile.mh->hasSplitSeg())
+                continue;
+
+            __block uint64_t textSegVmAddr = 0;
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( (segInfo.initProt & VM_PROT_EXECUTE) != 0 )
+                    return;
+                if ( segInfo.segmentName != "__DATA_SPTM" )
+                    return;
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                offsetInRegion = align(offsetInRegion, maxAlignOfSections);
+                offsetInRegion = align(offsetInRegion, minAlignmentP2);
+                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+                uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
+                SegmentMappingInfo loc;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
+                loc.dstSegment             = nullptr;
+                loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
+                loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
+                loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
+                loc.dstCacheFileSize       = (uint32_t)copySize;
+                loc.copySegmentSize        = (uint32_t)copySize;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
+                loc.parentRegion           = &dataSptmRegion;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
+                offsetInRegion += loc.dstCacheSegmentSize;
+            });
+        }
+
+        // align r/o region end
+        dataSptmRegion.bufferSize  = align(offsetInRegion, 14);
+        dataSptmRegion.sizeInUse   = dataSptmRegion.bufferSize;
+        dataSptmRegion.initProt    = VM_PROT_READ;
+        dataSptmRegion.maxProt     = VM_PROT_READ;
+        dataSptmRegion.name        = "__DATA_SPTM";
+    }
+
 
     // Branch GOTs
     if ( branchTargetsFromKexts != 0 ) {
@@ -653,35 +772,36 @@
                 continue;
 
             __block uint64_t textSegVmAddr = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( strcmp(segInfo.segName, "__HIB") == 0 )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( segInfo.segmentName == "__HIB" )
                     return;
-                if ( (strcmp(segInfo.segName, "__DATA_CONST") == 0)
-                    || (strcmp(segInfo.segName, "__PPLDATA_CONST") == 0)
-                    || (strcmp(segInfo.segName, "__LASTDATA_CONST") == 0) )
+                if (   ( segInfo.segmentName == "__DATA_CONST"     )
+                    || ( segInfo.segmentName == "__PPLDATA_CONST"  )
+                    || ( segInfo.segmentName == "__LASTDATA_CONST" )
+                    || ( segInfo.segmentName == "__LATE_CONST"     ) )
                     return;
-                if ( segInfo.protections != (VM_PROT_READ | VM_PROT_WRITE) )
+                if ( segInfo.initProt != (VM_PROT_READ | VM_PROT_WRITE) )
                     return;
                 // kxld packs __DATA so we will do
-                uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
-                offsetInRegion = align(offsetInRegion, segInfo.p2align);
+                uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
+                offsetInRegion = align(offsetInRegion, maxAlignOfSections);
                 offsetInRegion = align(offsetInRegion, minAlignmentP2);
-                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
-                uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
+                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+                uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
                 loc.dstCacheSegmentSize    = (uint32_t)dstCacheSegmentSize;
                 loc.dstCacheFileSize       = (uint32_t)copySize;
                 loc.copySegmentSize        = (uint32_t)copySize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &readWriteRegion;
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += loc.dstCacheSegmentSize;
             });
         }
@@ -703,27 +823,27 @@
 
             __block uint64_t textSegVmAddr = 0;
             __block uint64_t hibernateAddress = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( strcmp(segInfo.segName, "__HIB") != 0 )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( segInfo.segmentName != "__HIB" )
                     return;
-                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
+                size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
-                loc.dstCacheSegmentSize    = (uint32_t)segInfo.vmSize;
+                loc.dstCacheSegmentSize    = (uint32_t)segInfo.vmsize;
                 loc.dstCacheFileSize       = (uint32_t)copySize;
                 loc.copySegmentSize        = (uint32_t)copySize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &hibernateRegion;
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += loc.dstCacheSegmentSize;
 
-                hibernateAddress = segInfo.vmAddr;
+                hibernateAddress = segInfo.vmaddr;
             });
 
             if ( offsetInRegion != 0 ) {
@@ -760,31 +880,31 @@
                 continue;
 
             __block uint64_t textSegVmAddr = 0;
-            dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                    textSegVmAddr = segInfo.vmAddr;
-                if ( strcmp(segInfo.segName, "__LINKEDIT") == 0 )
+            ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, bool& stop) {
+                if ( segInfo.segmentName == "__TEXT" )
+                    textSegVmAddr = segInfo.vmaddr;
+                if ( segInfo.segmentName == "__LINKEDIT" )
                     return;
 
                 nonSplitSegRegions.emplace_back();
-                nonSplitSegRegions.back().initProt    = segInfo.protections;
-                nonSplitSegRegions.back().maxProt     = segInfo.protections;
+                nonSplitSegRegions.back().initProt    = segInfo.initProt;
+                nonSplitSegRegions.back().maxProt     = segInfo.maxProt;
                 nonSplitSegRegions.back().name        = "__REGION" + std::to_string(nonSplitSegRegions.size() - 1);
 
                 // Note we don't align the region offset as we have no split seg
                 uint64_t offsetInRegion = 0;
                 SegmentMappingInfo loc;
-                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-                loc.segName                = segInfo.segName;
+                loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+                loc.segName                = segInfo.segmentName;
                 loc.dstSegment             = nullptr;
                 loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
                 loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
-                loc.dstCacheSegmentSize    = (uint32_t)segInfo.vmSize;
+                loc.dstCacheSegmentSize    = (uint32_t)segInfo.vmsize;
                 loc.dstCacheFileSize       = (uint32_t)segInfo.fileSize;
                 loc.copySegmentSize        = (uint32_t)segInfo.fileSize;
-                loc.srcSegmentIndex        = segInfo.segIndex;
+                loc.srcSegmentIndex        = segInfo.segmentIndex;
                 loc.parentRegion           = &nonSplitSegRegions.back();
-                dylib.cacheLocation[segInfo.segIndex] = loc;
+                dylib.cacheLocation[segInfo.segmentIndex] = loc;
                 offsetInRegion += loc.dstCacheSegmentSize;
 
                 // record non-split seg region end
@@ -876,9 +996,9 @@
             // Use the size of the TEXT sections in the cache.  This is required as we pack segments
             __block uint64_t textSegSize = 0;
             if ( info.ma != nullptr ) {
-                info.ma->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                    if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                        textSegSize = segInfo.sizeOfSections == 0 ? segInfo.fileSize : segInfo.sizeOfSections;
+                ((const Header*)info.ma)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+                    if ( segInfo.segmentName == "__TEXT" )
+                        textSegSize = sizeOfSections == 0 ? segInfo.fileSize : sizeOfSections;
                 });
             }
             if (textSegSize != 0) {
@@ -952,7 +1072,7 @@
         // The pageable/aux KCs should embed the UUID of the base kernel collection
         if ( existingKernelCollection != nullptr ) {
             uuid_t uuid = {};
-            bool foundUUID = existingKernelCollection->getUuid(uuid);
+            bool foundUUID = ((mach_o::Header*)existingKernelCollection)->getUuid(uuid);
             if ( !foundUUID ) {
                 _diagnostics.error("Could not find UUID in base kernel collection");
                 return;
@@ -965,7 +1085,7 @@
         // The aux KC should embed the UUID of the pageable kernel collection if we have one
         if ( pageableKernelCollection != nullptr ) {
             uuid_t uuid = {};
-            bool foundUUID = pageableKernelCollection->getUuid(uuid);
+            bool foundUUID = ((mach_o::Header*)pageableKernelCollection)->getUuid(uuid);
             if ( !foundUUID ) {
                 _diagnostics.error("Could not find UUID in pageable kernel collection");
                 return;
@@ -1003,28 +1123,28 @@
     __block uint64_t offsetInRegion = 0;
     for (DylibInfo& dylib : sortedDylibs) {
         __block uint64_t textSegVmAddr = 0;
-        dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-            if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                textSegVmAddr = segInfo.vmAddr;
-            if ( segInfo.protections != VM_PROT_READ )
+        ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+            if ( segInfo.segmentName == "__TEXT" )
+                textSegVmAddr = segInfo.vmaddr;
+            if ( segInfo.initProt != VM_PROT_READ )
                 return;
-            if ( strcmp(segInfo.segName, "__LINKINFO") != 0 )
+            if ( segInfo.segmentName != "__LINKINFO" )
                 return;
             // Keep segments 4K or more aligned
-            offsetInRegion = align(offsetInRegion, std::max((int)segInfo.p2align, (int)12));
-            size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
+            offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 12U));
+            size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
             SegmentMappingInfo loc;
-            loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-            loc.segName                = segInfo.segName;
+            loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+            loc.segName                = segInfo.segmentName;
             loc.dstSegment             = nullptr;
             loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
             loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
-            loc.dstCacheSegmentSize    = (uint32_t)align(segInfo.sizeOfSections, 12);
+            loc.dstCacheSegmentSize    = (uint32_t)align(sizeOfSections, 12);
             loc.dstCacheFileSize       = (uint32_t)copySize;
             loc.copySegmentSize        = (uint32_t)copySize;
-            loc.srcSegmentIndex        = segInfo.segIndex;
+            loc.srcSegmentIndex        = segInfo.segmentIndex;
             loc.parentRegion           = &_readOnlyRegion;
-            dylib.cacheLocation[segInfo.segIndex] = loc;
+            dylib.cacheLocation[segInfo.segmentIndex] = loc;
             offsetInRegion += loc.dstCacheSegmentSize;
         });
     }
@@ -1036,15 +1156,15 @@
     // Do all __LINKEDIT, regardless of split seg
     for (DylibInfo& dylib : sortedDylibs) {
         __block uint64_t textSegVmAddr = 0;
-        dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-            if ( strcmp(segInfo.segName, "__TEXT") == 0 )
-                textSegVmAddr = segInfo.vmAddr;
-            if ( segInfo.protections != VM_PROT_READ )
+        ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+            if ( segInfo.segmentName == "__TEXT" )
+                textSegVmAddr = segInfo.vmaddr;
+            if ( segInfo.initProt != VM_PROT_READ )
                 return;
-            if ( strcmp(segInfo.segName, "__LINKEDIT") != 0 )
+            if ( segInfo.segmentName != "__LINKEDIT" )
                 return;
             // Keep segments 4K or more aligned
-            offsetInRegion = align(offsetInRegion, std::max((int)segInfo.p2align, (int)12));
+            offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 12U));
             size_t copySize = segInfo.fileSize;
 
             // HACK: When we adjust LINKEDIT, we may grow function starts.  This is because the kernel and kexts
@@ -1055,17 +1175,17 @@
             const uint32_t extraLinkeditSpace = 16;
 
             SegmentMappingInfo loc;
-            loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
-            loc.segName                = segInfo.segName;
+            loc.srcSegment             = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
+            loc.segName                = segInfo.segmentName;
             loc.dstSegment             = nullptr;
             loc.dstCacheUnslidAddress  = offsetInRegion; // This will be updated later once we've assigned addresses
             loc.dstCacheFileOffset     = (uint32_t)offsetInRegion;
             loc.dstCacheSegmentSize    = (uint32_t)align(copySize + extraLinkeditSpace, 12);
             loc.dstCacheFileSize       = (uint32_t)copySize + extraLinkeditSpace;
             loc.copySegmentSize        = (uint32_t)copySize;
-            loc.srcSegmentIndex        = segInfo.segIndex;
+            loc.srcSegmentIndex        = segInfo.segmentIndex;
             loc.parentRegion           = &_readOnlyRegion;
-            dylib.cacheLocation[segInfo.segIndex] = loc;
+            dylib.cacheLocation[segInfo.segmentIndex] = loc;
             offsetInRegion += loc.dstCacheSegmentSize;
         });
     }
@@ -1083,13 +1203,11 @@
         // The pageableKC (and sometimes auxKC) has 1 LC_DYLD_CHAINED_FIXUPS per kext
         // while other KCs have 1 for the whole KC.
         // It also tracks each segment in each kext for chained fixups, not the segments on the KC itself
-        __block uint64_t numSegmentsForChainedFixups = 0;
+        uint64_t numSegmentsForChainedFixups = 0;
         uint64_t numChainedFixupHeaders = 0;
         if ( fixupsArePerKext() ) {
             for (DylibInfo& dylib : sortedDylibs) {
-                dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
-                    ++numSegmentsForChainedFixups;
-                });
+                numSegmentsForChainedFixups += ((const Header*)dylib.input->mappedFile.mh)->segmentCount();
             }
             numChainedFixupHeaders = sortedDylibs.size();
 
@@ -1105,6 +1223,10 @@
         uint64_t numBytesForPageStarts = 0;
         if ( dataConstRegion.sizeInUse != 0 )
             numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(dataConstRegion.bufferSize));
+        if ( lateConstRegion.sizeInUse != 0 )
+            numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(lateConstRegion.bufferSize));
+        if ( dataSptmRegion.sizeInUse != 0 )
+            numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(dataSptmRegion.bufferSize));
         if ( branchGOTsRegion.bufferSize != 0 )
             numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(branchGOTsRegion.bufferSize));
         if ( readWriteRegion.sizeInUse != 0 )
@@ -1478,7 +1600,7 @@
     DylibSymbols& kernelDylibSymbols = dylibsToSymbols[kernelID];
     SymbolLocation symbolLocation = findVTablePatchingSymbol("__ZTV11OSMetaClass", kernelDylibSymbols);
     if ( symbolLocation.found() ) {
-        baseMetaClassVTableLoc = (uint8_t*)kernelMA + (symbolLocation.vmAddr - kernelMA->preferredLoadAddress());
+        baseMetaClassVTableLoc = (uint8_t*)kernelMA + (symbolLocation.vmAddr - ((const Header*)kernelMA)->preferredLoadAddress());
 
         VTable& vtable = vtables[baseMetaClassVTableLoc];
         vtable.ma                   = kernelMA;
@@ -1520,10 +1642,10 @@
 
         // And add classic if we have them
         existingKernelCollection->forEachRebase(diags, ^(const char *opcodeName, const dyld3::MachOAnalyzer::LinkEditInfo &leInfo,
-                                                                const dyld3::MachOAnalyzer::SegmentInfo *segments,
+                                                                const Header::SegmentInfo *segments,
                                                                 bool segIndexSet, uint32_t ptrSize, uint8_t segmentIndex,
                                                                 uint64_t segmentOffset, dyld3::MachOAnalyzer::Rebase kind, bool &stop) {
-            uint64_t rebaseVmAddr  = segments[segmentIndex].vmAddr + segmentOffset;
+            uint64_t rebaseVmAddr  = segments[segmentIndex].vmaddr + segmentOffset;
             uint64_t runtimeOffset = rebaseVmAddr - kernelBaseAddress;
             const uint8_t* fixupLoc = kernelBasePointer + runtimeOffset;
             uint64_t targetVMAddr = 0;
@@ -1589,7 +1711,7 @@
 
     bool kernelUsesClassicRelocs = existingKernelCollection->usesClassicRelocationsInKernelCollection();
     existingKernelCollection->forEachDylib(diags, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
-        uint64_t loadAddress = ma->preferredLoadAddress();
+        uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
 
         auto visitBaseKernelCollectionSymbols = ^(const char *symbolName, uint64_t n_value) {
             if ( strstr(symbolName, superMetaclassPointerToken) == nullptr )
@@ -1810,7 +1932,7 @@
     }
 
     pageableKernelCollection->forEachDylib(diags, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
-        uint64_t loadAddress = ma->preferredLoadAddress();
+        uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
         auto visitPageableKernelCollectionSymbols = ^(const char *symbolName, uint64_t n_value) {
             if ( strstr(symbolName, superMetaclassPointerToken) == nullptr )
                 return;
@@ -2043,7 +2165,7 @@
         Diagnostics&                dylibDiags          = *dylib.diags;
         const std::vector<std::string>& dependencies    = dylib.dependencies;
 
-        uint64_t loadAddress = ma->preferredLoadAddress();
+        uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
         bool alreadyPatched = (ma == kernelMA);
         auto visitSymbols = ^(const char *symbolName, uint64_t n_value) {
             if ( strstr(symbolName, superMetaclassPointerToken) == nullptr )
@@ -2739,8 +2861,6 @@
                 return;
             }
         }
-
-        // uint64_t baseAddress = ma->preferredLoadAddress();
 
         ma->withChainStarts(dylibDiag, 0, ^(const dyld_chained_starts_in_image* starts) {
             ma->forEachFixupInAllChains(dylibDiag, starts, false, ^(dyld3::MachOLoaded::ChainedFixupPointerOnDisk* fixupLoc, const dyld_chained_starts_in_segment* segInfo, bool& stop) {
@@ -2852,7 +2972,7 @@
     __block bool foundUseOfMagicSymbol = false;
     __block bool foundMissingWeakImport = false;
 
-    const uint64_t loadAddress = ma->preferredLoadAddress();
+    const uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
     ma->forEachBind(dylibDiag, ^(uint64_t runtimeOffset, int libOrdinal, uint8_t bindType,
                                  const char *symbolName, bool weakImport, bool lazyBind, uint64_t addend, bool &stop) {
         // printf("Bind at 0x%llx to '%s'\n", runtimeOffset, symbolName);
@@ -3131,7 +3251,7 @@
                                    std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations)
 {
     // We only patch vtables on macOS.  Luckily the platform is in the kernel binary
-    if ( !kernelMA->builtForPlatform(dyld3::Platform::macOS) )
+    if ( !((mach_o::Header*)kernelMA)->builtForPlatform(mach_o::Platform::macOS) )
         return;
 
     auto vtablePatcherOwner = std::make_unique<VTablePatcher>(numFixupLevels);
@@ -3145,13 +3265,13 @@
         // The kernel base address is still __TEXT, even if __DATA or __HIB is mapped prior to that.
         // The loader may have loaded something before __TEXT, but the existingKernelCollection pointer still corresponds to __TEXT
         __block uint64_t baseAddress = ~0ULL;
-        existingKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
-            baseAddress = std::min(baseAddress, info.vmAddr);
+        ((const Header*)existingKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
+            baseAddress = std::min(baseAddress, info.vmaddr);
         });
 
         // The existing collection is a pointer to the mach_header for the baseKC, but __HIB and other segments may be before that
         // Offset those here
-        uint64_t basePointerOffset = existingKernelCollection->preferredLoadAddress() - baseAddress;
+        uint64_t basePointerOffset = ((const Header*)existingKernelCollection)->preferredLoadAddress() - baseAddress;
         const uint8_t* basePointer = (uint8_t*)existingKernelCollection - basePointerOffset;
 
         vtablePatcher.addKernelCollection(existingKernelCollection, Options::AppCacheKind::kernel,
@@ -3163,13 +3283,13 @@
         // The kernel base address is still __TEXT, even if __DATA or __HIB is mapped prior to that.
         // The loader may have loaded something before __TEXT, but the existingKernelCollection pointer still corresponds to __TEXT
         __block uint64_t baseAddress = ~0ULL;
-        pageableKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
-            baseAddress = std::min(baseAddress, info.vmAddr);
+        ((const Header*)pageableKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
+            baseAddress = std::min(baseAddress, info.vmaddr);
         });
 
         // The existing collection is a pointer to the mach_header for the baseKC, but __HIB and other segments may be before that
         // Offset those here
-        uint64_t basePointerOffset = pageableKernelCollection->preferredLoadAddress() - baseAddress;
+        uint64_t basePointerOffset = ((const Header*)pageableKernelCollection)->preferredLoadAddress() - baseAddress;
         const uint8_t* basePointer = (uint8_t*)pageableKernelCollection - basePointerOffset;
 
         vtablePatcher.addKernelCollection(pageableKernelCollection, Options::AppCacheKind::pageableKC,
@@ -3709,7 +3829,7 @@
             }
 
             // Emit branch stubs
-            const uint64_t loadAddress = dylibFixup.ma->preferredLoadAddress();
+            const uint64_t loadAddress = ((const Header*)dylibFixup.ma)->preferredLoadAddress();
             for (const DylibFixups::BranchStubData& branchData : dylibFixup.branchStubs) {
                 // Branching from the auxKC to baseKC.  ld64 doesn't emit a stub in x86_64 kexts
                 // so we need to synthesize one now
@@ -3780,20 +3900,20 @@
         forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID, DylibStripMode stripMode,
                             const std::vector<std::string> &dependencies, Diagnostics& dylibDiag, bool &stopDylib) {
             intptr_t slide = ma->getSlide();
-            ma->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo &sectInfo,
-                                 bool malformedSectionRange, bool &stopSection) {
-                const uint8_t* content  = (uint8_t*)(sectInfo.sectAddr + slide);
+            ((const Header*)ma)->forEachSection(^(const Header::SectionInfo &sectInfo,
+                                 bool &stopSection) {
+                const uint8_t* content  = (uint8_t*)(sectInfo.address + slide);
                 const uint8_t* start    = (uint8_t*)content;
-                const uint8_t* end      = start + sectInfo.sectSize;
+                const uint8_t* end      = start + sectInfo.size;
                 if ( (missingBindLoc >= start) && (missingBindLoc < end) ) {
-                    std::string segmentName = sectInfo.segInfo.segName;
-                    std::string sectionName = sectInfo.sectName;
                     uint64_t sectionOffset = (missingBindLoc - start);
-
-                    dylibDiag.error("Failed to bind '%s' in '%s' (at offset 0x%llx in %s, %s) as "
+                    
+                    dylibDiag.error("Failed to bind '%s' in '%s' (at offset 0x%llx in %.*s, %.*s) as "
                                     "could not find a kext which exports this symbol",
                                     missingBind.symbolName.c_str(), missingBind.binaryID.data(),
-                                    sectionOffset, segmentName.c_str(), sectionName.c_str());
+                                    sectionOffset,
+                                    (int)sectInfo.segmentName.size(), sectInfo.segmentName.data(),
+                                    (int)sectInfo.sectionName.size(), sectInfo.sectionName.data());
 
                     reportedError = true;
                     stopSection = true;
@@ -3869,23 +3989,23 @@
     if ( header.dynSymbolTable != nullptr ) {
         classicRelocsBufferStart = byteBuffer.begin();
 
-        dyld3::MachOAnalyzer* cacheMA = (dyld3::MachOAnalyzer*)header.header;
+        const Header* cacheMH = (const Header*)header.header;
         __block uint64_t localRelocBaseAddress = 0;
-        cacheMA->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
-            if ( info.protections & VM_PROT_WRITE ) {
-                localRelocBaseAddress = info.vmAddr;
+        cacheMH->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+            if ( info.initProt & VM_PROT_WRITE ) {
+                localRelocBaseAddress = info.vmaddr;
                 stop = true;
             }
         });
 
         const std::vector<void*> allRebaseTargets = _aslrTracker.getRebaseTargets();
 
-        const dyld3::MachOAnalyzer* kernelMA = getKernelStaticExecutableFromCache();
-        kernelMA->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
+        const Header* kernelMH = (const Header*)getKernelStaticExecutableFromCache();
+        kernelMH->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
             std::vector<void*> segmentRebaseTargets;
-            uint64_t segmentVMOffset = info.vmAddr - cacheBaseAddress;
+            uint64_t segmentVMOffset = info.vmaddr - cacheBaseAddress;
             const uint8_t* segmentStartAddr = (const uint8_t*)(_fullAllocatedBuffer + segmentVMOffset);
-            const uint8_t* segmentEndAddr = (const uint8_t*)(segmentStartAddr + info.vmSize);
+            const uint8_t* segmentEndAddr = (const uint8_t*)(segmentStartAddr + info.vmsize);
             for (void* target : allRebaseTargets) {
                 if ( (target >= segmentStartAddr) && (target < segmentEndAddr) ) {
                     segmentRebaseTargets.push_back(target);
@@ -3897,7 +4017,7 @@
                 uint64_t targetSegmentOffset = (uint64_t)target - (uint64_t)segmentStartAddr;
                 //printf("Target: %s + 0x%llx: %p\n", info.segName, targetSegmentOffset, target);
 
-                uint64_t offsetFromBaseAddress = (info.vmAddr + targetSegmentOffset) - localRelocBaseAddress;
+                uint64_t offsetFromBaseAddress = (info.vmaddr + targetSegmentOffset) - localRelocBaseAddress;
                 relocation_info* reloc = (relocation_info*)byteBuffer.makeSpace(sizeof(relocation_info));
                 reloc->r_address = (uint32_t)offsetFromBaseAddress;
                 reloc->r_symbolnum = 0;
@@ -3940,8 +4060,8 @@
         assert(existingKernelCollection != nullptr);
         // The auxKC is mapped with __DATA first, so we need to get either the __DATA or __TEXT depending on what is earliest
         __block uint64_t baseAddress = ~0ULL;
-        existingKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
-            baseAddress = std::min(baseAddress, info.vmAddr);
+        ((const Header*)existingKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
+            baseAddress = std::min(baseAddress, info.vmaddr);
         });
         levelBaseAddresses[0] = baseAddress;
     }
@@ -3949,8 +4069,8 @@
     if ( pageableKernelCollection != nullptr ) {
         // We may have __DATA first, so we need to get either the __DATA or __TEXT depending on what is earliest
         __block uint64_t baseAddress = ~0ULL;
-        pageableKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
-            baseAddress = std::min(baseAddress, info.vmAddr);
+        ((const Header *)pageableKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
+            baseAddress = std::min(baseAddress, info.vmaddr);
         });
         uint8_t fixupLevel = getFixupLevel(Options::AppCacheKind::pageableKC);
         levelBaseAddresses[fixupLevel] = baseAddress;
@@ -4097,30 +4217,30 @@
         forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID,
                             DylibStripMode stripMode, const std::vector<std::string> &dependencies,
                             Diagnostics& dylibDiag, bool &stop) {
-            uint64_t loadAddress = ma->preferredLoadAddress();
+            uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
 
             __block uint64_t                    numSegments = 0;
             __block std::vector<SegmentFixups>  segmentFixups;
-            ma->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stopSegments) {
+            ((const Header*)ma)->forEachSegment(^(const Header::SegmentInfo &info, bool &stopSegments) {
                 // Third party kexts have writable __TEXT, so we need to add starts for all segments
                 // other than LINKEDIT
                 bool segmentCanHaveFixups = false;
                 if ( appCacheOptions.cacheKind == Options::AppCacheKind::pageableKC ) {
-                    segmentCanHaveFixups = (info.protections & VM_PROT_WRITE) != 0;
+                    segmentCanHaveFixups = (info.initProt & VM_PROT_WRITE) != 0;
                 } else {
                     // auxKC
-                    segmentCanHaveFixups = (strcmp(info.segName, "__LINKEDIT") != 0);
+                    segmentCanHaveFixups = info.segmentName != "__LINKEDIT";
                 }
 
                 if ( segmentCanHaveFixups) {
                     SegmentFixups segmentToFixup;
-                    segmentToFixup.segmentBuffer        = (uint8_t*)ma + (info.vmAddr - loadAddress);
-                    segmentToFixup.segmentIndex         = info.segIndex;
-                    segmentToFixup.unslidLoadAddress    = info.vmAddr;
-                    segmentToFixup.sizeInUse            = info.vmSize;
+                    segmentToFixup.segmentBuffer        = (uint8_t*)ma + (info.vmaddr - loadAddress);
+                    segmentToFixup.segmentIndex         = info.segmentIndex;
+                    segmentToFixup.unslidLoadAddress    = info.vmaddr;
+                    segmentToFixup.sizeInUse            = info.vmsize;
                     segmentToFixup.starts               = nullptr;
                     segmentToFixup.startsByteSize       = 0;
-                    segmentToFixup.numPagesToFixup      = numWritablePagesToFixup(info.vmSize);
+                    segmentToFixup.numPagesToFixup      = numWritablePagesToFixup(info.vmsize);
                     segmentFixups.push_back(segmentToFixup);
                 }
 
@@ -4143,7 +4263,7 @@
                 assert(_is64);
                 typedef Pointer64<LittleEndian> P;
 
-                uint32_t freeSpace = ma->loadCommandsFreeSpace();
+                uint32_t freeSpace = ((const Header*)ma)->loadCommandsFreeSpace();
                 assert(freeSpace >= sizeof(macho_linkedit_data_command<P>));
                 uint8_t* endOfLoadCommands = (uint8_t*)ma + sizeof(macho_header<P>) + ma->sizeofcmds;
 
@@ -4209,6 +4329,10 @@
 
         if ( dataConstRegion.sizeInUse != 0 )
             addSegmentStarts(dataConstRegion);
+        if ( lateConstRegion.sizeInUse != 0 )
+            addSegmentStarts(lateConstRegion);
+        if ( dataSptmRegion.sizeInUse != 0 )
+            addSegmentStarts(dataSptmRegion);
         if ( branchGOTsRegion.sizeInUse != 0 )
             addSegmentStarts(branchGOTsRegion);
         if ( readWriteRegion.sizeInUse != 0 )
@@ -4299,36 +4423,6 @@
         sectionsToAddToRegions[&readOnlyTextRegion] = 1;
     }
 
-    // __DATA_CONST
-    if ( dataConstRegion.sizeInUse != 0 ) {
-        vmOrder.emplace_back(&dataConstRegion, 14, 14);
-        fileOrder.emplace_back(&dataConstRegion, 14, 14);
-    }
-
-    // Split seg __TEXT_EXEC
-    if ( readExecuteRegion.sizeInUse != 0 ) {
-        vmOrder.emplace_back(&readExecuteRegion, 14, 14);
-        fileOrder.emplace_back(&readExecuteRegion, 14, 14);
-    }
-
-    // __BRANCH_STUBS
-    if ( branchStubsRegion.bufferSize != 0 ) {
-        vmOrder.emplace_back(&branchStubsRegion, 14, 14);
-        fileOrder.emplace_back(&branchStubsRegion, 14, 14);
-    }
-
-    // __TEXT_BOOT_EXEC
-    if ( textBootExecRegion.sizeInUse != 0 ) {
-        vmOrder.emplace_back(&textBootExecRegion, 14, 14);
-        fileOrder.emplace_back(&textBootExecRegion, 14, 14);
-    }
-
-    // __BRANCH_GOTS
-    if ( branchGOTsRegion.bufferSize != 0 ) {
-        vmOrder.emplace_back(&branchGOTsRegion, 14, 14);
-        fileOrder.emplace_back(&branchGOTsRegion, 14, 14);
-    }
-
     // -sectcreate
     // Align to 16k before we lay out all contiguous regions
     if ( !customSegments.empty() ) {
@@ -4354,6 +4448,48 @@
         // Align the last region after
         vmOrder.back().alignmentAfter = 14;
         fileOrder.back().alignmentAfter = 14;
+    }
+
+    // __DATA_CONST
+    if ( dataConstRegion.sizeInUse != 0 ) {
+        vmOrder.emplace_back(&dataConstRegion, 14, 14);
+        fileOrder.emplace_back(&dataConstRegion, 14, 14);
+    }
+
+    // __LATE_CONST
+    if ( lateConstRegion.sizeInUse != 0 ) {
+        vmOrder.emplace_back(&lateConstRegion, 14, 14);
+        fileOrder.emplace_back(&lateConstRegion, 14, 14);
+    }
+
+    // __DATA_SPTM
+    if ( dataSptmRegion.sizeInUse != 0 ) {
+        vmOrder.emplace_back(&dataSptmRegion, 14, 14);
+        fileOrder.emplace_back(&dataSptmRegion, 14, 14);
+    }
+
+    // Split seg __TEXT_EXEC
+    if ( readExecuteRegion.sizeInUse != 0 ) {
+        vmOrder.emplace_back(&readExecuteRegion, 14, 14);
+        fileOrder.emplace_back(&readExecuteRegion, 14, 14);
+    }
+
+    // __BRANCH_STUBS
+    if ( branchStubsRegion.bufferSize != 0 ) {
+        vmOrder.emplace_back(&branchStubsRegion, 14, 14);
+        fileOrder.emplace_back(&branchStubsRegion, 14, 14);
+    }
+
+    // __TEXT_BOOT_EXEC
+    if ( textBootExecRegion.sizeInUse != 0 ) {
+        vmOrder.emplace_back(&textBootExecRegion, 14, 14);
+        fileOrder.emplace_back(&textBootExecRegion, 14, 14);
+    }
+
+    // __BRANCH_GOTS
+    if ( branchGOTsRegion.bufferSize != 0 ) {
+        vmOrder.emplace_back(&branchGOTsRegion, 14, 14);
+        fileOrder.emplace_back(&branchGOTsRegion, 14, 14);
     }
 
     // __PRELINK_INFO
@@ -4439,7 +4575,7 @@
 
     const thread_command* unixThread = nullptr;
     if (const DylibInfo* dylib = getKernelStaticExecutableInputFile()) {
-        unixThread = dylib->input->mappedFile.mh->unixThreadLoadCommand();
+        unixThread = ((const Header*)dylib->input->mappedFile.mh)->unixThreadLoadCommand();
     }
 
     if (_is64) {
@@ -4684,7 +4820,7 @@
             macho_build_version_command<P>* cmd = (macho_build_version_command<P>*)header.buildVersion;
             cmd->set_cmd(LC_BUILD_VERSION);
             cmd->set_cmdsize(sizeof(build_version_command));
-            cmd->set_platform((uint32_t)_options.platform);
+            cmd->set_platform(_options.platform.value());
             cmd->set_minos(0);
             cmd->set_sdk(0);
             cmd->set_ntools(0);
@@ -4696,12 +4832,12 @@
         if ( header.unixThread != nullptr ) {
             const DylibInfo* dylib = getKernelStaticExecutableInputFile();
             const dyld3::MachOAnalyzer* ma = dylib->input->mappedFile.mh;
-            ma->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
+            ((const Header*)ma)->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
                 uint64_t startAddress = dylib->input->mappedFile.mh->entryAddrFromThreadCmd(header.unixThread);
-                if ( (startAddress < info.vmAddr) || (startAddress >= (info.vmAddr + info.vmSize)) )
+                if ( (startAddress < info.vmaddr) || (startAddress >= (info.vmaddr + info.vmsize)) )
                     return;
 
-                uint64_t segSlide = dylib->cacheLocation[info.segIndex].dstCacheUnslidAddress - info.vmAddr;
+                uint64_t segSlide = dylib->cacheLocation[info.segmentIndex].dstCacheUnslidAddress - info.vmaddr;
                 startAddress += segSlide;
 
                 macho_thread_command<P>* cmd = (macho_thread_command<P>*)header.unixThread;
@@ -4964,7 +5100,7 @@
         // Skip codeless kext's
         if ( ma == nullptr )
             continue;
-        uint64_t loadAddress = ma->preferredLoadAddress();
+        uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
 
         // _PrelinkExecutableLoadAddr
         CFNumberRef loadAddrRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &loadAddress);
@@ -5016,10 +5152,10 @@
             }
             __block uint64_t textSegmnentVMAddr = 0;
             __block uint64_t textSegmnentVMSize = 0;
-            ma->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
-                if ( !strcmp(info.segName, "__TEXT") ) {
-                    textSegmnentVMAddr = info.vmAddr;
-                    textSegmnentVMSize = info.vmSize;
+            ((const Header*)ma)->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+                if ( info.segmentName == "__TEXT" ) {
+                    textSegmnentVMAddr = info.vmaddr;
+                    textSegmnentVMSize = info.vmsize;
                     stop = true;
                 }
             });
@@ -5193,6 +5329,20 @@
                 firstDataRegion = &dataConstRegion;
             if ( (lastDataRegion == nullptr) || (dataConstRegion.buffer > lastDataRegion->buffer) )
                 lastDataRegion = &dataConstRegion;
+        }
+
+        if ( lateConstRegion.sizeInUse != 0 ) {
+            if ( firstDataRegion == nullptr )
+                firstDataRegion = &lateConstRegion;
+            if ( (lastDataRegion == nullptr) || (lateConstRegion.buffer > lastDataRegion->buffer) )
+                lastDataRegion = &lateConstRegion;
+        }
+
+        if ( dataSptmRegion.sizeInUse != 0 ) {
+            if ( firstDataRegion == nullptr )
+                firstDataRegion = &dataSptmRegion;
+            if ( (lastDataRegion == nullptr) || (dataSptmRegion.buffer > lastDataRegion->buffer) )
+                lastDataRegion = &dataSptmRegion;
         }
 
         if ( branchGOTsRegion.bufferSize != 0 ) {
@@ -5393,15 +5543,15 @@
                              uint32_t& authStubSectionIndex)
 {
     // section index 0 refers to mach_header
-    sectionAddresses.push_back(ma->preferredLoadAddress());
+    sectionAddresses.push_back(((const Header*)ma)->preferredLoadAddress());
     sectionBuffers.push_back(nullptr);
 
     intptr_t slide = ma->getSlide();
-    ma->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo& sectInfo, bool malformedSectionRange, bool& stop) {
-        if ( !strcmp(sectInfo.segInfo.segName, "__TEXT_EXEC") && !strcmp(sectInfo.sectName, "__auth_stubs") )
+    ((const Header*)ma)->forEachSection(^(const Header::SectionInfo& sectInfo, bool& stop) {
+        if ( (sectInfo.segmentName == "__TEXT_EXEC") && (sectInfo.sectionName == "__auth_stubs") )
             authStubSectionIndex = (uint32_t)sectionAddresses.size();
-        sectionAddresses.push_back(sectInfo.sectAddr);
-        sectionBuffers.push_back((uint8_t*)sectInfo.sectAddr + slide);
+        sectionAddresses.push_back(sectInfo.address);
+        sectionBuffers.push_back((uint8_t*)sectInfo.address + slide);
     });
 }
 
@@ -5565,7 +5715,7 @@
 
         const dyld3::MachOAnalyzer* ma = nullptr;
         for (const SegmentMappingInfo& loc : dylib.cacheLocation) {
-            if ( !strcmp(loc.segName, "__TEXT") ) {
+            if ( loc.segName == "__TEXT" ) {
                 // Assume __TEXT contains the mach header
                 ma = (const dyld3::MachOAnalyzer*)loc.dstSegment;
                 break;