Loading...
cache_builder/SubCache.cpp dyld-1066.10 dyld-1162
--- dyld/dyld-1066.10/cache_builder/SubCache.cpp
+++ dyld/dyld-1162/cache_builder/SubCache.cpp
@@ -754,7 +754,6 @@
 // All objc optimizations need to be contiguous, but that means if any need AUTH then all do
 void SubCache::addObjCReadWriteChunk(const BuilderConfig& config, Chunk* chunk)
 {
-    // Add canonical objc protocols
     if ( config.layout.hasAuthRegion ) {
         addAuthChunk(chunk);
     }
@@ -926,6 +925,17 @@
     this->addObjCReadOnlyChunk(this->objcHeaderInfoRO.get());
 }
 
+void SubCache::addObjCImageInfoChunk(ObjCOptimizer& objcOptimizer)
+{
+    this->objcImageInfo = std::make_unique<ObjCImageInfoChunk>();
+    this->objcImageInfo->cacheVMSize         = CacheVMSize(objcOptimizer.imageInfoSize);
+    this->objcImageInfo->subCacheFileSize    = CacheFileSize(objcOptimizer.imageInfoSize);
+
+    objcOptimizer.imageInfoChunk = this->objcImageInfo.get();
+
+    this->addObjCReadOnlyChunk(this->objcImageInfo.get());
+}
+
 void SubCache::addObjCSelectorStringsChunk(ObjCSelectorOptimizer& objCSelectorOptimizer)
 {
     this->objcSelectorStrings = std::make_unique<ObjCStringsChunk>();
@@ -1003,6 +1013,19 @@
     this->addObjCReadOnlyChunk(this->objcSwiftDemangledNameStrings.get());
 }
 
+void SubCache::addObjCCanonicalProtocolsChunk(const BuilderConfig& config,
+                                              ObjCProtocolOptimizer& objcProtocolOptimizer)
+{
+    this->objcCanonicalProtocols = std::make_unique<ObjCCanonicalProtocolsChunk>();
+    this->objcCanonicalProtocols->cacheVMSize         = CacheVMSize(objcProtocolOptimizer.canonicalProtocolsTotalByteSize);
+    this->objcCanonicalProtocols->subCacheFileSize    = CacheFileSize(objcProtocolOptimizer.canonicalProtocolsTotalByteSize);
+
+    objcProtocolOptimizer.canonicalProtocolsChunk = this->objcCanonicalProtocols.get();
+
+    // Add canonical objc protocols
+    addObjCReadWriteChunk(config, this->objcCanonicalProtocols.get());
+}
+
 void SubCache::addObjCIMPCachesChunk(ObjCIMPCachesOptimizer& objcIMPCachesOptimizer)
 {
     this->objcIMPCaches = std::make_unique<ObjCIMPCachesChunk>();
@@ -1014,17 +1037,17 @@
     this->addLinkeditChunk(this->objcIMPCaches.get());
 }
 
-void SubCache::addObjCCanonicalProtocolsChunk(const BuilderConfig& config,
-                                              ObjCProtocolOptimizer& objcProtocolOptimizer)
-{
-    this->objcCanonicalProtocols = std::make_unique<ObjCCanonicalProtocolsChunk>();
-    this->objcCanonicalProtocols->cacheVMSize         = CacheVMSize(objcProtocolOptimizer.canonicalProtocolsTotalByteSize);
-    this->objcCanonicalProtocols->subCacheFileSize    = CacheFileSize(objcProtocolOptimizer.canonicalProtocolsTotalByteSize);
-
-    objcProtocolOptimizer.canonicalProtocolsChunk = this->objcCanonicalProtocols.get();
-
-    // Add canonical objc protocols
-    addObjCReadWriteChunk(config, this->objcCanonicalProtocols.get());
+void SubCache::addObjCCategoriesChunk(const BuilderConfig& config,
+                                     ObjCCategoryOptimizer& objcCategoryOptimizer)
+{
+    this->objcCategories = std::make_unique<ObjCPreAttachedCategoriesChunk>();
+    this->objcCategories->cacheVMSize        = CacheVMSize(objcCategoryOptimizer.categoriesTotalByteSize);
+    this->objcCategories->subCacheFileSize   = CacheFileSize(objcCategoryOptimizer.categoriesTotalByteSize);
+
+    objcCategoryOptimizer.categoriesChunk = this->objcCategories.get();
+
+    // Add objc categories
+    addObjCReadOnlyChunk(this->objcCategories.get());
 }
 
 void SubCache::addCacheTrieChunk(DylibTrieOptimizer& dylibTrieOptimizer)
@@ -1362,7 +1385,7 @@
     dyldCacheHeader->platform                      = (uint8_t)options.platform;
     dyldCacheHeader->formatVersion                 = 0; //dyld3::closure::kFormatVersion;
     dyldCacheHeader->dylibsExpectedOnDisk          = !options.dylibsRemovedFromDisk;
-    dyldCacheHeader->simulator                     = options.isSimultor();
+    dyldCacheHeader->simulator                     = options.isSimulator();
     dyldCacheHeader->locallyBuiltCache             = options.isLocallyBuiltCache;
     dyldCacheHeader->builtFromChainedFixups        = false; // no longer used
     dyldCacheHeader->sharedRegionStart             = this->subCacheVMAddress.rawValue();
@@ -1947,6 +1970,110 @@
     return Error();
 }
 
