Loading...
cache_builder/SubCache.cpp dyld-1231.3 dyld-1162
--- dyld/dyld-1231.3/cache_builder/SubCache.cpp
+++ dyld/dyld-1162/cache_builder/SubCache.cpp
@@ -25,7 +25,6 @@
 #include "BuilderConfig.h"
 #include "BuilderOptions.h"
 #include "CacheDylib.h"
-#include "Chunk.h"
 #include "CodeSigningTypes.h"
 #include "DyldSharedCache.h"
 #include "SubCache.h"
@@ -56,58 +55,62 @@
 
 uint32_t Region::initProt() const
 {
-    uint32_t initProt = 0;
-    switch ( this->kind ) {
-        case Region::Kind::text:
-            initProt = VM_PROT_READ | VM_PROT_EXECUTE;
-            break;
-        case Region::Kind::data:
-        case Region::Kind::auth:
-            initProt = VM_PROT_READ | VM_PROT_WRITE;
-            break;
-        case Region::Kind::dataConst:
-        case Region::Kind::authConst:
-        case Region::Kind::tproConst:
-        case Region::Kind::tproAuthConst:
-            initProt = VM_PROT_READ;
-            break;
-        case Region::Kind::readOnly:
-        case Region::Kind::linkedit:
-            initProt = VM_PROT_READ;
-            break;
-        case Region::Kind::dynamicConfig:
-            // HACK: This is not actually mapped, but it is used in vm calculations
-            initProt = VM_PROT_READ;
-            break;
-        case Region::Kind::unmapped:
-        case Region::Kind::codeSignature:
-            // This isn't mapped, so we should never ask for its initProt
-            assert(0);
-            break;
-        case Region::Kind::numKinds:
-            assert(0);
-            break;
-    }
-
-    return initProt;
-}
-
-uint32_t Region::maxProt() const
-{
     uint32_t maxProt = 0;
     switch ( this->kind ) {
         case Region::Kind::text:
             maxProt = VM_PROT_READ | VM_PROT_EXECUTE;
             break;
-        case Region::Kind::tproConst:
         case Region::Kind::data:
+            maxProt = VM_PROT_READ | VM_PROT_WRITE;
+            break;
         case Region::Kind::dataConst:
-        case Region::Kind::tproAuthConst:
+            maxProt = VM_PROT_READ;
+            break;
         case Region::Kind::auth:
+            maxProt = VM_PROT_READ | VM_PROT_WRITE;
+            break;
+        case Region::Kind::authConst:
+            maxProt = VM_PROT_READ;
+            break;
+        case Region::Kind::linkedit:
+            maxProt = VM_PROT_READ;
+            break;
+        case Region::Kind::dynamicConfig:
+            // HACK: This is not actually mapped, but it is used in vm calculations
+            maxProt = VM_PROT_READ;
+            break;
+        case Region::Kind::unmapped:
+        case Region::Kind::codeSignature:
+            // This isn't mapped, so we should never ask for its maxprot
+            assert(0);
+            break;
+        case Region::Kind::numKinds:
+            assert(0);
+            break;
+    }
+
+    return maxProt;
+}
+
+uint32_t Region::maxProt() const
+{
+    uint32_t maxProt = 0;
+    switch ( this->kind ) {
+        case Region::Kind::text:
+            maxProt = VM_PROT_READ | VM_PROT_EXECUTE;
+            break;
+        case Region::Kind::data:
+            maxProt = VM_PROT_READ | VM_PROT_WRITE;
+            break;
+        case Region::Kind::dataConst:
+            maxProt = VM_PROT_READ | VM_PROT_WRITE;
+            break;
+        case Region::Kind::auth:
+            maxProt = VM_PROT_READ | VM_PROT_WRITE;
+            break;
         case Region::Kind::authConst:
             maxProt = VM_PROT_READ | VM_PROT_WRITE;
             break;
-        case Region::Kind::readOnly:
         case Region::Kind::linkedit:
             maxProt = VM_PROT_READ;
             break;
@@ -136,19 +139,14 @@
             // We should never ask this region if it has auth content
             assert(0);
             break;
-        case Region::Kind::tproConst:
-        case Region::Kind::tproAuthConst:
         case Region::Kind::data:
         case Region::Kind::dataConst:
-            // Note TPRO never contains authenticated fixups, so its name is wrong
-            // but its really there to be placed next to the AUTH regions
             result = false;
             break;
         case Region::Kind::auth:
         case Region::Kind::authConst:
             result = true;
             break;
-        case Region::Kind::readOnly:
         case Region::Kind::linkedit:
         case Region::Kind::dynamicConfig:
             // We should never ask this region if it has auth content
@@ -172,13 +170,10 @@
 {
     switch ( this->kind ) {
         case Region::Kind::text:
-        case Region::Kind::tproConst:
         case Region::Kind::data:
         case Region::Kind::dataConst:
-        case Region::Kind::tproAuthConst:
         case Region::Kind::auth:
         case Region::Kind::authConst:
-        case Region::Kind::readOnly:
         case Region::Kind::linkedit:
             return true;
         case Region::Kind::unmapped:
@@ -195,13 +190,10 @@
 {
     switch ( this->kind ) {
         case Region::Kind::text:
-        case Region::Kind::tproConst:
         case Region::Kind::data:
         case Region::Kind::dataConst:
-        case Region::Kind::tproAuthConst:
         case Region::Kind::auth:
         case Region::Kind::authConst:
-        case Region::Kind::readOnly:
         case Region::Kind::linkedit:
         case Region::Kind::dynamicConfig:
             return true;
@@ -229,16 +221,10 @@
             bool nextIsRW = (next.initProt() & VM_PROT_WRITE) != 0;
             return nextIsRW;
         }
-        case Region::Kind::tproConst:
-        case Region::Kind::tproAuthConst:
         case Region::Kind::data:
         case Region::Kind::auth: {
             // HACK: Remove once we have rdar://96315050
             if ( (this->kind == Region::Kind::auth) && (next.kind == Region::Kind::authConst) )
-                return false;
-
-            // Don't add adding from data to tproConst as we didn't have padding from data to auth before
-            if ( (next.kind == Kind::tproConst) || (next.kind == Kind::tproAuthConst) )
                 return false;
 
             // Add padding if DATA is adjacent to something immutable, eg TEXT/DATA_CONST
@@ -247,17 +233,12 @@
         }
         case Region::Kind::dataConst:
         case Region::Kind::authConst: {
-            // Always add padding from DATA_CONST to TPRO_CONST as TPRO_CONST will actually be dirtied
-            if ( (next.kind == Kind::tproConst) || (next.kind == Kind::tproAuthConst) )
-                return true;
-
             // Don't add padding if *_CONST is next to *_CONST, otherwise add padding
             bool nextInitIsRO = (next.initProt() & VM_PROT_WRITE) == 0;
             bool nextMaxIsRW = (next.maxProt() & VM_PROT_WRITE) != 0;
             bool nextIsDataConst = nextInitIsRO & nextMaxIsRW;
             return !nextIsDataConst;
         }
-        case Region::Kind::readOnly:
         case Region::Kind::linkedit:
         case Region::Kind::dynamicConfig: {
             // Add padding if LINKEDIT is adjacent to something that is mutable,
@@ -340,14 +321,11 @@
         switch ( region.kind ) {
             case cache_builder::Region::Kind::text:
                 break;
-            case cache_builder::Region::Kind::tproConst:
-            case cache_builder::Region::Kind::tproAuthConst:
             case cache_builder::Region::Kind::dataConst:
             case cache_builder::Region::Kind::data:
             case cache_builder::Region::Kind::auth:
             case cache_builder::Region::Kind::authConst:
                 return true;
-            case Region::Kind::readOnly:
             case cache_builder::Region::Kind::linkedit:
             case cache_builder::Region::Kind::unmapped:
             case cache_builder::Region::Kind::dynamicConfig:
@@ -366,14 +344,11 @@
             continue;
         switch ( region.kind ) {
             case cache_builder::Region::Kind::text:
-            case cache_builder::Region::Kind::tproConst:
-            case cache_builder::Region::Kind::tproAuthConst:
             case cache_builder::Region::Kind::dataConst:
             case cache_builder::Region::Kind::data:
             case cache_builder::Region::Kind::auth:
             case cache_builder::Region::Kind::authConst:
                 break;
-            case Region::Kind::readOnly:
             case cache_builder::Region::Kind::linkedit:
                 return true;
             case cache_builder::Region::Kind::unmapped:
@@ -725,20 +700,6 @@
     this->regions[(uint32_t)Region::Kind::text].chunks.push_back(chunk);
 }
 
-void SubCache::addTPROConstChunk(const BuilderConfig& config, Chunk* chunk)
-{
-    // Rosetta can't handle an extra shared cache mapping, so use DATA instead
-    // We use DATA instead of DATA_CONST because we don't want the MemoryManager
-    // and DataConstWriter to both mprotect the same pages.  But the DataConstWriter
-    // will ignore everything in DATA while the MemoryManager will find TPRO there
-    if ( config.layout.discontiguous.has_value() )
-        this->addDataChunk(chunk);
-    else if ( config.layout.hasAuthRegion )
-        this->regions[(uint32_t)Region::Kind::tproAuthConst].chunks.push_back(chunk);
-    else
-        this->regions[(uint32_t)Region::Kind::tproConst].chunks.push_back(chunk);
-}
-
 void SubCache::addDataChunk(Chunk* chunk)
 {
     this->regions[(uint32_t)Region::Kind::data].chunks.push_back(chunk);
@@ -759,15 +720,6 @@
     this->regions[(uint32_t)Region::Kind::authConst].chunks.push_back(chunk);
 }
 
-void SubCache::addReadOnlyChunk(const BuilderConfig& config, Chunk* chunk)
-{
-    // Rosetta can't handle an extra shared cache mapping, so use __TEXT instead
-    if ( config.layout.discontiguous.has_value() )
-        this->addTextChunk(chunk);
-    else
-        this->regions[(uint32_t)Region::Kind::readOnly].chunks.push_back(chunk);
-}
-
 void SubCache::addLinkeditChunk(Chunk* chunk)
 {
     this->regions[(uint32_t)Region::Kind::linkedit].chunks.push_back(chunk);
@@ -781,6 +733,22 @@
 void SubCache::addCodeSignatureChunk(Chunk* chunk)
 {
     this->regions[(uint32_t)Region::Kind::codeSignature].chunks.push_back(chunk);
+}
+
+// HACK: We need to insert the libobjc __TEXT first so that its before all the other OBJC_RO chunks
+void SubCache::addObjCTextChunk(Chunk* chunk)
+{
+    std::vector<Chunk*>& chunks = this->regions[(uint32_t)Region::Kind::text].chunks;
+    chunks.insert(chunks.begin(), chunk);
+}
+
+// ObjC optimizations need to add read-only chunks.  For now these are added to the start
+// of TEXT, so that they are in the same subCache when split by One Cache.  In future we want to
+// move these to LINKEDIT
+void SubCache::addObjCReadOnlyChunk(Chunk* chunk)
+{
+    std::vector<Chunk*>& chunks = this->regions[(uint32_t)Region::Kind::text].chunks;
+    chunks.insert(chunks.begin(), chunk);
 }
 
 // All objc optimizations need to be contiguous, but that means if any need AUTH then all do
@@ -794,17 +762,18 @@
     }
 }
 
-void SubCache::addDylib(const BuilderConfig& config, CacheDylib& cacheDylib)
+void SubCache::addDylib(CacheDylib& cacheDylib, bool addLinkedit)
 {
     for ( DylibSegmentChunk& segmentInfo : cacheDylib.segments ) {
         switch ( segmentInfo.kind ) {
             case Chunk::Kind::dylibText:
-                this->addTextChunk(&segmentInfo);
-                break;
-            case Chunk::Kind::tproDataConst:
-                this->addTPROConstChunk(config, &segmentInfo);
+                if ( cacheDylib.installName == "/usr/lib/libobjc.A.dylib" )
+                    this->addObjCTextChunk(&segmentInfo);
+                else
+                    this->addTextChunk(&segmentInfo);
                 break;
             case Chunk::Kind::dylibData:
+            case Chunk::Kind::dylibDataConstWorkaround:
                 this->addDataChunk(&segmentInfo);
                 break;
             case Chunk::Kind::dylibDataConst:
@@ -818,13 +787,15 @@
                     this->addDataChunk(&segmentInfo);
                 break;
             case Chunk::Kind::dylibAuth:
+            case Chunk::Kind::dylibAuthConstWorkaround:
                 this->addAuthChunk(&segmentInfo);
                 break;
             case Chunk::Kind::dylibAuthConst:
                 this->addAuthConstChunk(&segmentInfo);
                 break;
             case Chunk::Kind::dylibReadOnly:
-                this->addReadOnlyChunk(config, &segmentInfo);
+                // FIXME: Read-only data should really be in a read-only mapping.
+                this->addTextChunk(&segmentInfo);
                 break;
             case Chunk::Kind::dylibLinkedit:
                 // Skip adding here.  We'll do this in addLinkeditFromDylib()
@@ -835,7 +806,8 @@
         }
     }
 
-    this->addLinkeditFromDylib(cacheDylib);
+    if ( addLinkedit )
+        this->addLinkeditFromDylib(cacheDylib);
 }
 
 // Linkedit is stored in Chunks in its own array on the dylib.  This adds it to the subCache.
@@ -849,98 +821,16 @@
         this->addLinkeditChunk(&chunk);
 }
 
-void SubCache::forEachTPRORegionInData(SubCache* mainSubCache, std::span<SubCache*> subCaches,
-                                       void (^callback)(Region& region, const Chunk* firstChunk, const Chunk* lastChunk))
-{
-    // Find all subcaches with TPRO regions, or on x86_64 its those with DATA in them
-    auto runOnSubCache = ^(SubCache* subCache) {
-        for ( Region& region : subCache->regions ) {
-            if ( region.kind != Region::Kind::data )
-                continue;
-
-            const Chunk* firstTPROChunk = nullptr;
-            const Chunk* lastTPROChunk = nullptr;
-            for ( const Chunk* chunk : region.chunks ) {
-                if ( chunk->isTPROChunk() ) {
-                    if ( !firstTPROChunk ) {
-                        firstTPROChunk = chunk;
-                        lastTPROChunk = chunk;
-                    } else {
-                        lastTPROChunk = chunk;
-                    }
-                } else if ( firstTPROChunk ) {
-                    // HACK: If we find an alignment chunk then add it as-if its a TPRO chunk. This is to
-                    // make sure callers can get page-aligned TPRO regions
-                    if ( const AlignChunk* alignChunk = chunk->isAlignChunk() ) {
-                        if ( alignChunk->alignment() >= 4_KB ) {
-                            lastTPROChunk = chunk;
-                            continue;
-                        }
-                    }
-
-                    // Found a non-tpro chunk.  Break here and do the callback outside the chunk loop
-                    // We don't need to continue the loop as we sorted all the TPRO to be adjacent
-                    break;
-                }
-            }
-
-            if ( firstTPROChunk ) {
-                // Ended with a tpro chunk.  Make the callback for it
-                callback(region, firstTPROChunk, lastTPROChunk);
-            }
-        }
-    };
-
-    runOnSubCache(mainSubCache);
-    for ( SubCache* subCache : subCaches )
-        runOnSubCache(subCache);
-}
-
-static void forEachTPRORegion(const BuilderConfig& config, SubCache* mainSubCache,
-                              std::span<SubCache*> subCaches,
-                              void (^callback)(CacheVMAddress firstChunkAddress, CacheVMAddress lastChunkAddress, CacheVMSize lastChunkSize))
-{
-    // Find all subcaches with TPRO regions, or on x86_64 its those with DATA in them
-    if ( config.layout.tproIsInData ) {
-        SubCache::forEachTPRORegionInData(mainSubCache, subCaches, ^(Region& region, const Chunk *firstChunk, const Chunk *lastChunk) {
-            callback(firstChunk->cacheVMAddress, lastChunk->cacheVMAddress, lastChunk->cacheVMSize);
-        });
-        return;
-    }
-
-    auto runOnSubCache = ^(const SubCache* subCache) {
-        for ( const Region& region : subCache->regions ) {
-            if ( (region.kind == Region::Kind::tproConst) || (region.kind == Region::Kind::tproAuthConst) )
-                callback(region.subCacheVMAddress, region.subCacheVMAddress, region.subCacheVMSize);
-        }
-    };
-
-    runOnSubCache(mainSubCache);
-    for ( const SubCache* subCache : subCaches )
-        runOnSubCache(subCache);
-}
-
-static uint32_t numTPRORegions(const BuilderConfig& config, SubCache* mainSubCache,
-                               std::span<SubCache*> subCaches)
-{
-    __block uint32_t count = 0;
-    forEachTPRORegion(config, mainSubCache, subCaches, ^(CacheVMAddress, CacheVMAddress, CacheVMSize) {
-        ++count;
-    });
-    return count;
-}
-
-void SubCache::addCacheHeaderChunk(const BuilderConfig& config, const std::span<CacheDylib> cacheDylibs)
+void SubCache::addCacheHeaderChunk(const std::span<CacheDylib> cacheDylibs)
 {
     // calculate size of header info and where first dylib's mach_header should start
     uint64_t numMappings = this->regions.size();
     uint64_t startOffset = sizeof(dyld_cache_header) + (numMappings * sizeof(dyld_cache_mapping_info));
     startOffset += numMappings * sizeof(dyld_cache_mapping_and_slide_info);
 
-    // Only the main cache has a list of subCaches and TPRO mappings to write
+    // Only the main cache has a list of subCaches to write
     if ( this->isMainCache() ) {
         startOffset += sizeof(dyld_subcache_entry) * this->subCaches.size();
-        startOffset += sizeof(dyld_cache_tpro_mapping_info) * numTPRORegions(config, this, this->subCaches);
     }
 
     if ( this->needsCacheHeaderImageList() ) {
@@ -979,12 +869,6 @@
     // we sort the Chunk's.  For now just add placeholder(s) and we'll update the
     // size in calculateSlideInfoSize()
 
-    // TPRO_CONST
-    if ( !this->regions[(uint32_t)Region::Kind::tproConst].chunks.empty() ) {
-        this->tproConstSlideInfo = std::make_unique<SlideInfoChunk>();
-        addLinkeditChunk(this->tproConstSlideInfo.get());
-    }
-
     // DATA
     if ( !this->regions[(uint32_t)Region::Kind::data].chunks.empty() ) {
         this->dataSlideInfo = std::make_unique<SlideInfoChunk>();
@@ -997,12 +881,6 @@
         addLinkeditChunk(this->dataConstSlideInfo.get());
     }
 
-    // TPRO_CONST (on arm64e)
-    if ( !this->regions[(uint32_t)Region::Kind::tproAuthConst].chunks.empty() ) {
-        this->tproAuthConstSlideInfo = std::make_unique<SlideInfoChunk>();
-        addLinkeditChunk(this->tproAuthConstSlideInfo.get());
-    }
-
     // AUTH
     if ( !this->regions[(uint32_t)Region::Kind::auth].chunks.empty() ) {
         this->authSlideInfo = std::make_unique<SlideInfoChunk>();
@@ -1036,7 +914,7 @@
     this->addLinkeditChunk(this->objcOptsHeader.get());
 }
 
-void SubCache::addObjCHeaderInfoReadOnlyChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer)
+void SubCache::addObjCHeaderInfoReadOnlyChunk(ObjCOptimizer& objcOptimizer)
 {
     this->objcHeaderInfoRO = std::make_unique<ObjCHeaderInfoReadOnlyChunk>();
     this->objcHeaderInfoRO->cacheVMSize         = CacheVMSize(objcOptimizer.headerInfoReadOnlyByteSize);
@@ -1044,10 +922,10 @@
 
     objcOptimizer.headerInfoReadOnlyChunk = this->objcHeaderInfoRO.get();
 
-    this->addReadOnlyChunk(config, this->objcHeaderInfoRO.get());
-}
-
-void SubCache::addObjCImageInfoChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer)
+    this->addObjCReadOnlyChunk(this->objcHeaderInfoRO.get());
+}
+
+void SubCache::addObjCImageInfoChunk(ObjCOptimizer& objcOptimizer)
 {
     this->objcImageInfo = std::make_unique<ObjCImageInfoChunk>();
     this->objcImageInfo->cacheVMSize         = CacheVMSize(objcOptimizer.imageInfoSize);
@@ -1055,10 +933,10 @@
 
     objcOptimizer.imageInfoChunk = this->objcImageInfo.get();
 
-    this->addReadOnlyChunk(config, this->objcImageInfo.get());
-}
-
-void SubCache::addObjCSelectorStringsChunk(const BuilderConfig& config, ObjCSelectorOptimizer& objCSelectorOptimizer)
+    this->addObjCReadOnlyChunk(this->objcImageInfo.get());
+}
+
+void SubCache::addObjCSelectorStringsChunk(ObjCSelectorOptimizer& objCSelectorOptimizer)
 {
     this->objcSelectorStrings = std::make_unique<ObjCStringsChunk>();
     this->objcSelectorStrings->cacheVMSize      = CacheVMSize(objCSelectorOptimizer.selectorStringsTotalByteSize);
@@ -1066,10 +944,10 @@
 
     objCSelectorOptimizer.selectorStringsChunk = this->objcSelectorStrings.get();
 
-    this->addReadOnlyChunk(config, this->objcSelectorStrings.get());
-}
-
-void SubCache::addObjCSelectorHashTableChunk(const BuilderConfig& config, ObjCSelectorOptimizer& objCSelectorOptimizer)
+    this->addObjCReadOnlyChunk(this->objcSelectorStrings.get());
+}
+
+void SubCache::addObjCSelectorHashTableChunk(ObjCSelectorOptimizer& objCSelectorOptimizer)
 {
     this->objcSelectorsHashTable = std::make_unique<ObjCSelectorHashTableChunk>();
     this->objcSelectorsHashTable->cacheVMSize       = CacheVMSize(objCSelectorOptimizer.selectorHashTableTotalByteSize);
@@ -1077,10 +955,10 @@
 
     objCSelectorOptimizer.selectorHashTableChunk = this->objcSelectorsHashTable.get();
 
-    this->addReadOnlyChunk(config, this->objcSelectorsHashTable.get());
-}
-
-void SubCache::addObjCClassNameStringsChunk(const BuilderConfig& config, ObjCClassOptimizer& objcClassOptimizer)
+    this->addObjCReadOnlyChunk(this->objcSelectorsHashTable.get());
+}
+
+void SubCache::addObjCClassNameStringsChunk(ObjCClassOptimizer& objcClassOptimizer)
 {
     this->objcClassNameStrings = std::make_unique<ObjCStringsChunk>();
     this->objcClassNameStrings->cacheVMSize         = CacheVMSize(objcClassOptimizer.nameStringsTotalByteSize);
@@ -1088,10 +966,10 @@
 
     objcClassOptimizer.classNameStringsChunk = this->objcClassNameStrings.get();
 
-    this->addReadOnlyChunk(config, this->objcClassNameStrings.get());
-}
-
-void SubCache::addObjCClassHashTableChunk(const BuilderConfig& config, ObjCClassOptimizer& objcClassOptimizer)
+    this->addObjCReadOnlyChunk(this->objcClassNameStrings.get());
+}
+
+void SubCache::addObjCClassHashTableChunk(ObjCClassOptimizer& objcClassOptimizer)
 {
     this->objcClassesHashTable = std::make_unique<ObjCClassHashTableChunk>();
     this->objcClassesHashTable->cacheVMSize         = CacheVMSize(objcClassOptimizer.classHashTableTotalByteSize);
@@ -1099,10 +977,10 @@
 
     objcClassOptimizer.classHashTableChunk = this->objcClassesHashTable.get();
 
-    this->addReadOnlyChunk(config, this->objcClassesHashTable.get());
-}
-
-void SubCache::addObjCProtocolNameStringsChunk(const BuilderConfig& config, ObjCProtocolOptimizer& objcProtocolOptimizer)
+    this->addObjCReadOnlyChunk(this->objcClassesHashTable.get());
+}
+
+void SubCache::addObjCProtocolNameStringsChunk(ObjCProtocolOptimizer& objcProtocolOptimizer)
 {
     this->objcProtocolNameStrings = std::make_unique<ObjCStringsChunk>();
     this->objcProtocolNameStrings->cacheVMSize      = CacheVMSize(objcProtocolOptimizer.nameStringsTotalByteSize);
@@ -1110,10 +988,10 @@
 
     objcProtocolOptimizer.protocolNameStringsChunk = this->objcProtocolNameStrings.get();
 
-    this->addReadOnlyChunk(config, this->objcProtocolNameStrings.get());
-}
-
-void SubCache::addObjCProtocolHashTableChunk(const BuilderConfig& config, ObjCProtocolOptimizer& objcProtocolOptimizer)
+    this->addObjCReadOnlyChunk(this->objcProtocolNameStrings.get());
+}
+
+void SubCache::addObjCProtocolHashTableChunk(ObjCProtocolOptimizer& objcProtocolOptimizer)
 {
     this->objcProtocolsHashTable = std::make_unique<ObjCProtocolHashTableChunk>();
     this->objcProtocolsHashTable->cacheVMSize       = CacheVMSize(objcProtocolOptimizer.protocolHashTableTotalByteSize);
@@ -1121,10 +999,10 @@
 
     objcProtocolOptimizer.protocolHashTableChunk = this->objcProtocolsHashTable.get();
 
-    this->addReadOnlyChunk(config, this->objcProtocolsHashTable.get());
-}
-
-void SubCache::addObjCProtocolSwiftDemangledNamesChunk(const BuilderConfig& config, ObjCProtocolOptimizer& objcProtocolOptimizer)
+    this->addObjCReadOnlyChunk(this->objcProtocolsHashTable.get());
+}
+
+void SubCache::addObjCProtocolSwiftDemangledNamesChunk(ObjCProtocolOptimizer& objcProtocolOptimizer)
 {
     this->objcSwiftDemangledNameStrings = std::make_unique<ObjCStringsChunk>();
     this->objcSwiftDemangledNameStrings->cacheVMSize        = CacheVMSize(objcProtocolOptimizer.swiftDemangledNameStringsTotalByteSize);
@@ -1132,7 +1010,7 @@
 
     objcProtocolOptimizer.swiftDemangledNameStringsChunk = this->objcSwiftDemangledNameStrings.get();
 
-    this->addReadOnlyChunk(config, this->objcSwiftDemangledNameStrings.get());
+    this->addObjCReadOnlyChunk(this->objcSwiftDemangledNameStrings.get());
 }
 
 void SubCache::addObjCCanonicalProtocolsChunk(const BuilderConfig& config,
@@ -1169,7 +1047,7 @@
     objcCategoryOptimizer.categoriesChunk = this->objcCategories.get();
 
     // Add objc categories
-    addReadOnlyChunk(config, this->objcCategories.get());
+    addObjCReadOnlyChunk(this->objcCategories.get());
 }
 
 void SubCache::addCacheTrieChunk(DylibTrieOptimizer& dylibTrieOptimizer)
