Loading...
--- dyld/dyld-1330/common/CachePatching.cpp
+++ dyld/dyld-1235.2/common/CachePatching.cpp
@@ -28,7 +28,6 @@
#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
#include "CacheDylib.h"
-#include <ranges>
#endif // BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
#include <assert.h>
@@ -199,33 +198,21 @@
}
}
-void PatchTable::dump() const
-{
-#if BUILDING_SHARED_CACHE_UTIL
- switch ( this->version() ) {
- case 4:
- return ((PatchTableV4*)this)->dump();
- default:
- assert("Unknown patch table version");
- break;
- }
-#endif
-}
-
const char* PatchTable::patchKindName(PatchKind patchKind)
{
+ const char* name = "(unknown patch kind)";
switch ( patchKind ) {
case PatchKind::regular:
- return "";
+ name = "";
break;
case PatchKind::cfObj2:
- return "(CF obj2)";
+ name = "(CF obj2)";
break;
case PatchKind::objcClass:
- return "(objc class)";
- break;
- }
- return "(unknown patch kind)";
+ name = "(objc class)";
+ break;
+ }
+ return name;
}
//
@@ -746,185 +733,6 @@
}
}
-void PatchTableV4::dump() const
-{
-#if BUILDING_SHARED_CACHE_UTIL
-
- printf("version: %d\n", this->version());
- printf("patch table address: 0x%llx\n", this->tableVMAddr);
-
- {
- const dyld_cache_patch_info_v4* patchInfo = this->info();
- printf("header: {\n");
- printf(" patchTableVersion: %d\n", patchInfo->patchTableVersion);
- printf(" patchLocationVersion: %d\n", patchInfo->patchLocationVersion);
- printf(" patchTableArrayAddr: %lld\n", patchInfo->patchTableArrayAddr);
- printf(" patchTableArrayCount: %lld\n", patchInfo->patchTableArrayCount);
- printf(" patchImageExportsArrayAddr: %lld\n", patchInfo->patchImageExportsArrayAddr);
- printf(" patchImageExportsArrayCount: %lld\n", patchInfo->patchImageExportsArrayCount);
- printf(" patchClientsArrayAddr: %lld\n", patchInfo->patchClientsArrayAddr);
- printf(" patchClientsArrayCount: %lld\n", patchInfo->patchClientsArrayCount);
- printf(" patchClientExportsArrayAddr: %lld\n", patchInfo->patchClientExportsArrayAddr);
- printf(" patchClientExportsArrayCount: %lld\n", patchInfo->patchClientExportsArrayCount);
- printf(" patchLocationArrayAddr: %lld\n", patchInfo->patchLocationArrayAddr);
- printf(" patchLocationArrayCount: %lld\n", patchInfo->patchLocationArrayCount);
- printf(" gotClientsArrayAddr: %lld\n", patchInfo->gotClientsArrayAddr);
- printf(" gotClientsArrayCount: %lld\n", patchInfo->gotClientsArrayCount);
- printf(" gotClientExportsArrayAddr: %lld\n", patchInfo->gotClientExportsArrayAddr);
- printf(" gotClientExportsArrayCount: %lld\n", patchInfo->gotClientExportsArrayCount);
- printf(" gotLocationArrayAddr: %lld\n", patchInfo->gotLocationArrayAddr);
- printf(" gotLocationArrayCount: %lld\n", patchInfo->gotLocationArrayCount);
- printf(" patchExportNamesAddr: %lld\n", patchInfo->patchExportNamesAddr);
- printf(" patchExportNamesSize: %lld\n", patchInfo->patchExportNamesSize);
- printf("}\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_image_patches_v2> elements = this->images();
- printf("dyld_cache_image_patches_v2 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- printf(" [%ld]: { [%d, %d], [%d, %d] }\n",
- &element - elements.data(),
- element.patchClientsStartIndex, element.patchClientsCount,
- element.patchExportsStartIndex, element.patchExportsCount);
- }
- printf("} // dyld_cache_image_patches_v2\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_image_export_v2> elements = this->imageExports();
- printf("dyld_cache_image_export_v2 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- printf(" [%ld]: { 0x%x, 0x%x, %d }\n",
- &element - elements.data(),
- element.dylibOffsetOfImpl, element.exportNameOffset,
- element.patchKind);
- }
- printf("} // dyld_cache_image_export_v2\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_image_clients_v2> elements = this->imageClients();
- printf("dyld_cache_image_clients_v2 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- printf(" [%ld]: { %d, [%d, %d] }\n",
- &element - elements.data(),
- element.clientDylibIndex, element.patchExportsStartIndex,
- element.patchExportsCount);
- }
- printf("} // dyld_cache_image_clients_v2\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_patchable_export_v2> elements = this->clientExports();
- printf("dyld_cache_patchable_export_v2 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- printf(" [%ld]: { %d, [%d, %d] }\n",
- &element - elements.data(),
- element.imageExportIndex, element.patchLocationsStartIndex,
- element.patchLocationsCount);
- }
- printf("} // dyld_cache_patchable_export_v2\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_patchable_location_v4> elements = this->patchableLocations();
- printf("dyld_cache_patchable_location_v4 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- // TODO: regular vs auth
- printf(" [%ld]: { 0x%x }\n",
- &element - elements.data(),
- element.dylibOffsetOfUse);
- }
- printf("} // dyld_cache_patchable_location_v4\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_image_got_clients_v3> elements = this->gotClients();
- printf("dyld_cache_image_got_clients_v3 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- printf(" [%ld]: { [%d, %d] }\n",
- &element - elements.data(),
- element.patchExportsStartIndex, element.patchExportsCount);
- }
- printf("} // dyld_cache_image_got_clients_v3\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_patchable_export_v3> elements = this->gotClientExports();
- printf("dyld_cache_patchable_export_v3 (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- printf(" [%ld]: { %d, [%d, %d] }\n",
- &element - elements.data(),
- element.imageExportIndex,
- element.patchLocationsStartIndex, element.patchLocationsCount);
- }
- printf("} // dyld_cache_patchable_export_v3\n");
- }
-
- printf("\n");
-
- {
- std::span<const dyld_cache_patchable_location_v4_got> elements = this->gotPatchableLocations();
- printf("dyld_cache_patchable_location_v4_got (total = %zu): {\n", elements.size());
- for ( const auto& element : elements ) {
- // TODO: regular vs auth
- printf(" [%ld]: { 0x%llx }\n",
- &element - elements.data(),
- element.cacheOffsetOfUse);
- }
- printf("} // dyld_cache_patchable_location_v4_got\n");
- }
-
- printf("\n");
-
- {
- std::string_view elements = this->exportNames();
- uint32_t totalStrings = 0;
- for ( std::string_view str = elements; !str.empty(); ++totalStrings ) {
- auto pos = str.find('\0');
- if ( pos == std::string::npos )
- break;
- str = str.substr(pos + 1);
- }
-
- printf("export_names (total = %d): {\n", totalStrings);
-
- uint32_t index = 0;
- for ( std::string_view str = elements; !str.empty(); ++index ) {
- auto pos = str.find('\0');
- if ( pos == std::string::npos )
- break;
-
- printf(" [%d]: { 0x%lx, \"%s\" }\n",
- index,
- str.data() - elements.data(),
- str.data());
-
- str = str.substr(pos + 1);
- }
- printf("} // export_names\n");
- }
-
- printf("\n");
-
-#endif // BUILDING_SHARED_CACHE_UTIL
-}
-
#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
namespace cache_builder
@@ -948,7 +756,7 @@
const CacheDylib::BindTarget& bindTarget = cacheDylib.bindTargets[bindIndex];
// Skip binds with no uses
- const std::span<const DyldCachePatchableLocation> clientUses = dylibPatchInfo.bindUses[bindIndex];
+ const std::vector<dyld_cache_patchable_location>& clientUses = dylibPatchInfo.bindUses[bindIndex];
if ( clientUses.empty() )
continue;
@@ -956,29 +764,29 @@
if ( bindTarget.kind == CacheDylib::BindTarget::Kind::absolute )
continue;
- assert(bindTarget.kind == CacheDylib::BindTarget::Kind::inputImage);
- const CacheDylib::BindTarget::InputImage& inputImageTarget = bindTarget.inputImage;
- InputDylibVMAddress bindTargetVMAddr = inputImageTarget.targetDylib->inputLoadAddress + inputImageTarget.targetRuntimeOffset;
- assert(inputImageTarget.targetDylib->needsPatchTable && "target dylibs must be patchable");
+ assert(bindTarget.kind == CacheDylib::BindTarget::Kind::cacheImage);
+ const CacheDylib::BindTarget::CacheImage& cacheImageTarget = bindTarget.cacheImage;
+ CacheVMAddress bindTargetVMAddr = cacheImageTarget.targetDylib->cacheLoadAddress + cacheImageTarget.targetRuntimeOffset;
+ assert(cacheImageTarget.targetDylib->needsPatchTable && "target dylibs must be patchable");
// Find the target dylib. We need to add this dylib as a client of the target
- DylibClients& targetDylibClients = dylibClients[inputImageTarget.targetDylib->cacheIndex];
+ DylibClients& targetDylibClients = dylibClients[cacheImageTarget.targetDylib->cacheIndex];
// Add this dylib as a client if its not already there
if ( targetDylibClients.clients.empty() || (targetDylibClients.clients.back().clientCacheDylib != &cacheDylib) )
targetDylibClients.clients.emplace_back(&cacheDylib);
DylibClient& targetDylibClient = targetDylibClients.clients.back();
- std::vector<DyldCachePatchableLocation>& uses = targetDylibClient.uses[bindTargetVMAddr];
+ std::vector<dyld_cache_patchable_location>& uses = targetDylibClient.uses[bindTargetVMAddr];
uses.insert(uses.end(), clientUses.begin(), clientUses.end());
- targetDylibClients.exportsToName.insert({ bindTargetVMAddr, dylibPatchInfo.bindTargetNames[bindIndex] });
+ exportsToName.insert({ bindTargetVMAddr, dylibPatchInfo.bindTargetNames[bindIndex] });
if ( log ) {
printf("%d patch loc(s) in %s, of symbol %s in %s\n",
(uint32_t)clientUses.size(), cacheDylib.installName.data(),
dylibPatchInfo.bindTargetNames[bindIndex].c_str(),
- cacheDylibs[inputImageTarget.targetDylib->cacheIndex].installName.data());
+ cacheDylibs[cacheImageTarget.targetDylib->cacheIndex].installName.data());
}
}
@@ -1002,7 +810,7 @@
const CacheDylib::BindTarget& bindTarget = cacheDylib.bindTargets[bindIndex];
// Skip binds with no uses
- const std::span<const PatchInfo::GOTInfo> clientUses = bindGOTUses[bindIndex];
+ const std::vector<PatchInfo::GOTInfo>& clientUses = bindGOTUses[bindIndex];
if ( clientUses.empty() )
continue;
@@ -1010,25 +818,25 @@
if ( bindTarget.kind == CacheDylib::BindTarget::Kind::absolute )
continue;
- assert(bindTarget.kind == CacheDylib::BindTarget::Kind::inputImage);
- const CacheDylib::BindTarget::InputImage& inputImageTarget = bindTarget.inputImage;
- InputDylibVMAddress bindTargetVMAddr = inputImageTarget.targetDylib->inputLoadAddress + inputImageTarget.targetRuntimeOffset;
+ assert(bindTarget.kind == CacheDylib::BindTarget::Kind::cacheImage);
+ const CacheDylib::BindTarget::CacheImage& cacheImageTarget = bindTarget.cacheImage;
+ CacheVMAddress bindTargetVMAddr = cacheImageTarget.targetDylib->cacheLoadAddress + cacheImageTarget.targetRuntimeOffset;
// Find the target dylib. We need to add this dylib as a client of the target
- DylibClients& targetDylibClients = dylibClients[inputImageTarget.targetDylib->cacheIndex];
-
- GOTClient& gotClient = targetDylibClients.gotClient;
- std::vector<DyldCachePatchableGOTLocation>& uses = gotClient.uses[bindTargetVMAddr];
+ DylibClients& targetDylibClients = dylibClients[cacheImageTarget.targetDylib->cacheIndex];
+
+ DylibClient& targetDylibClient = targetDylibClients.gotClient;
+ std::vector<dyld_cache_patchable_location>& uses = targetDylibClient.uses[bindTargetVMAddr];
for ( const PatchInfo::GOTInfo& gotInfo : clientUses )
- uses.push_back(gotInfo.useLocation);
-
- targetDylibClients.exportsToName.insert({ bindTargetVMAddr, dylibPatchInfo.bindTargetNames[bindIndex] });
+ uses.push_back(gotInfo.patchInfo);
+
+ exportsToName.insert({ bindTargetVMAddr, dylibPatchInfo.bindTargetNames[bindIndex] });
if ( log ) {
printf("%d patch loc(s) in %s, of symbol %s in %s\n",
(uint32_t)clientUses.size(), cacheDylib.installName.data(),
dylibPatchInfo.bindTargetNames[bindIndex].c_str(),
- cacheDylibs[inputImageTarget.targetDylib->cacheIndex].installName.data());
+ cacheDylibs[cacheImageTarget.targetDylib->cacheIndex].installName.data());
}
}
}
@@ -1048,18 +856,18 @@
uint64_t numGotClientExports = 0;
uint64_t numGotPatchLocations = 0;
+ typedef std::unordered_map<CacheVMAddress, uint32_t, CacheVMAddressHash, CacheVMAddressEqual> ExportNameOffsetMap;
+ ExportNameOffsetMap exportNameOffsets;
+
for ( uint32_t dylibIndex = 0; dylibIndex != cacheDylibs.size(); ++dylibIndex ) {
DylibClients& dylibClientData = dylibClients[dylibIndex];
- std::vector<InputDylibVMAddress> usedExports;
-
- typedef std::unordered_map<InputDylibVMAddress, uint32_t, InputDylibVMAddressHash, InputDylibVMAddressEqual> ExportNameOffsetMap;
- ExportNameOffsetMap exportNameOffsets;
+ std::vector<CacheVMAddress> usedExports;
for ( const DylibClient& clientDylib : dylibClientData.clients ) {
bool clientUsed = false;
- for ( auto& exportDylibVMAddrAndUses : clientDylib.uses ) {
- InputDylibVMAddress exportDylibVMAddr = exportDylibVMAddrAndUses.first;
- const std::span<const DyldCachePatchableLocation> uses = exportDylibVMAddrAndUses.second;
+ for ( auto& exportVMAddrAndUses : clientDylib.uses ) {
+ CacheVMAddress exportCacheVMAddr = exportVMAddrAndUses.first;
+ const std::vector<dyld_cache_patchable_location>& uses = exportVMAddrAndUses.second;
if ( uses.empty() )
continue;
@@ -1069,15 +877,15 @@
numPatchLocations += uses.size();
// Track this location as one the target dylib needs to export
- usedExports.push_back(exportDylibVMAddr);
+ usedExports.push_back(exportCacheVMAddr);
// We need space for the name too
- auto itAndInserted = exportNameOffsets.insert({ exportDylibVMAddr, numPatchExportNameBytes });
+ auto itAndInserted = exportNameOffsets.insert({ exportCacheVMAddr, numPatchExportNameBytes });
if ( itAndInserted.second ) {
// We inserted the name, so make space for it
// We should have an export already, from the previous scan to size the tables
- auto exportNameIt = dylibClientData.exportsToName.find(exportDylibVMAddr);
- assert(exportNameIt != dylibClientData.exportsToName.end());
+ auto exportNameIt = exportsToName.find(exportCacheVMAddr);
+ assert(exportNameIt != exportsToName.end());
const std::string_view& exportName = exportNameIt->second;
numPatchExportNameBytes += exportName.size() + 1;
}
@@ -1090,10 +898,9 @@
// GOTs
{
- for ( auto& exportDylibVMAddrAndUses : dylibClientData.gotClient.uses ) {
- InputDylibVMAddress exportDylibVMAddr = exportDylibVMAddrAndUses.first;
- std::vector<DyldCachePatchableGOTLocation>& uses = exportDylibVMAddrAndUses.second;
-
+ for ( auto& exportVMAddrAndUses : dylibClientData.gotClient.uses ) {
+ CacheVMAddress exportCacheVMAddr = exportVMAddrAndUses.first;
+ std::vector<dyld_cache_patchable_location>& uses = exportVMAddrAndUses.second;
if ( uses.empty() )
continue;
@@ -1105,15 +912,15 @@
numGotPatchLocations += uses.size();
// Track this location as one the target dylib needs to export
- usedExports.push_back(exportDylibVMAddr);
+ usedExports.push_back(exportCacheVMAddr);
// We need space for the name too
- auto itAndInserted = exportNameOffsets.insert({ exportDylibVMAddr, numPatchExportNameBytes });
+ auto itAndInserted = exportNameOffsets.insert({ exportCacheVMAddr, numPatchExportNameBytes });
if ( itAndInserted.second ) {
// We inserted the name, so make space for it
// We should have an export already, from the previous scan to size the tables
- auto exportNameIt = dylibClientData.exportsToName.find(exportDylibVMAddr);
- assert(exportNameIt != dylibClientData.exportsToName.end());
+ auto exportNameIt = exportsToName.find(exportCacheVMAddr);
+ assert(exportNameIt != exportsToName.end());
const std::string_view& exportName = exportNameIt->second;
numPatchExportNameBytes += exportName.size() + 1;
}
@@ -1126,50 +933,20 @@
dylibClientData.setUsedExports(std::move(usedExports));
// Track how many exports this image needs
- numImageExports += dylibClientData.getUsedInputDylibExports().size();
- }
-
- // align to 4
- while ( (numPatchExportNameBytes % 4) != 0 )
- ++numPatchExportNameBytes;
+ numImageExports += dylibClientData.getUsedExports().size();
+ }
// Now reserve the space
+
patchImages.reserve(numPatchImages);
imageExports.reserve(numImageExports);
patchClients.reserve(numPatchClients);
clientExports.reserve(numClientExports);
patchLocations.reserve(numPatchLocations);
+ patchExportNames.reserve(numPatchExportNameBytes);
gotClients.reserve(numGOTClients);
gotClientExports.reserve(numGotClientExports);
gotPatchLocations.reserve(numGotPatchLocations);
- patchExportNames.reserve(numPatchExportNameBytes);
-
- uint64_t patchInfoSize = sizeof(dyld_cache_patch_info_v4);
- patchInfoSize += sizeof(dyld_cache_image_patches_v2) * numPatchImages;
- patchInfoSize += sizeof(dyld_cache_image_export_v2) * numImageExports;
- patchInfoSize += sizeof(dyld_cache_image_clients_v2) * numPatchClients;
- patchInfoSize += sizeof(dyld_cache_patchable_export_v3) * numClientExports;
- patchInfoSize += sizeof(dyld_cache_patchable_location_v4) * numPatchLocations;
- patchInfoSize += sizeof(dyld_cache_image_got_clients_v3) * numGOTClients;
- patchInfoSize += sizeof(dyld_cache_patchable_export_v3) * numGotClientExports;
- patchInfoSize += sizeof(dyld_cache_patchable_location_v4_got) * numGotPatchLocations;
- patchInfoSize += numPatchExportNameBytes;
-
- totalSize = patchInfoSize;
-
-#if 0
- fprintf(stderr, "sizeof(dyld_cache_patch_info_v3): %lu\n", sizeof(dyld_cache_patch_info_v3));
- fprintf(stderr, "sizeof(dyld_cache_image_patches_v2) * patchImages.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_patches_v2) * patchImages.size(), patchImages.size());
- fprintf(stderr, "sizeof(dyld_cache_image_export_v2) * imageExports.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_export_v2) * imageExports.size(), imageExports.size());
- fprintf(stderr, "sizeof(dyld_cache_image_clients_v2) * patchClients.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_clients_v2) * patchClients.size(), patchClients.size());
- fprintf(stderr, "sizeof(dyld_cache_patchable_export_v2) * clientExports.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_export_v2) * clientExports.size(), clientExports.size());
- fprintf(stderr, "sizeof(dyld_cache_patchable_location_v2) * patchLocations.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_location_v2) * patchLocations.size(), patchLocations.size());
- fprintf(stderr, "sizeof(dyld_cache_image_got_clients_v3) * gotClients.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_got_clients_v3) * gotClients.size(), gotClients.size());
- fprintf(stderr, "sizeof(dyld_cache_patchable_export_v3) * gotClientExports.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_export_v3) * gotClientExports.size(), gotClientExports.size());
- fprintf(stderr, "sizeof(dyld_cache_patchable_location_v3) * gotPatchLocations.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_location_v3) * gotPatchLocations.size(), gotPatchLocations.size());
- fprintf(stderr, "patchExportNames.size(): %lu\n", patchExportNames.size());
- fprintf(stderr, "patchInfoSize: %lld\n", patchInfoSize);
-#endif
}
void PatchTableBuilder::calculatePatchTable(const std::span<CacheDylib>& cacheDylibs,
@@ -1177,13 +954,6 @@
const PatchableSingletonsSet& patchableCFObj2,
CacheVMAddress cacheBaseAddress)
{
- // Calculate the real VM addresses for all exports. This needs to be done late as the input dylib addresses
- // can change sort order when the cache moves segments
- for ( uint32_t dylibIndex = 0; dylibIndex != cacheDylibs.size(); ++dylibIndex ) {
- DylibClients& dylibClientData = dylibClients[dylibIndex];
- dylibClientData.calculateCacheUsedExports(cacheDylibs[dylibIndex]);
- }
-
typedef std::unordered_map<CacheVMAddress, uint32_t, CacheVMAddressHash, CacheVMAddressEqual> ExportNameOffsetMap;
ExportNameOffsetMap exportNameOffsets;
@@ -1197,7 +967,7 @@
patchImage.patchClientsStartIndex = (uint32_t)patchClients.size();
patchImage.patchClientsCount = 0;
patchImage.patchExportsStartIndex = (uint32_t)imageExports.size();
- patchImage.patchExportsCount = (uint32_t)dylibClientData.getUsedCacheDylibExports().size();
+ patchImage.patchExportsCount = (uint32_t)dylibClientData.getUsedExports().size();
if ( !cacheDylibs[dylibIndex].needsPatchTable ) {
assert(patchImage.patchExportsCount == 0);
@@ -1216,8 +986,7 @@
for ( const DylibClient& clientDylib : dylibClientData.clients ) {
bool clientUsed = false;
- InputDylibVMAddress clientInputDylibVMAddr = clientDylib.clientCacheDylib->inputLoadAddress;
- CacheVMAddress clientCacheDylibVMAddr = clientDylib.clientCacheDylib->cacheLoadAddress;
+ CacheVMAddress clientDylibVMAddr = clientDylib.clientCacheDylib->cacheLoadAddress;
// We might add a client. If we do, then set it up now so that we have the
// right offset to the exports table
@@ -1226,19 +995,10 @@
clientImage.patchExportsStartIndex = (uint32_t)clientExports.size();
clientImage.patchExportsCount = 0;
- // Make a sorted map of cache addresses so that code in dyld at runtime can do binary search
- std::map<CacheVMAddress, InputDylibVMAddress, CacheVMAddressLessThan> exportMap;
for ( auto& exportVMAddrAndUses : clientDylib.uses ) {
- InputDylibVMAddress exportInputDylibVMAddr = exportVMAddrAndUses.first;
- CacheVMAddress exportCacheDylibVMAddr = cacheDylibs[dylibIndex].adjustor->adjustVMAddr(exportInputDylibVMAddr);
- exportMap[exportCacheDylibVMAddr] = exportInputDylibVMAddr;
- }
-
- for ( auto& cacheAndInputAddress : exportMap ) {
- const CacheVMAddress exportCacheDylibVMAddr = cacheAndInputAddress.first;
- const InputDylibVMAddress exportInputDylibVMAddr = cacheAndInputAddress.second;
-
- const std::span<const DyldCachePatchableLocation> uses = clientDylib.uses.at(exportInputDylibVMAddr);
+ CacheVMAddress exportCacheVMAddr = exportVMAddrAndUses.first;
+
+ const std::vector<dyld_cache_patchable_location>& uses = exportVMAddrAndUses.second;
if ( uses.empty() )
continue;
@@ -1246,7 +1006,10 @@
clientUsed = true;
// We should have an export already, from the previous scan to size the tables
- uint32_t imageExportIndex = dylibClientData.findExportIndex(exportCacheDylibVMAddr);
+ auto exportIt = dylibClientData.findExport(exportCacheVMAddr);
+ assert(exportIt != dylibClientData.getUsedExports().end());
+
+ uint32_t imageExportIndex = (uint32_t)std::distance(dylibClientData.getUsedExports().cbegin(), exportIt);
// Add an export for this client dylib
dyld_cache_patchable_export_v2 cacheExport;
@@ -1258,12 +1021,9 @@
// Now add the list of locations.
// At this point we need to translate from the locations the cache recorded to what we encode
- for ( const DyldCachePatchableLocation& use : uses ) {
+ for ( const dyld_cache_patchable_location& use : uses ) {
dyld_cache_patchable_location_v4 loc;
- // Translate from the offset in the input dylib to an offset in the final dylib
- InputDylibVMAddress inputVMAddr = clientInputDylibVMAddr + use.clientDylibOffset;
- CacheVMAddress cacheVMAddr = clientDylib.clientCacheDylib->adjustor->adjustVMAddr(inputVMAddr);
- loc.dylibOffsetOfUse = (uint32_t)(cacheVMAddr - clientCacheDylibVMAddr).rawValue();
+ loc.dylibOffsetOfUse = (uint32_t)(use.cacheVMAddr - clientDylibVMAddr).rawValue();
if ( use.authenticated ) {
loc.auth.high7 = use.high7;
loc.auth.isWeakImport = use.isWeakImport;
@@ -1295,25 +1055,18 @@
gotClient.patchExportsStartIndex = (uint32_t)gotClientExports.size();
gotClient.patchExportsCount = 0;
- // Make a sorted map of cache addresses so that code in dyld at runtime can do binary search
- std::map<CacheVMAddress, InputDylibVMAddress, CacheVMAddressLessThan> exportMap;
for ( auto& exportVMAddrAndUses : dylibClientData.gotClient.uses ) {
- InputDylibVMAddress exportInputDylibVMAddr = exportVMAddrAndUses.first;
- CacheVMAddress exportCacheDylibVMAddr = cacheDylibs[dylibIndex].adjustor->adjustVMAddr(exportInputDylibVMAddr);
- exportMap[exportCacheDylibVMAddr] = exportInputDylibVMAddr;
- }
-
- for ( auto& cacheAndInputAddress : exportMap ) {
- const CacheVMAddress exportCacheDylibVMAddr = cacheAndInputAddress.first;
- const InputDylibVMAddress exportInputDylibVMAddr = cacheAndInputAddress.second;
-
- const std::span<const DyldCachePatchableGOTLocation> uses = dylibClientData.gotClient.uses.at(exportInputDylibVMAddr);
-
+ CacheVMAddress exportCacheVMAddr = exportVMAddrAndUses.first;
+
+ const std::vector<dyld_cache_patchable_location>& uses = exportVMAddrAndUses.second;
if ( uses.empty() )
continue;
// We should have an export already, from the previous scan to size the tables
- uint32_t imageExportIndex = dylibClientData.findExportIndex(exportCacheDylibVMAddr);
+ auto exportIt = dylibClientData.findExport(exportCacheVMAddr);
+ assert(exportIt != dylibClientData.getUsedExports().end());
+
+ uint32_t imageExportIndex = (uint32_t)std::distance(dylibClientData.getUsedExports().cbegin(), exportIt);
// Add an export for this GOT client
dyld_cache_patchable_export_v3 cacheExport;
@@ -1325,10 +1078,9 @@
// Now add the list of locations.
// At this point we need to translate from the locations the cache recorded to what we encode
- for (const DyldCachePatchableGOTLocation& use : uses) {
+ for (const dyld_cache_patchable_location& use : uses) {
dyld_cache_patchable_location_v4_got loc;
- CacheVMAddress cacheVMAddr = use.clientGOT->cacheVMAddress + use.clientGOTOffset;
- loc.cacheOffsetOfUse = (cacheVMAddr - cacheBaseAddress).rawValue();
+ loc.cacheOffsetOfUse = (use.cacheVMAddr - cacheBaseAddress).rawValue();
loc.unusedPadding = 0;
if ( use.authenticated ) {
loc.auth.high7 = use.high7;
@@ -1356,16 +1108,13 @@
CacheVMAddress imageBaseAddress = cacheDylib.cacheLoadAddress;
// Add all the exports for this image
- for ( const auto& cacheAndInputAddress : dylibClientData.getUsedCacheDylibExports() ) {
- const CacheVMAddress exportCacheDylibVMAddr = cacheAndInputAddress.cacheAddr;
- const InputDylibVMAddress exportInputDylibVMAddr = cacheAndInputAddress.inputAddr;
-
+ for ( const CacheVMAddress exportCacheVMAddr : dylibClientData.getUsedExports() ) {
// Add the name, if no-one else has
uint32_t exportNameOffset = 0;
- auto nameItAndInserted = exportNameOffsets.insert({ exportCacheDylibVMAddr, (uint32_t)patchExportNames.size() });
+ auto nameItAndInserted = exportNameOffsets.insert({ exportCacheVMAddr, (uint32_t)patchExportNames.size() });
if ( nameItAndInserted.second ) {
// We inserted the name, so make space for it
- const std::string_view& exportName = dylibClientData.exportsToName[exportInputDylibVMAddr];
+ const std::string_view& exportName = exportsToName[exportCacheVMAddr];
patchExportNames.insert(patchExportNames.end(), &exportName[0], &exportName[0] + exportName.size() + 1);
exportNameOffset = nameItAndInserted.first->second;
}
@@ -1374,16 +1123,17 @@
exportNameOffset = nameItAndInserted.first->second;
}
+
PatchKind patchKind = PatchKind::regular;
- if ( patchableObjCClasses.count(exportCacheDylibVMAddr) ) {
+ if ( patchableObjCClasses.count(exportCacheVMAddr) ) {
patchKind = PatchKind::objcClass;
}
- else if ( patchableCFObj2.count(exportCacheDylibVMAddr) ) {
+ else if ( patchableCFObj2.count(exportCacheVMAddr) ) {
patchKind = PatchKind::cfObj2;
}
dyld_cache_image_export_v2 imageExport;
- imageExport.dylibOffsetOfImpl = (uint32_t)(exportCacheDylibVMAddr - imageBaseAddress).rawValue();
+ imageExport.dylibOffsetOfImpl = (uint32_t)(exportCacheVMAddr - imageBaseAddress).rawValue();
imageExport.exportNameOffset = (uint32_t)exportNameOffset;
imageExport.patchKind = (uint32_t)patchKind;
imageExports.push_back(imageExport);
@@ -1398,7 +1148,32 @@
uint64_t PatchTableBuilder::getPatchTableSize() const
{
- return totalSize;
+ uint64_t patchInfoSize = sizeof(dyld_cache_patch_info_v3);
+ patchInfoSize += sizeof(dyld_cache_image_patches_v2) * patchImages.size();
+ patchInfoSize += sizeof(dyld_cache_image_export_v2) * imageExports.size();
+ patchInfoSize += sizeof(dyld_cache_image_clients_v2) * patchClients.size();
+ patchInfoSize += sizeof(dyld_cache_patchable_export_v2) * clientExports.size();
+ patchInfoSize += sizeof(dyld_cache_patchable_location_v2) * patchLocations.size();
+ patchInfoSize += sizeof(dyld_cache_image_got_clients_v3) * gotClients.size();
+ patchInfoSize += sizeof(dyld_cache_patchable_export_v3) * gotClientExports.size();
+ patchInfoSize += sizeof(dyld_cache_patchable_location_v3) * gotPatchLocations.size();
+ patchInfoSize += patchExportNames.size();
+
+#if 0
+ fprintf(stderr, "sizeof(dyld_cache_patch_info_v3): %lu\n", sizeof(dyld_cache_patch_info_v3));
+ fprintf(stderr, "sizeof(dyld_cache_image_patches_v2) * patchImages.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_patches_v2) * patchImages.size(), patchImages.size());
+ fprintf(stderr, "sizeof(dyld_cache_image_export_v2) * imageExports.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_export_v2) * imageExports.size(), imageExports.size());
+ fprintf(stderr, "sizeof(dyld_cache_image_clients_v2) * patchClients.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_clients_v2) * patchClients.size(), patchClients.size());
+ fprintf(stderr, "sizeof(dyld_cache_patchable_export_v2) * clientExports.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_export_v2) * clientExports.size(), clientExports.size());
+ fprintf(stderr, "sizeof(dyld_cache_patchable_location_v2) * patchLocations.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_location_v2) * patchLocations.size(), patchLocations.size());
+ fprintf(stderr, "sizeof(dyld_cache_image_got_clients_v3) * gotClients.size(): %lu with %lu uses\n", sizeof(dyld_cache_image_got_clients_v3) * gotClients.size(), gotClients.size());
+ fprintf(stderr, "sizeof(dyld_cache_patchable_export_v3) * gotClientExports.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_export_v3) * gotClientExports.size(), gotClientExports.size());
+ fprintf(stderr, "sizeof(dyld_cache_patchable_location_v3) * gotPatchLocations.size(): %lu with %lu uses\n", sizeof(dyld_cache_patchable_location_v3) * gotPatchLocations.size(), gotPatchLocations.size());
+ fprintf(stderr, "patchExportNames.size(): %lu\n", patchExportNames.size());
+ fprintf(stderr, "patchInfoSize: %lld\n", patchInfoSize);
+#endif
+
+ return patchInfoSize;
}
Error PatchTableBuilder::write(uint8_t* buffer, uint64_t bufferSize,
@@ -1461,26 +1236,6 @@
return Error();
}
-Error PatchTableBuilder::prepare(const std::span<CacheDylib>& cacheDylibs,
- const std::span<PatchInfo>& patchInfos)
-{
- if ( cacheDylibs.size() != patchInfos.size() ) {
- return Error("Mismatch in patch table inputs: %lld vs %lld",
- (uint64_t)cacheDylibs.size(), (uint64_t)patchInfos.size());
- }
-
- // Each dylib has a list of its uses of each bindTarget in its array. We now need to combine those in
- // to the list of uses of each exported symbol from each dylib
- this->dylibClients.resize(cacheDylibs.size());
- this->mergePatchInfos(cacheDylibs, patchInfos);
-
- // We now have everything in the state we want, ie, each dylib has a list of who uses it.
- // That is the form the patch table uses on-disk
- this->calculateRequiredSpace(cacheDylibs);
-
- return Error();
-}
-
Error PatchTableBuilder::build(const std::span<CacheDylib>& cacheDylibs,
const std::span<PatchInfo>& patchInfos,
const PatchableClassesSet& patchableObjCClasses,
@@ -1491,25 +1246,29 @@
return Error("Mismatch in patch table inputs: %lld vs %lld",
(uint64_t)cacheDylibs.size(), (uint64_t)patchInfos.size());
}
- if ( cacheDylibs.size() != dylibClients.size() ) {
- return Error("Mismatch in patch table state: %lld vs %lld",
- (uint64_t)cacheDylibs.size(), (uint64_t)dylibClients.size());
- }
-
+
+ // Each dylib has a list of its uses of each bindTarget in its array. We now need to combine those in
+ // to the list of uses of each exported symbol from each dylib
+ this->dylibClients.resize(cacheDylibs.size());
+ this->mergePatchInfos(cacheDylibs, patchInfos);
+
+ // We now have everything in the state we want, ie, each dylib has a list of who uses it.
+ // That is the form the patch table uses on-disk
+ this->calculateRequiredSpace(cacheDylibs);
this->calculatePatchTable(cacheDylibs, patchableObjCClasses, patchableCFObj2, cacheBaseAddress);
return Error();
}
//
-// MARK: --- DyldCachePatchableLocation methods ---
+// MARK: --- dyld_cache_patchable_location methods ---
//
-DyldCachePatchableLocation::DyldCachePatchableLocation(InputDylibVMOffset clientDylibOffset,
- dyld3::MachOFile::PointerMetaData pmd,
- uint64_t addend, bool isWeakImport)
-{
- this->clientDylibOffset = clientDylibOffset;
+dyld_cache_patchable_location::dyld_cache_patchable_location(CacheVMAddress cacheVMAddr,
+ dyld3::MachOFile::PointerMetaData pmd,
+ uint64_t addend, bool isWeakImport)
+{
+ this->cacheVMAddr = cacheVMAddr;
this->high7 = pmd.high8 >> 1;
this->isWeakImport = isWeakImport ? 1 : 0;
this->unused = 0;
@@ -1523,46 +1282,6 @@
assert((this->high7 << 1) == pmd.high8);
}
-//
-// MARK: --- DyldCachePatchableGOTLocation methods ---
-//
-
-DyldCachePatchableGOTLocation::DyldCachePatchableGOTLocation(const Chunk* clientGOT, VMOffset clientGOTOffset,
- dyld3::MachOFile::PointerMetaData pmd,
- uint64_t addend, bool isWeakImport)
-{
- this->clientGOT = clientGOT;
- this->clientGOTOffset = clientGOTOffset;
- this->high7 = pmd.high8 >> 1;
- this->isWeakImport = isWeakImport ? 1 : 0;
- this->unused = 0;
- this->authenticated = pmd.authenticated;
- this->usesAddressDiversity = pmd.usesAddrDiversity;
- this->key = pmd.key;
- this->discriminator = pmd.diversity;
- this->addend = addend;
- // check for truncations
- assert(this->addend == addend);
- assert((this->high7 << 1) == pmd.high8);
-}
-
-
-//
-// MARK: --- PatchTable methods ---
-//
-void DylibClients::calculateCacheUsedExports(const CacheDylib& cacheDylib)
-{
- usedCacheDylibExports.reserve(usedInputDylibExports.size());
- for ( const InputDylibVMAddress& inputVMAddr : this->usedInputDylibExports ) {
- CacheVMAddress cacheVMAddr = cacheDylib.adjustor->adjustVMAddr(inputVMAddr);
- usedCacheDylibExports.emplace_back(cacheVMAddr, inputVMAddr);
- }
-
- std::ranges::sort(usedCacheDylibExports, [](auto& l, auto& r) {
- return l.cacheAddr < r.cacheAddr;
- });
-}
-
} // namespace cache_builder
#endif // BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS