Loading...
--- dyld/dyld-1284.13/cache_builder/CacheDylib.cpp
+++ dyld/dyld-1235.2/cache_builder/CacheDylib.cpp
@@ -22,6 +22,7 @@
* @APPLE_LICENSE_HEADER_END@
*/
+#include "Allocator.h"
#include "Array.h"
#include "BuilderConfig.h"
#include "BuilderOptions.h"
@@ -35,20 +36,12 @@
#include "StringUtils.h"
#include "Trie.hpp"
-// mach_o
-#include "Header.h"
-#include "Image.h"
-#include "FunctionVariants.h"
-
#include <CommonCrypto/CommonHMAC.h>
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonDigestSPI.h>
#include <optional>
#include <vector>
-
-// mach_o_writer
-#include "HeaderWriter.h"
// FIXME: We should get this from cctools
#define DYLD_CACHE_ADJ_V2_FORMAT 0x7F
@@ -70,10 +63,6 @@
using namespace cache_builder;
using dyld3::MachOFile;
using error::Error;
-using mach_o::Header;
-using mach_o::Version32;
-using mach_o::Image;
-using mach_o::FunctionVariantFixups;
//
// MARK: --- cache_builder::CacheDylib methods ---
@@ -88,16 +77,14 @@
CacheDylib::CacheDylib(InputFile& inputFile)
: inputFile(&inputFile)
, inputMF(inputFile.mf)
- , inputHdr((const Header*)inputFile.mf)
- , inputLoadAddress(this->inputHdr->preferredLoadAddress())
- , installName(this->inputHdr->installName())
+ , inputLoadAddress(this->inputMF->preferredLoadAddress())
+ , installName(inputFile.mf->installName())
{
}
CacheDylib::CacheDylib(std::string_view installName)
: inputFile(nullptr)
, inputMF(nullptr)
- , inputHdr(nullptr)
, inputLoadAddress(0ull)
, installName(installName)
{
@@ -210,10 +197,10 @@
// This allows new method lists added by the category optimizer to be signed.
// Note the linker eagerly moves these sections to AUTH, as of rdar://111858154,
// so it is not expected that this code ever finds anything to move, but we'll keep it to be safe
- ((const Header*)mf)->forEachSection(^(const Header::SegmentInfo &segInfo, const Header::SectionInfo §Info, bool &stop) {
- if ( segInfo.segmentIndex != segmentIndexToSearch )
+ mf->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo §Info, bool malformedSectionRange, bool &stop) {
+ if ( sectInfo.segInfo.segIndex != segmentIndexToSearch )
return;
- if ( (sectInfo.sectionName == "__objc_const") || (sectInfo.sectionName == "__objc_data") ) {
+ if ( !strcmp(sectInfo.sectName, "__objc_const") || !strcmp(sectInfo.sectName, "__objc_data")) {
foundAuthFixup = true;
stop = true;
}
@@ -227,34 +214,37 @@
objc_visitor::Visitor& objcVisitor)
{
bool hasUnalignedFixups = ::hasUnalignedFixups(this->inputMF);
- this->inputHdr->forEachSegment(^(const Header::SegmentInfo& info, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop) {
+ this->inputMF->forEachSegment(^(const MachOFile::SegmentInfo& info, bool& stop) {
+ // Segment name is 16-characters long, and not necessarily null terminated
+ std::string_view segmentName(info.segName, strnlen(info.segName, 16));
+
auto addSegment = [&](DylibSegmentChunk::Kind kind) {
// TODO: Cache VMSize/fileSize might be less than input VMSize if we deduplicate strings for example
- uint64_t inputFileSize = std::min((uint64_t)info.fileSize, sizeOfSections);
- uint64_t cacheFileSize = sizeOfSections;
- uint64_t vmSize = sizeOfSections;
+ uint64_t inputFileSize = std::min(info.fileSize, info.sizeOfSections);
+ uint64_t cacheFileSize = info.sizeOfSections;
+ uint64_t vmSize = info.sizeOfSections;
// LINKEDIT doesn't get space any more. Its individual chunks will get their own space
- if ( info.segmentName == "__LINKEDIT" ) {
+ if ( segmentName == "__LINKEDIT" ) {
inputFileSize = 0;
cacheFileSize = 0;
vmSize = 0;
}
- uint64_t minAlignment = 1 << maxAlignOfSections;
+ uint64_t minAlignment = 1 << info.p2align;
// Always align __TEXT to a page as split seg can't handle less
- if ( info.segmentName == "__TEXT" )
+ if ( segmentName == "__TEXT" )
minAlignment = config.layout.machHeaderAlignment;
else if ( hasUnalignedFixups )
- minAlignment = (this->inputHdr->uses16KPages() ? 0x4000 : 0x1000);
+ minAlignment = (this->inputMF->uses16KPages() ? 0x4000 : 0x1000);
DylibSegmentChunk segment(kind, minAlignment);
- segment.segmentName = info.segmentName;
+ segment.segmentName = segmentName;
segment.inputFile = this->inputFile;
- segment.inputFileOffset = InputDylibFileOffset((uint64_t)info.fileOffset);
+ segment.inputFileOffset = InputDylibFileOffset(info.fileOffset);
segment.inputFileSize = InputDylibFileSize(inputFileSize);
- segment.inputVMAddress = InputDylibVMAddress(info.vmaddr);
- segment.inputVMSize = InputDylibVMSize(info.vmsize);
+ segment.inputVMAddress = InputDylibVMAddress(info.vmAddr);
+ segment.inputVMSize = InputDylibVMSize(info.vmSize);
segment.cacheVMSize = CacheVMSize(vmSize);
segment.subCacheFileSize = CacheFileSize(cacheFileSize);
@@ -267,13 +257,13 @@
};
// __TEXT
- if ( info.initProt == (VM_PROT_READ | VM_PROT_EXECUTE) ) {
+ if ( info.protections == (VM_PROT_READ | VM_PROT_EXECUTE) ) {
addSegment(DylibSegmentChunk::Kind::dylibText);
return;
}
// DATA*
- if ( info.initProt == (VM_PROT_READ | VM_PROT_WRITE) ) {
+ if ( info.protections == (VM_PROT_READ | VM_PROT_WRITE) ) {
// If we don't have split seg v2, then all __DATA* segments must look like __DATA so that they
// stay contiguous
__block bool isSplitSegV2 = false;
@@ -290,12 +280,12 @@
return;
}
- if ( info.segmentName == "__TPRO_CONST" ) {
+ if ( segmentName == "__TPRO_CONST" ) {
addSegment(DylibSegmentChunk::Kind::tproDataConst);
return;
}
- if ( info.segmentName == "__OBJC_CONST" ) {
+ if ( segmentName == "__OBJC_CONST" ) {
// In arm64e, "__OBJC_CONST __objc_class_ro" contains authenticated values
if ( config.layout.hasAuthRegion )
addSegment(DylibSegmentChunk::Kind::dylibAuthConst);
@@ -304,20 +294,20 @@
return;
}
- if ( info.segmentName == "__DATA_DIRTY" ) {
+ if ( segmentName == "__DATA_DIRTY" ) {
addSegment(DylibSegmentChunk::Kind::dylibDataDirty);
return;
}
bool hasAuthFixups = false;
- if ( (info.segmentName == "__AUTH") || (info.segmentName == "__AUTH_CONST") ) {
+ if ( (segmentName == "__AUTH") || (segmentName == "__AUTH_CONST") ) {
hasAuthFixups = true;
} else if ( config.layout.hasAuthRegion ) {
// HACK: Some dylibs don't get __AUTH segments. This matches ld64
- hasAuthFixups = segmentHasAuthFixups(this->inputMF, info.segmentIndex);
- }
-
- bool isConst = info.segmentName.ends_with("_CONST");
+ hasAuthFixups = segmentHasAuthFixups(this->inputMF, info.segIndex);
+ }
+
+ bool isConst = segmentName.ends_with("_CONST");
if ( hasAuthFixups ) {
// AUTH/AUTH_CONST
if ( isConst ) {
@@ -344,8 +334,8 @@
}
// LINKEDIT/readOnly
- if ( info.initProt == (VM_PROT_READ) ) {
- if ( info.segmentName != "__LINKEDIT" ) {
+ if ( info.protections == (VM_PROT_READ) ) {
+ if ( segmentName != "__LINKEDIT" ) {
addSegment(DylibSegmentChunk::Kind::dylibReadOnly);
return;
}
@@ -560,14 +550,6 @@
});
break;
}
- case LC_FUNCTION_VARIANTS: {
- const linkedit_data_command* linkeditCmd = (const linkedit_data_command*)cmd;
-
- addLinkedit(Kind::linkeditFunctionVariants, InputDylibFileOffset((uint64_t)linkeditCmd->dataoff),
- InputDylibFileSize((uint64_t)linkeditCmd->datasize), CacheVMSize((uint64_t)linkeditCmd->datasize),
- pointerSize);
- break;
- }
}
});
diag.assertNoError();
@@ -712,12 +694,12 @@
__block std::optional<VMAddress> vmAddr;
- this->inputHdr->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- if ( info.segmentName == segmentName ) {
+ this->inputMF->forEachSegment(^(const MachOFile::SegmentInfo& info, bool& stop) {
+ if ( info.segName == segmentName ) {
if ( isStart )
- vmAddr = VMAddress(info.vmaddr);
+ vmAddr = VMAddress(info.vmAddr);
else if ( isEnd )
- vmAddr = VMAddress(info.vmaddr) + VMOffset(info.vmsize);
+ vmAddr = VMAddress(info.vmAddr) + VMOffset(info.vmSize);
stop = true;
}
@@ -772,7 +754,7 @@
// look first in /usr/lib/libc++, most will be here
for ( const CacheDylib* cacheDylib : cacheDylibs ) {
- if ( cacheDylib->inputHdr->hasWeakDefs() && startsWith(cacheDylib->installName, "/usr/lib/libc++.") ) {
+ if ( cacheDylib->inputMF->hasWeakDefs() && startsWith(cacheDylib->installName, "/usr/lib/libc++.") ) {
std::optional<BindTargetAndName> bindTargetAndName = cacheDylib->hasExportedSymbol(diag, symbolName, SearchMode::onlySelf);
if ( bindTargetAndName.has_value() )
return bindTargetAndName.value();
@@ -907,7 +889,6 @@
return {};
bool isAbsoluteSymbol = ((flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
bool isWeakDef = (flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
- bool isFuncVariant = (flags & EXPORT_SYMBOL_FLAGS_FUNCTION_VARIANT);
uint64_t value = MachOFile::read_uleb128(diag, p, trieEnd);
if ( isAbsoluteSymbol ) {
@@ -915,14 +896,8 @@
return (BindTargetAndName) { result, symbolName };
}
- uint16_t fvTableIndex = 0;
- if ( isFuncVariant ) {
- // next uleb128 is func-variant table index
- fvTableIndex = (uint16_t)MachOFile::read_uleb128(diag, p, trieEnd);
- }
-
// Bind to image
- BindTarget result = { BindTarget::Kind::inputImage, { .inputImage = { VMOffset(value), this, isWeakDef, isFuncVariant, fvTableIndex } } };
+ BindTarget result = { BindTarget::Kind::inputImage, { .inputImage = { VMOffset(value), this, isWeakDef } } };
return (BindTargetAndName) { result, symbolName };
}
}
@@ -982,9 +957,7 @@
// Actually change the bindTarget to reflect the new type
bindTarget.kind = BindTarget::Kind::cacheImage;
bindTarget.inputImage.~InputImage();
- bindTarget.cacheImage = (BindTarget::CacheImage) { VMOffset(targetCacheVMAddr - inputImage.targetDylib->cacheLoadAddress),
- inputImage.targetDylib, inputImage.isWeakDef,
- inputImage.isFunctionVariant, inputImage.functionVariantTableIndex };
+ bindTarget.cacheImage = (BindTarget::CacheImage) { VMOffset(targetCacheVMAddr - inputImage.targetDylib->cacheLoadAddress), inputImage.targetDylib, inputImage.isWeakDef };
break;
}
case BindTarget::Kind::cacheImage:
@@ -995,9 +968,6 @@
bindTarget.addend = addend;
bindTarget.isWeakImport = weakImport;
-#if DEBUG
- bindTarget.name = symbolName;
-#endif
this->bindTargets.push_back(std::move(bindTarget));
dylibPatchInfo.bindTargetNames.push_back(std::move(bindTargetAndName.second));
};
@@ -1045,8 +1015,8 @@
}
// The cache segments don't have the permissions. Get that from the load commands
- this->cacheHdr->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- segmentLayout[info.segmentIndex].protections = info.initProt;
+ this->cacheMF->forEachSegment(^(const MachOFile::SegmentInfo& info, bool& stop) {
+ segmentLayout[info.segIndex].protections = info.protections;
});
mach_o::Layout layout(this->inputMF, { segmentLayout.data(), segmentLayout.data() + segmentLayout.size() }, linkedit);
@@ -1079,8 +1049,7 @@
dyld3::MachOFile::ChainedFixupPointerOnDisk* fixupLoc,
CacheVMAddress fixupVMAddr, MachOFile::PointerMetaData pmd,
CoalescedGOTMap& coalescedGOTs, CoalescedGOTMap& coalescedAuthGOTs,
- CoalescedGOTMap& coalescedAuthPtrs, PatchInfo& dylibPatchInfo,
- FunctionVariantsOptimizer& functionVariantsOptimizer)
+ CoalescedGOTMap& coalescedAuthPtrs, PatchInfo& dylibPatchInfo)
{
switch ( bindTarget.kind ) {
case BindTarget::Kind::absolute: {
@@ -1127,6 +1096,7 @@
CacheVMAddress targetDylibLoadAddress = bindTarget.cacheImage.targetDylib->cacheLoadAddress;
CacheVMAddress targetVMAddr = targetDylibLoadAddress + bindTarget.cacheImage.targetRuntimeOffset;
uint64_t finalVMAddrWithAddend = targetVMAddr.rawValue() + addend;
+
if ( config.layout.is64 ) {
uint64_t finalVMAddr = finalVMAddrWithAddend;
@@ -1196,31 +1166,6 @@
} else {
// Location wasn't coalesced. So add to the regular list of uses
dylibPatchInfo.bindUses[bindOrdinal].emplace_back(fixupVMAddr, patchTablePMD, patchTableAddend, bindTarget.isWeakImport);
- // if target is a function variant, record that dyld may need to update pointer at launch
- if ( bindTarget.cacheImage.isFunctionVariant ) {
- uint64_t fvTableVmAddr = 0;
- uint32_t fvTableVmSize = 0;
- for ( const LinkeditDataChunk& chunk : bindTarget.cacheImage.targetDylib->linkeditChunks ) {
- if ( chunk.isFunctionVariantsTable() ) {
- fvTableVmAddr = chunk.cacheVMAddress.rawValue();
- fvTableVmSize = (uint32_t)chunk.cacheVMSize.rawValue();
- break;
- }
- }
- dyld_cache_function_variant_entry entry;
- entry.fixupLocVmAddr = fixupVMAddr.rawValue();
- entry.functionVariantTableVmAddr = fvTableVmAddr;
- entry.functionVariantTableSizeDiv4 = fvTableVmSize/4;
- entry.dylibHeaderVmAddr = bindTarget.cacheImage.targetDylib->cacheLoadAddress.rawValue();
- entry.variantIndex = bindTarget.cacheImage.functionVariantTableIndex;
- entry.pacAuth = pmd.authenticated;
- entry.pacAddress = pmd.usesAddrDiversity;
- entry.pacKey = pmd.key;
- entry.pacDiversity = pmd.diversity;
- entry.targetDylibIndex = bindTarget.cacheImage.targetDylib->cacheIndex;
- assert(entry.variantIndex == bindTarget.cacheImage.functionVariantTableIndex);
- functionVariantsOptimizer.infos.push_back(entry);
- }
}
}
break;
@@ -1230,8 +1175,7 @@
void CacheDylib::bindWithChainedFixups(Diagnostics& diag, const BuilderConfig& config,
CoalescedGOTMap& coalescedGOTs, CoalescedGOTMap& coalescedAuthGOTs,
- CoalescedGOTMap& coalescedAuthPtrs, PatchInfo& dylibPatchInfo,
- FunctionVariantsOptimizer& functionVariantsOptimizer)
+ CoalescedGOTMap& coalescedAuthPtrs, PatchInfo& dylibPatchInfo)
{
auto fixupHandler = ^(MachOFile::ChainedFixupPointerOnDisk* fixupLoc, uint16_t chainedFormat,
uint32_t segIndex, CacheVMAddress fixupVMAddr,
@@ -1295,7 +1239,7 @@
this->bindLocation(diag, config, targetInTable, addend, bindOrdinal, segIndex,
fixupLoc, fixupVMAddr, pmd,
coalescedGOTs, coalescedAuthGOTs,
- coalescedAuthPtrs, dylibPatchInfo, functionVariantsOptimizer);
+ coalescedAuthPtrs, dylibPatchInfo);
};
this->inputMF->withFileLayout(diag, ^(const mach_o::Layout &layout) {
@@ -1328,8 +1272,7 @@
void CacheDylib::bindWithOpcodeFixups(Diagnostics& diag, const BuilderConfig& config,
CoalescedGOTMap& coalescedGOTs, CoalescedGOTMap& coalescedAuthGOTs,
- CoalescedGOTMap& coalescedAuthPtrs, PatchInfo& dylibPatchInfo,
- FunctionVariantsOptimizer& functionVariantsOptimizer)
+ CoalescedGOTMap& coalescedAuthPtrs, PatchInfo& dylibPatchInfo)
{
auto handleFixup = ^(uint64_t fixupRuntimeOffset, int bindOrdinal, uint32_t segmentIndex, bool& stopSegment) {
DylibSegmentChunk& segmentInfo = this->segments[segmentIndex];
@@ -1350,7 +1293,7 @@
this->bindLocation(diag, config, targetInTable, addend, bindOrdinal, segmentIndex,
(dyld3::MachOFile::ChainedFixupPointerOnDisk*)fixupLoc,
fixupVMAddr, dyld3::MachOFile::PointerMetaData(),
- coalescedGOTs, coalescedAuthGOTs, coalescedAuthPtrs, dylibPatchInfo, functionVariantsOptimizer);
+ coalescedGOTs, coalescedAuthGOTs, coalescedAuthPtrs, dylibPatchInfo);
};
// Use the fixups from the source dylib
@@ -1381,8 +1324,8 @@
}
// The cache segments don't have the permissions. Get that from the load commands
- this->cacheHdr->forEachSegment(^(const Header::SegmentInfo& info, bool& stop) {
- segmentLayout[info.segmentIndex].protections = info.initProt;
+ this->cacheMF->forEachSegment(^(const MachOFile::SegmentInfo& info, bool& stop) {
+ segmentLayout[info.segIndex].protections = info.protections;
});
mach_o::Layout layout(this->inputMF, { segmentLayout.data(), segmentLayout.data() + segmentLayout.size() }, linkedit);
@@ -1435,7 +1378,7 @@
}
void CacheDylib::bind(Diagnostics& diag, const BuilderConfig& config, Timer::AggregateTimer& timer,
- PatchInfo& dylibPatchInfo, FunctionVariantsOptimizer& functionVariantsOptimizer)
+ PatchInfo& dylibPatchInfo)
{
Timer::AggregateTimer::Scope timedScope(timer, "dylib bind time");
@@ -1473,9 +1416,9 @@
dylibPatchInfo.bindAuthPtrUses.resize(this->bindTargets.size());
if ( this->inputMF->hasChainedFixups() )
- bindWithChainedFixups(diag, config, coalescedGOTs, coalescedAuthGOTs, coalescedAuthPtrs, dylibPatchInfo, functionVariantsOptimizer);
+ bindWithChainedFixups(diag, config, coalescedGOTs, coalescedAuthGOTs, coalescedAuthPtrs, dylibPatchInfo);
else if ( this->inputMF->hasOpcodeFixups() ) {
- bindWithOpcodeFixups(diag, config, coalescedGOTs, coalescedAuthGOTs, coalescedAuthPtrs, dylibPatchInfo, functionVariantsOptimizer);
+ bindWithOpcodeFixups(diag, config, coalescedGOTs, coalescedAuthGOTs, coalescedAuthPtrs, dylibPatchInfo);
} else {
// Cache dylibs shouldn't use old style fixups.
}
@@ -1489,11 +1432,12 @@
void CacheDylib::updateObjCSelectorReferences(Diagnostics& diag, const BuilderConfig& config,
Timer::AggregateTimer& timer, ObjCSelectorOptimizer& objcSelectorOptimizer)
{
- if ( !this->inputHdr->hasObjC() )
+ if ( !this->inputMF->hasObjC() )
return;
Timer::AggregateTimer::Scope timedScope(timer, "dylib updateObjCSelectorReferences time");
+ STACK_ALLOCATOR(allocator, 0);
__block objc_visitor::Visitor objcVisitor = this->makeCacheObjCVisitor(config,
objcSelectorOptimizer.selectorStringsChunk,
nullptr,
@@ -1700,17 +1644,13 @@
Timer::AggregateTimer& timer,
const Chunk* selectorStringsChunk)
{
- if ( !this->inputHdr->hasObjC() )
+ if ( !this->inputMF->hasObjC() )
return;
Timer::AggregateTimer::Scope timedScope(timer, "dylib convertObjCMethodListsToOffsets time");
+ STACK_ALLOCATOR(allocator, 0);
__block objc_visitor::Visitor objcVisitor = this->makeCacheObjCVisitor(config, selectorStringsChunk, nullptr, nullptr);
-
- // protocols can be listed multiple times in the _objc_protolist section, so we'll visit them multiple times here
- // We don't want to convert the method list twice, so keep track of all seen method lists
- // FIXME: Remove this once ld removes the duplicates (rdar://133008657)
- __block std::unordered_set<const void*> seenMethodLists;
objcVisitor.forEachMethodList(^(objc_visitor::MethodList& objcMethodList,
std::optional<metadata_visitor::ResolvedValue> extendedMethodTypes) {
@@ -1718,10 +1658,6 @@
if ( !objcMethodList.usesRelativeOffsets() )
return;
- // Skip method lists we've already converted
- if ( bool inserted = seenMethodLists.insert(objcMethodList.getLocation()).second; !inserted )
- return;
-
uint32_t numMethods = objcMethodList.numMethods();
for ( uint32_t i = 0; i != numMethods; ++i ) {
objc_visitor::Method objcMethod = objcMethodList.getMethod(objcVisitor, i);
@@ -1742,11 +1678,12 @@
Timer::AggregateTimer& timer,
const Chunk* selectorStringsChunk)
{
- if ( !this->inputHdr->hasObjC() )
+ if ( !this->inputMF->hasObjC() )
return;
Timer::AggregateTimer::Scope timedScope(timer, "dylib sortObjCMethodLists time");
+ STACK_ALLOCATOR(allocator, 0);
__block objc_visitor::Visitor objcVisitor = this->makeCacheObjCVisitor(config, selectorStringsChunk, nullptr, nullptr);
objcVisitor.forEachMethodList(^(objc_visitor::MethodList& objcMethodList,
@@ -1771,22 +1708,24 @@
return;
}
+ const dyld3::MachOFile* mf = this->cacheMF;
+
__block uint32_t textSectionIndex = ~0U;
__block const uint8_t* textSectionContent = nullptr;
__block uint32_t selRefSectionIndex = ~0U;
__block uint64_t selRefSectionVMAddr = 0;
// The mach_header is section 0
__block uint32_t sectionIndex = 1;
- this->cacheHdr->forEachSection(^(const Header::SegmentInfo &segInfo, const Header::SectionInfo §Info, bool &stop) {
- if ( (sectInfo.segmentName == "__TEXT" ) && (sectInfo.sectionName == "__text") ) {
+ mf->forEachSection(^(const dyld3::MachOFile::SectionInfo §Info, bool malformedSectionRange, bool &stop) {
+ if ( !strcmp(sectInfo.segInfo.segName, "__TEXT") && !strcmp(sectInfo.sectName, "__text") ) {
textSectionIndex = sectionIndex;
- VMOffset sectionOffsetInSegment(sectInfo.address - segInfo.vmaddr);
- textSectionContent = this->segments[sectInfo.segIndex].subCacheBuffer;
+ VMOffset sectionOffsetInSegment(sectInfo.sectAddr - sectInfo.segInfo.vmAddr);
+ textSectionContent = this->segments[sectInfo.segInfo.segIndex].subCacheBuffer;
textSectionContent += sectionOffsetInSegment.rawValue();
}
- if ( sectInfo.segmentName.starts_with("__DATA") && (sectInfo.sectionName == "__objc_selrefs") ) {
+ if ( !strncmp(sectInfo.segInfo.segName, "__DATA", 6) && !strcmp(sectInfo.sectName, "__objc_selrefs") ) {
selRefSectionIndex = sectionIndex;
- selRefSectionVMAddr = sectInfo.address;
+ selRefSectionVMAddr = sectInfo.sectAddr;
}
++sectionIndex;
});
@@ -1838,26 +1777,27 @@
Timer::AggregateTimer::Scope timedScope(timer, "dylib optimizeLoadsFromConstants time");
- if ( !this->cacheHdr->is64() )
+ const dyld3::MachOFile* mf = this->cacheMF;
+ if ( !mf->is64() )
return;
__block const uint8_t* textSectionContent = nullptr;
__block CacheVMAddress textSectionVMAddr;
__block const uint8_t* selRefSectionContent = nullptr;
__block CacheVMAddress selRefSectionVMAddr;
- this->cacheHdr->forEachSection(^(const Header::SegmentInfo &segInfo, const Header::SectionInfo §Info, bool &stop) {
- VMOffset sectionOffsetInSegment(sectInfo.address - segInfo.vmaddr);
- if ( ( sectInfo.segmentName == "__TEXT" ) && (sectInfo.sectionName == "__text") ) {
- textSectionContent = this->segments[sectInfo.segIndex].subCacheBuffer;
+ mf->forEachSection(^(const dyld3::MachOFile::SectionInfo §Info, bool malformedSectionRange, bool &stop) {
+ VMOffset sectionOffsetInSegment(sectInfo.sectAddr - sectInfo.segInfo.vmAddr);
+ if ( !strcmp(sectInfo.segInfo.segName, "__TEXT") && !strcmp(sectInfo.sectName, "__text") ) {
+ textSectionContent = this->segments[sectInfo.segInfo.segIndex].subCacheBuffer;
textSectionContent += sectionOffsetInSegment.rawValue();
- textSectionVMAddr = CacheVMAddress(sectInfo.address);
- }
- if ( sectInfo.segmentName.starts_with("__DATA") && (sectInfo.sectionName == "__objc_selrefs") ) {
- selRefSectionContent = this->segments[sectInfo.segIndex].subCacheBuffer;
+ textSectionVMAddr = CacheVMAddress(sectInfo.sectAddr);
+ }
+ if ( !strncmp(sectInfo.segInfo.segName, "__DATA", 6) && !strcmp(sectInfo.sectName, "__objc_selrefs") ) {
+ selRefSectionContent = this->segments[sectInfo.segInfo.segIndex].subCacheBuffer;
selRefSectionContent += sectionOffsetInSegment.rawValue();
- selRefSectionVMAddr = CacheVMAddress(sectInfo.address);
+ selRefSectionVMAddr = CacheVMAddress(sectInfo.sectAddr);
}
});
@@ -2101,6 +2041,7 @@
if ( !this->inputMF->hasChainedFixupsLoadCommand() )
return Error();
+ STACK_ALLOCATOR(allocator, 0);
__block objc_visitor::Visitor objcVisitor = this->makeCacheObjCVisitor(config, nullptr, nullptr, nullptr);
// Walk the classes in this dylib, and see if any have an IMP cache
@@ -2318,26 +2259,27 @@
};
// Walk all the stubs in the stubs sections
- this->cacheHdr->forEachSection(^(const Header::SegmentInfo &segInfo, const Header::SectionInfo §Info, bool &stop) {
- unsigned sectionType = (sectInfo.flags & SECTION_TYPE);
+ this->cacheMF->forEachSection(^(const dyld3::MachOFile::SectionInfo §Info,
+ bool malformedSectionRange, bool &stop) {
+ unsigned sectionType = (sectInfo.sectFlags & SECTION_TYPE);
if ( sectionType != S_SYMBOL_STUBS )
return;
// We can only optimize certain stubs sections, depending on the arch
- if ( sectInfo.sectionName != this->developmentStubs.sectionName )
+ if ( sectInfo.sectName != this->developmentStubs.sectionName )
return;
- if ( sectInfo.segmentName != this->developmentStubs.segmentName )
+ if ( sectInfo.segInfo.segName != this->developmentStubs.segmentName )
return;
// reserved1/reserved2 tell us how large stubs are, and our offset in to the symbol table
const uint64_t indirectTableOffset = sectInfo.reserved1;
const uint64_t stubsSize = sectInfo.reserved2;
- const uint64_t stubsCount = sectInfo.size / stubsSize;
-
- CacheVMAddress stubsSectionBaseAddress(sectInfo.address);
+ const uint64_t stubsCount = sectInfo.sectSize / stubsSize;
+
+ CacheVMAddress stubsSectionBaseAddress(sectInfo.sectAddr);
// Work out where the stub buffer is in the cache
- const DylibSegmentChunk& segment = this->segments[segInfo.segmentIndex];
+ const DylibSegmentChunk& segment = this->segments[sectInfo.segInfo.segIndex];
CacheVMAddress segmentBaseAddress = segment.cacheVMAddress;
VMOffset sectionOffsetInSegment = stubsSectionBaseAddress - segmentBaseAddress;
const uint8_t* sectionBuffer = segment.subCacheBuffer + sectionOffsetInSegment.rawValue();
@@ -2361,7 +2303,7 @@
continue;
}
- if ( this->cacheHdr->isArch("arm64") ) {
+ if ( this->cacheMF->isArch("arm64") ) {
uint64_t targetLPAddr = StubOptimizer::gotAddrFromArm64Stub(diag, this->installName,
stubInstrs,
oldStubVMAddr.rawValue());
@@ -2389,7 +2331,7 @@
StubOptimizer::generateArm64StubTo(newStubBuffer, newStubVMAddr.rawValue(),
gotTargetVMAddr->rawValue());
}
- } else if ( this->cacheHdr->isArch("arm64e") ) {
+ } else if ( this->cacheMF->isArch("arm64e") ) {
uint64_t targetLPAddr = StubOptimizer::gotAddrFromArm64eStub(diag, this->installName,
stubInstrs,
oldStubVMAddr.rawValue());
@@ -2417,7 +2359,7 @@
StubOptimizer::generateArm64eStubTo(newStubBuffer, newStubVMAddr.rawValue(),
gotTargetVMAddr->rawValue());
}
- } else if ( this->cacheHdr->isArch("arm64_32") ) {
+ } else if ( this->cacheMF->isArch("arm64_32") ) {
uint64_t targetLPAddr = StubOptimizer::gotAddrFromArm64_32Stub(diag, this->installName,
stubInstrs,
oldStubVMAddr.rawValue());
@@ -2468,29 +2410,29 @@
{
// Section #0 is the mach_header
__block uint32_t sectionIndex = 1;
- this->cacheHdr->forEachSection(^(const Header::SegmentInfo &segInfo, const Header::SectionInfo §Info, bool &stop) {
- if ( sectInfo.segmentName == "__TEXT" ) {
- if ( sectInfo.sectionName == "__text" ) {
+ this->cacheMF->forEachSection(^(const dyld3::MachOFile::SectionInfo §Info, bool malformedSectionRange, bool &stop) {
+ if ( !strcmp(sectInfo.segInfo.segName, "__TEXT") ) {
+ if ( !strcmp(sectInfo.sectName, "__text") ) {
textSectionIndex = sectionIndex;
- textSectionVMAddr = sectInfo.address;
+ textSectionVMAddr = sectInfo.sectAddr;
// Work out the buffer for the text section
- const DylibSegmentChunk& segment = this->segments[segInfo.segmentIndex];
+ const DylibSegmentChunk& segment = this->segments[sectInfo.segInfo.segIndex];
CacheVMAddress segmentBaseAddress = segment.cacheVMAddress;
- CacheVMAddress sectionBaseAddress(sectInfo.address);
+ CacheVMAddress sectionBaseAddress(sectInfo.sectAddr);
VMOffset sectionOffsetInSegment = sectionBaseAddress - segmentBaseAddress;
textSectionBuffer = segment.subCacheBuffer + sectionOffsetInSegment.rawValue();
- } else if ( sectInfo.sectionName == "__stubs" ) {
+ } else if ( !strcmp(sectInfo.sectName, "__stubs") ) {
// On arm64e devices, we ignore __stubs and only handle __auth_stubs
- if ( !this->cacheHdr->isArch("arm64e") ) {
+ if ( !this->cacheMF->isArch("arm64e") ) {
stubSectionIndex = sectionIndex;
- stubSectionVMAddr = sectInfo.address;
+ stubSectionVMAddr = sectInfo.sectAddr;
}
- } else if ( sectInfo.sectionName == "__auth_stubs" ) {
+ } else if ( !strcmp(sectInfo.sectName, "__auth_stubs") ) {
// On arm64e devices, we ignore __stubs and only handle __auth_stubs
- if ( this->cacheHdr->isArch("arm64e") ) {
+ if ( this->cacheMF->isArch("arm64e") ) {
stubSectionIndex = sectionIndex;
- stubSectionVMAddr = sectInfo.address;
+ stubSectionVMAddr = sectInfo.sectAddr;
}
}
}
@@ -2664,7 +2606,7 @@
CacheFileOffset readWriteFileOffset)
{
// validate there is enough free space to add the load commands
- uint32_t freeSpace = ((const Header*)objcMF)->loadCommandsFreeSpace();
+ uint32_t freeSpace = objcMF->loadCommandsFreeSpace();
const uint32_t segSize = sizeof(macho_segment_command<P>);
if ( freeSpace < 2*segSize ) {
diag.warning("not enough space in libojbc.dylib to add load commands for objc optimization regions");
@@ -2672,18 +2614,11 @@
}
// find location of LINKEDIT LC_SEGMENT load command, we need to insert new segments before it
- uint32_t linkeditIndex = 0;
- uint8_t* linkeditSeg = nullptr;
- linkeditSeg = (uint8_t*)((mach_o::Header*)objcMF)->findLoadCommand(linkeditIndex, ^bool(const load_command *lc) {
- CString segmentName;
- if ( lc->cmd == LC_SEGMENT )
- segmentName = ((const segment_command*)lc)->segname;
- else if ( lc->cmd == LC_SEGMENT_64 )
- segmentName = ((const segment_command_64*)lc)->segname;
-
- return segmentName == "__LINKEDIT";
+ __block uint8_t* linkeditSeg = nullptr;
+ objcMF->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& info, bool& stop) {
+ if ( strcmp(info.segName, "__LINKEDIT") == 0 )
+ linkeditSeg = (uint8_t*)objcMF + info.loadCommandOffset;
});
-
if ( linkeditSeg == nullptr ) {
diag.warning("__LINKEDIT not found in libojbc.dylib");
return;
@@ -2764,7 +2699,7 @@
CacheVMAddress readWriteVMAddr = headerInfoReadWriteChunk->cacheVMAddress;
CacheVMSize readWriteVMSize = (canonicalProtocolsChunk->cacheVMAddress + canonicalProtocolsChunk->cacheVMSize) - readWriteVMAddr;
- if ( this->inputHdr->is64() ) {
+ if ( this->inputMF->is64() ) {
typedef Pointer64<LittleEndian> P;
addObjcSegments<P>(diag, this->cacheMF,
readOnlyVMAddr, readOnlyVMSize, readOnlyFileOffset,
@@ -2779,7 +2714,7 @@
void CacheDylib::removeLinkedDylibs(Diagnostics& diag)
{
- mach_o::HeaderWriter* header = (mach_o::HeaderWriter*)cacheHdr;
+ mach_o::Header* header = (mach_o::Header*)cacheMF;
uint32_t lcLibSystemIndex = 0;
if ( !header->findLoadCommand(lcLibSystemIndex, ^bool(const load_command *lc) {
const dylib_command* dyliblc = mach_o::Header::isDylibLoadCommand(lc);
@@ -2815,15 +2750,15 @@
void CacheDylib::addLinkedDylib(Diagnostics& diag, const CacheDylib& dylib)
{
const char* dylibInstallName = nullptr;
- Version32 compatVersion;
- Version32 currentVersion;
- dylib.inputHdr->getDylibInstallName(&dylibInstallName, &compatVersion, ¤tVersion);
+ uint32_t compatVersion;
+ uint32_t currentVersion;
+ dylib.inputMF->getDylibInstallName(&dylibInstallName, &compatVersion, ¤tVersion);
// find the range of all LC_LOAD* commands, new dylib will be added as last
uint32_t lcLoadStart = 0;
uint32_t lcLoadEnd = 0;
- mach_o::HeaderWriter* header = (mach_o::HeaderWriter*)this->cacheHdr;
+ mach_o::Header* header = (mach_o::Header*)this->cacheMF;
header->findLoadCommandRange(lcLoadStart, lcLoadEnd, ^bool(const load_command *lc) {
return mach_o::Header::isDylibLoadCommand(lc) != nullptr;
});
@@ -3013,17 +2948,18 @@
CacheVMSize sectionVMSize,
bool& stop))
{
- this->inputHdr->forEachSection(^(const Header::SegmentInfo &segInfo, const Header::SectionInfo §Info,
- bool &stop) {
- const DylibSegmentChunk& segment = this->segments[sectInfo.segIndex];
-
- VMAddress sectionVMAddr(sectInfo.address);
- VMAddress segmentVMAddr(segInfo.vmaddr);
+ this->inputMF->forEachSection(^(const dyld3::MachOFile::SectionInfo §Info,
+ bool malformedSectionRange, bool &stop) {
+ const DylibSegmentChunk& segment = this->segments[sectInfo.segInfo.segIndex];
+
+ VMAddress sectionVMAddr(sectInfo.sectAddr);
+ VMAddress segmentVMAddr(sectInfo.segInfo.vmAddr);
VMOffset sectionOffsetInSegment = sectionVMAddr - segmentVMAddr;
uint8_t* sectionBuffer = segment.subCacheBuffer + sectionOffsetInSegment.rawValue();
CacheVMAddress cacheVMAddr = segment.cacheVMAddress + sectionOffsetInSegment;
- callback(sectInfo.segmentName, sectInfo.sectionName,
- sectionBuffer, cacheVMAddr, CacheVMSize(sectInfo.size), stop);
+ callback(std::string_view(sectInfo.segInfo.segName, strnlen(sectInfo.segInfo.segName, 16)),
+ std::string_view(sectInfo.sectName, strnlen(sectInfo.sectName, 16)),
+ sectionBuffer, cacheVMAddr, CacheVMSize(sectInfo.sectSize), stop);
});
}