@@ -1278,18 +1156,6 @@
     opt.foreignTypeConformancesHashTable = this->swiftForeignTypeHashTable.get();
 
     this->addLinkeditChunk(this->swiftForeignTypeHashTable.get());
-}
-
-void SubCache::addSwiftPrespecializedMetadataPointerTableChunks(SwiftProtocolConformanceOptimizer& opt)
-{
-    for ( PointerHashTableOptimizerInfo& tableInfo : opt.prespecializedMetadataHashTables ) {
-        PointerHashTableChunk* chunk = this->pointerHashTables.emplace_back(std::make_unique<PointerHashTableChunk>()).get();
-        chunk->cacheVMSize       = CacheVMSize(tableInfo.size);
-        chunk->subCacheFileSize  = CacheFileSize(tableInfo.size);
-
-        tableInfo.chunk = chunk;
-        this->addLinkeditChunk(chunk);
-    }
 }
 
 void SubCache::addUnmappedSymbols(const BuilderConfig& config, UnmappedSymbolsOptimizer& opt)
@@ -1389,26 +1255,6 @@
             case Region::Kind::text:
                 flags    = this->isStubsCache() ? DYLD_CACHE_MAPPING_TEXT_STUBS : 0;
                 break;
-            case Region::Kind::tproConst:
-                flags    = DYLD_CACHE_MAPPING_CONST_DATA | DYLD_CACHE_MAPPING_CONST_TPRO_DATA;
-
-                // Get the slide info
-                if ( this->tproConstSlideInfo ) {
-                    slideInfoFileOffset = this->tproConstSlideInfo->subCacheFileOffset;
-                    slideInfoFileSize   = this->tproConstSlideInfo->usedFileSize;
-                }
-                break;
-            case Region::Kind::tproAuthConst:
-                // Note, we don't set AUTH here.  TPRO_CONST doesn't actually contain authenticated fixups, ie, is just data
-                // but we still give it its own Region so that we can place it adjacent to dirty data
-                flags    = DYLD_CACHE_MAPPING_CONST_DATA | DYLD_CACHE_MAPPING_CONST_TPRO_DATA;
-
-                // Get the slide info
-                if ( this->tproAuthConstSlideInfo ) {
-                    slideInfoFileOffset = this->tproAuthConstSlideInfo->subCacheFileOffset;
-                    slideInfoFileSize   = this->tproAuthConstSlideInfo->usedFileSize;
-                }
-                break;
             case Region::Kind::data:
                 flags    = 0;
 
