Loading...
cache_builder/SubCache.cpp dyld-1235.2 dyld-1323.3
--- dyld/dyld-1235.2/cache_builder/SubCache.cpp
+++ dyld/dyld-1323.3/cache_builder/SubCache.cpp
@@ -28,6 +28,7 @@
 #include "Chunk.h"
 #include "CodeSigningTypes.h"
 #include "DyldSharedCache.h"
+#include "Header.h"
 #include "SubCache.h"
 #include "JSONWriter.h"
 
@@ -37,8 +38,10 @@
 #include <CommonCrypto/CommonDigest.h>
 #include <CommonCrypto/CommonDigestSPI.h>
 
-using dyld3::GradedArchs;
 using dyld3::MachOFile;
+
+using mach_o::Header;
+using mach_o::Platform;
 
 using error::Error;
 
@@ -359,7 +362,7 @@
     return false;
 }
 
-static bool hasLinkeditRegion(std::span<Region> regions)
+static bool hasReadOnlyRegion(std::span<Region> regions)
 {
     for ( const Region& region : regions ) {
         if ( region.chunks.empty() )
@@ -374,6 +377,33 @@
             case cache_builder::Region::Kind::authConst:
                 break;
             case Region::Kind::readOnly:
+                return true;
+            case cache_builder::Region::Kind::linkedit:
+            case cache_builder::Region::Kind::unmapped:
+            case cache_builder::Region::Kind::dynamicConfig:
+            case cache_builder::Region::Kind::codeSignature:
+            case cache_builder::Region::Kind::numKinds:
+                break;
+        }
+    }
+    return false;
+}
+
+static bool hasLinkeditRegion(std::span<Region> regions)
+{
+    for ( const Region& region : regions ) {
+        if ( region.chunks.empty() )
+            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:
+            case Region::Kind::readOnly:
+                break;
             case cache_builder::Region::Kind::linkedit:
                 return true;
             case cache_builder::Region::Kind::unmapped:
@@ -386,43 +416,46 @@
     return false;
 }
 
-void SubCache::setSuffix(dyld3::Platform platform, bool forceDevelopmentSubCacheSuffix,
-                         size_t subCacheIndex)
+void SubCache::setSuffix(Platform platform, bool forceDevelopmentSubCacheSuffix, size_t subCacheIndex)
 {
     assert(this->isSubCache() || this->isStubsCache());
     assert(subCacheIndex > 0);
 
     const char* dataSuffix = forceDevelopmentSubCacheSuffix ? ".development.dylddata" : ".dylddata";
     const char* linkeditSuffix = forceDevelopmentSubCacheSuffix ? ".development.dyldlinkedit" : ".dyldlinkedit";
+    const char* readonlySuffix = forceDevelopmentSubCacheSuffix ? ".development.dyldreadonly" : ".dyldreadonly";
     const char* subCacheSuffix = forceDevelopmentSubCacheSuffix ? ".development" : "";
 
-    if ( platform == dyld3::Platform::macOS ) {
-        // macOS never has a .development suffix
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex);
-    } else if ( platform == dyld3::Platform::driverKit ) {
+    if ( (platform == Platform::macOS) || platform.isSimulator() ) {
+        // macOS/sims never has a .development suffix
+        this->fileSuffix = "." + json::decimal(subCacheIndex);
+    } else if ( platform == Platform::driverKit ) {
         // driverKit never has a .development suffix
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex);
+        this->fileSuffix = "." + json::decimal(subCacheIndex);
     } else if ( this->isStubsDevelopmentCache() ) {
         // Dev stubs always have a suffix
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex) + ".development";
+        this->fileSuffix = "." + json::decimal(subCacheIndex) + ".development";
     } else if ( this->isStubsCustomerCache() ) {
         // Customer stubs never have a suffix
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex);
+        this->fileSuffix = "." + json::decimal(subCacheIndex);
     } else if ( hasDataRegion(this->regions) ) {
         // Data only subcaches have their own suffix
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex) + dataSuffix;
+        this->fileSuffix = "." + json::decimal(subCacheIndex) + dataSuffix;
+    } else if ( hasReadOnlyRegion(this->regions) ) {
+        // read-only only subcaches have their own suffix
+        this->fileSuffix = "." + json::decimal(subCacheIndex) + readonlySuffix;
     } else if ( hasLinkeditRegion(this->regions) ) {
         // Linkedit only subcaches have their own suffix
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex) + linkeditSuffix;
+        this->fileSuffix = "." + json::decimal(subCacheIndex) + linkeditSuffix;
     } else {
-        this->fileSuffix = "." + dyld3::json::decimal(subCacheIndex) + subCacheSuffix;
+        this->fileSuffix = "." + json::decimal(subCacheIndex) + subCacheSuffix;
     }
 }
 
 static std::string getCodeSigningIdentifier(const BuilderOptions& options)
 {
     std::string cacheIdentifier = "com.apple.dyld.cache.";
-    cacheIdentifier += options.archs.name();
+    cacheIdentifier += options.arch.name();
     if ( options.dylibsRemovedFromDisk ) {
         switch ( options.kind ) {
             case CacheKind::development:
@@ -710,6 +743,14 @@
     // Note: cdHash is defined as first 20 bytes of hash
     memcpy(this->cdHash, fullCdHash, 20);
 
+    if ( layout.agile ) {
+        // hash of entire code directory (cdHash) uses same hash as each page
+        uint8_t altfullCdHash[CS_HASH_SIZE_SHA256];
+        CCDigest(kCCDigestSHA256, (const uint8_t*)cd256, layout.cd256Size, altfullCdHash);
+        // Note: cdHash is defined as first 20 bytes of hash
+        memcpy(this->agilecdHash, altfullCdHash, 20);
+    }
+
     // Set the UUID string in the subcache
     uuid_unparse_upper(dyldCacheHeader->uuid, this->uuidString);
 }
@@ -812,7 +853,7 @@
                 break;
             case Chunk::Kind::dylibDataDirty:
                 // On arm64e, dataDirty goes in to auth
-                if ( cacheDylib.inputMF->isArch("arm64e") )
+                if ( cacheDylib.inputHdr->isArch("arm64e") )
                     this->addAuthChunk(&segmentInfo);
                 else
                     this->addDataChunk(&segmentInfo);
@@ -834,8 +875,6 @@
                 break;
         }
     }
