Loading...
common/MetadataVisitor.cpp dyld-1066.8 dyld-1330
--- dyld/dyld-1066.8/common/MetadataVisitor.cpp
+++ dyld/dyld-1330/common/MetadataVisitor.cpp
@@ -22,6 +22,10 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <TargetConditionals.h>
+
+#if !TARGET_OS_EXCLAVEKIT
+
 #include "MetadataVisitor.h"
 
 #if SUPPORT_VM_LAYOUT
@@ -43,6 +47,8 @@
 typedef cache_builder::Fixup::Cache64 Cache64;
 #endif
 
+using mach_o::Header;
+
 //
 // MARK: --- ResolvedValue methods ---
 //
@@ -102,8 +108,10 @@
 
 #if POINTERS_ARE_UNSLID
 
-Visitor::Visitor(const DyldSharedCache* dyldCache, const dyld3::MachOAnalyzer* dylibMA)
-    : dylibMA(dylibMA), dylibBaseAddress(dylibMA->preferredLoadAddress())
+Visitor::Visitor(const DyldSharedCache* dyldCache, const dyld3::MachOAnalyzer* dylibMA,
+                 std::optional<VMAddress> selectorStringsBaseAddress)
+    : dylibMA(dylibMA), dylibBaseAddress(((const Header*)dylibMA)->preferredLoadAddress()),
+      selectorStringsBaseAddress(selectorStringsBaseAddress)
 {
     pointerSize = dylibMA->pointerSize();
 
@@ -114,7 +122,7 @@
             cache->forEachSlideInfo(^(uint64_t mappingStartAddress, uint64_t mappingSize, const uint8_t *mappingPagesStart, uint64_t slideInfoOffset, uint64_t slideInfoSize, const dyld_cache_slide_info *slideInfoHeader) {
                 if ( slideInfoHeader->version == 1 ) {
                     this->sharedCacheChainedPointerFormat       = SharedCacheFormat::v1;
-                    this->onDiskDylibChainedPointerBaseAddress  = VMAddress(0ULL);
+                    this->onDiskDylibChainedPointerBaseAddress  = VMAddress(dyldCache->unslidLoadAddress());
                 } else if ( slideInfoHeader->version == 2 ) {
                     const dyld_cache_slide_info2* slideInfo = (dyld_cache_slide_info2*)(slideInfoHeader);
                     assert(slideInfo->delta_mask == 0x00FFFF0000000000);
@@ -128,6 +136,9 @@
                     assert(slideInfo->delta_mask == 0x00000000C0000000);
                     this->sharedCacheChainedPointerFormat       = SharedCacheFormat::v4;
                     this->onDiskDylibChainedPointerBaseAddress  = VMAddress(slideInfo->value_add);
+                } else if ( slideInfoHeader->version == 5 ) {
+                    this->sharedCacheChainedPointerFormat       = SharedCacheFormat::v5;
+                    this->onDiskDylibChainedPointerBaseAddress  = VMAddress(dyldCache->unslidLoadAddress());
                 } else {
                     assert(false);
                 }
@@ -142,7 +153,7 @@
 #elif SUPPORT_VM_LAYOUT
 
 Visitor::Visitor(const dyld3::MachOAnalyzer* dylibMA)
-    : dylibMA(dylibMA), dylibBaseAddress(dylibMA->preferredLoadAddress())
+    : dylibMA(dylibMA), dylibBaseAddress(((const Header*)dylibMA)->preferredLoadAddress())
 {
     pointerSize = dylibMA->pointerSize();
 }
@@ -184,12 +195,14 @@
 
 #endif
 
+#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS || POINTERS_ARE_UNSLID
+VMAddress Visitor::sharedCacheSelectorStringsBaseAddress() const
+{
+    return this->selectorStringsBaseAddress.value();
+}
+#endif
+
 #if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-VMAddress Visitor::sharedCacheSelectorStringsBaseAddress() const
-{
-    return this->selectorStringsBaseAddress.value();
-}
-
 VMAddress Visitor::getOnDiskDylibChainedPointerBaseAddress() const
 {
     assert(this->isOnDiskDylib);
@@ -200,6 +213,12 @@
 {
     return this->dylibMF;
 }
+
+const Header* Visitor::hdr() const
+{
+    return (const Header*)this->dylibMF;
+}
+
 
 bool Visitor::isOnDiskBinary() const
 {
@@ -262,7 +281,7 @@
             case SharedCacheFormat::none:
                 assert(false);
             case SharedCacheFormat::v1: {
-                // Nothing to do here.  We don't have chained fixup bits to remove, or a value_add to apply
+                runtimeOffset = *(uint32_t*)value.value() - onDiskDylibChainedPointerBaseAddress.rawValue();
                 break;
             }
             case SharedCacheFormat::v2_x86_64_tbi: {
@@ -293,6 +312,14 @@
                 rawValue = (rawValue & valueMask);
                 // Already a runtime offset, so no need to do anything with valueAdd
                 runtimeOffset = rawValue;
+                break;
+            }
+            case SharedCacheFormat::v5: {
+                // Just use the chained pointer format for arm64/arm64e shared caches
+                auto* chainedValue = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+                chainedValue->isRebase(DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE,
+                                       onDiskDylibChainedPointerBaseAddress.rawValue(),
+                                       runtimeOffset);
                 break;
             }
         }
@@ -424,7 +451,10 @@
             case SharedCacheFormat::none:
                 assert(false);
             case SharedCacheFormat::v1: {
-                // Nothing to do here.  We don't have chained fixup bits to remove, or a value_add to apply
+                uint64_t rawvalue = *(uint32_t*)value.value();
+                if ( rawvalue == 0 )
+                    return { };
+                runtimeOffset = rawvalue - onDiskDylibChainedPointerBaseAddress.rawValue();
                 break;
             }
             case SharedCacheFormat::v2_x86_64_tbi: {
@@ -462,6 +492,17 @@
                 rawValue = (rawValue & valueMask);
                 // Already a runtime offset, so no need to do anything with valueAdd
                 runtimeOffset = rawValue;
+                break;
+            }
+            case SharedCacheFormat::v5: {
+                // Just use the chained pointer format for arm64/arm64e shared caches
+                auto* chainedValue = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+                if ( chainedValue->raw64 == 0 )
+                    return { };
+
+                chainedValue->isRebase(DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE,
+                                       onDiskDylibChainedPointerBaseAddress.rawValue(),
+                                       runtimeOffset);
                 break;
             }
         }
@@ -574,7 +615,109 @@
 
 std::optional<VMAddress> Visitor::resolveOptionalRebaseToVMAddress(const ResolvedValue& value) const
 {
-#if SUPPORT_VM_LAYOUT
+#if POINTERS_ARE_UNSLID
+    const void* targetValue = (const void*)*(uintptr_t*)value.value();
+
+    // FIXME: We didn't expect a null here.  Should we find a way to error out, or just let the parser
+    // crash with a nullptr dereference.
+    if ( targetValue == nullptr )
+        return std::nullopt;
+
+    uint64_t runtimeOffset = 0;
+
+    if ( this->sharedCacheChainedPointerFormat != SharedCacheFormat::none ) {
+        // Crack the shared cache slide format
+        switch ( this->sharedCacheChainedPointerFormat ) {
+            case SharedCacheFormat::none:
+                assert(false);
+            case SharedCacheFormat::v1: {
+                uint64_t rawvalue = *(uint32_t*)value.value();
+                if ( rawvalue == 0 )
+                    return { };
+                runtimeOffset = rawvalue - onDiskDylibChainedPointerBaseAddress.rawValue();
+                break;
+            }
+            case SharedCacheFormat::v2_x86_64_tbi: {
+                const auto* fixup = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+                uint64_t rawValue = fixup->raw64;
+                if ( rawValue == 0 )
+                    return { };
+
+                const uint64_t   deltaMask    = 0x00FFFF0000000000;
+                const uint64_t   valueMask    = ~deltaMask;
+                rawValue = (rawValue & valueMask);
+                // Already a runtime offset, so no need to do anything with valueAdd
+                runtimeOffset = rawValue;
+                break;
+            }
+            case SharedCacheFormat::v3: {
+                // Just use the chained pointer format for arm64e
+                auto* chainedValue = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+                if ( chainedValue->raw64 == 0 )
+                    return { };
+
+                chainedValue->isRebase(DYLD_CHAINED_PTR_ARM64E,
+                                       onDiskDylibChainedPointerBaseAddress.rawValue(),
+                                       runtimeOffset);
+                break;
+            }
+            case SharedCacheFormat::v4: {
+                const auto* fixup = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+                uint64_t rawValue = fixup->raw32;
+                if ( rawValue == 0 )
+                    return { };
+
+                const uint64_t   deltaMask    = 0x00000000C0000000;
+                const uint64_t   valueMask    = ~deltaMask;
+                rawValue = (rawValue & valueMask);
+                // Already a runtime offset, so no need to do anything with valueAdd
+                runtimeOffset = rawValue;
+                break;
+            }
+            case SharedCacheFormat::v5: {
+                // Just use the chained pointer format for arm64/arm64e shared caches
+                auto* chainedValue = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+                if ( chainedValue->raw64 == 0 )
+                    return { };
+
+                chainedValue->isRebase(DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE,
+                                       onDiskDylibChainedPointerBaseAddress.rawValue(),
+                                       runtimeOffset);
+                break;
+            }
+        }
+    } else {
+        const auto* fixup = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)value.value();
+        if ( this->chainedPointerFormat == 0 ) {
+            // HACK: 32-bit cache dylibs don't have enough bits to have real chains, so we pretend they
+            // have no chains, just raw VMAddr's
+            assert(dylibMA->hasOpcodeFixups());
+
+            // HACK: This is a binary without chained fixups.  Is it safe to assume this is a rebase?
+            uint64_t rebaseVMAddr = (pointerSize == 8) ? fixup->raw64 : fixup->raw32;
+            if ( rebaseVMAddr == 0 )
+                return { };
+
+            runtimeOffset = rebaseVMAddr - this->onDiskDylibChainedPointerBaseAddress.rawValue();
+        } else {
+            if ( pointerSize == 8 ) {
+                if ( fixup->raw64 == 0 )
+                    return { };
+            } else {
+                if ( fixup->raw32 == 0 )
+                    return { };
+            }
+
+            bool isRebase = fixup->isRebase(this->chainedPointerFormat,
+                                            onDiskDylibChainedPointerBaseAddress.rawValue(),
+                                            runtimeOffset);
+            assert(isRebase);
+        }
+    }
+
+    VMAddress targetVMAddress = onDiskDylibChainedPointerBaseAddress + VMOffset(runtimeOffset);
+    return targetVMAddress;
+#elif SUPPORT_VM_LAYOUT
     // In dyld, we just use raw pointers for everything, and don't need to indirect via segment+offset like
     // in the cache builder
     const void* targetValue = (const void*)*(uintptr_t*)value.value();
@@ -681,3 +824,5 @@
     }
 }
 #endif
+
+#endif // !TARGET_OS_EXCLAVEKIT