@@ -1444,9 +1290,6 @@
                     slideInfoFileOffset = this->authConstSlideInfo->subCacheFileOffset;
                     slideInfoFileSize   = this->authConstSlideInfo->usedFileSize;
                 }
-                break;
-            case Region::Kind::readOnly:
-                flags    = DYLD_CACHE_READ_ONLY_DATA;
                 break;
             case Region::Kind::linkedit:
                 flags    = 0;
@@ -1581,14 +1424,12 @@
     dyldCacheHeader->cacheAtlasSize                = 0; // set later only on the main cache file
     dyldCacheHeader->dynamicDataOffset             = 0; // set later only on the main cache file
     dyldCacheHeader->dynamicDataMaxSize            = 0; // set later only on the main cache file
-    dyldCacheHeader->tproMappingsOffset            = 0; // set later only on the main cache file
-    dyldCacheHeader->tproMappingsCount             = 0; // set later only on the main cache file
 
     // Fill in old mappings
     // And new mappings which also have slide info
     this->writeCacheHeaderMappings();
 
-    this->addCacheHeaderImageInfo(options, config, cacheDylibs);
+    this->addCacheHeaderImageInfo(options, cacheDylibs);
 }
 
 void SubCache::addMainCacheHeaderInfo(const BuilderOptions& options, const BuilderConfig& config,
@@ -1622,7 +1463,7 @@
     if ( !objcOptimizer.objcDylibs.empty() ) {
         const auto& opt = swiftProtocolConformanceOpt;
         dyldCacheHeader->swiftOptsOffset = (opt.optsHeaderChunk->cacheVMAddress - cacheBaseAddress).rawValue();
-        dyldCacheHeader->swiftOptsSize   = opt.optsHeaderChunk->subCacheFileSize.rawValue();
+        dyldCacheHeader->objcOptsSize    = opt.optsHeaderChunk->subCacheFileSize.rawValue();
     }
 
     dyldCacheHeader->patchInfoAddr = patchTableOptimizer.patchTableChunk->cacheVMAddress.rawValue();
@@ -1667,25 +1508,6 @@
         dyldCacheHeader->dynamicDataOffset  = (dynamicConfig->cacheVMAddress - cacheBaseAddress).rawValue();
         dyldCacheHeader->dynamicDataMaxSize = dynamicConfig->cacheVMSize.rawValue();
     }