-
-    this->addLinkeditFromDylib(cacheDylib);
 }
 
 // Linkedit is stored in Chunks in its own array on the dylib.  This adds it to the subCache.
@@ -930,7 +969,8 @@
     return count;
 }
 
-void SubCache::addCacheHeaderChunk(const BuilderConfig& config, const std::span<CacheDylib> cacheDylibs)
+void SubCache::addCacheHeaderChunk(const BuilderOptions& options, const BuilderConfig& config,
+                                   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();
@@ -943,7 +983,7 @@
         startOffset += sizeof(dyld_cache_tpro_mapping_info) * numTPRORegions(config, this, this->subCaches);
     }
 
-    if ( this->needsCacheHeaderImageList() ) {
+    if ( this->needsCacheHeaderImageList(options) ) {
         startOffset += sizeof(dyld_cache_image_info) * cacheDylibs.size();
         startOffset += sizeof(dyld_cache_image_text_info) * cacheDylibs.size();
         for ( const CacheDylib& cacheDylib : cacheDylibs ) {
@@ -1025,7 +1065,7 @@
     addCodeSignatureChunk(this->codeSignature.get());
 }
 
-void SubCache::addObjCOptsHeaderChunk(ObjCOptimizer& objcOptimizer)
+void SubCache::addObjCOptsHeaderChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer)
 {
     this->objcOptsHeader = std::make_unique<ObjCOptsHeaderChunk>();
     this->objcOptsHeader->cacheVMSize       = CacheVMSize(objcOptimizer.optsHeaderByteSize);
@@ -1033,7 +1073,7 @@
 
     objcOptimizer.optsHeaderChunk = this->objcOptsHeader.get();
 
-    this->addLinkeditChunk(this->objcOptsHeader.get());
+    this->addReadOnlyChunk(config, this->objcOptsHeader.get());
 }
 
 void SubCache::addObjCHeaderInfoReadOnlyChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer)
@@ -1148,7 +1188,7 @@
     addObjCReadWriteChunk(config, this->objcCanonicalProtocols.get());
 }
 
-void SubCache::addObjCIMPCachesChunk(ObjCIMPCachesOptimizer& objcIMPCachesOptimizer)
+void SubCache::addObjCIMPCachesChunk(const BuilderConfig& config, ObjCIMPCachesOptimizer& objcIMPCachesOptimizer)
 {
     this->objcIMPCaches = std::make_unique<ObjCIMPCachesChunk>();
     this->objcIMPCaches->cacheVMSize                        = CacheVMSize(objcIMPCachesOptimizer.impCachesTotalByteSize);
@@ -1156,7 +1196,7 @@
 
     objcIMPCachesOptimizer.impCachesChunk = this->objcIMPCaches.get();
 
-    this->addLinkeditChunk(this->objcIMPCaches.get());
+    this->addReadOnlyChunk(config, this->objcIMPCaches.get());
 }
 
 void SubCache::addObjCCategoriesChunk(const BuilderConfig& config,
@@ -1185,16 +1225,26 @@
 
 void SubCache::addPatchTableChunk(PatchTableOptimizer& patchTableOptimizer)
 {
-    // We can't compute the size yet.  We need to know how many fixups we have
-    // And yet we have an estimate, so we'll use it
+    // We can't compute the size yet so just make an empty chunk
 
     this->patchTable = std::make_unique<PatchTableChunk>();
-    this->patchTable->cacheVMSize       = CacheVMSize(patchTableOptimizer.patchTableTotalByteSize);
-    this->patchTable->subCacheFileSize  = CacheFileSize(patchTableOptimizer.patchTableTotalByteSize);
+    this->patchTable->cacheVMSize       = CacheVMSize(0ULL);
+    this->patchTable->subCacheFileSize  = CacheFileSize(0ULL);
 
     patchTableOptimizer.patchTableChunk = this->patchTable.get();
 
     this->addLinkeditChunk(this->patchTable.get());
+}
+
+void SubCache::addFunctionVariantsChunk(FunctionVariantsOptimizer& optimizer)
+{
+    this->functionVariants                    = std::make_unique<FunctionVariantsPatchTableChunk>();
+    this->functionVariants->cacheVMSize       = CacheVMSize(optimizer.fvInfoTotalByteSize);
+    this->functionVariants->subCacheFileSize  = CacheFileSize(optimizer.fvInfoTotalByteSize);
+
+    optimizer.chunk = this->functionVariants.get();
+
+    this->addLinkeditChunk(this->functionVariants.get());
 }
 
 void SubCache::addCacheDylibsLoaderChunk(PrebuiltLoaderBuilder& builder)
@@ -1236,7 +1286,21 @@
     this->addLinkeditChunk(this->executablesTrie.get());
 }
 
