Loading...
common/CachePatching.h dyld-1340 dyld-1042.1
--- dyld/dyld-1340/common/CachePatching.h
+++ dyld/dyld-1042.1/common/CachePatching.h
@@ -29,7 +29,7 @@
 #include "Types.h"
 
 #if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-#include "../cache_builder/Error.h"
+#include "Error.h"
 
 #include <assert.h>
 #include <map>
@@ -79,7 +79,10 @@
                         discriminator           : 16;
 
     uint64_t getAddend() const {
-        return addend;
+        uint64_t unsingedAddend = addend;
+        int64_t signedAddend = (int64_t)unsingedAddend;
+        signedAddend = (signedAddend << 52) >> 52;
+        return (uint64_t)signedAddend;
     }
 };
 
@@ -167,7 +170,10 @@
                 discriminator           : 16;
 
     uint64_t getAddend() const {
-        return addend;
+        uint64_t unsingedAddend = addend;
+        int64_t signedAddend = (int64_t)unsingedAddend;
+        signedAddend = (signedAddend << 52) >> 52;
+        return (uint64_t)signedAddend;
     }
 };
 
@@ -210,107 +216,12 @@
                 discriminator           : 16;
 
     uint64_t getAddend() const {
-        return addend;
-    }
-};
-
-//
-// MARK: --- V4 patching.  This is V3 plus a new layout for larger addends ---
-//
-
-struct dyld_cache_patch_info_v4 : dyld_cache_patch_info_v3 {
-    // We didn't add any new files, just changed the type of the patch location structs below
-};
-
-struct dyld_cache_patchable_location_v4
-{
-    struct Auth
-    {
-        uint32_t    authenticated           : 1,    // == 1
-                    high7                   : 7,
-                    isWeakImport            : 1,
-                    addend                  : 5,    // 0..31
-                    usesAddressDiversity    : 1,
-                    keyIsD                  : 1,    // B keys are not permitted.  So this is just whether the A key is I or D (0 => I, 1 => D)
-                    discriminator           : 16;
-    };
-    struct Regular
-    {
-        uint32_t    authenticated           : 1,    // == 0
-                    high7                   : 7,
-                    isWeakImport            : 1,
-                    addend                  : 23;
-    };
-
-    uint32_t    dylibOffsetOfUse;               // Offset from the dylib we used to get a dyld_cache_image_clients_v2
-    union {
-        Auth auth;
-        Regular regular;
-    };
-
-    void getPMD(dyld3::MachOFile::PointerMetaData& pmd) const {
-        if ( this->auth.authenticated ) {
-            pmd.diversity         = auth.discriminator;
-            pmd.high8             = auth.high7 << 1;
-            pmd.authenticated     = auth.authenticated;
-            pmd.key               = auth.keyIsD ? 2 : 0;
-            pmd.usesAddrDiversity = auth.usesAddressDiversity;
-        } else {
-            pmd.diversity         = 0;
-            pmd.high8             = regular.high7 << 1;
-            pmd.authenticated     = 0;
-            pmd.key               = 0;
-            pmd.usesAddrDiversity = 0;
-        }
-    }
-
-    uint64_t getAddend() const {
-        return this->auth.authenticated ? this->auth.addend : this->regular.addend;
-    }
-
-    bool isWeakImport() const {
-        return this->auth.authenticated ? this->auth.isWeakImport : this->regular.isWeakImport;
-    }
-};
-
-static_assert(sizeof(dyld_cache_patchable_location_v4) == sizeof(uint64_t), "Overflow");
-
-struct dyld_cache_patchable_location_v4_got
-{
-    uint64_t    cacheOffsetOfUse;               // Offset from the cache header
-    union {
-        dyld_cache_patchable_location_v4::Auth auth;
-        dyld_cache_patchable_location_v4::Regular regular;
-    };
-    uint32_t unusedPadding;
-
-    void getPMD(dyld3::MachOFile::PointerMetaData& pmd) const {
-        if ( this->auth.authenticated ) {
-            pmd.diversity         = auth.discriminator;
-            pmd.high8             = auth.high7 << 1;
-            pmd.authenticated     = auth.authenticated;
-            pmd.key               = auth.keyIsD ? 2 : 0;
-            pmd.usesAddrDiversity = auth.usesAddressDiversity;
-        } else {
-            pmd.diversity         = 0;
-            pmd.high8             = regular.high7 << 1;
-            pmd.authenticated     = 0;
-            pmd.key               = 0;
-            pmd.usesAddrDiversity = 0;
-        }
-    }
-
-    uint64_t getAddend() const {
-        return this->auth.authenticated ? this->auth.addend : this->regular.addend;
-    }
-
-    bool isWeakImport() const {
-        return this->auth.authenticated ? this->auth.isWeakImport : this->regular.isWeakImport;
-    }
-};
-
-static_assert(sizeof(dyld_cache_patchable_location_v4_got) == (2 * sizeof(uint64_t)), "Overflow");
-
+        uint64_t unsingedAddend = addend;
+        int64_t signedAddend = (int64_t)unsingedAddend;
+        signedAddend = (signedAddend << 52) >> 52;
+        return (uint64_t)signedAddend;
+    }
+};
 
 // The base class for patch tables.  Forwards to one of the subclasses, depending on the version
 // Note that the version 1 table doesn't use the struct below, as it had a different layout.
@@ -348,21 +259,18 @@
 
     // Walk all uses of a given export in a given dylib
     typedef void (^ExportUseHandler)(uint32_t userImageIndex, uint32_t userVMOffset,
-                                     dyld3::MachOFile::PointerMetaData pmd, uint64_t addend,
-                                     bool isWeakImport);
+                                     dyld3::MachOFile::PointerMetaData pmd, uint64_t addend);
     void forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
                                      ExportUseHandler handler) const;
 
     typedef void (^ExportUseInImageHandler)(uint32_t userVMOffset,
-                                            dyld3::MachOFile::PointerMetaData pmd, uint64_t addend,
-                                            bool isWeakImport);
+                                            dyld3::MachOFile::PointerMetaData pmd, uint64_t addend);
     void forEachPatchableUseOfExportInImage(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
                                             uint32_t userImageIndex,
                                             ExportUseInImageHandler handler) const;
 
     typedef void (^ExportCacheUseHandler)(uint64_t cacheVMOffset,
-                                          dyld3::MachOFile::PointerMetaData pmd, uint64_t addend,
-                                          bool isWeakImport);
+                                          dyld3::MachOFile::PointerMetaData pmd, uint64_t addend);
     typedef uint64_t (^GetDylibAddressHandler)(uint32_t dylibCacheIndex);
     void forEachPatchableCacheUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
                                           uint64_t cacheUnslidAddress,
@@ -370,7 +278,7 @@
                                           ExportCacheUseHandler handler) const;
 
     typedef void (^GOTUseHandler)(uint64_t cacheVMOffset, dyld3::MachOFile::PointerMetaData pmd,
-                                  uint64_t addend, bool isWeakImport);
+                                  uint64_t addend);
     void forEachPatchableGOTUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
                                         GOTUseHandler handler) const;
 
@@ -379,8 +287,6 @@
     }
 
     static const char* patchKindName(PatchKind patchKind);
-
-    void dump() const;
 
 private:
     const dyld_cache_patch_info* info() const;
@@ -456,115 +362,36 @@
 
 private:
     const dyld_cache_patch_info_v3*             info() const;
-    std::span<dyld_cache_patchable_location_v3> gotPatchableLocations() const;
-
-protected:
-    // These are also used by PatchTableV4, so we need them to be protected, not private
     std::span<dyld_cache_image_got_clients_v3>  gotClients() const;
     std::span<dyld_cache_patchable_export_v3>   gotClientExports() const;
+    std::span<dyld_cache_patchable_location_v3> gotPatchableLocations() const;
     std::span<dyld_cache_patchable_export_v3>   gotClientExportsForImage(uint32_t imageIndex) const;
-};
-
-// Wraps a dyld_cache_patch_info_v4 with various helper methods.  Use PatchTable above to
-// dispatch to this automatically
-struct PatchTableV4 : PatchTableV3
-{
-    // "virtual" methods from PatchTable
-    using PatchTableV3::numImages;
-    using PatchTableV3::patchableExportCount;
-    using PatchTableV3::imageHasClient;
-    using PatchTableV3::forEachPatchableExport;
-
-    // We need new versions of all of these as the patch location is used by them
-    void forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
-                                     ExportUseHandler handler) const;
-    void forEachPatchableUseOfExportInImage(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
-                                            uint32_t userImageIndex,
-                                            ExportUseInImageHandler handler) const;
-    void forEachPatchableCacheUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
-                                          uint64_t cacheUnslidAddress,
-                                          GetDylibAddressHandler getDylibHandler,
-                                          ExportCacheUseHandler handler) const;
-    void forEachPatchableGOTUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
-                                        GOTUseHandler handler) const;
-
-    void dump() const;
-
-private:
-    const dyld_cache_patch_info_v4*     info() const;
-
-    std::span<dyld_cache_patchable_location_v4> patchableLocations() const;
-    std::span<dyld_cache_patchable_location_v4_got> gotPatchableLocations() const;
 };
 
 #if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
 namespace cache_builder
 {
 
-enum class UniquedGOTKind { regular, authGot, authPtr };
-
 struct CacheDylib;
-struct Chunk;
-
-// This defines a location in a dylib which should be tracked in the patch table
-struct DyldCachePatchableLocation
-{
-    DyldCachePatchableLocation(InputDylibVMOffset clientDylibOffset,
-                               dyld3::MachOFile::PointerMetaData pmd,
-                               uint64_t addend, bool isWeakImport);
-    ~DyldCachePatchableLocation() = default;
-    DyldCachePatchableLocation(const DyldCachePatchableLocation&) = default;
-    DyldCachePatchableLocation(DyldCachePatchableLocation&&) = default;
-    DyldCachePatchableLocation& operator=(const DyldCachePatchableLocation&) = default;
-    DyldCachePatchableLocation& operator=(DyldCachePatchableLocation&&) = default;
-
-    bool operator==(const DyldCachePatchableLocation& other) const = default;
-
-    // When building the patch table, we might not know the final address of the locations, but we do know
-    // where they are in a given input dylib, so record that on all fixups and adjust them later to VMAddrs
-    InputDylibVMOffset  clientDylibOffset;
+
+struct dyld_cache_patchable_location
+{
+    dyld_cache_patchable_location(CacheVMAddress cacheVMAddr, dyld3::MachOFile::PointerMetaData pmd, uint64_t addend);
+    ~dyld_cache_patchable_location() = default;
+    dyld_cache_patchable_location(const dyld_cache_patchable_location&) = default;
+    dyld_cache_patchable_location(dyld_cache_patchable_location&&) = default;
+    dyld_cache_patchable_location& operator=(const dyld_cache_patchable_location&) = default;
+    dyld_cache_patchable_location& operator=(dyld_cache_patchable_location&&) = default;
+
+    bool operator==(const dyld_cache_patchable_location& other) const = default;
+
+    CacheVMAddress      cacheVMAddr;
     uint64_t            high7                   : 7,
-                        unused                  : 4,
-                        isWeakImport            : 1,
+                        addend                  : 5,    // 0..31
                         authenticated           : 1,
                         usesAddressDiversity    : 1,
                         key                     : 2,
-                        discriminator           : 16,
-                        addend                  : 32;
-};
-
-// This defines a location in a coalesced GOT which should be tracked in the patch table
-struct DyldCachePatchableGOTLocation
-{
-    DyldCachePatchableGOTLocation(const Chunk* clientGOT, VMOffset clientGOTOffset,
-                                  dyld3::MachOFile::PointerMetaData pmd,
-                                  uint64_t addend, bool isWeakImport);
-    ~DyldCachePatchableGOTLocation() = default;
-    DyldCachePatchableGOTLocation(const DyldCachePatchableGOTLocation&) = default;
-    DyldCachePatchableGOTLocation(DyldCachePatchableGOTLocation&&) = default;
-    DyldCachePatchableGOTLocation& operator=(const DyldCachePatchableGOTLocation&) = default;
-    DyldCachePatchableGOTLocation& operator=(DyldCachePatchableGOTLocation&&) = default;
-
-    bool operator==(const DyldCachePatchableGOTLocation& other) const = default;
-
-    // When building the patch table, we might not know the final address of the locations, but we do know
-    // where they are in a given GOT, so record that on all fixups and adjust them later to VMAddrs
-    const Chunk*        clientGOT;
-    VMOffset            clientGOTOffset;
-    uint64_t            high7                   : 7,
-                        unused                  : 4,
-                        isWeakImport            : 1,
-                        authenticated           : 1,
-                        usesAddressDiversity    : 1,
-                        key                     : 2,
-                        discriminator           : 16,
-                        addend                  : 32;
-};
-
-struct DylibOffset
-{
-    const CacheDylib*   cacheDylib = nullptr;
-    InputDylibVMOffset  vmOffset;
+                        discriminator           : 16;
 };
 
 // There will be one of these PatchInfo structs for each dylib in the cache
@@ -572,17 +399,13 @@
 {
     struct GOTInfo
     {
-        DyldCachePatchableGOTLocation   useLocation;
-
-        // uint64_t -> absolute value
-        // DylibOffset -> offset in to some cache dylib
-        std::variant<uint64_t, DylibOffset> targetValue;
+        dyld_cache_patchable_location   patchInfo;
+        VMOffset                        targetValue;
     };
 
-    std::vector<std::vector<DyldCachePatchableLocation>>    bindUses;
+    std::vector<std::vector<dyld_cache_patchable_location>> bindUses;
     std::vector<std::vector<GOTInfo>>                       bindGOTUses;
     std::vector<std::vector<GOTInfo>>                       bindAuthGOTUses;
-    std::vector<std::vector<GOTInfo>>                       bindAuthPtrUses;
     std::vector<std::string>                                bindTargetNames;
 };
 
@@ -598,35 +421,15 @@
     DylibClient& operator=(const DylibClient&) = delete;
     DylibClient& operator=(DylibClient&&) = default;
 
-    // The key to this map is the address in the dylib which defines the symbol,
-    // while the map value is a vector of all locations in other dylibs which use the definition
-    typedef std::map<InputDylibVMAddress, std::vector<DyldCachePatchableLocation>, InputDylibVMAddressLessThan> UsesMap;
-
-    const CacheDylib*   clientCacheDylib;
+    typedef std::map<CacheVMAddress, std::vector<dyld_cache_patchable_location>, CacheVMAddressLessThan> UsesMap;
+
+    const CacheDylib*   clientCacheDylib = nullptr;
     UsesMap             uses;
 };
 
-struct GOTClient
-{
-    GOTClient()
-    {
-    }
-    ~GOTClient()                  = default;
-    GOTClient(const GOTClient&) = delete;
-    GOTClient(GOTClient&&)      = default;
-    GOTClient& operator=(const GOTClient&) = delete;
-    GOTClient& operator=(GOTClient&&) = default;
-
-    // The key to this map is the address in the dylib which defines the symbol,
-    // while the map value is a vector of all locations in the coalesced GOT sections which use it
-    typedef std::map<InputDylibVMAddress, std::vector<DyldCachePatchableGOTLocation>, InputDylibVMAddressLessThan> UsesMap;
-
-    UsesMap             uses;
-};
-
 struct DylibClients
 {
-    DylibClients()
+    DylibClients() : gotClient(nullptr)
     {
     }
     ~DylibClients()                  = default;
@@ -635,58 +438,41 @@
     DylibClients& operator=(const DylibClients&) = delete;
     DylibClients& operator=(DylibClients&&) = default;
 
-    typedef std::unordered_map<InputDylibVMAddress, std::string_view,
-                               InputDylibVMAddressHash, InputDylibVMAddressEqual> ExportToNameMap;
-
     // Other dylibs which point to this dylib, not via uniqued GOTs
-    std::vector<DylibClient>            clients;
-
-    // Uniqued GOTs which use this dylib
-    GOTClient                           gotClient;
-
-    // The names of any used exports
-    ExportToNameMap                     exportsToName;
+    std::vector<DylibClient>                         clients;
+
+    // For and uniqued GOTs which use this dylib
+    DylibClient                                      gotClient;
 
 private:
-    struct CacheToInputAddr
-    {
-        CacheVMAddress      cacheAddr;
-        InputDylibVMAddress inputAddr;
-    };
-
-    std::vector<InputDylibVMAddress>    usedInputDylibExports;
-
-    // We later fill this in once we know the VM addresses of everything
-    std::vector<CacheToInputAddr>       usedCacheDylibExports;
+    std::vector<CacheVMAddress>                      usedExports;
 
 public:
 
-    const std::vector<InputDylibVMAddress>& getUsedInputDylibExports() const { return usedInputDylibExports; }
-    const std::vector<CacheToInputAddr>&    getUsedCacheDylibExports() const { return usedCacheDylibExports; }
+    const std::vector<CacheVMAddress>& getUsedExports() const { return usedExports; }
 
     // This accepts the new exports by value, so that callers can pass
     // an rvalue reference to avoid an unnecessary copy.
-    void setUsedExports(std::vector<InputDylibVMAddress> newUsedExports) {
-        assert(usedInputDylibExports.empty() && "Used exports should be set only once");
-
-        usedInputDylibExports = std::move(newUsedExports);
-
-        std::sort(usedInputDylibExports.begin(), usedInputDylibExports.end(), InputDylibVMAddressLessThan());
-        usedInputDylibExports.erase(std::unique(usedInputDylibExports.begin(), usedInputDylibExports.end(),
-                                                InputDylibVMAddressEqual()), usedInputDylibExports.end());
-    }
-
-    uint32_t findExportIndex(const CacheVMAddress& addr) const {
-        auto it = std::lower_bound(usedCacheDylibExports.begin(), usedCacheDylibExports.end(), addr, [](auto& entry, auto& searchAddr) {
-            return entry.cacheAddr < searchAddr;
-        });
-        assert(it != usedCacheDylibExports.end() && "no export entry");
-        assert(it->cacheAddr == addr && "no export entry");
-
-        return (uint32_t)std::distance(usedCacheDylibExports.begin(), it);
-    }
-
-    void calculateCacheUsedExports(const CacheDylib& cacheDylib);
+    void setUsedExports(std::vector<CacheVMAddress> newUsedExports) {
+        assert(usedExports.empty() && "Used exports should be set only once");
+
+        usedExports = std::move(newUsedExports);
+
+        std::sort(usedExports.begin(), usedExports.end(), CacheVMAddressLessThan());
+        usedExports.erase(std::unique(usedExports.begin(), usedExports.end(),
+            CacheVMAddressEqual()), usedExports.end());
+    }
+
+    decltype(usedExports)::const_iterator findExport(const CacheVMAddress& addr) const {
+        auto exportIt = std::lower_bound(usedExports.cbegin(),
+                                         usedExports.cend(), addr,
+                                         CacheVMAddressLessThan());
+        if (exportIt != usedExports.cend() && *exportIt == addr) {
+            return exportIt;
+        }
+
+        return usedExports.cend();
+    }
 };
 
 struct PatchTableBuilder
@@ -694,8 +480,6 @@
     typedef std::unordered_set<CacheVMAddress, CacheVMAddressHash, CacheVMAddressEqual> PatchableClassesSet;
     typedef std::unordered_set<CacheVMAddress, CacheVMAddressHash, CacheVMAddressEqual> PatchableSingletonsSet;
 
-    error::Error    prepare(const std::span<CacheDylib>& cacheDylibs,
-                            const std::span<PatchInfo>& patchInfos);
     error::Error    build(const std::span<CacheDylib>& cacheDylibs,
                           const std::span<PatchInfo>& patchInfos,
                           const PatchableClassesSet& patchableObjCClasses,
@@ -703,7 +487,7 @@
                           CacheVMAddress cacheBaseAddress);
     uint64_t        getPatchTableSize() const;
     error::Error    write(uint8_t* buffer, uint64_t bufferSize, uint64_t patchInfoAddr) const;
-
+    
 private:
     // Takes the PatchInfo's for each dylib, and merges them in to the data structures needed
     // in the builder
@@ -715,22 +499,23 @@
                                     const PatchableClassesSet& patchableObjCClasses,
                                     const PatchableSingletonsSet& patchableCFObj2,
                                     CacheVMAddress cacheBaseAddress);