+Error SubCache::computeSlideInfoV5(const BuilderConfig&           config,
+                                   cache_builder::SlideInfoChunk* slideChunk,
+                                   Region&                        region)
+{
+    __block Diagnostics diag;
+
+    bool canContainAuthPointers = region.canContainAuthPointers();
+
+    assert((region.subCacheVMSize.rawValue() % config.slideInfo.slideInfoPageSize) == 0);
+    dyld_cache_slide_info5* info    = (dyld_cache_slide_info5*)slideChunk->subCacheBuffer;
+    info->version                   = 5;
+    info->page_size                 = config.slideInfo.slideInfoPageSize;
+    info->page_starts_count         = (uint32_t)region.subCacheVMSize.rawValue() / config.slideInfo.slideInfoPageSize;
+    info->value_add                 = config.layout.cacheBaseAddress.rawValue();
+
+    assert((sizeof(dyld_cache_slide_info5) + (info->page_starts_count * sizeof(uint16_t))) <= slideChunk->cacheVMSize.rawValue());
+
+    std::fill(&info->page_starts[0], &info->page_starts[info->page_starts_count], DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE);
+
+    // Walk each fixup in each segment.  Every time we cross a page, add a page start
+    __block dyld_cache_slide_pointer5* lastFixup     = nullptr;
+    __block uint64_t                   lastPageIndex = ~0ULL;
+    for ( Chunk* chunk : region.chunks ) {
+        SlidChunk* slidChunk = chunk->isSlidChunk();
+
+        slidChunk->tracker.forEachFixup(^(void *loc, bool& stop) {
+            // V5 fixups must be 8-byte aligned
+            assert(((uint64_t)loc % 8) == 0);
+
+            VMOffset       vmOffsetInSegment((uint64_t)loc - (uint64_t)slidChunk->subCacheBuffer);
+            CacheVMAddress fixupVMAddr = slidChunk->cacheVMAddress + vmOffsetInSegment;
+            uint64_t       pageIndex   = (fixupVMAddr - region.subCacheVMAddress).rawValue() / info->page_size;
+
+            // If we are on a new page, then start a new chain
+            if ( pageIndex != lastPageIndex ) {
+                uint64_t vmOffsetInPage      = fixupVMAddr.rawValue() % info->page_size;
+                info->page_starts[pageIndex] = vmOffsetInPage;
+            }
+            else {
+                // Patch the previous fixup on this page to point to this one
+                lastFixup->auth.next = ((uint64_t)loc - (uint64_t)lastFixup) / 8;
+            }
+
+            dyld_cache_slide_pointer5* fixupLocation = (dyld_cache_slide_pointer5*)loc;
+
+            // Convert this fixup from the chained format in the cache builder, to the version we want in the cache file
+            CacheVMAddress vmAddr = Fixup::Cache64::getCacheVMAddressFromLocation(config.layout.cacheBaseAddress,
+                                                                                  loc);
+
+            uint8_t high8 = Fixup::Cache64::getHigh8(loc);
+            VMOffset cacheVMOffset = vmAddr - config.layout.cacheBaseAddress;
+
+            uint16_t    authDiversity  = 0;
+            bool        authIsAddr     = false;
+            uint8_t     authKey        = 0;
+            if ( Fixup::Cache64::hasAuthData(loc, authDiversity, authIsAddr, authKey) ) {
+                // Authenticated value
+                assert(high8 == 0);
+                assert(canContainAuthPointers);
+                assert((authKey == 0) || (authKey == 2)); // IA (0) or DA (2)
+
+                fixupLocation->auth.runtimeOffset       = cacheVMOffset.rawValue();
+                fixupLocation->auth.diversity           = authDiversity;
+                fixupLocation->auth.addrDiv             = authIsAddr ? 1 : 0;
+                fixupLocation->auth.keyIsData           = (authKey == 2) ? 1 : 0;
+                fixupLocation->auth.next                = 0;
+                fixupLocation->auth.auth                = 1;
+
+                if ( fixupLocation->auth.runtimeOffset != cacheVMOffset.rawValue() ) {
+                    diag.error("cache offset 0x%llx exceeds v5 format", cacheVMOffset.rawValue());
+                    stop = true;
+                    return;
+                }
+            } else {
+                // Unauthenticated value
+                fixupLocation->regular.runtimeOffset    = cacheVMOffset.rawValue();
+                fixupLocation->regular.high8            = high8;
+                fixupLocation->regular.next             = 0;
+                fixupLocation->regular.unused           = 0;
+                fixupLocation->regular.auth             = 0;
+
+                if ( fixupLocation->regular.runtimeOffset != cacheVMOffset.rawValue() ) {
+                    diag.error("cache offset 0x%llx exceeds v5 format", cacheVMOffset.rawValue());
+                    stop = true;
+                    return;
+                }
+            }
+
+            lastFixup     = fixupLocation;
+            lastPageIndex = pageIndex;
+        });
+        if ( diag.hasError() )
+            break;
+    }
+
+    if ( diag.hasError() )
+        return Error("could not build slide info because: %s", diag.errorMessageCStr());
+
+    // V5 doesn't deduplicate content like V1, so the used size is the original size too
+    slideChunk->usedFileSize = slideChunk->subCacheFileSize;
+
+    return Error();
+}
+
 Error SubCache::computeSlideInfoForRegion(const BuilderConfig&           config,
                                           cache_builder::SlideInfoChunk* slideChunk,
                                           Region&                        region)
@@ -1958,6 +2085,8 @@
             return computeSlideInfoV2(config, slideChunk, region);
         case cache_builder::SlideInfo::SlideInfoFormat::v3:
             return computeSlideInfoV3(config, slideChunk, region);
+        case cache_builder::SlideInfo::SlideInfoFormat::v5:
+            return computeSlideInfoV5(config, slideChunk, region);
     }
 
     return Error();