-void SubCache::addSwiftOptsHeaderChunk(SwiftProtocolConformanceOptimizer& opt)
+void SubCache::addPrewarmingDataChunk(const BuilderConfig& config, PrewarmingOptimizer& opt)
+{
+    if ( opt.prewarmingByteSize == 0 )
+        return;
+
+    this->prewarmingChunk = std::make_unique<PrewarmingChunk>(Chunk::Kind::prewarmingData);
+    this->prewarmingChunk->cacheVMSize      = CacheVMSize(opt.prewarmingByteSize);
+    this->prewarmingChunk->subCacheFileSize = CacheFileSize(opt.prewarmingByteSize);
+
+    opt.prewarmingChunk = this->prewarmingChunk.get();
+
+    this->addReadOnlyChunk(config, this->prewarmingChunk.get());
+}
+
+void SubCache::addSwiftOptsHeaderChunk(const BuilderConfig& config, SwiftOptimizer& opt)
 {
     this->swiftOptsHeader = std::make_unique<SwiftOptsHeaderChunk>();
     this->swiftOptsHeader->cacheVMSize      = CacheVMSize(opt.optsHeaderByteSize);
@@ -1244,10 +1308,10 @@
 
     opt.optsHeaderChunk = this->swiftOptsHeader.get();
 
-    this->addLinkeditChunk(this->swiftOptsHeader.get());
-}
-
-void SubCache::addSwiftTypeHashTableChunk(SwiftProtocolConformanceOptimizer& opt)
+    this->addReadOnlyChunk(config, this->swiftOptsHeader.get());
+}
+
+void SubCache::addSwiftTypeHashTableChunk(const BuilderConfig& config, SwiftOptimizer& opt)
 {
     this->swiftTypeHashTable = std::make_unique<SwiftProtocolConformancesHashTableChunk>();
     this->swiftTypeHashTable->cacheVMSize       = CacheVMSize(opt.typeConformancesHashTableSize);
@@ -1255,10 +1319,10 @@
 
     opt.typeConformancesHashTable = this->swiftTypeHashTable.get();
 
-    this->addLinkeditChunk(this->swiftTypeHashTable.get());
-}
-
-void SubCache::addSwiftMetadataHashTableChunk(SwiftProtocolConformanceOptimizer& opt)
+    this->addReadOnlyChunk(config, this->swiftTypeHashTable.get());
+}
+
+void SubCache::addSwiftMetadataHashTableChunk(const BuilderConfig& config, SwiftOptimizer& opt)
 {
     this->swiftMetadataHashTable = std::make_unique<SwiftProtocolConformancesHashTableChunk>();
     this->swiftMetadataHashTable->cacheVMSize       = CacheVMSize(opt.metadataConformancesHashTableSize);
@@ -1266,10 +1330,10 @@
 
     opt.metadataConformancesHashTable = this->swiftMetadataHashTable.get();
 
-    this->addLinkeditChunk(this->swiftMetadataHashTable.get());
-}
-
-void SubCache::addSwiftForeignHashTableChunk(SwiftProtocolConformanceOptimizer& opt)
+    this->addReadOnlyChunk(config, this->swiftMetadataHashTable.get());
+}
+
+void SubCache::addSwiftForeignHashTableChunk(const BuilderConfig& config, SwiftOptimizer& opt)
 {
     this->swiftForeignTypeHashTable = std::make_unique<SwiftProtocolConformancesHashTableChunk>();
     this->swiftForeignTypeHashTable->cacheVMSize        = CacheVMSize(opt.foreignTypeConformancesHashTableSize);
@@ -1277,10 +1341,10 @@
 
     opt.foreignTypeConformancesHashTable = this->swiftForeignTypeHashTable.get();
 
-    this->addLinkeditChunk(this->swiftForeignTypeHashTable.get());
-}
-
-void SubCache::addSwiftPrespecializedMetadataPointerTableChunks(SwiftProtocolConformanceOptimizer& opt)
+    this->addReadOnlyChunk(config, this->swiftForeignTypeHashTable.get());
+}
+
+void SubCache::addSwiftPrespecializedMetadataPointerTableChunks(const BuilderConfig& config, SwiftOptimizer& opt)
 {
     for ( PointerHashTableOptimizerInfo& tableInfo : opt.prespecializedMetadataHashTables ) {
         PointerHashTableChunk* chunk = this->pointerHashTables.emplace_back(std::make_unique<PointerHashTableChunk>()).get();
@@ -1288,7 +1352,7 @@
         chunk->subCacheFileSize  = CacheFileSize(tableInfo.size);
 
         tableInfo.chunk = chunk;
-        this->addLinkeditChunk(chunk);
+        this->addReadOnlyChunk(config, chunk);
     }
 }
 