-
-    // Find all the TPRO regions
-    if ( dyldCacheHeader->tproMappingsCount != 0 ) {
-        assert(cacheHeaderChunk.subCacheFileOffset.rawValue() == 0);
-        auto* mappings = (dyld_cache_tpro_mapping_info*)((uint8_t*)dyldCacheHeader + dyldCacheHeader->tproMappingsOffset);
-        __block uint32_t index = 0;
-        forEachTPRORegion(config, this, this->subCaches, ^(CacheVMAddress firstChunkAddress, CacheVMAddress lastChunkAddress, CacheVMSize lastChunkSize) {
-            assert(index < dyldCacheHeader->tproMappingsCount);
-
-            CacheVMAddress vmAddr = firstChunkAddress;
-            CacheVMSize vmSize = (lastChunkAddress - firstChunkAddress) + lastChunkSize;
-
-            dyld_cache_tpro_mapping_info* mapping = & mappings[index];
-            mapping->unslidAddress = vmAddr.rawValue();
-            mapping->size = vmSize.rawValue();
-
-            ++index;
-        });
-    }
 }
 
 void SubCache::addSymbolsCacheHeaderInfo(const UnmappedSymbolsOptimizer& optimizer)
@@ -1709,7 +1531,6 @@
 }
 
 void SubCache::addCacheHeaderImageInfo(const BuilderOptions& options,
-                                       const BuilderConfig& config,
                                        const std::span<CacheDylib> cacheDylibs)
 {
     if ( !this->needsCacheHeaderImageList() )
@@ -1727,14 +1548,9 @@
     dyldCacheHeader->subCacheArrayOffset = (uint32_t)(dyldCacheHeader->imagesTextOffset + sizeof(dyld_cache_image_text_info) * cacheDylibs.size());
     dyldCacheHeader->subCacheArrayCount  = (uint32_t)this->subCaches.size();
 
-    // Always set the TPRO offset, but the count will only be set in the main cache
-    dyldCacheHeader->tproMappingsOffset = (uint32_t)(dyldCacheHeader->subCacheArrayOffset + sizeof(dyld_subcache_entry) * dyldCacheHeader->subCacheArrayCount);
-    if ( this->isMainCache() )
-        dyldCacheHeader->tproMappingsCount = numTPRORegions(config, this, this->subCaches);
-
     // calculate start of text image array and trailing string pool
     auto*    textImages   = (dyld_cache_image_text_info*)((uint8_t*)dyldCacheHeader + dyldCacheHeader->imagesTextOffset);
-    uint32_t stringOffset = (uint32_t)(dyldCacheHeader->tproMappingsOffset + sizeof(dyld_cache_tpro_mapping_info) * dyldCacheHeader->tproMappingsCount);
+    uint32_t stringOffset = (uint32_t)(dyldCacheHeader->subCacheArrayOffset + sizeof(dyld_subcache_entry) * dyldCacheHeader->subCacheArrayCount);
 
     // write text image array and image names pool at same time
     for ( const CacheDylib& cacheDylib : cacheDylibs ) {
@@ -1978,9 +1794,6 @@
     __block MachOFile::ChainedFixupPointerOnDisk* lastFixup = nullptr;
     __block uint64_t lastPageIndex = ~0ULL;
     for ( Chunk* chunk : region.chunks ) {
-        if ( chunk->isAlignChunk() )
-            continue;
-
         SlidChunk* slidChunk = chunk->isSlidChunk();
 
         slidChunk->tracker.forEachFixup(^(void *loc, bool& stop) {
@@ -2284,10 +2097,8 @@
     Diagnostics diag;
 
     for ( Chunk* chunk : region.chunks ) {
-        if ( chunk->isAlignChunk() )
-            continue;
-
         SlidChunk* slidChunk = chunk->isSlidChunk();
+
         slidChunk->tracker.forEachFixup(^(void *loc, bool& stop) {
             if ( config.layout.is64 ) {
                 CacheVMAddress vmAddr = Fixup::Cache64::getCacheVMAddressFromLocation(config.layout.cacheBaseAddress, loc);
@@ -2314,12 +2125,6 @@
             case Region::Kind::text:
                 // No slide info for text
                 break;
-            case Region::Kind::tproConst:
-                if ( config.slideInfo.slideInfoFormat.has_value() )
-                    err = computeSlideInfoForRegion(config, this->tproConstSlideInfo.get(), region);
-                else
-                    err = convertChainsToVMAddresses(config, region);
-                break;
             case Region::Kind::data:
                 if ( config.slideInfo.slideInfoFormat.has_value() )
                     err = computeSlideInfoForRegion(config, this->dataSlideInfo.get(), region);
@@ -2332,12 +2137,6 @@
                 else
                     err = convertChainsToVMAddresses(config, region);
                 break;
-            case Region::Kind::tproAuthConst:
-                if ( config.slideInfo.slideInfoFormat.has_value() )
-                    err = computeSlideInfoForRegion(config, this->tproAuthConstSlideInfo.get(), region);
-                else
-                    err = convertChainsToVMAddresses(config, region);
-                break;
             case Region::Kind::auth:
                 if ( config.slideInfo.slideInfoFormat.has_value() )
                     err = computeSlideInfoForRegion(config, this->authSlideInfo.get(), region);
@@ -2350,9 +2149,8 @@
                 else
                     err = convertChainsToVMAddresses(config, region);
                 break;
-            case Region::Kind::readOnly:
             case Region::Kind::linkedit:
-                // No slide info for linkedit
+                // No slide info for text
                 break;
             case Region::Kind::unmapped:
             case Region::Kind::dynamicConfig: