Loading...
--- dyld/dyld-1286.10/cache-builder/AppCacheBuilder.cpp
+++ dyld/dyld-957/cache-builder/AppCacheBuilder.cpp
@@ -36,10 +36,6 @@
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonDigestSPI.h>
-#include "Header.h"
-
-using mach_o::Header;
-
AppCacheBuilder::AppCacheBuilder(const DyldSharedCache::CreateOptions& options,
const Options& appCacheOptions,
const dyld3::closure::FileSystem& fileSystem)
@@ -109,7 +105,7 @@
bool stop = false;
for (const AppCacheDylibInfo& dylib : sortedDylibs) {
for (const SegmentMappingInfo& loc : dylib.cacheLocation) {
- if ( loc.segName == "__TEXT" ) {
+ if (!strcmp(loc.segName, "__TEXT")) {
// Assume __TEXT contains the mach header
callback((const dyld3::MachOAnalyzer*)loc.dstSegment, dylib.dylibID, dylib.stripMode,
dylib.dependencies, *dylib.errors, stop);
@@ -121,11 +117,9 @@
}
}
-void AppCacheBuilder::forEachDylibInfo(void (^callback)(const DylibInfo& dylib, Diagnostics& dylibDiag,
- cache_builder::ASLR_Tracker& dylibASLRTracker,
- const CacheBuilder::DylibSectionCoalescer* sectionCoalescer)) {
+void AppCacheBuilder::forEachDylibInfo(void (^callback)(const DylibInfo& dylib, Diagnostics& dylibDiag, ASLR_Tracker& dylibASLRTracker)) {
for (const AppCacheDylibInfo& dylibInfo : sortedDylibs)
- callback(dylibInfo, *dylibInfo.errors, _aslrTracker, &dylibInfo._coalescer);
+ callback(dylibInfo, *dylibInfo.errors, _aslrTracker);
}
const CacheBuilder::DylibInfo* AppCacheBuilder::getKernelStaticExecutableInputFile() const {
@@ -163,45 +157,33 @@
// readOnlyTextRegion
callback(readOnlyTextRegion);
+ // readExecuteRegion
+ if ( readExecuteRegion.sizeInUse != 0 )
+ callback(readExecuteRegion);
+
+ // branchStubsRegion
+ if ( branchStubsRegion.bufferSize != 0 )
+ callback(branchStubsRegion);
+
+ // dataConstRegion
+ if ( dataConstRegion.sizeInUse != 0 )
+ callback(dataConstRegion);
+
+ // branchGOTsRegion
+ if ( branchGOTsRegion.bufferSize != 0 )
+ callback(branchGOTsRegion);
+
+ // readWriteRegion
+ if ( readWriteRegion.sizeInUse != 0 )
+ callback(readWriteRegion);
+
+ // hibernateRegion
+ if ( hibernateRegion.sizeInUse != 0 )
+ callback(hibernateRegion);
+
// -sectcreate
for (const Region& region : customDataRegions)
callback(region);
-
- // readExecuteRegion
- if ( readExecuteRegion.sizeInUse != 0 )
- callback(readExecuteRegion);
-
- // branchStubsRegion
- if ( branchStubsRegion.bufferSize != 0 )
- callback(branchStubsRegion);
-
- // textBootExecRegion
- if ( textBootExecRegion.sizeInUse != 0 )
- callback(textBootExecRegion);
-
- // dataConstRegion
- if ( dataConstRegion.sizeInUse != 0 )
- callback(dataConstRegion);
-
- // lateConstRegion
- if ( lateConstRegion.sizeInUse != 0 )
- callback(lateConstRegion);
-
- // dataSptmRegion
- if ( dataSptmRegion.sizeInUse != 0 )
- callback(dataSptmRegion);
-
- // branchGOTsRegion
- if ( branchGOTsRegion.bufferSize != 0 )
- callback(branchGOTsRegion);
-
- // readWriteRegion
- if ( readWriteRegion.sizeInUse != 0 )
- callback(readWriteRegion);
-
- // hibernateRegion
- if ( hibernateRegion.sizeInUse != 0 )
- callback(hibernateRegion);
// prelinkInfoRegion
if ( prelinkInfoDict != nullptr )
@@ -299,94 +281,31 @@
return totalTargets;
}
-bool AppCacheBuilder::hasSancovGateSection() const
-{
- for ( const AppCacheDylibInfo& dylib : sortedDylibs ) {
- const dyld3::MachOAnalyzer* ma = dylib.input->mappedFile.mh;
- if ( ma->hasSection("__DATA", "__sancov_gate") )
- return true;
- }
-
- return false;
-}
-
-bool AppCacheBuilder::removeStubs()
-{
- // Only eliminate stubs in the base kernel collection. We could eliminate stubs
- // in the auxKC too, for those calls resolved within the auxKC, but its not worth it right now
- if ( appCacheOptions.cacheKind != Options::AppCacheKind::kernel )
- return false;
-
- if ( _options.archs != &dyld3::GradedArchs::arm64e )
- return false;
-
- if ( hasSancovGateSection() )
- return false;
-
- return true;
-}
-
-void AppCacheBuilder::parseStubs()
-{
- if ( !removeStubs() )
- return;
-
- for (AppCacheDylibInfo& dylib : sortedDylibs) {
-
- const dyld3::MachOAnalyzer* ma = dylib.input->mappedFile.mh;
-
- // We can only remove sections if we know we have split seg v2 to point to it
- uint32_t splitSegSize = 0;
- const void* splitSegStart = ma->getSplitSeg(splitSegSize);
- if (!splitSegStart)
- continue;
-
- if ((*(const uint8_t*)splitSegStart) != DYLD_CACHE_ADJ_V2_FORMAT)
- continue;
-
- // Find __TEXT_EXEC __auth_stubs, and remove it if we have it
- __block bool lastSectionWasAuthStubs = false;
- ((const Header*)ma)->forEachSection(^(const Header::SectionInfo& sectInfo, bool& stop) {
- if ( sectInfo.segmentName != "__TEXT_EXEC" )
- return;
- lastSectionWasAuthStubs = false;
- if ( sectInfo.sectionName == "__auth_stubs" ) {
- // The auth stubs are only valid if the sections is 16-byte stubs
- if ( ((sectInfo.flags & SECTION_TYPE) == S_SYMBOL_STUBS) && (sectInfo.reserved2 == 16) )
- lastSectionWasAuthStubs = true;
- }
- });
-
- if ( lastSectionWasAuthStubs )
- dylib._coalescer.auth_stubs.sectionIsObliterated = true;
- }
-}
-
void AppCacheBuilder::assignSegmentRegionsAndOffsets()
{
// Segments can be re-ordered in memory relative to the order of the LC_SEGMENT load comamnds
// so first make space for all the cache location objects so that we get the order the same
// as the LC_SEGMENTs
for (DylibInfo& dylib : sortedDylibs) {
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, bool& stop) {
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
dylib.cacheLocation.push_back({});
});
}
// If we are building the kernel collection, then inherit the base address of the statically linked kernel
- const Header* kernelHdr = nullptr;
+ const dyld3::MachOAnalyzer* kernelMA = nullptr;
if ( appCacheOptions.cacheKind == Options::AppCacheKind::kernel ) {
for (DylibInfo& dylib : sortedDylibs) {
if ( dylib.input->mappedFile.mh->isStaticExecutable() ) {
- kernelHdr = (const Header*)dylib.input->mappedFile.mh;
+ kernelMA = dylib.input->mappedFile.mh;
break;
}
}
- if ( kernelHdr == nullptr ) {
+ if ( kernelMA == nullptr ) {
_diagnostics.error("Could not find kernel image");
return;
}
- cacheBaseAddress = kernelHdr->preferredLoadAddress();
+ cacheBaseAddress = kernelMA->preferredLoadAddress();
}
// x86_64 doesn't have stubs for kext branches. So work out how many potential targets
@@ -398,10 +317,10 @@
minimumSegmentAlignmentP2 = 12;
}
- auto getMinAlignment = ^(const Header* hdr) {
+ auto getMinAlignment = ^(const dyld3::MachOAnalyzer* ma) {
// The kernel wants to be able to unmap its own segments so always align it.
// And align the pageable KC as each kext can be mapped individually
- if ( hdr == kernelHdr )
+ if ( ma == kernelMA )
return minimumSegmentAlignmentP2;
if ( fixupsArePerKext() )
return minimumSegmentAlignmentP2;
@@ -417,27 +336,26 @@
continue;
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.initProt != (VM_PROT_READ) )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( segInfo.protections != (VM_PROT_READ) )
return;
- if ( ( segInfo.segmentName == "__DATA_CONST" )
- || ( segInfo.segmentName == "__PPLDATA_CONST" )
- || ( segInfo.segmentName == "__LASTDATA_CONST" )
- || ( segInfo.segmentName == "__LATE_CONST" ) )
+ if ( (strcmp(segInfo.segName, "__DATA_CONST") == 0)
+ || (strcmp(segInfo.segName, "__PPLDATA_CONST") == 0)
+ || (strcmp(segInfo.segName, "__LASTDATA_CONST") == 0) )
return;
- if ( segInfo.segmentName == "__LINKEDIT" )
+ if ( strcmp(segInfo.segName, "__LINKEDIT") == 0 )
return;
- if ( segInfo.segmentName == "__LINKINFO" )
+ if ( strcmp(segInfo.segName, "__LINKINFO") == 0 )
return;
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
+ uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
+ uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
// __CTF is not mapped in to the kernel, so remove it from the final binary.
- if ( segInfo.segmentName == "__CTF" ) {
+ if ( strcmp(segInfo.segName, "__CTF") == 0 ) {
copySize = 0;
dstCacheSegmentSize = 0;
}
@@ -445,20 +363,20 @@
// kxld packs __TEXT so we will do
// Note we align to at least 16-bytes as LDR's can scale up to 16 from their address
// and aligning them less than 16 would break that
- offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 4U));
+ offsetInRegion = align(offsetInRegion, std::max(segInfo.p2align, 4U));
offsetInRegion = align(offsetInRegion, minAlignmentP2);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &readOnlyTextRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += dstCacheSegmentSize;
});
}
@@ -475,57 +393,39 @@
{
// __TEXT segments with r/x permissions
__block uint64_t offsetInRegion = 0;
- for (AppCacheDylibInfo& dylib : sortedDylibs) {
+ for (DylibInfo& dylib : sortedDylibs) {
bool canBePacked = dylib.input->mappedFile.mh->hasSplitSeg();
if (!canBePacked)
continue;
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t segSizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.segmentName == "__HIB" )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( strcmp(segInfo.segName, "__HIB") == 0 )
return;
- if ( (segInfo.segmentName == "__TEXT_BOOT_EXEC" ) && dylib.input->mappedFile.mh->isStaticExecutable() )
- return;
- if ( segInfo.initProt != (VM_PROT_READ | VM_PROT_EXECUTE) )
+ if ( segInfo.protections != (VM_PROT_READ | VM_PROT_EXECUTE) )
return;
-
- // We may have coalesced the sections at the end of this segment. In that case, shrink the segment to remove them.
- __block size_t sizeOfSections = 0;
- __block bool foundRemovedSection = false;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSection(^(const Header::SectionInfo §Info, bool &stopSection) {
- if ( sectInfo.segmentName != segInfo.segmentName )
- return;
- if ( dylib._coalescer.sectionWasObliterated(segInfo.segmentName, sectInfo.sectionName) ) {
- foundRemovedSection = true;
- } else {
- sizeOfSections = sectInfo.address + sectInfo.size - segInfo.vmaddr;
- }
- });
- if ( !foundRemovedSection )
- sizeOfSections = segSizeOfSections;
-
// kxld packs __TEXT_EXEC so we will do
// Note we align to at least 16-bytes as LDR's can scale up to 16 from their address
// and aligning them less than 16 would break that
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 4U));
+ uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
+ offsetInRegion = align(offsetInRegion, std::max(segInfo.p2align, 4U));
offsetInRegion = align(offsetInRegion, minAlignmentP2);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
+ uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &readExecuteRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
});
}
@@ -547,111 +447,41 @@
branchStubsRegion.name = "__BRANCH_STUBS";
}
- // __TEXT_BOOT_EXEC segments in xnu with r/x permissions
+ // __DATA_CONST segments
{
__block uint64_t offsetInRegion = 0;
- for (AppCacheDylibInfo& dylib : sortedDylibs) {
- bool canBePacked = dylib.input->mappedFile.mh->hasSplitSeg();
- if (!canBePacked)
+ for (DylibInfo& dylib : sortedDylibs) {
+ if (!dylib.input->mappedFile.mh->hasSplitSeg())
continue;
- // Only do this for xnu
- if ( !dylib.input->mappedFile.mh->isStaticExecutable() )
- continue;
-
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t segSizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.segmentName != "__TEXT_BOOT_EXEC" )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( (segInfo.protections & VM_PROT_EXECUTE) != 0 )
return;
- if ( segInfo.initProt != (VM_PROT_READ | VM_PROT_EXECUTE) )
+ if ( (strcmp(segInfo.segName, "__DATA_CONST") != 0)
+ && (strcmp(segInfo.segName, "__PPLDATA_CONST") != 0)
+ && (strcmp(segInfo.segName, "__LASTDATA_CONST") != 0) )
return;
-
- // We may have coalesced the sections at the end of this segment. In that case, shrink the segment to remove them.
- __block size_t sizeOfSections = 0;
- __block bool foundRemovedSection = false;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSection(^(const Header::SectionInfo §Info, bool &stopSection) {
- if ( sectInfo.segmentName != segInfo.segmentName )
- return;
- if ( dylib._coalescer.sectionWasObliterated(segInfo.segmentName, sectInfo.sectionName)) {
- foundRemovedSection = true;
- } else {
- sizeOfSections = sectInfo.address + sectInfo.size - segInfo.vmaddr;
- }
- });
- if ( !foundRemovedSection )
- sizeOfSections = segSizeOfSections;
-
- // kxld packs __TEXT_EXEC so we will do
- // Note we align to at least 16-bytes as LDR's can scale up to 16 from their address
- // and aligning them less than 16 would break that
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 4U));
+ // kxld packs __DATA_CONST so we will do
+ uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
+ offsetInRegion = align(offsetInRegion, segInfo.p2align);
offsetInRegion = align(offsetInRegion, minAlignmentP2);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
+ uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
- loc.parentRegion = &textBootExecRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
- offsetInRegion += loc.dstCacheSegmentSize;
- });
- }
-
- // align r/x region end
- textBootExecRegion.bufferSize = align(offsetInRegion, 14);
- textBootExecRegion.sizeInUse = textBootExecRegion.bufferSize;
- textBootExecRegion.initProt = VM_PROT_READ | VM_PROT_EXECUTE;
- textBootExecRegion.maxProt = VM_PROT_READ | VM_PROT_EXECUTE;
- textBootExecRegion.name = "__TEXT_BOOT_EXEC";
- }
-
- // __DATA_CONST segments
- {
- __block uint64_t offsetInRegion = 0;
- for (DylibInfo& dylib : sortedDylibs) {
- if (!dylib.input->mappedFile.mh->hasSplitSeg())
- continue;
-
- __block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( (segInfo.initProt & VM_PROT_EXECUTE) != 0 )
- return;
- if ( ( segInfo.segmentName != "__DATA_CONST" )
- && ( segInfo.segmentName != "__PPLDATA_CONST" )
- && ( segInfo.segmentName != "__LASTDATA_CONST") )
- return;
- if ( segInfo.segmentName == "__LATE_CONST" )
- return;
- // kxld packs __DATA_CONST so we will do
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- offsetInRegion = align(offsetInRegion, maxAlignOfSections);
- offsetInRegion = align(offsetInRegion, minAlignmentP2);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
- SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
- loc.dstSegment = nullptr;
- loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
- loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
- loc.dstCacheFileSize = (uint32_t)copySize;
- loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &dataConstRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
});
}
@@ -663,96 +493,6 @@
dataConstRegion.maxProt = VM_PROT_READ;
dataConstRegion.name = "__DATA_CONST";
}
-
- // __LATE_CONST segments
- {
- __block uint64_t offsetInRegion = 0;
- for (DylibInfo& dylib : sortedDylibs) {
- if (!dylib.input->mappedFile.mh->hasSplitSeg())
- continue;
-
- __block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( (segInfo.initProt & VM_PROT_EXECUTE) != 0 )
- return;
- if ( segInfo.segmentName != "__LATE_CONST" )
- return;
- // pack __LATE_CONST
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- offsetInRegion = align(offsetInRegion, maxAlignOfSections);
- offsetInRegion = align(offsetInRegion, minAlignmentP2);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
- SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
- loc.dstSegment = nullptr;
- loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
- loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
- loc.dstCacheFileSize = (uint32_t)copySize;
- loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
- loc.parentRegion = &lateConstRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
- offsetInRegion += loc.dstCacheSegmentSize;
- });
- }
-
- // align r/o region end
- lateConstRegion.bufferSize = align(offsetInRegion, 14);
- lateConstRegion.sizeInUse = lateConstRegion.bufferSize;
- lateConstRegion.initProt = VM_PROT_READ;
- lateConstRegion.maxProt = VM_PROT_READ;
- lateConstRegion.name = "__LATE_CONST";
- }
-
- // __DATA_SPTM segments
- {
- __block uint64_t offsetInRegion = 0;
- for (DylibInfo& dylib : sortedDylibs) {
- if (!dylib.input->mappedFile.mh->hasSplitSeg())
- continue;
-
- __block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( (segInfo.initProt & VM_PROT_EXECUTE) != 0 )
- return;
- if ( segInfo.segmentName != "__DATA_SPTM" )
- return;
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- offsetInRegion = align(offsetInRegion, maxAlignOfSections);
- offsetInRegion = align(offsetInRegion, minAlignmentP2);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
- SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
- loc.dstSegment = nullptr;
- loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
- loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
- loc.dstCacheFileSize = (uint32_t)copySize;
- loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
- loc.parentRegion = &dataSptmRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
- offsetInRegion += loc.dstCacheSegmentSize;
- });
- }
-
- // align r/o region end
- dataSptmRegion.bufferSize = align(offsetInRegion, 14);
- dataSptmRegion.sizeInUse = dataSptmRegion.bufferSize;
- dataSptmRegion.initProt = VM_PROT_READ;
- dataSptmRegion.maxProt = VM_PROT_READ;
- dataSptmRegion.name = "__DATA_SPTM";
- }
-
// Branch GOTs
if ( branchTargetsFromKexts != 0 ) {
@@ -772,36 +512,35 @@
continue;
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.segmentName == "__HIB" )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( strcmp(segInfo.segName, "__HIB") == 0 )
return;
- if ( ( segInfo.segmentName == "__DATA_CONST" )
- || ( segInfo.segmentName == "__PPLDATA_CONST" )
- || ( segInfo.segmentName == "__LASTDATA_CONST" )
- || ( segInfo.segmentName == "__LATE_CONST" ) )
+ if ( (strcmp(segInfo.segName, "__DATA_CONST") == 0)
+ || (strcmp(segInfo.segName, "__PPLDATA_CONST") == 0)
+ || (strcmp(segInfo.segName, "__LASTDATA_CONST") == 0) )
return;
- if ( segInfo.initProt != (VM_PROT_READ | VM_PROT_WRITE) )
+ if ( segInfo.protections != (VM_PROT_READ | VM_PROT_WRITE) )
return;
// kxld packs __DATA so we will do
- uint32_t minAlignmentP2 = getMinAlignment((const Header*)dylib.input->mappedFile.mh);
- offsetInRegion = align(offsetInRegion, maxAlignOfSections);
+ uint32_t minAlignmentP2 = getMinAlignment(dylib.input->mappedFile.mh);
+ offsetInRegion = align(offsetInRegion, segInfo.p2align);
offsetInRegion = align(offsetInRegion, minAlignmentP2);
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
- uint64_t dstCacheSegmentSize = align(sizeOfSections, minAlignmentP2);
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
+ uint64_t dstCacheSegmentSize = align(segInfo.sizeOfSections, minAlignmentP2);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
loc.dstCacheSegmentSize = (uint32_t)dstCacheSegmentSize;
loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &readWriteRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
});
}
@@ -822,44 +561,28 @@
continue;
__block uint64_t textSegVmAddr = 0;
- __block uint64_t hibernateAddress = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.segmentName != "__HIB" )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( strcmp(segInfo.segName, "__HIB") != 0 )
return;
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)segInfo.vmsize;
+ loc.dstCacheSegmentSize = (uint32_t)segInfo.vmSize;
loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &hibernateRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
- hibernateAddress = segInfo.vmaddr;
+ hibernateAddress = segInfo.vmAddr;
});
-
- if ( offsetInRegion != 0 ) {
- // Pad out the VM offset so that the cache header starts where the base address
- // really should be
- uint64_t paddedSize = cacheBaseAddress - hibernateAddress;
- if ( offsetInRegion > paddedSize ) {
- _diagnostics.error("Could not lay out __HIB segment");
- return;
- }
- offsetInRegion = paddedSize;
-
- // Set the base address to the hibernate address so that we actually put the
- // hibernate segment there
- cacheBaseAddress = hibernateAddress;
- }
// Only xnu has __HIB, so no need to continue once we've found it.
break;
@@ -880,31 +603,31 @@
continue;
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.segmentName == "__LINKEDIT" )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( strcmp(segInfo.segName, "__LINKEDIT") == 0 )
return;
nonSplitSegRegions.emplace_back();
- nonSplitSegRegions.back().initProt = segInfo.initProt;
- nonSplitSegRegions.back().maxProt = segInfo.maxProt;
+ nonSplitSegRegions.back().initProt = segInfo.protections;
+ nonSplitSegRegions.back().maxProt = segInfo.protections;
nonSplitSegRegions.back().name = "__REGION" + std::to_string(nonSplitSegRegions.size() - 1);
// Note we don't align the region offset as we have no split seg
uint64_t offsetInRegion = 0;
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)segInfo.vmsize;
+ loc.dstCacheSegmentSize = (uint32_t)segInfo.vmSize;
loc.dstCacheFileSize = (uint32_t)segInfo.fileSize;
loc.copySegmentSize = (uint32_t)segInfo.fileSize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &nonSplitSegRegions.back();
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
// record non-split seg region end
@@ -993,16 +716,16 @@
}
// _PrelinkExecutableSize
- // Use the size of the TEXT sections in the cache. This is required as we pack segments
- __block uint64_t textSegSize = 0;
+ // This seems to be the file size of __TEXT
+ __block uint64_t textSegFileSize = 0;
if ( info.ma != nullptr ) {
- ((const Header*)info.ma)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegSize = sizeOfSections == 0 ? segInfo.fileSize : sizeOfSections;
+ info.ma->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegFileSize = segInfo.fileSize;
});
}
- if (textSegSize != 0) {
- CFNumberRef fileSizeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &textSegSize);
+ if (textSegFileSize != 0) {
+ CFNumberRef fileSizeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &textSegFileSize);
CFDictionarySetValue(dictCopyRef, CFSTR("_PrelinkExecutableSize"), fileSizeRef);
CFRelease(fileSizeRef);
}
@@ -1072,7 +795,7 @@
// The pageable/aux KCs should embed the UUID of the base kernel collection
if ( existingKernelCollection != nullptr ) {
uuid_t uuid = {};
- bool foundUUID = ((mach_o::Header*)existingKernelCollection)->getUuid(uuid);
+ bool foundUUID = existingKernelCollection->getUuid(uuid);
if ( !foundUUID ) {
_diagnostics.error("Could not find UUID in base kernel collection");
return;
@@ -1085,7 +808,7 @@
// The aux KC should embed the UUID of the pageable kernel collection if we have one
if ( pageableKernelCollection != nullptr ) {
uuid_t uuid = {};
- bool foundUUID = ((mach_o::Header*)pageableKernelCollection)->getUuid(uuid);
+ bool foundUUID = pageableKernelCollection->getUuid(uuid);
if ( !foundUUID ) {
_diagnostics.error("Could not find UUID in pageable kernel collection");
return;
@@ -1123,28 +846,28 @@
__block uint64_t offsetInRegion = 0;
for (DylibInfo& dylib : sortedDylibs) {
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.initProt != VM_PROT_READ )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( segInfo.protections != VM_PROT_READ )
return;
- if ( segInfo.segmentName != "__LINKINFO" )
+ if ( strcmp(segInfo.segName, "__LINKINFO") != 0 )
return;
// Keep segments 4K or more aligned
- offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 12U));
- size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)sizeOfSections);
+ offsetInRegion = align(offsetInRegion, std::max((int)segInfo.p2align, (int)12));
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)align(sizeOfSections, 12);
+ loc.dstCacheSegmentSize = (uint32_t)align(segInfo.sizeOfSections, 12);
loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &_readOnlyRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
});
}
@@ -1156,36 +879,28 @@
// Do all __LINKEDIT, regardless of split seg
for (DylibInfo& dylib : sortedDylibs) {
__block uint64_t textSegVmAddr = 0;
- ((const Header*)dylib.input->mappedFile.mh)->forEachSegment(^(const Header::SegmentInfo& segInfo, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
- if ( segInfo.segmentName == "__TEXT" )
- textSegVmAddr = segInfo.vmaddr;
- if ( segInfo.initProt != VM_PROT_READ )
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ if ( strcmp(segInfo.segName, "__TEXT") == 0 )
+ textSegVmAddr = segInfo.vmAddr;
+ if ( segInfo.protections != VM_PROT_READ )
return;
- if ( segInfo.segmentName != "__LINKEDIT" )
+ if ( strcmp(segInfo.segName, "__LINKEDIT") != 0 )
return;
// Keep segments 4K or more aligned
- offsetInRegion = align(offsetInRegion, std::max(maxAlignOfSections, 12U));
- size_t copySize = segInfo.fileSize;
-
- // HACK: When we adjust LINKEDIT, we may grow function starts. This is because the kernel and kexts
- // have __TEXT_EXEC __text (or other __text) which is going to be moved away from __TEXT.
- // That is, the first function start is effectively going to be an offset from __TEXT to __TEXT_EXEC
- // and that may grow.
- // Everything is ULEB encoded. We've only seen a need for 8-bytes more, but use 16-bytes to be safe
- const uint32_t extraLinkeditSpace = 16;
-
+ offsetInRegion = align(offsetInRegion, std::max((int)segInfo.p2align, (int)12));
+ size_t copySize = std::min((size_t)segInfo.fileSize, (size_t)segInfo.sizeOfSections);
SegmentMappingInfo loc;
- loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmaddr - textSegVmAddr;
- loc.segName = segInfo.segmentName;
+ loc.srcSegment = (uint8_t*)dylib.input->mappedFile.mh + segInfo.vmAddr - textSegVmAddr;
+ loc.segName = segInfo.segName;
loc.dstSegment = nullptr;
loc.dstCacheUnslidAddress = offsetInRegion; // This will be updated later once we've assigned addresses
loc.dstCacheFileOffset = (uint32_t)offsetInRegion;
- loc.dstCacheSegmentSize = (uint32_t)align(copySize + extraLinkeditSpace, 12);
- loc.dstCacheFileSize = (uint32_t)copySize + extraLinkeditSpace;
+ loc.dstCacheSegmentSize = (uint32_t)align(segInfo.sizeOfSections, 12);
+ loc.dstCacheFileSize = (uint32_t)copySize;
loc.copySegmentSize = (uint32_t)copySize;
- loc.srcSegmentIndex = segInfo.segmentIndex;
+ loc.srcSegmentIndex = segInfo.segIndex;
loc.parentRegion = &_readOnlyRegion;
- dylib.cacheLocation[segInfo.segmentIndex] = loc;
+ dylib.cacheLocation[segInfo.segIndex] = loc;
offsetInRegion += loc.dstCacheSegmentSize;
});
}
@@ -1203,11 +918,13 @@
// The pageableKC (and sometimes auxKC) has 1 LC_DYLD_CHAINED_FIXUPS per kext
// while other KCs have 1 for the whole KC.
// It also tracks each segment in each kext for chained fixups, not the segments on the KC itself
- uint64_t numSegmentsForChainedFixups = 0;
+ __block uint64_t numSegmentsForChainedFixups = 0;
uint64_t numChainedFixupHeaders = 0;
if ( fixupsArePerKext() ) {
for (DylibInfo& dylib : sortedDylibs) {
- numSegmentsForChainedFixups += ((const Header*)dylib.input->mappedFile.mh)->segmentCount();
+ dylib.input->mappedFile.mh->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& segInfo, bool& stop) {
+ ++numSegmentsForChainedFixups;
+ });
}
numChainedFixupHeaders = sortedDylibs.size();
@@ -1223,10 +940,6 @@
uint64_t numBytesForPageStarts = 0;
if ( dataConstRegion.sizeInUse != 0 )
numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(dataConstRegion.bufferSize));
- if ( lateConstRegion.sizeInUse != 0 )
- numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(lateConstRegion.bufferSize));
- if ( dataSptmRegion.sizeInUse != 0 )
- numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(dataSptmRegion.bufferSize));
if ( branchGOTsRegion.bufferSize != 0 )
numBytesForPageStarts += sizeof(dyld_chained_starts_in_segment) + (sizeof(uint16_t) * numWritablePagesToFixup(branchGOTsRegion.bufferSize));
if ( readWriteRegion.sizeInUse != 0 )
@@ -1394,17 +1107,16 @@
std::map<std::string, DylibSymbols>& dylibsToSymbols);
void findVTables(uint8_t currentLevel, const dyld3::MachOAnalyzer* kernelMA,
std::map<std::string, DylibSymbols>& dylibsToSymbols,
- const cache_builder::ASLR_Tracker& aslrTracker,
+ const AppCacheBuilder::ASLR_Tracker& aslrTracker,
const std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations);
void calculateSymbols();
void patchVTables(Diagnostics& diags,
std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations,
- cache_builder::ASLR_Tracker& aslrTracker,
+ AppCacheBuilder::ASLR_Tracker& aslrTracker,
uint8_t currentLevel);
private:
- __attribute__((format(printf, 2, 3)))
void logFunc(const char* format, ...) {
if ( logPatching ) {
va_list list;
@@ -1414,7 +1126,6 @@
}
};
- __attribute__((format(printf, 2, 3)))
void logFuncVerbose(const char* format, ...) {
if ( logPatchingVerbose ) {
va_list list;
@@ -1600,7 +1311,7 @@
DylibSymbols& kernelDylibSymbols = dylibsToSymbols[kernelID];
SymbolLocation symbolLocation = findVTablePatchingSymbol("__ZTV11OSMetaClass", kernelDylibSymbols);
if ( symbolLocation.found() ) {
- baseMetaClassVTableLoc = (uint8_t*)kernelMA + (symbolLocation.vmAddr - ((const Header*)kernelMA)->preferredLoadAddress());
+ baseMetaClassVTableLoc = (uint8_t*)kernelMA + (symbolLocation.vmAddr - kernelMA->preferredLoadAddress());
VTable& vtable = vtables[baseMetaClassVTableLoc];
vtable.ma = kernelMA;
@@ -1642,10 +1353,10 @@
// And add classic if we have them
existingKernelCollection->forEachRebase(diags, ^(const char *opcodeName, const dyld3::MachOAnalyzer::LinkEditInfo &leInfo,
- const Header::SegmentInfo *segments,
+ const dyld3::MachOAnalyzer::SegmentInfo *segments,
bool segIndexSet, uint32_t ptrSize, uint8_t segmentIndex,
uint64_t segmentOffset, dyld3::MachOAnalyzer::Rebase kind, bool &stop) {
- uint64_t rebaseVmAddr = segments[segmentIndex].vmaddr + segmentOffset;
+ uint64_t rebaseVmAddr = segments[segmentIndex].vmAddr + segmentOffset;
uint64_t runtimeOffset = rebaseVmAddr - kernelBaseAddress;
const uint8_t* fixupLoc = kernelBasePointer + runtimeOffset;
uint64_t targetVMAddr = 0;
@@ -1711,7 +1422,7 @@
bool kernelUsesClassicRelocs = existingKernelCollection->usesClassicRelocationsInKernelCollection();
existingKernelCollection->forEachDylib(diags, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
- uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
+ uint64_t loadAddress = ma->preferredLoadAddress();
auto visitBaseKernelCollectionSymbols = ^(const char *symbolName, uint64_t n_value) {
if ( strstr(symbolName, superMetaclassPointerToken) == nullptr )
@@ -1932,7 +1643,7 @@
}
pageableKernelCollection->forEachDylib(diags, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
- uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
+ uint64_t loadAddress = ma->preferredLoadAddress();
auto visitPageableKernelCollectionSymbols = ^(const char *symbolName, uint64_t n_value) {
if ( strstr(symbolName, superMetaclassPointerToken) == nullptr )
return;
@@ -2133,7 +1844,7 @@
void VTablePatcher::findVTables(uint8_t currentLevel, const dyld3::MachOAnalyzer* kernelMA,
std::map<std::string, DylibSymbols>& dylibsToSymbols,
- const cache_builder::ASLR_Tracker& aslrTracker,
+ const AppCacheBuilder::ASLR_Tracker& aslrTracker,
const std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations)
{
const bool is64 = pointerSize == 8;
@@ -2165,7 +1876,7 @@
Diagnostics& dylibDiags = *dylib.diags;
const std::vector<std::string>& dependencies = dylib.dependencies;
- uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
+ uint64_t loadAddress = ma->preferredLoadAddress();
bool alreadyPatched = (ma == kernelMA);
auto visitSymbols = ^(const char *symbolName, uint64_t n_value) {
if ( strstr(symbolName, superMetaclassPointerToken) == nullptr )
@@ -2403,7 +2114,7 @@
void VTablePatcher::patchVTables(Diagnostics& diags,
std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations,
- cache_builder::ASLR_Tracker& aslrTracker,
+ AppCacheBuilder::ASLR_Tracker& aslrTracker,
uint8_t currentLevel)
{
const bool is64 = pointerSize == 8;
@@ -2475,7 +2186,7 @@
}
}
- logFunc("Found %lu vtable items: '%s'\n", vtable.entries.size(), vtable.name.c_str());
+ logFunc("Found %d vtable items: '%s'\n", vtable.entries.size(), vtable.name.c_str());
};
// Map from MachO to diagnostics to emit for that file
@@ -2678,7 +2389,7 @@
struct DylibFixups {
void processFixups(const std::map<std::string, DylibSymbols>& dylibsToSymbols,
const std::unordered_map<std::string_view, std::vector<DylibSymbolLocation>>& symbolMap,
- const std::string& kernelID, const cache_builder::ASLR_Tracker& aslrTracker);
+ const std::string& kernelID, const CacheBuilder::ASLR_Tracker& aslrTracker);
// Inputs
const dyld3::MachOAnalyzer* ma = nullptr;
@@ -2706,7 +2417,7 @@
void DylibFixups::processFixups(const std::map<std::string, DylibSymbols>& dylibsToSymbols,
const std::unordered_map<std::string_view, std::vector<DylibSymbolLocation>>& symbolMap,
- const std::string& kernelID, const cache_builder::ASLR_Tracker& aslrTracker) {
+ const std::string& kernelID, const CacheBuilder::ASLR_Tracker& aslrTracker) {
auto& resolvedBindLocations = dylibSymbols.resolvedBindLocations;
const std::string& dylibID = dylibSymbols.dylibName;
@@ -2861,6 +2572,8 @@
return;
}
}
+
+ // uint64_t baseAddress = ma->preferredLoadAddress();
ma->withChainStarts(dylibDiag, 0, ^(const dyld_chained_starts_in_image* starts) {
ma->forEachFixupInAllChains(dylibDiag, starts, false, ^(dyld3::MachOLoaded::ChainedFixupPointerOnDisk* fixupLoc, const dyld_chained_starts_in_segment* segInfo, bool& stop) {
@@ -2972,7 +2685,7 @@
__block bool foundUseOfMagicSymbol = false;
__block bool foundMissingWeakImport = false;
- const uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
+ const uint64_t loadAddress = ma->preferredLoadAddress();
ma->forEachBind(dylibDiag, ^(uint64_t runtimeOffset, int libOrdinal, uint8_t bindType,
const char *symbolName, bool weakImport, bool lazyBind, uint64_t addend, bool &stop) {
// printf("Bind at 0x%llx to '%s'\n", runtimeOffset, symbolName);
@@ -3245,152 +2958,13 @@
return std::make_unique<std::unordered_set<std::string>>(std::move(symbols));
}
-void AppCacheBuilder::patchVTables(const dyld3::MachOAnalyzer* kernelMA,
- const std::string& kernelID,
- std::map<std::string, DylibSymbols>& dylibsToSymbols,
- std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations)
-{
- // We only patch vtables on macOS. Luckily the platform is in the kernel binary
- if ( !((mach_o::Header*)kernelMA)->builtForPlatform(mach_o::Platform::macOS) )
- return;
-
- auto vtablePatcherOwner = std::make_unique<VTablePatcher>(numFixupLevels);
- VTablePatcher& vtablePatcher = *vtablePatcherOwner.get();
-
- uint8_t currentLevel = getCurrentFixupLevel();
-
- // Add all the collections to the vtable patcher
- if ( existingKernelCollection != nullptr ) {
- // The baseKC for x86_64 has __HIB mapped first , so we need to get either the __DATA or __TEXT depending on what is earliest
- // The kernel base address is still __TEXT, even if __DATA or __HIB is mapped prior to that.
- // The loader may have loaded something before __TEXT, but the existingKernelCollection pointer still corresponds to __TEXT
- __block uint64_t baseAddress = ~0ULL;
- ((const Header*)existingKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- baseAddress = std::min(baseAddress, info.vmaddr);
- });
-
- // The existing collection is a pointer to the mach_header for the baseKC, but __HIB and other segments may be before that
- // Offset those here
- uint64_t basePointerOffset = ((const Header*)existingKernelCollection)->preferredLoadAddress() - baseAddress;
- const uint8_t* basePointer = (uint8_t*)existingKernelCollection - basePointerOffset;
-
- vtablePatcher.addKernelCollection(existingKernelCollection, Options::AppCacheKind::kernel,
- basePointer, baseAddress);
- }
-
- if ( pageableKernelCollection != nullptr ) {
- // The baseKC for x86_64 has __HIB mapped first , so we need to get either the __DATA or __TEXT depending on what is earliest
- // The kernel base address is still __TEXT, even if __DATA or __HIB is mapped prior to that.
- // The loader may have loaded something before __TEXT, but the existingKernelCollection pointer still corresponds to __TEXT
- __block uint64_t baseAddress = ~0ULL;
- ((const Header*)pageableKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- baseAddress = std::min(baseAddress, info.vmaddr);
- });
-
- // The existing collection is a pointer to the mach_header for the baseKC, but __HIB and other segments may be before that
- // Offset those here
- uint64_t basePointerOffset = ((const Header*)pageableKernelCollection)->preferredLoadAddress() - baseAddress;
- const uint8_t* basePointer = (uint8_t*)pageableKernelCollection - basePointerOffset;
-
- vtablePatcher.addKernelCollection(pageableKernelCollection, Options::AppCacheKind::pageableKC,
- basePointer, baseAddress);
- }
-
- // Also add our KC
- vtablePatcher.addKernelCollection((const dyld3::MachOAppCache*)cacheHeader.header, appCacheOptions.cacheKind,
- (const uint8_t*)_fullAllocatedBuffer, cacheBaseAddress);
-
- // Add all the dylibs to the patcher
- {
- if ( existingKernelCollection != nullptr ) {
- uint8_t fixupLevel = getFixupLevel(Options::AppCacheKind::kernel);
-
- __block std::map<std::string, std::vector<std::string>> kextDependencies;
- kextDependencies[kernelID] = {};
- existingKernelCollection->forEachPrelinkInfoLibrary(_diagnostics,
- ^(const char *bundleName, const char* relativePath,
- const std::vector<const char *> &deps) {
- std::vector<std::string>& dependencies = kextDependencies[bundleName];
- dependencies.insert(dependencies.end(), deps.begin(), deps.end());
- });
-
- existingKernelCollection->forEachDylib(_diagnostics, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
- auto depsIt = kextDependencies.find(dylibID);
- assert(depsIt != kextDependencies.end());
- vtablePatcher.addDylib(_diagnostics, ma, dylibID, depsIt->second, fixupLevel);
- });
- }
-
- if ( pageableKernelCollection != nullptr ) {
- uint8_t fixupLevel = getFixupLevel(Options::AppCacheKind::pageableKC);
-
- __block std::map<std::string, std::vector<std::string>> kextDependencies;
- pageableKernelCollection->forEachPrelinkInfoLibrary(_diagnostics,
- ^(const char *bundleName, const char* relativePath,
- const std::vector<const char *> &deps) {
- std::vector<std::string>& dependencies = kextDependencies[bundleName];
- dependencies.insert(dependencies.end(), deps.begin(), deps.end());
- });
-
- pageableKernelCollection->forEachDylib(_diagnostics, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
- auto depsIt = kextDependencies.find(dylibID);
- assert(depsIt != kextDependencies.end());
- vtablePatcher.addDylib(_diagnostics, ma, dylibID, depsIt->second, fixupLevel);
- });
- }
-
- forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID, DylibStripMode stripMode,
- const std::vector<std::string> &dependencies, Diagnostics& dylibDiag, bool &stop) {
- vtablePatcher.addDylib(dylibDiag, ma, dylibID, dependencies, currentLevel);
- });
- }
-
- vtablePatcher.findMetaclassDefinitions(dylibsToSymbols, kernelID, kernelMA, appCacheOptions.cacheKind);
- vtablePatcher.findExistingFixups(_diagnostics, existingKernelCollection, pageableKernelCollection);
- if ( _diagnostics.hasError() )
- return;
-
- // Add vtables from the base KC if we have one
- if ( existingKernelCollection != nullptr ) {
- vtablePatcher.findBaseKernelVTables(_diagnostics, existingKernelCollection, dylibsToSymbols);
- if ( _diagnostics.hasError() )
- return;
- }
-
- // Add vtables from the pageable KC if we have one
- if ( pageableKernelCollection != nullptr ) {
- vtablePatcher.findPageableKernelVTables(_diagnostics, pageableKernelCollection, dylibsToSymbols);
- if ( _diagnostics.hasError() )
- return;
- }
-
- // Add vables from our level
- vtablePatcher.findVTables(currentLevel, kernelMA, dylibsToSymbols, _aslrTracker, missingBindLocations);
-
- // Don't run the patcher if we have a failure finding the vtables
- if ( vtablePatcher.hasError() ) {
- _diagnostics.error("One or more binaries has an error which prevented linking. See other errors.");
- return;
- }
-
- // Now patch all of the vtables.
- vtablePatcher.patchVTables(_diagnostics, missingBindLocations, _aslrTracker, currentLevel);
- if ( _diagnostics.hasError() )
- return;
-
- if ( vtablePatcher.hasError() ) {
- _diagnostics.error("One or more binaries has an error which prevented linking. See other errors.");
- return;
- }
-
- // FIXME: We could move vtablePatcherOwner to a worker thread to be destroyed
- vtablePatcherOwner.reset();
-}
-
void AppCacheBuilder::processFixups()
{
auto dylibsToSymbolsOwner = std::make_unique<std::map<std::string, DylibSymbols>>();
std::map<std::string, DylibSymbols>& dylibsToSymbols = *dylibsToSymbolsOwner.get();
+
+ auto vtablePatcherOwner = std::make_unique<VTablePatcher>(numFixupLevels);
+ VTablePatcher& vtablePatcher = *vtablePatcherOwner.get();
const uint32_t kernelLevel = 0;
uint8_t currentLevel = getCurrentFixupLevel();
@@ -3829,7 +3403,7 @@
}
// Emit branch stubs
- const uint64_t loadAddress = ((const Header*)dylibFixup.ma)->preferredLoadAddress();
+ const uint64_t loadAddress = dylibFixup.ma->preferredLoadAddress();
for (const DylibFixups::BranchStubData& branchData : dylibFixup.branchStubs) {
// Branching from the auxKC to baseKC. ld64 doesn't emit a stub in x86_64 kexts
// so we need to synthesize one now
@@ -3884,9 +3458,133 @@
}
// Now that we've processes all rebases/binds, patch all the vtables
- this->patchVTables(kernelMA, kernelID, dylibsToSymbols, missingBindLocations);
+
+ // Add all the collections to the vtable patcher
+ if ( existingKernelCollection != nullptr ) {
+ // The baseKC for x86_64 has __HIB mapped first , so we need to get either the __DATA or __TEXT depending on what is earliest
+ // The kernel base address is still __TEXT, even if __DATA or __HIB is mapped prior to that.
+ // The loader may have loaded something before __TEXT, but the existingKernelCollection pointer still corresponds to __TEXT
+ __block uint64_t baseAddress = ~0ULL;
+ existingKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
+ baseAddress = std::min(baseAddress, info.vmAddr);
+ });
+
+ // The existing collection is a pointer to the mach_header for the baseKC, but __HIB and other segments may be before that
+ // Offset those here
+ uint64_t basePointerOffset = existingKernelCollection->preferredLoadAddress() - baseAddress;
+ const uint8_t* basePointer = (uint8_t*)existingKernelCollection - basePointerOffset;
+
+ vtablePatcher.addKernelCollection(existingKernelCollection, Options::AppCacheKind::kernel,
+ basePointer, baseAddress);
+ }
+
+ if ( pageableKernelCollection != nullptr ) {
+ // The baseKC for x86_64 has __HIB mapped first , so we need to get either the __DATA or __TEXT depending on what is earliest
+ // The kernel base address is still __TEXT, even if __DATA or __HIB is mapped prior to that.
+ // The loader may have loaded something before __TEXT, but the existingKernelCollection pointer still corresponds to __TEXT
+ __block uint64_t baseAddress = ~0ULL;
+ pageableKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
+ baseAddress = std::min(baseAddress, info.vmAddr);
+ });
+
+ // The existing collection is a pointer to the mach_header for the baseKC, but __HIB and other segments may be before that
+ // Offset those here
+ uint64_t basePointerOffset = pageableKernelCollection->preferredLoadAddress() - baseAddress;
+ const uint8_t* basePointer = (uint8_t*)pageableKernelCollection - basePointerOffset;
+
+ vtablePatcher.addKernelCollection(pageableKernelCollection, Options::AppCacheKind::pageableKC,
+ basePointer, baseAddress);
+ }
+
+ // Also add our KC
+ vtablePatcher.addKernelCollection((const dyld3::MachOAppCache*)cacheHeader.header, appCacheOptions.cacheKind,
+ (const uint8_t*)_fullAllocatedBuffer, cacheBaseAddress);
+
+ // Add all the dylibs to the patcher
+ {
+ if ( existingKernelCollection != nullptr ) {
+ uint8_t fixupLevel = getFixupLevel(Options::AppCacheKind::kernel);
+
+ __block std::map<std::string, std::vector<std::string>> kextDependencies;
+ kextDependencies[kernelID] = {};
+ existingKernelCollection->forEachPrelinkInfoLibrary(_diagnostics,
+ ^(const char *bundleName, const char* relativePath,
+ const std::vector<const char *> &deps) {
+ std::vector<std::string>& dependencies = kextDependencies[bundleName];
+ dependencies.insert(dependencies.end(), deps.begin(), deps.end());
+ });
+
+ existingKernelCollection->forEachDylib(_diagnostics, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
+ auto depsIt = kextDependencies.find(dylibID);
+ assert(depsIt != kextDependencies.end());
+ vtablePatcher.addDylib(_diagnostics, ma, dylibID, depsIt->second, fixupLevel);
+ });
+ }
+
+ if ( pageableKernelCollection != nullptr ) {
+ uint8_t fixupLevel = getFixupLevel(Options::AppCacheKind::pageableKC);
+
+ __block std::map<std::string, std::vector<std::string>> kextDependencies;
+ pageableKernelCollection->forEachPrelinkInfoLibrary(_diagnostics,
+ ^(const char *bundleName, const char* relativePath,
+ const std::vector<const char *> &deps) {
+ std::vector<std::string>& dependencies = kextDependencies[bundleName];
+ dependencies.insert(dependencies.end(), deps.begin(), deps.end());
+ });
+
+ pageableKernelCollection->forEachDylib(_diagnostics, ^(const dyld3::MachOAnalyzer *ma, const char *dylibID, bool &stop) {
+ auto depsIt = kextDependencies.find(dylibID);
+ assert(depsIt != kextDependencies.end());
+ vtablePatcher.addDylib(_diagnostics, ma, dylibID, depsIt->second, fixupLevel);
+ });
+ }
+
+ forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID, DylibStripMode stripMode,
+ const std::vector<std::string> &dependencies, Diagnostics& dylibDiag, bool &stop) {
+ vtablePatcher.addDylib(dylibDiag, ma, dylibID, dependencies, currentLevel);
+ });
+ }
+
+ vtablePatcher.findMetaclassDefinitions(dylibsToSymbols, kernelID, kernelMA, appCacheOptions.cacheKind);
+ vtablePatcher.findExistingFixups(_diagnostics, existingKernelCollection, pageableKernelCollection);
if ( _diagnostics.hasError() )
return;
+
+ // Add vtables from the base KC if we have one
+ if ( existingKernelCollection != nullptr ) {
+ vtablePatcher.findBaseKernelVTables(_diagnostics, existingKernelCollection, dylibsToSymbols);
+ if ( _diagnostics.hasError() )
+ return;
+ }
+
+ // Add vtables from the pageable KC if we have one
+ if ( pageableKernelCollection != nullptr ) {
+ vtablePatcher.findPageableKernelVTables(_diagnostics, pageableKernelCollection, dylibsToSymbols);
+ if ( _diagnostics.hasError() )
+ return;
+ }
+
+ // Add vables from our level
+ vtablePatcher.findVTables(currentLevel, kernelMA, dylibsToSymbols, _aslrTracker, missingBindLocations);
+
+ // Don't run the patcher if we have a failure finding the vtables
+ if ( vtablePatcher.hasError() ) {
+ _diagnostics.error("One or more binaries has an error which prevented linking. See other errors.");
+ return;
+ }
+
+ // Now patch all of the vtables.
+ vtablePatcher.patchVTables(_diagnostics, missingBindLocations, _aslrTracker, currentLevel);
+ if ( _diagnostics.hasError() )
+ return;
+
+ if ( vtablePatcher.hasError() ) {
+ _diagnostics.error("One or more binaries has an error which prevented linking. See other errors.");
+ return;
+ }
+
+ // FIXME: We could move vtablePatcherOwner to a worker thread to be destroyed
+ vtablePatcherOwner.reset();
// Also error out if we have an error on any of the dylib diagnostic objects
@@ -3900,20 +3598,20 @@
forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID, DylibStripMode stripMode,
const std::vector<std::string> &dependencies, Diagnostics& dylibDiag, bool &stopDylib) {
intptr_t slide = ma->getSlide();
- ((const Header*)ma)->forEachSection(^(const Header::SectionInfo §Info,
- bool &stopSection) {
- const uint8_t* content = (uint8_t*)(sectInfo.address + slide);
+ ma->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo §Info,
+ bool malformedSectionRange, bool &stopSection) {
+ const uint8_t* content = (uint8_t*)(sectInfo.sectAddr + slide);
const uint8_t* start = (uint8_t*)content;
- const uint8_t* end = start + sectInfo.size;
+ const uint8_t* end = start + sectInfo.sectSize;
if ( (missingBindLoc >= start) && (missingBindLoc < end) ) {
+ std::string segmentName = sectInfo.segInfo.segName;
+ std::string sectionName = sectInfo.sectName;
uint64_t sectionOffset = (missingBindLoc - start);
-
- dylibDiag.error("Failed to bind '%s' in '%s' (at offset 0x%llx in %.*s, %.*s) as "
+
+ dylibDiag.error("Failed to bind '%s' in '%s' (at offset 0x%llx in %s, %s) as "
"could not find a kext which exports this symbol",
missingBind.symbolName.c_str(), missingBind.binaryID.data(),
- sectionOffset,
- (int)sectInfo.segmentName.size(), sectInfo.segmentName.data(),
- (int)sectInfo.sectionName.size(), sectInfo.sectionName.data());
+ sectionOffset, segmentName.c_str(), sectionName.c_str());
reportedError = true;
stopSection = true;
@@ -3989,23 +3687,23 @@
if ( header.dynSymbolTable != nullptr ) {
classicRelocsBufferStart = byteBuffer.begin();
- const Header* cacheMH = (const Header*)header.header;
+ dyld3::MachOAnalyzer* cacheMA = (dyld3::MachOAnalyzer*)header.header;
__block uint64_t localRelocBaseAddress = 0;
- cacheMH->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
- if ( info.initProt & VM_PROT_WRITE ) {
- localRelocBaseAddress = info.vmaddr;
+ cacheMA->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
+ if ( info.protections & VM_PROT_WRITE ) {
+ localRelocBaseAddress = info.vmAddr;
stop = true;
}
});
const std::vector<void*> allRebaseTargets = _aslrTracker.getRebaseTargets();
- const Header* kernelMH = (const Header*)getKernelStaticExecutableFromCache();
- kernelMH->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+ const dyld3::MachOAnalyzer* kernelMA = getKernelStaticExecutableFromCache();
+ kernelMA->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
std::vector<void*> segmentRebaseTargets;
- uint64_t segmentVMOffset = info.vmaddr - cacheBaseAddress;
+ uint64_t segmentVMOffset = info.vmAddr - cacheBaseAddress;
const uint8_t* segmentStartAddr = (const uint8_t*)(_fullAllocatedBuffer + segmentVMOffset);
- const uint8_t* segmentEndAddr = (const uint8_t*)(segmentStartAddr + info.vmsize);
+ const uint8_t* segmentEndAddr = (const uint8_t*)(segmentStartAddr + info.vmSize);
for (void* target : allRebaseTargets) {
if ( (target >= segmentStartAddr) && (target < segmentEndAddr) ) {
segmentRebaseTargets.push_back(target);
@@ -4017,7 +3715,7 @@
uint64_t targetSegmentOffset = (uint64_t)target - (uint64_t)segmentStartAddr;
//printf("Target: %s + 0x%llx: %p\n", info.segName, targetSegmentOffset, target);
- uint64_t offsetFromBaseAddress = (info.vmaddr + targetSegmentOffset) - localRelocBaseAddress;
+ uint64_t offsetFromBaseAddress = (info.vmAddr + targetSegmentOffset) - localRelocBaseAddress;
relocation_info* reloc = (relocation_info*)byteBuffer.makeSpace(sizeof(relocation_info));
reloc->r_address = (uint32_t)offsetFromBaseAddress;
reloc->r_symbolnum = 0;
@@ -4060,8 +3758,8 @@
assert(existingKernelCollection != nullptr);
// The auxKC is mapped with __DATA first, so we need to get either the __DATA or __TEXT depending on what is earliest
__block uint64_t baseAddress = ~0ULL;
- ((const Header*)existingKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- baseAddress = std::min(baseAddress, info.vmaddr);
+ existingKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
+ baseAddress = std::min(baseAddress, info.vmAddr);
});
levelBaseAddresses[0] = baseAddress;
}
@@ -4069,8 +3767,8 @@
if ( pageableKernelCollection != nullptr ) {
// We may have __DATA first, so we need to get either the __DATA or __TEXT depending on what is earliest
__block uint64_t baseAddress = ~0ULL;
- ((const Header *)pageableKernelCollection)->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- baseAddress = std::min(baseAddress, info.vmaddr);
+ pageableKernelCollection->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo& info, bool& stop) {
+ baseAddress = std::min(baseAddress, info.vmAddr);
});
uint8_t fixupLevel = getFixupLevel(Options::AppCacheKind::pageableKC);
levelBaseAddresses[fixupLevel] = baseAddress;
@@ -4101,9 +3799,11 @@
// We have a dyld_chained_starts_in_image plus an offset for each segment
dyld_chained_starts_in_image* startsInImage = (dyld_chained_starts_in_image*)byteBuffer.makeSpace(sizeof(dyld_chained_starts_in_image) + (segmentCount * sizeof(uint32_t)));
+ const uint8_t* endOfStarts = nullptr;
for (SegmentFixups& segmentFixups : startsInSegments) {
uint64_t startsInSegmentByteSize = sizeof(dyld_chained_starts_in_segment) + (segmentFixups.numPagesToFixup * sizeof(uint16_t));
dyld_chained_starts_in_segment* startsInSegment = (dyld_chained_starts_in_segment*)byteBuffer.makeSpace(startsInSegmentByteSize);
+ endOfStarts = (const uint8_t*)startsInSegment + startsInSegmentByteSize;
segmentFixups.starts = startsInSegment;
segmentFixups.startsByteSize = startsInSegmentByteSize;
@@ -4217,30 +3917,30 @@
forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID,
DylibStripMode stripMode, const std::vector<std::string> &dependencies,
Diagnostics& dylibDiag, bool &stop) {
- uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
+ uint64_t loadAddress = ma->preferredLoadAddress();
__block uint64_t numSegments = 0;
__block std::vector<SegmentFixups> segmentFixups;
- ((const Header*)ma)->forEachSegment(^(const Header::SegmentInfo &info, bool &stopSegments) {
+ ma->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stopSegments) {
// Third party kexts have writable __TEXT, so we need to add starts for all segments
// other than LINKEDIT
bool segmentCanHaveFixups = false;
if ( appCacheOptions.cacheKind == Options::AppCacheKind::pageableKC ) {
- segmentCanHaveFixups = (info.initProt & VM_PROT_WRITE) != 0;
+ segmentCanHaveFixups = (info.protections & VM_PROT_WRITE) != 0;
} else {
// auxKC
- segmentCanHaveFixups = info.segmentName != "__LINKEDIT";
+ segmentCanHaveFixups = (strcmp(info.segName, "__LINKEDIT") != 0);
}
if ( segmentCanHaveFixups) {
SegmentFixups segmentToFixup;
- segmentToFixup.segmentBuffer = (uint8_t*)ma + (info.vmaddr - loadAddress);
- segmentToFixup.segmentIndex = info.segmentIndex;
- segmentToFixup.unslidLoadAddress = info.vmaddr;
- segmentToFixup.sizeInUse = info.vmsize;
+ segmentToFixup.segmentBuffer = (uint8_t*)ma + (info.vmAddr - loadAddress);
+ segmentToFixup.segmentIndex = info.segIndex;
+ segmentToFixup.unslidLoadAddress = info.vmAddr;
+ segmentToFixup.sizeInUse = info.vmSize;
segmentToFixup.starts = nullptr;
segmentToFixup.startsByteSize = 0;
- segmentToFixup.numPagesToFixup = numWritablePagesToFixup(info.vmsize);
+ segmentToFixup.numPagesToFixup = numWritablePagesToFixup(info.vmSize);
segmentFixups.push_back(segmentToFixup);
}
@@ -4263,7 +3963,7 @@
assert(_is64);
typedef Pointer64<LittleEndian> P;
- uint32_t freeSpace = ((const Header*)ma)->loadCommandsFreeSpace();
+ uint32_t freeSpace = ma->loadCommandsFreeSpace();
assert(freeSpace >= sizeof(macho_linkedit_data_command<P>));
uint8_t* endOfLoadCommands = (uint8_t*)ma + sizeof(macho_header<P>) + ma->sizeofcmds;
@@ -4329,10 +4029,6 @@
if ( dataConstRegion.sizeInUse != 0 )
addSegmentStarts(dataConstRegion);
- if ( lateConstRegion.sizeInUse != 0 )
- addSegmentStarts(lateConstRegion);
- if ( dataSptmRegion.sizeInUse != 0 )
- addSegmentStarts(dataSptmRegion);
if ( branchGOTsRegion.sizeInUse != 0 )
addSegmentStarts(branchGOTsRegion);
if ( readWriteRegion.sizeInUse != 0 )
@@ -4392,157 +4088,6 @@
#endif
}
-void AppCacheBuilder::getRegionOrder(bool dataRegionFirstInVMOrder,
- bool hibernateRegionFirstInVMOrder,
- std::vector<AlignedRegion>& fileOrder,
- std::vector<AlignedRegion>& vmOrder,
- std::map<const Region*, uint32_t>& sectionsToAddToRegions)
-{
- if ( hibernateRegionFirstInVMOrder ) {
- vmOrder.emplace_back(&hibernateRegion, 14, 14);
- // Add a section too
- sectionsToAddToRegions[&hibernateRegion] = 1;
- } else if ( dataRegionFirstInVMOrder ) {
- if ( prelinkInfoDict != nullptr ) {
- vmOrder.emplace_back(&prelinkInfoRegion, 14, 14);
- }
- if ( readWriteRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&readWriteRegion, 14, 14);
- }
- }
-
- // Cache header (__TEXT)
- vmOrder.emplace_back(&cacheHeaderRegion, 14, 14);
- fileOrder.emplace_back(&cacheHeaderRegion, 14, 14);
-
- // Split seg __TEXT (ie, __PRELINK_TEXT)
- {
- vmOrder.emplace_back(&readOnlyTextRegion, 14, 14);
- fileOrder.emplace_back(&readOnlyTextRegion, 14, 14);
- // Add a section too
- sectionsToAddToRegions[&readOnlyTextRegion] = 1;
- }
-
- // -sectcreate
- // Align to 16k before we lay out all contiguous regions
- if ( !customSegments.empty() ) {
- uint32_t alignFileBefore = 14;
- for (CustomSegment& customSegment : customSegments) {
- Region& region = *customSegment.parentRegion;
- vmOrder.emplace_back(®ion, 0, 0);
- fileOrder.emplace_back(®ion, alignFileBefore, 0);
- alignFileBefore = 0;
-
- // Maybe add sections too
- uint32_t sectionsToAdd = 0;
- if ( customSegment.sections.size() > 1 ) {
- // More than one section, so they all need names
- sectionsToAdd = (uint32_t)customSegment.sections.size();
- } else if ( !customSegment.sections.front().sectionName.empty() ) {
- // Only one section, but it has a name
- sectionsToAdd = 1;
- }
- sectionsToAddToRegions[®ion] = sectionsToAdd;
- }
-
- // Align the last region after
- vmOrder.back().alignmentAfter = 14;
- fileOrder.back().alignmentAfter = 14;
- }
-
- // __DATA_CONST
- if ( dataConstRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&dataConstRegion, 14, 14);
- fileOrder.emplace_back(&dataConstRegion, 14, 14);
- }
-
- // __LATE_CONST
- if ( lateConstRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&lateConstRegion, 14, 14);
- fileOrder.emplace_back(&lateConstRegion, 14, 14);
- }
-
- // __DATA_SPTM
- if ( dataSptmRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&dataSptmRegion, 14, 14);
- fileOrder.emplace_back(&dataSptmRegion, 14, 14);
- }
-
- // Split seg __TEXT_EXEC
- if ( readExecuteRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&readExecuteRegion, 14, 14);
- fileOrder.emplace_back(&readExecuteRegion, 14, 14);
- }
-
- // __BRANCH_STUBS
- if ( branchStubsRegion.bufferSize != 0 ) {
- vmOrder.emplace_back(&branchStubsRegion, 14, 14);
- fileOrder.emplace_back(&branchStubsRegion, 14, 14);
- }
-
- // __TEXT_BOOT_EXEC
- if ( textBootExecRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&textBootExecRegion, 14, 14);
- fileOrder.emplace_back(&textBootExecRegion, 14, 14);
- }
-
- // __BRANCH_GOTS
- if ( branchGOTsRegion.bufferSize != 0 ) {
- vmOrder.emplace_back(&branchGOTsRegion, 14, 14);
- fileOrder.emplace_back(&branchGOTsRegion, 14, 14);
- }
-
- // __PRELINK_INFO
- if ( prelinkInfoDict != nullptr )
- {
- fileOrder.emplace_back(&prelinkInfoRegion, 14, 14);
- if ( !dataRegionFirstInVMOrder )
- vmOrder.emplace_back(&prelinkInfoRegion, 14, 14);
- // Add a section too
- sectionsToAddToRegions[&prelinkInfoRegion] = 1;
- }
-
- // Split seg __DATA
- if ( readWriteRegion.sizeInUse != 0 ) {
- fileOrder.emplace_back(&readWriteRegion, 14, 14);
- if ( !dataRegionFirstInVMOrder ) {
- vmOrder.emplace_back(&readWriteRegion, 14, 14);
- }
- }
-
- // Split seg __HIB
- // Align to 16k
- if ( hibernateRegion.sizeInUse != 0 ) {
- fileOrder.emplace_back(&hibernateRegion, 14, 14);
- // VM offset was already handled earlier
- }
-
- // Non split seg regions
- // Align to 16k before we lay out all contiguous regions
- if ( !nonSplitSegRegions.empty() ) {
- uint32_t alignFileBefore = 14;
- for (Region& region : nonSplitSegRegions) {
- vmOrder.emplace_back(®ion, 0, 0);
- fileOrder.emplace_back(®ion, alignFileBefore, 0);
- alignFileBefore = 0;
- }
-
- // Align the last region after
- vmOrder.back().alignmentAfter = 14;
- fileOrder.back().alignmentAfter = 14;
- }
-
- // __LINKEDIT
- vmOrder.emplace_back(&_readOnlyRegion, 14, 14);
- fileOrder.emplace_back(&_readOnlyRegion, 14, 14);
-
- // __LINKEDIT fixups sub region
- if ( fixupsSubRegion.sizeInUse != 0 ) {
- vmOrder.emplace_back(&fixupsSubRegion, 14, 14);
- fileOrder.emplace_back(&fixupsSubRegion, 14, 14);
- }
-}
-
void AppCacheBuilder::allocateBuffer()
{
// Whether to order the regions __TEXT, __DATA, __LINKEDIT or __DATA, __TEXT, __LINKEDIT in VM address order
@@ -4553,7 +4098,7 @@
assert(0 && "Cache kind should have been set");
break;
case Options::AppCacheKind::kernel:
- if ( hibernateRegion.sizeInUse != 0 )
+ if ( hibernateAddress != 0 )
hibernateRegionFirstInVMOrder = true;
break;
case Options::AppCacheKind::pageableKC:
@@ -4567,15 +4112,232 @@
break;
}
- std::vector<AlignedRegion> fileOrder;
- std::vector<AlignedRegion> vmOrder;
+ // Count how many bytes we need from all our regions
+ __block uint64_t numRegionFileBytes = 0;
+ __block uint64_t numRegionVMBytes = 0;
+
+ std::vector<std::pair<Region*, uint64_t>> regions;
+ std::vector<std::pair<Region*, uint64_t>> regionsVMOrder;
std::map<const Region*, uint32_t> sectionsToAddToRegions;
- getRegionOrder(dataRegionFirstInVMOrder, hibernateRegionFirstInVMOrder,
- fileOrder, vmOrder, sectionsToAddToRegions);
+
+ if ( hibernateRegionFirstInVMOrder ) {
+ regionsVMOrder.push_back({ &hibernateRegion, numRegionVMBytes });
+ // Pad out the VM offset so that the cache header starts where the base address
+ // really should be
+ uint64_t paddedSize = cacheBaseAddress - hibernateAddress;
+ if ( hibernateRegion.bufferSize > paddedSize ) {
+ _diagnostics.error("Could not lay out __HIB segment");
+ return;
+ }
+ numRegionVMBytes = paddedSize;
+ // Set the base address to the hibernate address so that we actually put the
+ // hibernate segment there
+ cacheBaseAddress = hibernateAddress;
+
+ // Add a section too
+ sectionsToAddToRegions[&hibernateRegion] = 1;
+ } else if ( dataRegionFirstInVMOrder ) {
+ if ( prelinkInfoDict != nullptr ) {
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &prelinkInfoRegion, numRegionVMBytes });
+ numRegionVMBytes += prelinkInfoRegion.bufferSize;
+ }
+ if ( readWriteRegion.sizeInUse != 0 ) {
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &readWriteRegion, numRegionVMBytes });
+ numRegionVMBytes += readWriteRegion.bufferSize;
+ }
+ }
+
+ // Cache header
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regions.push_back({ &cacheHeaderRegion, 0 });
+ regionsVMOrder.push_back({ &cacheHeaderRegion, numRegionVMBytes });
+
+ // Split seg __TEXT
+ {
+ // File offset
+ readOnlyTextRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += readOnlyTextRegion.bufferSize;
+ regions.push_back({ &readOnlyTextRegion, 0 });
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &readOnlyTextRegion, numRegionVMBytes });
+ numRegionVMBytes += readOnlyTextRegion.bufferSize;
+
+ // Add a section too
+ sectionsToAddToRegions[&readOnlyTextRegion] = 1;
+ }
+
+ // Split seg __TEXT_EXEC
+ if ( readExecuteRegion.sizeInUse != 0 ) {
+ // File offset
+ readExecuteRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += readExecuteRegion.bufferSize;
+ regions.push_back({ &readExecuteRegion, 0 });
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &readExecuteRegion, numRegionVMBytes });
+ numRegionVMBytes += readExecuteRegion.bufferSize;
+ }
+
+ // __BRANCH_STUBS
+ if ( branchStubsRegion.bufferSize != 0 ) {
+ // File offset
+ branchStubsRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += branchStubsRegion.bufferSize;
+ regions.push_back({ &branchStubsRegion, 0 });
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &branchStubsRegion, numRegionVMBytes });
+ numRegionVMBytes += branchStubsRegion.bufferSize;
+ }
+
+ // __DATA_CONST
+ if ( dataConstRegion.sizeInUse != 0 ) {
+ // File offset
+ dataConstRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += dataConstRegion.bufferSize;
+ regions.push_back({ &dataConstRegion, 0 });
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &dataConstRegion, numRegionVMBytes });
+ numRegionVMBytes += dataConstRegion.bufferSize;
+ }
+
+ // __BRANCH_GOTS
+ if ( branchGOTsRegion.bufferSize != 0 ) {
+ // File offset
+ branchGOTsRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += branchGOTsRegion.bufferSize;
+ regions.push_back({ &branchGOTsRegion, 0 });
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &branchGOTsRegion, numRegionVMBytes });
+ numRegionVMBytes += branchGOTsRegion.bufferSize;
+ }
+
+ // -sectcreate
+ // Align to 16k before we lay out all contiguous regions
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ for (CustomSegment& customSegment : customSegments) {
+ Region& region = *customSegment.parentRegion;
+
+ region.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += region.bufferSize;
+ regions.push_back({ ®ion, 0 });
+ // VM offset
+ // Note we can't align the vm offset in here
+ assert( (numRegionVMBytes % 4096) == 0);
+ regionsVMOrder.push_back({ ®ion, numRegionVMBytes });
+ numRegionVMBytes += region.bufferSize;
+
+ // Maybe add sections too
+ uint32_t sectionsToAdd = 0;
+ if ( customSegment.sections.size() > 1 ) {
+ // More than one section, so they all need names
+ sectionsToAdd = (uint32_t)customSegment.sections.size();
+ } else if ( !customSegment.sections.front().sectionName.empty() ) {
+ // Only one section, but it has a name
+ sectionsToAdd = 1;
+ }
+ sectionsToAddToRegions[®ion] = sectionsToAdd;
+ }
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+
+ // __PRELINK_INFO
+ // Align to 16k
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ if ( prelinkInfoDict != nullptr )
+ {
+ // File offset
+ prelinkInfoRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += prelinkInfoRegion.bufferSize;
+ regions.push_back({ &prelinkInfoRegion, 0 });
+
+ if ( !dataRegionFirstInVMOrder ) {
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &prelinkInfoRegion, numRegionVMBytes });
+ numRegionVMBytes += prelinkInfoRegion.bufferSize;
+ }
+
+ // Add a section too
+ sectionsToAddToRegions[&prelinkInfoRegion] = 1;
+ }
+
+ // Split seg __DATA
+ // Align to 16k
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ if ( readWriteRegion.sizeInUse != 0 ) {
+ // File offset
+ readWriteRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += readWriteRegion.bufferSize;
+ regions.push_back({ &readWriteRegion, 0 });
+
+ if ( !dataRegionFirstInVMOrder ) {
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &readWriteRegion, numRegionVMBytes });
+ numRegionVMBytes += readWriteRegion.bufferSize;
+ }
+ }
+
+ // Split seg __HIB
+ // Align to 16k
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ if ( hibernateRegion.sizeInUse != 0 ) {
+ // File offset
+ hibernateRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += hibernateRegion.bufferSize;
+ regions.push_back({ &hibernateRegion, 0 });
+
+ // VM offset was already handled earlier
+ }
+
+ // Non split seg regions
+ // Align to 16k before we lay out all contiguous regions
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ for (Region& region : nonSplitSegRegions) {
+ region.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += region.bufferSize;
+ regions.push_back({ ®ion, 0 });
+ // VM offset
+ // Note we can't align the vm offset in here
+ assert( (numRegionVMBytes % 4096) == 0);
+ regionsVMOrder.push_back({ ®ion, numRegionVMBytes });
+ numRegionVMBytes += region.bufferSize;
+ }
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+
+ // __LINKEDIT
+ // Align to 16k
+ // File offset
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ _readOnlyRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += _readOnlyRegion.bufferSize;
+ regions.push_back({ &_readOnlyRegion, 0 });
+ // VM offset
+ numRegionVMBytes = align(numRegionVMBytes, 14);
+ regionsVMOrder.push_back({ &_readOnlyRegion, numRegionVMBytes });
+ numRegionVMBytes += _readOnlyRegion.bufferSize;
+
+ // __LINKEDIT fixups sub region
+ // Align to 16k
+ numRegionFileBytes = align(numRegionFileBytes, 14);
+ if ( fixupsSubRegion.sizeInUse != 0 ) {
+ fixupsSubRegion.cacheFileOffset = numRegionFileBytes;
+ numRegionFileBytes += fixupsSubRegion.bufferSize;
+ //regions.push_back({ &fixupsSubRegion, 0 });
+
+ // VM offset
+ regionsVMOrder.push_back({ &fixupsSubRegion, numRegionVMBytes });
+ numRegionVMBytes += fixupsSubRegion.bufferSize;
+ }
const thread_command* unixThread = nullptr;
if (const DylibInfo* dylib = getKernelStaticExecutableInputFile()) {
- unixThread = ((const Header*)dylib->input->mappedFile.mh)->unixThreadLoadCommand();
+ unixThread = dylib->input->mappedFile.mh->unixThreadLoadCommand();
}
if (_is64) {
@@ -4630,19 +4392,13 @@
}
// Add an LC_SEGMENT_64 for each region
- std::unordered_map<const Region*, uint64_t> regionLoadCommandOffsets;
- for ( const AlignedRegion& region : fileOrder ) {
- // The fixups sub region doesn't get a load command, as its a range inside LINKEDIT
- if ( region.region == &fixupsSubRegion )
- continue;
-
- regionLoadCommandOffsets[region.region] = cacheHeaderSize + cacheLoadCommandsSize;
-
+ for (auto& regionAndOffset : regions) {
++cacheNumLoadCommands;
+ regionAndOffset.second = cacheHeaderSize + cacheLoadCommandsSize;
cacheLoadCommandsSize += sizeof(segment_command_64);
// Add space for any sections too
- auto sectionIt = sectionsToAddToRegions.find(region.region);
+ auto sectionIt = sectionsToAddToRegions.find(regionAndOffset.first);
if ( sectionIt != sectionsToAddToRegions.end() ) {
uint32_t numSections = sectionIt->second;
cacheLoadCommandsSize += sizeof(section_64) * numSections;
@@ -4664,51 +4420,6 @@
// Align the app cache header before the rest of the bytes
cacheHeaderRegionSize = align(cacheHeaderRegionSize, 14);
- // Cache header
- cacheHeaderRegion.bufferSize = cacheHeaderRegionSize;
- cacheHeaderRegion.sizeInUse = cacheHeaderRegion.bufferSize;
- cacheHeaderRegion.cacheFileOffset = 0;
- cacheHeaderRegion.initProt = VM_PROT_READ;
- cacheHeaderRegion.maxProt = VM_PROT_READ;
- cacheHeaderRegion.name = "__TEXT";
-
- // Walk all the regions and compute the total file and VM bytes
- uint64_t numRegionVMBytes = 0;
- {
- uint64_t vmAddr = cacheBaseAddress;
- for ( AlignedRegion& alignedRegion : vmOrder ) {
- if ( alignedRegion.alignmentBefore != 0 )
- vmAddr = align(vmAddr, alignedRegion.alignmentBefore);
-
- Region* region = alignedRegion.region;
- region->unslidLoadAddress = vmAddr;
- vmAddr += region->bufferSize;
-
- if ( alignedRegion.alignmentAfter != 0 )
- vmAddr = align(vmAddr, alignedRegion.alignmentAfter);
- }
-
- numRegionVMBytes = vmAddr - cacheBaseAddress;
- }
-
- uint64_t numRegionFileBytes = 0;
- {
- uint64_t fileOffset = 0;
- for ( AlignedRegion& alignedRegion : fileOrder ) {
- if ( alignedRegion.alignmentBefore != 0 )
- fileOffset = align(fileOffset, alignedRegion.alignmentBefore);
-
- Region* region = alignedRegion.region;
- region->cacheFileOffset = fileOffset;
- fileOffset += region->bufferSize;
-
- if ( alignedRegion.alignmentAfter != 0 )
- fileOffset = align(fileOffset, alignedRegion.alignmentAfter);
- }
-
- numRegionFileBytes = fileOffset;
- }
-
assert(numRegionFileBytes <= numRegionVMBytes);
_allocatedBufferSize = cacheHeaderRegionSize + numRegionVMBytes;
@@ -4730,10 +4441,33 @@
// Assign region vm and buffer addresses now that we know the size of
// the cache header
- for ( AlignedRegion& alignedRegion : vmOrder ) {
- Region* region = alignedRegion.region;
- region->buffer = (uint8_t*)_fullAllocatedBuffer + (region->unslidLoadAddress - cacheBaseAddress);
- }
+ {
+ // All vm offsets prior to the cache header are already correct
+ // All those after the cache header need to be shifted by the cache
+ // header size
+ bool seenCacheHeader = false;
+ for (const auto& regionAndVMOffset : regionsVMOrder) {
+ Region* region = regionAndVMOffset.first;
+ uint64_t vmOffset = regionAndVMOffset.second;
+ region->unslidLoadAddress = cacheBaseAddress + vmOffset;
+ if ( seenCacheHeader ) {
+ // Shift by the cache header size
+ region->unslidLoadAddress += cacheHeaderRegionSize;
+ } else {
+ // The offset is correct but add in the base address
+ seenCacheHeader = (region == &cacheHeaderRegion);
+ }
+ region->buffer = (uint8_t*)_fullAllocatedBuffer + (region->unslidLoadAddress - cacheBaseAddress);
+ }
+ }
+
+ // Cache header
+ cacheHeaderRegion.bufferSize = cacheHeaderRegionSize;
+ cacheHeaderRegion.sizeInUse = cacheHeaderRegion.bufferSize;
+ cacheHeaderRegion.cacheFileOffset = 0;
+ cacheHeaderRegion.initProt = VM_PROT_READ;
+ cacheHeaderRegion.maxProt = VM_PROT_READ;
+ cacheHeaderRegion.name = "__TEXT";
#if 0
for (const auto& regionAndVMOffset : regionsVMOrder) {
@@ -4765,23 +4499,57 @@
header.chainedFixups = (linkedit_data_command*)(cacheHeaderRegion.buffer + chainedFixupsOffset);
}
- for ( AlignedRegion& alignedRegion : fileOrder ) {
- Region* region = alignedRegion.region;
- // The fixups sub region doesn't get a load command, as its a range inside LINKEDIT
- if ( region == &fixupsSubRegion )
- continue;
-
- assert(region->initProt != 0);
- assert(region->maxProt != 0);
-
- uint64_t loadCommandOffset = regionLoadCommandOffsets.at(region);
- segment_command_64* loadCommand = (segment_command_64*)(cacheHeaderRegion.buffer + loadCommandOffset);
- header.segments.push_back({ loadCommand, region });
+ for (auto& regionAndOffset : regions) {
+ assert(regionAndOffset.first->initProt != 0);
+ assert(regionAndOffset.first->maxProt != 0);
+ segment_command_64* loadCommand = (segment_command_64*)(cacheHeaderRegion.buffer + regionAndOffset.second);
+ header.segments.push_back({ loadCommand, regionAndOffset.first });
}
for (const auto& dylibAndOffset : dylibs) {
fileset_entry_command* loadCommand = (fileset_entry_command*)(cacheHeaderRegion.buffer + dylibAndOffset.second);
header.dylibs.push_back({ loadCommand, dylibAndOffset.first });
}
+
+ // Move the offsets of all the other regions
+ // Split seg __TEXT
+ readOnlyTextRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // Split seg __TEXT_EXEC
+ readExecuteRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // __BRANCH_STUBS
+ branchStubsRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // Split seg __DATA_CONST
+ dataConstRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // __BRANCH_GOTS
+ branchGOTsRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // Split seg __DATA
+ readWriteRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // Split seg __HIB
+ hibernateRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // -sectcreate
+ for (Region& region : customDataRegions) {
+ region.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+ }
+
+ // Non split seg regions
+ for (Region& region : nonSplitSegRegions) {
+ region.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+ }
+
+ // __PRELINK_INFO
+ prelinkInfoRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // __LINKEDIT
+ _readOnlyRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
+
+ // __LINKEDIT fixups sub region
+ fixupsSubRegion.cacheFileOffset += cacheHeaderRegion.sizeInUse;
} else {
assert(false);
}
@@ -4820,7 +4588,7 @@
macho_build_version_command<P>* cmd = (macho_build_version_command<P>*)header.buildVersion;
cmd->set_cmd(LC_BUILD_VERSION);
cmd->set_cmdsize(sizeof(build_version_command));
- cmd->set_platform(_options.platform.value());
+ cmd->set_platform((uint32_t)_options.platform);
cmd->set_minos(0);
cmd->set_sdk(0);
cmd->set_ntools(0);
@@ -4832,12 +4600,12 @@
if ( header.unixThread != nullptr ) {
const DylibInfo* dylib = getKernelStaticExecutableInputFile();
const dyld3::MachOAnalyzer* ma = dylib->input->mappedFile.mh;
- ((const Header*)ma)->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+ ma->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
uint64_t startAddress = dylib->input->mappedFile.mh->entryAddrFromThreadCmd(header.unixThread);
- if ( (startAddress < info.vmaddr) || (startAddress >= (info.vmaddr + info.vmsize)) )
+ if ( (startAddress < info.vmAddr) || (startAddress >= (info.vmAddr + info.vmSize)) )
return;
- uint64_t segSlide = dylib->cacheLocation[info.segmentIndex].dstCacheUnslidAddress - info.vmaddr;
+ uint64_t segSlide = dylib->cacheLocation[info.segIndex].dstCacheUnslidAddress - info.vmAddr;
startAddress += segSlide;
macho_thread_command<P>* cmd = (macho_thread_command<P>*)header.unixThread;
@@ -5100,7 +4868,7 @@
// Skip codeless kext's
if ( ma == nullptr )
continue;
- uint64_t loadAddress = ((const Header*)ma)->preferredLoadAddress();
+ uint64_t loadAddress = ma->preferredLoadAddress();
// _PrelinkExecutableLoadAddr
CFNumberRef loadAddrRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &loadAddress);
@@ -5152,10 +4920,10 @@
}
__block uint64_t textSegmnentVMAddr = 0;
__block uint64_t textSegmnentVMSize = 0;
- ((const Header*)ma)->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
- if ( info.segmentName == "__TEXT" ) {
- textSegmnentVMAddr = info.vmaddr;
- textSegmnentVMSize = info.vmsize;
+ ma->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo &info, bool &stop) {
+ if ( !strcmp(info.segName, "__TEXT") ) {
+ textSegmnentVMAddr = info.vmAddr;
+ textSegmnentVMSize = info.vmSize;
stop = true;
}
});
@@ -5278,9 +5046,6 @@
return;
}
- // Find stubs to remove, if any
- parseStubs();
-
// assign addresses for each segment of each dylib in new cache
assignSegmentRegionsAndOffsets();
if ( _diagnostics.hasError() )
@@ -5331,20 +5096,6 @@
lastDataRegion = &dataConstRegion;
}
- if ( lateConstRegion.sizeInUse != 0 ) {
- if ( firstDataRegion == nullptr )
- firstDataRegion = &lateConstRegion;
- if ( (lastDataRegion == nullptr) || (lateConstRegion.buffer > lastDataRegion->buffer) )
- lastDataRegion = &lateConstRegion;
- }
-
- if ( dataSptmRegion.sizeInUse != 0 ) {
- if ( firstDataRegion == nullptr )
- firstDataRegion = &dataSptmRegion;
- if ( (lastDataRegion == nullptr) || (dataSptmRegion.buffer > lastDataRegion->buffer) )
- lastDataRegion = &dataSptmRegion;
- }
-
if ( branchGOTsRegion.bufferSize != 0 ) {
if ( firstDataRegion == nullptr )
firstDataRegion = &branchGOTsRegion;
@@ -5378,7 +5129,7 @@
_aslrTracker.setDataRegion(firstDataRegion->buffer, size);
}
}
- adjustAllImagesForNewSegmentLocations(cacheBaseAddress, nullptr);
+ adjustAllImagesForNewSegmentLocations(cacheBaseAddress, nullptr, nullptr);
if ( _diagnostics.hasError() )
return;
@@ -5397,17 +5148,12 @@
// optimize away stubs
uint64_t t6 = mach_absolute_time();
-
- if ( removeStubs() ) {
- // Stubs were removed, but we need to rewrite calls which would have gone through those stubs
- rewriteRemovedStubs();
- } else {
- // Stubs weren't removed, so do the existing stub optimizer
- __block std::vector<StubOptimizerInfo> images;
+ {
+ __block std::vector<std::pair<const mach_header*, const char*>> images;
forEachCacheDylib(^(const dyld3::MachOAnalyzer *ma, const std::string &dylibID,
DylibStripMode stripMode, const std::vector<std::string>& dependencies,
Diagnostics& dylibDiag, bool& stop) {
- images.push_back({ ma, dylibID.c_str(), nullptr, nullptr });
+ images.push_back({ ma, dylibID.c_str() });
});
// FIXME: Should we keep the same never stub eliminate symbols? Eg, for gmalloc.
const char* const neverStubEliminateSymbols[] = {
@@ -5416,8 +5162,8 @@
uint64_t cacheUnslidAddr = cacheBaseAddress;
int64_t cacheSlide = (long)_fullAllocatedBuffer - cacheUnslidAddr;
- std::unordered_map<uint64_t, std::pair<uint64_t, uint8_t*>> stubsToIslandAddr;
- optimizeAwayStubs(images, cacheSlide, nullptr, stubsToIslandAddr, neverStubEliminateSymbols);
+ optimizeAwayStubs(images, cacheSlide, cacheUnslidAddr,
+ nullptr, neverStubEliminateSymbols);
}
// FIPS seal corecrypto, This must be done after stub elimination (so that __TEXT,__text is not changed after sealing)
@@ -5537,213 +5283,6 @@
}
}
-static void getSectionLayout(const dyld3::MachOAnalyzer* ma,
- std::vector<uint64_t>& sectionAddresses,
- std::vector<uint8_t*>& sectionBuffers,
- uint32_t& authStubSectionIndex)
-{
- // section index 0 refers to mach_header
- sectionAddresses.push_back(((const Header*)ma)->preferredLoadAddress());
- sectionBuffers.push_back(nullptr);
-
- intptr_t slide = ma->getSlide();
- ((const Header*)ma)->forEachSection(^(const Header::SectionInfo& sectInfo, bool& stop) {
- if ( (sectInfo.segmentName == "__TEXT_EXEC") && (sectInfo.sectionName == "__auth_stubs") )
- authStubSectionIndex = (uint32_t)sectionAddresses.size();
- sectionAddresses.push_back(sectInfo.address);
- sectionBuffers.push_back((uint8_t*)sectInfo.address + slide);
- });
-}
-
-// Auth stubs will load a value then jump to it. This returns the list of locations they jump to
-static void getAuthStubTargets(Diagnostics& diag, const dyld3::MachOAnalyzer* ma,
- std::string_view dylibID,
- const std::vector<uint64_t>& sectionAddresses,
- const std::vector<uint8_t*>& sectionBuffers,
- uint32_t stubSectionIndex,
- std::map<uint64_t, uint64_t>& stubToTargetMap)
-{
- uint32_t splitSegSize = 0;
- const uint8_t* infoStart = (const uint8_t*)ma->getSplitSeg(splitSegSize);
- const uint8_t* infoEnd = infoStart + splitSegSize;
- if ( *infoStart++ != DYLD_CACHE_ADJ_V2_FORMAT ) {
- diag.error("malformed split seg info in %s", dylibID.data());
- return;
- }
-
- // Whole :== <count> FromToSection+
- // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
- // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
- // FromOffset :== <kind> <count> <from-sect-offset-delta>
- const uint8_t* p = infoStart;
- uint64_t sectionCount = read_uleb128(p, infoEnd);
- for (uint64_t i=0; i < sectionCount; ++i) {
- uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
- uint64_t toSectionIndex = read_uleb128(p, infoEnd);
- uint64_t toOffsetCount = read_uleb128(p, infoEnd);
- uint64_t toSectionOffset = 0;
- for (uint64_t j=0; j < toOffsetCount; ++j) {
- uint64_t toSectionDelta = read_uleb128(p, infoEnd);
- uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
- toSectionOffset += toSectionDelta;
- for (uint64_t k=0; k < fromOffsetCount; ++k) {
- uint64_t kind = read_uleb128(p, infoEnd);
- if ( kind > 13 ) {
- diag.error("bad kind (%llu) value in %s\n", kind, dylibID.data());
- }
- uint64_t fromSectDeltaCount = dyld3::MachOFile::read_uleb128(diag, p, infoEnd);
- if ( diag.hasError() )
- return;
- uint64_t fromSectionOffset = 0;
- for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
- uint64_t delta = dyld3::MachOFile::read_uleb128(diag, p, infoEnd);
- if ( diag.hasError() )
- return;
- fromSectionOffset += delta;
- if ( fromSectionIndex == stubSectionIndex ) {
- // The stub is 16-bytes in size, and contains the stub fixup here.
- // We need to work out the stub for the fixup
- uint64_t stubOffset = fromSectionOffset & ~0xF;
- uint64_t stubAddr = sectionAddresses[fromSectionIndex] + stubOffset;
-
- uint64_t* gotPtr = (uint64_t*)(sectionBuffers[toSectionIndex] + toSectionOffset);
- uint64_t gotTargetAddr = *gotPtr;
- printf("");
-
- stubToTargetMap[stubAddr] = gotTargetAddr;
- }
- }
- }
- }
- }
-}
-
-static void rewriteBranchesToStubs(Diagnostics& diag, const dyld3::MachOAnalyzer* ma,
- std::string_view dylibID,
- const std::vector<uint64_t>& sectionAddresses,
- const std::vector<uint8_t*>& sectionBuffers,
- uint32_t stubSectionIndex,
- const std::map<uint64_t, uint64_t>& stubToTargetMap)
-{
- static const int64_t b128MegLimit = 0x07FFFFFF;
-
- uint32_t splitSegSize = 0;
- const uint8_t* infoStart = (const uint8_t*)ma->getSplitSeg(splitSegSize);
- const uint8_t* infoEnd = infoStart + splitSegSize;
- if ( *infoStart++ != DYLD_CACHE_ADJ_V2_FORMAT ) {
- diag.error("malformed split seg info in %s", dylibID.data());
- return;
- }
-
- // Whole :== <count> FromToSection+
- // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
- // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
- // FromOffset :== <kind> <count> <from-sect-offset-delta>
- const uint8_t* p = infoStart;
- uint64_t sectionCount = read_uleb128(p, infoEnd);
- for (uint64_t i=0; i < sectionCount; ++i) {
- uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
- uint64_t toSectionIndex = read_uleb128(p, infoEnd);
- uint64_t toOffsetCount = read_uleb128(p, infoEnd);
- uint64_t toSectionOffset = 0;
- for (uint64_t j=0; j < toOffsetCount; ++j) {
- uint64_t toSectionDelta = read_uleb128(p, infoEnd);
- uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
- toSectionOffset += toSectionDelta;
- for (uint64_t k=0; k < fromOffsetCount; ++k) {
- uint64_t kind = read_uleb128(p, infoEnd);
- if ( kind > 13 ) {
- diag.error("bad kind (%llu) value in %s\n", kind, dylibID.data());
- }
- uint64_t fromSectDeltaCount = dyld3::MachOFile::read_uleb128(diag, p, infoEnd);
- if ( diag.hasError() )
- return;
- uint64_t fromSectionOffset = 0;
- for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
- uint64_t delta = dyld3::MachOFile::read_uleb128(diag, p, infoEnd);
- if ( diag.hasError() )
- return;
- fromSectionOffset += delta;
- if ( toSectionIndex == stubSectionIndex ) {
- // The stub is 16-bytes in size, and contains the stub fixup here.
- // We need to work out the stub for the fixup
- uint32_t* instrPtr = (uint32_t*)(sectionBuffers[fromSectionIndex] + fromSectionOffset);
- uint64_t instrAddr = sectionAddresses[fromSectionIndex] + fromSectionOffset;
- uint64_t stubAddr = sectionAddresses[toSectionIndex] + toSectionOffset;
-
- auto it = stubToTargetMap.find(stubAddr);
- if ( it == stubToTargetMap.end() ) {
- diag.error("couldn't find stub at 0x%llx, for branch 0x%llx in %s\n", stubAddr, instrAddr, dylibID.data());
- }
-
- uint64_t finalTargetAddr = it->second;
-
- if ( kind != DYLD_CACHE_ADJ_V2_ARM64_BR26 ) {
- diag.error("bad kind (%llu) value in %s\n", kind, dylibID.data());
- return;
- }
- // skip all but BL or B
- uint32_t& instruction = *instrPtr;
- if ( (instruction & 0x7C000000) != 0x14000000 ) {
- diag.error("bad instruction (0x%x) value in %s\n", instruction, dylibID.data());
- return;
- }
-
- int64_t deltaToFinalTarget = finalTargetAddr - instrAddr;
- // if final target within range, change to branch there directly
- if ( (deltaToFinalTarget > -b128MegLimit) && (deltaToFinalTarget < b128MegLimit) ) {
- instruction = (instruction & 0xFC000000) | ((deltaToFinalTarget >> 2) & 0x03FFFFFF);
- } else {
- diag.error("branch (%llx -> %llx) out of reach (%llx) in %s\n", fromSectionOffset, toSectionOffset,
- deltaToFinalTarget, dylibID.data());
- }
- }
- }
- }
- }
- }
-}
-
-void AppCacheBuilder::rewriteRemovedStubs()
-{
- if ( _diagnostics.hasError() )
- return;
-
- for (AppCacheDylibInfo& dylib : sortedDylibs) {
- if ( !dylib._coalescer.auth_stubs.sectionIsObliterated )
- continue;
-
- const dyld3::MachOAnalyzer* ma = nullptr;
- for (const SegmentMappingInfo& loc : dylib.cacheLocation) {
- if ( loc.segName == "__TEXT" ) {
- // Assume __TEXT contains the mach header
- ma = (const dyld3::MachOAnalyzer*)loc.dstSegment;
- break;
- }
- }
-
- // We need to find what the auth stubs pointed to, then rewrite all
- // users of the auth stubs to jump to those locations instead
- std::vector<uint64_t> sectionAddresses;
- std::vector<uint8_t*> sectionBuffers;
- uint32_t authStubSectionIndex = ~0U;
- getSectionLayout(ma, sectionAddresses, sectionBuffers, authStubSectionIndex);
-
- std::map<uint64_t, uint64_t> stubToTargetMap;
- getAuthStubTargets(_diagnostics, dylib.input->mappedFile.mh, dylib.dylibID,
- sectionAddresses, sectionBuffers, authStubSectionIndex,
- stubToTargetMap);
- if ( _diagnostics.hasError() )
- return;
-
- rewriteBranchesToStubs(_diagnostics, dylib.input->mappedFile.mh, dylib.dylibID,
- sectionAddresses, sectionBuffers, authStubSectionIndex,
- stubToTargetMap);
- if ( _diagnostics.hasError() )
- return;
- }
-}
-
void AppCacheBuilder::fipsSign()
{
if ( appCacheOptions.cacheKind != Options::AppCacheKind::kernel )