@@ -1485,15 +1549,16 @@
 }
 
 void SubCache::writeCacheHeader(const BuilderOptions& options, const BuilderConfig& config,
-                                const std::span<CacheDylib> cacheDylibs)
+                                const std::span<CacheDylib> cacheDylibs,
+                                uint32_t osVersion, uint32_t altPlatform, uint32_t altOsVersion)
 {
     Chunk& cacheHeaderChunk = *this->cacheHeader.get();
     dyld_cache_header* dyldCacheHeader = (dyld_cache_header*)cacheHeaderChunk.subCacheBuffer;
 
     // "dyld_v1" + spaces + archName(), with enough spaces to pad to 15 bytes
     std::string magic = "dyld_v1";
-    magic.append(15 - magic.length() - strlen(options.archs.name()), ' ');
-    magic.append(options.archs.name());
+    magic.append(15 - magic.length() - strlen(options.arch.name()), ' ');
+    magic.append(options.arch.name());
     assert(magic.length() == 15);
 
     // Num of mappings depends on cache layout.
@@ -1539,12 +1604,14 @@
     dyldCacheHeader->progClosuresSize              = 0; // no longer used
     dyldCacheHeader->progClosuresTrieAddr          = 0; // no longer used
     dyldCacheHeader->progClosuresTrieSize          = 0; // no longer used
-    dyldCacheHeader->platform                      = (uint8_t)options.platform;
+    dyldCacheHeader->platform                      = options.platform.value();
     dyldCacheHeader->formatVersion                 = 0; //dyld3::closure::kFormatVersion;
     dyldCacheHeader->dylibsExpectedOnDisk          = !options.dylibsRemovedFromDisk;
     dyldCacheHeader->simulator                     = options.isSimulator();
     dyldCacheHeader->locallyBuiltCache             = options.isLocallyBuiltCache;
     dyldCacheHeader->builtFromChainedFixups        = false; // no longer used
+    dyldCacheHeader->newFormatTLVs                 = true;
+    dyldCacheHeader->padding                       = 0;
     dyldCacheHeader->sharedRegionStart             = this->subCacheVMAddress.rawValue();
     dyldCacheHeader->sharedRegionSize              = 0;
     dyldCacheHeader->maxSlide                      = 0; // overwritten later in build if the cache supports ASLR
@@ -1562,9 +1629,9 @@
     dyldCacheHeader->programsPBLSetPoolSize        = 0; // set later only on the main cache file
     dyldCacheHeader->programTrieAddr               = 0; // set later only on the main cache file
     dyldCacheHeader->programTrieSize               = 0; // set later only on the main cache file
-    dyldCacheHeader->osVersion                     = 0; // set later only on the main cache file
-    dyldCacheHeader->altPlatform                   = 0; // set later only on the main cache file
-    dyldCacheHeader->altOsVersion                  = 0; // set later only on the main cache file
+    dyldCacheHeader->osVersion                     = osVersion;
+    dyldCacheHeader->altPlatform                   = altPlatform;
+    dyldCacheHeader->altOsVersion                  = altOsVersion;
     dyldCacheHeader->swiftOptsOffset               = 0; // set later only on the main cache file
     dyldCacheHeader->swiftOptsSize                 = 0; // set later only on the main cache file
     dyldCacheHeader->subCacheArrayOffset           = 0;
@@ -1583,6 +1650,8 @@
     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
+    dyldCacheHeader->prewarmingDataOffset          = 0; // set later only on the main cache file
+    dyldCacheHeader->prewarmingDataSize            = 0; // set later only on the main cache file
 
     // Fill in old mappings
     // And new mappings which also have slide info
@@ -1594,14 +1663,15 @@
 void SubCache::addMainCacheHeaderInfo(const BuilderOptions& options, const BuilderConfig& config,
                                       const std::span<CacheDylib> cacheDylibs,
                                       CacheVMSize totalVMSize, uint64_t maxSlide,
-                                      uint32_t osVersion, uint32_t altPlatform, uint32_t altOsVersion,
                                       CacheVMAddress dyldInCacheUnslidAddr,
                                       CacheVMAddress dyldInCacheEntryUnslidAddr,
                                       const DylibTrieOptimizer& dylibTrieOptimizer,
                                       const ObjCOptimizer& objcOptimizer,
-                                      const SwiftProtocolConformanceOptimizer& swiftProtocolConformanceOpt,
+                                      const SwiftOptimizer& swiftOpt,
                                       const PatchTableOptimizer& patchTableOptimizer,
-                                      const PrebuiltLoaderBuilder& prebuiltLoaderBuilder)
+                                      const FunctionVariantsOptimizer& functionVariantOptimizer,
+                                      const PrebuiltLoaderBuilder& prebuiltLoaderBuilder,
+                                      const PrewarmingOptimizer& prewarmingOptimizer)
 {
     const CacheVMAddress cacheBaseAddress = config.layout.cacheBaseAddress;
 
@@ -1614,13 +1684,13 @@
     dyldCacheHeader->dylibsTrieAddr = dylibTrieOptimizer.dylibsTrieChunk->cacheVMAddress.rawValue();
     dyldCacheHeader->dylibsTrieSize = dylibTrieOptimizer.dylibsTrieChunk->subCacheFileSize.rawValue();
 
-    if ( !objcOptimizer.objcDylibs.empty() ) {
+    // Disable objc optimizations from EK shared cache
+    bool emitObjcOpts = !options.platform.isExclaveKit();
+    if ( !objcOptimizer.objcDylibs.empty() && emitObjcOpts ) {
         dyldCacheHeader->objcOptsOffset = (objcOptimizer.optsHeaderChunk->cacheVMAddress - cacheBaseAddress).rawValue();
         dyldCacheHeader->objcOptsSize   = objcOptimizer.optsHeaderChunk->subCacheFileSize.rawValue();
-    }
-
-    if ( !objcOptimizer.objcDylibs.empty() ) {
-        const auto& opt = swiftProtocolConformanceOpt;
+
+        const auto& opt = swiftOpt;
         dyldCacheHeader->swiftOptsOffset = (opt.optsHeaderChunk->cacheVMAddress - cacheBaseAddress).rawValue();
         dyldCacheHeader->swiftOptsSize   = opt.optsHeaderChunk->subCacheFileSize.rawValue();
     }
@@ -1637,16 +1707,15 @@
     dyldCacheHeader->dyldInCacheMH      = dyldInCacheUnslidAddr.rawValue();
     dyldCacheHeader->dyldInCacheEntry   = dyldInCacheEntryUnslidAddr.rawValue();
 
-    dyldCacheHeader->osVersion      = osVersion;
-    dyldCacheHeader->altPlatform    = altPlatform;
-    dyldCacheHeader->altOsVersion   = altOsVersion;
-
     // record max slide now that final size is established
     dyldCacheHeader->maxSlide           = maxSlide;
 
     // TODO: Build the atlas
     dyldCacheHeader->cacheAtlasOffset              = 0; // set later only on the main cache file
     dyldCacheHeader->cacheAtlasSize                = 0; // set later only on the main cache file
+
+    dyldCacheHeader->functionVariantInfoAddr = functionVariantOptimizer.chunk->cacheVMAddress.rawValue();
+    dyldCacheHeader->functionVariantInfoSize = functionVariantOptimizer.fvInfoTotalByteSize;
 
     // The main cache has offsets to all the caches
     if ( !this->subCaches.empty() ) {
@@ -1686,6 +1755,11 @@
             ++index;
         });
     }
