Loading...
--- dyld/dyld-1122.1/common/CachePatching.h
+++ dyld/dyld-1335/common/CachePatching.h
@@ -380,6 +380,8 @@
static const char* patchKindName(PatchKind patchKind);
+ void dump() const;
+
private:
const dyld_cache_patch_info* info() const;
@@ -486,6 +488,8 @@
void forEachPatchableGOTUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
GOTUseHandler handler) const;
+ void dump() const;
+
private:
const dyld_cache_patch_info_v4* info() const;
@@ -497,21 +501,28 @@
namespace cache_builder
{
+enum class UniquedGOTKind { regular, authGot, authPtr };
+
struct CacheDylib;
-
-struct dyld_cache_patchable_location
-{
- dyld_cache_patchable_location(CacheVMAddress cacheVMAddr, dyld3::MachOFile::PointerMetaData pmd,
- uint64_t addend, bool isWeakImport);
- ~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;
+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;
uint64_t high7 : 7,
unused : 4,
isWeakImport : 1,
@@ -522,18 +533,56 @@
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;
+};
+
// There will be one of these PatchInfo structs for each dylib in the cache
struct PatchInfo
{
struct GOTInfo
{
- dyld_cache_patchable_location patchInfo;
- VMOffset targetValue;
+ DyldCachePatchableGOTLocation useLocation;
+
+ // uint64_t -> absolute value
+ // DylibOffset -> offset in to some cache dylib
+ std::variant<uint64_t, DylibOffset> targetValue;
};
- std::vector<std::vector<dyld_cache_patchable_location>> bindUses;
+ std::vector<std::vector<DyldCachePatchableLocation>> bindUses;
std::vector<std::vector<GOTInfo>> bindGOTUses;
std::vector<std::vector<GOTInfo>> bindAuthGOTUses;
+ std::vector<std::vector<GOTInfo>> bindAuthPtrUses;
std::vector<std::string> bindTargetNames;
};
@@ -549,15 +598,35 @@
DylibClient& operator=(const DylibClient&) = delete;
DylibClient& operator=(DylibClient&&) = default;
- typedef std::map<CacheVMAddress, std::vector<dyld_cache_patchable_location>, CacheVMAddressLessThan> UsesMap;
-
- const CacheDylib* clientCacheDylib = nullptr;
+ // 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;
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() : gotClient(nullptr)
+ DylibClients()
{
}
~DylibClients() = default;
@@ -566,41 +635,58 @@
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;
-
- // For and uniqued GOTs which use this dylib
- DylibClient gotClient;
+ std::vector<DylibClient> clients;
+
+ // Uniqued GOTs which use this dylib
+ GOTClient gotClient;
+
+ // The names of any used exports
+ ExportToNameMap exportsToName;
private:
- std::vector<CacheVMAddress> usedExports;
+ 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;
public:
- const std::vector<CacheVMAddress>& getUsedExports() const { return usedExports; }
+ const std::vector<InputDylibVMAddress>& getUsedInputDylibExports() const { return usedInputDylibExports; }
+ const std::vector<CacheToInputAddr>& getUsedCacheDylibExports() const { return usedCacheDylibExports; }
// This accepts the new exports by value, so that callers can pass
// an rvalue reference to avoid an unnecessary copy.
- 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();
- }
+ 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);
};
struct PatchTableBuilder
@@ -608,6 +694,8 @@
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,
@@ -615,7 +703,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
@@ -627,12 +715,8 @@
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;
@@ -643,7 +727,10 @@
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;
+
const bool log = false;
};