-
+    
+    typedef std::unordered_map<CacheVMAddress, std::string_view,
+                               CacheVMAddressHash, CacheVMAddressEqual> ExportToNameMap;
+    
     std::vector<DylibClients>   dylibClients;
+    ExportToNameMap             exportsToName;
     
-    std::vector<dyld_cache_image_patches_v2>            patchImages;
-    std::vector<dyld_cache_image_export_v2>             imageExports;
-    std::vector<dyld_cache_image_clients_v2>            patchClients;
-    std::vector<dyld_cache_patchable_export_v2>         clientExports;
-    std::vector<dyld_cache_patchable_location_v4>       patchLocations;
-    std::vector<char>                                   patchExportNames;
-    std::vector<dyld_cache_image_got_clients_v3>        gotClients;
-    std::vector<dyld_cache_patchable_export_v3>         gotClientExports;
-    std::vector<dyld_cache_patchable_location_v4_got>   gotPatchLocations;
-
-    // Once we've run prepare() we know the final size
-    uint64_t                    totalSize = 0;
-
+    std::vector<dyld_cache_image_patches_v2>        patchImages;
+    std::vector<dyld_cache_image_export_v2>         imageExports;
+    std::vector<dyld_cache_image_clients_v2>        patchClients;
+    std::vector<dyld_cache_patchable_export_v2>     clientExports;
+    std::vector<dyld_cache_patchable_location_v2>   patchLocations;
+    std::vector<char>                               patchExportNames;
+    std::vector<dyld_cache_image_got_clients_v3>    gotClients;
+    std::vector<dyld_cache_patchable_export_v3>     gotClientExports;
+    std::vector<dyld_cache_patchable_location_v3>   gotPatchLocations;
+    
     const bool                  log = false;
 };