+
+    if ( prewarmingOptimizer.prewarmingChunk != nullptr ) {
+        dyldCacheHeader->prewarmingDataOffset = (prewarmingOptimizer.prewarmingChunk->cacheVMAddress - cacheBaseAddress).rawValue();
+        dyldCacheHeader->prewarmingDataSize   = prewarmingOptimizer.prewarmingChunk->subCacheFileSize.rawValue();
+    }
 }
 
 void SubCache::addSymbolsCacheHeaderInfo(const UnmappedSymbolsOptimizer& optimizer)
@@ -1712,7 +1786,7 @@
                                        const BuilderConfig& config,
                                        const std::span<CacheDylib> cacheDylibs)
 {
-    if ( !this->needsCacheHeaderImageList() )
+    if ( !this->needsCacheHeaderImageList(options) )
         return;
 
     Chunk&             cacheHeaderChunk   = *this->cacheHeader.get();
@@ -1738,7 +1812,7 @@
 
     // write text image array and image names pool at same time
     for ( const CacheDylib& cacheDylib : cacheDylibs ) {
-        cacheDylib.inputMF->getUuid(textImages->uuid);
+        cacheDylib.inputHdr->getUuid(textImages->uuid);
         textImages->loadAddress     = cacheDylib.cacheLoadAddress.rawValue();
         textImages->textSegmentSize = (uint32_t)cacheDylib.segments.front().cacheVMSize.rawValue();
         textImages->pathOffset      = stringOffset;
@@ -1846,16 +1920,17 @@
     return this->kind == Kind::stubsCustomer;
 }
 
-bool SubCache::needsCacheHeaderImageList() const
+bool SubCache::needsCacheHeaderImageList(const BuilderOptions& options) const
 {
     // Symbols and stubs files don't need an image list
-    // We'd like to not add the image list to subcaches, only the main cache, but Rosetta needs
-    // the image list on subCaches.
     switch ( this->kind ) {
         case Kind::mainDevelopment:
         case Kind::mainCustomer:
+            return true;
         case Kind::subUniversal:
-            return true;
+            // We'd like to not add the image list to subcaches, only the main cache, but Rosetta needs
+            // the image list on subCaches.
+            return options.arch.sameCpu(mach_o::Architecture::x86_64);
         case Kind::stubsDevelopment:
         case Kind::stubsCustomer:
         case Kind::symbols: