Loading...
--- dyld/dyld-1340/mach_o/ChainedFixups.cpp
+++ dyld/dyld-1162/mach_o/ChainedFixups.cpp
@@ -29,14 +29,17 @@
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
+#if BUILDING_MACHO_WRITER
+#include "Algorithm.h"
+#include "Array.h"
+#endif
+
#include "Array.h"
#include "ChainedFixups.h"
#include "Misc.h"
#include "Image.h"
-
-
using dyld3::Array;
namespace mach_o {
@@ -52,14 +55,10 @@
{
}
-const dyld_chained_fixups_header* ChainedFixups::linkeditHeader() const
-{
+const dyld_chained_fixups_header* ChainedFixups::bytes(size_t& size) const
+{
+ size = _fixupsSize;
return _fixupsHeader;
-}
-
-const dyld_chained_starts_offsets* ChainedFixups::startsSectionHeader() const
-{
- return _chainStartsHeader;
}
void ChainedFixups::forEachBindTarget(void (^callback)(const Fixup::BindTarget&, bool& stop)) const
@@ -155,8 +154,22 @@
return (dyld_chained_starts_in_segment*)((uint8_t*)imageStarts + segInfoOffset);
}
+const ChainedFixups::PointerFormat& ChainedFixups::pointerFormat() const
+{
+ const dyld_chained_starts_in_image* imageStarts = (dyld_chained_starts_in_image*)((uint8_t*)_fixupsHeader + _fixupsHeader->starts_offset);
+ for (uint32_t segIndex=0; segIndex < imageStarts->seg_count; ++segIndex) {
+ uint32_t segInfoOffset = imageStarts->seg_info_offset[segIndex];
+ if ( segInfoOffset == 0 )
+ continue;
+ const dyld_chained_starts_in_segment* segStarts = (dyld_chained_starts_in_segment*)((uint8_t*)imageStarts + segInfoOffset);
+ if ( segStarts->pointer_format != 0 )
+ return PointerFormat::make(segStarts->pointer_format);
+ }
+ assert(0 && "can't find pointer format");
+}
+
void ChainedFixups::forEachFixupChainStartLocation(std::span<const MappedSegment> segments,
- void (^callback)(const void* loc, uint32_t segIndex, uint32_t pageIndex, uint32_t pageSize, const PointerFormat&, bool& stop)) const
+ void (^callback)(const void* loc, uint32_t segIndex, const PointerFormat&, bool& stop)) const
{
bool stop = false;
for (uint32_t segIndex=0; segIndex < segments.size(); ++segIndex) {
@@ -172,15 +185,15 @@
bool chainEnd = false;
while ( !chainEnd ) {
chainEnd = (segStarts->page_start[overflowIndex] & DYLD_CHAINED_PTR_START_LAST);
- uint16_t startOffset = (segStarts->page_start[overflowIndex] & ~DYLD_CHAINED_PTR_START_LAST);
- const uint8_t* chainStart = (uint8_t*)(segments[segIndex].content) + pageIndex * segStarts->page_size + startOffset;
- callback(chainStart, segIndex, pageIndex, segStarts->page_size, pf, stop);
+ uint16_t startOffset = (segStarts->page_start[overflowIndex] & ~DYLD_CHAINED_PTR_START_LAST);
+ uint32_t* chainStart = (uint32_t*)((uint8_t*)(segments[segIndex].content) + startOffset);
+ callback(chainStart, segIndex, pf, stop);
++overflowIndex;
}
}
else {
const uint8_t* chainStart = ((uint8_t*)(segments[segIndex].content)) + pageIndex * segStarts->page_size + offsetInPage;
- callback(chainStart, segIndex, pageIndex, segStarts->page_size, pf, stop);
+ callback(chainStart, segIndex, pf, stop);
}
if ( stop )
return;
@@ -190,8 +203,12 @@
}
-Error ChainedFixups::validLinkedit(uint64_t preferredLoadAddress, std::span<const MappedSegment> segments) const
-{
+Error ChainedFixups::valid(std::span<const MappedSegment> segments) const
+{
+#if BUILDING_MACHO_WRITER
+ if ( _buildError.hasError() )
+ return Error("%s", _buildError.message());
+#endif
// validate dyld_chained_fixups_header
if ( _fixupsHeader->fixups_version != 0 )
return Error("chained fixups, unknown header version (%d)", _fixupsHeader->fixups_version);
@@ -303,39 +320,20 @@
}
// validate import table size can fit
uint32_t maxBindOrdinal = PointerFormat::make(pointer_format_for_all).maxBindOrdinal(false);
- if ( (_fixupsHeader->imports_count != 0) && (_fixupsHeader->imports_count >= maxBindOrdinal) )
+ if ( _fixupsHeader->imports_count >= maxBindOrdinal )
return Error("chained fixups, imports_count (%d) exceeds max of %d", _fixupsHeader->imports_count, maxBindOrdinal);
// validate max_valid_pointer is larger than last segment
- if ( maxValidPointerSeen != 0 ) {
- size_t lastDataSegmentIndex = segments.size() - (segments.back().segName == "__LINKEDIT" ? 2 : 1);
- const MappedSegment& lastDataSegment = segments[lastDataSegmentIndex];
- // note: runtime offset is relative to the load address but max valid pointer encodes an 'absolute' valid pointer
- uint64_t lastDataSegmentLastVMAddr = preferredLoadAddress + lastDataSegment.runtimeOffset + lastDataSegment.runtimeSize;
- if ( maxValidPointerSeen < lastDataSegmentLastVMAddr )
- return Error("chained fixups, max_valid_pointer (0x%x) too small for image last vm address 0x%llx", maxValidPointerSeen, lastDataSegmentLastVMAddr);
- }
+ //if ( maxValidPointerSeen != 0 ) {
+ // uint64_t lastSegmentLastVMAddr = segmentsInfo[leInfo.layout.linkeditSegIndex-1].vmAddr + segmentsInfo[leInfo.layout.linkeditSegIndex-1].vmSize;
+ // if ( maxValidPointerSeen < lastSegmentLastVMAddr ) {
+ // return Error("chained fixups, max_valid_pointer too small for image");
+ // }
+ //}
return Error::none();
}
-Error ChainedFixups::validStartsSection(std::span<const MappedSegment> segments) const
-{
- // validate dyld_chained_starts_offsets
- if ( !PointerFormat::valid(_chainStartsHeader->pointer_format) ) {
- return Error("chained fixups, unknown pointer_format (%d)", _chainStartsHeader->pointer_format);
- }
- return Error::none();
-}
-
-Error ChainedFixups::valid(uint64_t preferredLoadAddress, std::span<const MappedSegment> segments,
- bool startsInSection) const
-{
- if ( startsInSection ) {
- return validStartsSection(segments);
- } else {
- return validLinkedit(preferredLoadAddress, segments);
- }
-}
+
const char* ChainedFixups::importsFormatName(uint32_t format)
{
switch (format) {
@@ -355,52 +353,563 @@
}
void ChainedFixups::PointerFormat::forEachFixupLocationInChain(const void* chainStartLoc, uint64_t prefLoadAddr, const MappedSegment* seg,
- std::span<const uint64_t> segOffsetTable, uint32_t pageIndex, uint32_t pageSize,
- void (^callback)(const Fixup& f, bool& stop)) const
-{
- bool stop = false;
- const void* nextLoc = nullptr;
- const void* endPage = nullptr;
- // note: seg is null for firmware and firmware does not require chains to be limited to one page
- if ( seg != nullptr ) {
- const void* startPage = (void*)((uint8_t*)seg->content + pageIndex*pageSize);
- endPage = (void*)((uint8_t*)startPage + pageSize);
- if ( (chainStartLoc < startPage) || (chainStartLoc > endPage) )
- return; // error: chain is not on page
- }
+ void (^callback)(const Fixup& info, bool& stop)) const
+{
+ bool stop = false;
+ const void* nextLoc = nullptr;
for ( const void* fixupLoc = chainStartLoc; (fixupLoc != nullptr) && !stop; fixupLoc = nextLoc) {
- // get next before calling callback, because callback may update location (change PointerFormat bits into runtime pointer)
+ // get next before calling callback, because callback may update location (set runtime pointer)
nextLoc = this->nextLocation(fixupLoc);
- callback(this->parseChainEntry(fixupLoc, seg, prefLoadAddr, segOffsetTable), stop);
- if ( (nextLoc != nullptr) && (endPage != nullptr) ) {
- if ( nextLoc > endPage )
- break; // error: chain went off end of page
- }
- }
-}
-
-
-// copy of dyld_chained_ptr_arm64e_rebase that allows 4-byte strides
-struct __attribute__((packed)) unaligned_dyld_chained_ptr_arm64e_rebase
-{
- uint64_t target : 43,
- high8 : 8,
- next : 11, // 4 or 8-byte stide
- bind : 1, // == 0
- auth : 1; // == 0
-};
-
-// copy of dyld_chained_ptr_arm64e_auth_rebase that allows 4-byte strides
-struct __attribute__((packed)) unaligned_dyld_chained_ptr_arm64e_auth_rebase
-{
- uint64_t target : 32, // runtimeOffset
- diversity : 16,
- addrDiv : 1,
- key : 2,
- next : 11, // 4 or 8-byte stide
- bind : 1, // == 0
- auth : 1; // == 1
-};
+ callback(this->parseChainEntry(fixupLoc, seg, prefLoadAddr), stop);
+ }
+}
+
+
+#if BUILDING_MACHO_WRITER
+
+
+template <typename T>
+static T align8(T value)
+{
+ return (value + 7) & (-8);
+}
+
+size_t ChainedFixups::linkeditSize(std::span<const Fixup::BindTarget> bindTargets,
+ std::span<const SegmentFixupsInfo> segments,
+ uint32_t pageSize)
+{
+ // scan binds to figure out which imports table format to use
+ uint16_t imFormat;
+ size_t stringPoolSize;
+ if ( Error err = importsFormat(bindTargets, imFormat, stringPoolSize) )
+ return 0;
+
+ // allocate space in _bytes for full dyld_chained_fixups data structure
+ size_t maxBytesNeeded = align8(sizeof(dyld_chained_fixups_header));
+ maxBytesNeeded += offsetof(dyld_chained_starts_in_image,seg_info_offset[segments.size()]);
+ for ( const SegmentFixupsInfo& segment : segments ) {
+ const MappedSegment& seg = segment.mappedSegment;
+ uint32_t extras = segment.numPageExtras;
+ std::span<const Fixup> segFixups = segment.fixups;
+ if ( seg.writable && (seg.runtimeSize != 0) && !segFixups.empty() ) {
+ uint64_t lastFixupSegmentOffset = (uint64_t)segFixups.back().location - (uint64_t)seg.content;
+ uint64_t lastFixupPage = (lastFixupSegmentOffset / pageSize) + 1;
+ size_t segInfoSize = align8(offsetof(dyld_chained_starts_in_segment, page_start[lastFixupPage + extras]));
+ maxBytesNeeded += segInfoSize;
+ }
+ }
+
+ maxBytesNeeded = align8(maxBytesNeeded);
+
+ size_t importTableSize = 0;
+ if ( imFormat == DYLD_CHAINED_IMPORT_ADDEND64 )
+ importTableSize = align8(sizeof(dyld_chained_import_addend64) * bindTargets.size());
+ else if ( imFormat == DYLD_CHAINED_IMPORT_ADDEND )
+ importTableSize = align8(sizeof(dyld_chained_import_addend) * bindTargets.size());
+ else
+ importTableSize = align8(sizeof(dyld_chained_import) * bindTargets.size());
+
+ maxBytesNeeded += importTableSize;
+ maxBytesNeeded += align8(stringPoolSize);
+
+ return maxBytesNeeded;
+}
+
+void ChainedFixups::calculateSegmentPageExtras(std::span<SegmentFixupsInfo> segments,
+ const PointerFormat& pointerFormat,
+ uint32_t pageSize)
+{
+ for ( SegmentFixupsInfo& segmentFixupInfo : segments ) {
+ const MappedSegment& segment = segmentFixupInfo.mappedSegment;
+ const std::span<const Fixup> fixupsInSegment = segmentFixupInfo.fixups;
+ uint32_t numExtras = 0;
+
+ // skip segments with no fixups
+ if ( !segment.writable || (segment.runtimeSize == 0) || fixupsInSegment.empty() )
+ continue;
+
+ int curPageIndex = -1;
+ const Fixup* prevFixup = nullptr;
+ bool pageHasExtras = false;
+ for ( const Fixup& fixup : fixupsInSegment ) {
+ uint64_t offset = (uint8_t*)fixup.location - (uint8_t*)segment.content;
+ int pageIndex = (int)(offset/pageSize);
+ if ( pageIndex != curPageIndex ) {
+ curPageIndex = pageIndex;
+ prevFixup = nullptr;
+ pageHasExtras = false;
+ }
+ if ( prevFixup != nullptr ) {
+ intptr_t delta = (uint8_t*)fixup.location - (uint8_t*)(prevFixup->location);
+ if ( delta > pointerFormat.maxNext() ) {
+ // prev/next are too far apart for chain to span, instead terminate chain at prevFixup
+ // then start new overflow chain
+ if ( !pageHasExtras ) {
+ // A page with extras needs a start and end of the chain too
+ numExtras += 2;
+ pageHasExtras = true;
+ }
+ ++numExtras;
+ }
+ }
+ prevFixup = &fixup;
+ }
+
+ segmentFixupInfo.numPageExtras = numExtras;
+ }
+}
+
+Error ChainedFixups::importsFormat(std::span<const Fixup::BindTarget> bindTargets, uint16_t& importsFormat, size_t& stringPoolSize)
+{
+ bool hasLargeOrdinal = false;
+ bool has32bitAddend = false;
+ bool has64bitAddend = false;
+ stringPoolSize = 1;
+ for (const Fixup::BindTarget& bind : bindTargets) {
+ stringPoolSize += (bind.symbolName.size() + 1);
+ if ( bind.libOrdinal < -15 ) {
+ // TODO: currently only -1, -2, and -3 have meaning. Should we error here for < -3 ?
+ return Error("special libOrdinal (%d) too small", bind.libOrdinal);
+ }
+ if ( bind.libOrdinal > 240 ) {
+ hasLargeOrdinal = true;
+ if ( bind.libOrdinal > 65520 ) {
+ return Error("libOrdinal (%d) too large", bind.libOrdinal);
+ }
+ }
+ if ( bind.addend != 0 ) {
+ int32_t addend32 = (int32_t)bind.addend;
+ if ( (int64_t)addend32 == bind.addend )
+ has32bitAddend = true;
+ else
+ has64bitAddend = true;
+ }
+ }
+ bool hasLargeStringOffsets = dyld_chained_import{.name_offset=(uint32_t)stringPoolSize}.name_offset != stringPoolSize;
+
+ if ( hasLargeStringOffsets || has64bitAddend || hasLargeOrdinal )
+ importsFormat = DYLD_CHAINED_IMPORT_ADDEND64;
+ else if ( has32bitAddend )
+ importsFormat = DYLD_CHAINED_IMPORT_ADDEND;
+ else
+ importsFormat = DYLD_CHAINED_IMPORT;
+
+ if ( stringPoolSize > 0xFFFFFFFF )
+ return Error("imports string pool > 4GB");
+
+ return Error::none();
+}
+
+#if BUILDING_UNIT_TESTS
+ChainedFixups::ChainedFixups(std::span<const Fixup::BindTarget> bindTargets,
+ std::span<const Fixup> fixups,
+ std::span<const MappedSegment> segments,
+ uint64_t preferredLoadAddress,
+ const PointerFormat& pointerFormat, uint32_t pageSize, bool setDataChains)
+{
+ std::vector<std::vector<Fixup>> fixupsInSegments;
+ fixupsInSegments.reserve(segments.size());
+
+ {
+ // unify and sort fixups to make chains
+ std::vector<Fixup> sortedFixups(fixups.begin(), fixups.end());
+ std::sort(sortedFixups.begin(), sortedFixups.end());
+
+ // verify there are no locations with multiple fixups
+ if ( sortedFixups.size() > 1 ) {
+ Fixup lastLoc = sortedFixups.back();
+ for (const Fixup& f : sortedFixups) {
+ if ( f.location == lastLoc.location ) {
+ _buildError = Error("multiple fixups at same location in %.*s at offset=0x%lX",
+ (int)f.segment->segName.size(), f.segment->segName.data(), (uint8_t*)f.location - (uint8_t*)(f.segment->content));
+ return;
+ }
+ lastLoc = f;
+ }
+ }
+
+ for ( const Fixup fixup : sortedFixups) {
+ uint64_t segmentIndex = fixup.segment - &segments.front();
+ fixupsInSegments[segmentIndex].push_back(fixup);
+ }
+ }
+
+ std::vector<SegmentFixupsInfo> segmentFixupInfos;
+ for ( uint32_t segIndex = 0; segIndex != segments.size(); ++segIndex ) {
+ segmentFixupInfos.push_back({ segments[segIndex], fixupsInSegments[segIndex], 0 });
+ }
+
+ calculateSegmentPageExtras(segmentFixupInfos, pointerFormat, pageSize);
+
+ buildFixups(bindTargets, segmentFixupInfos, preferredLoadAddress, pointerFormat, pageSize, setDataChains);
+}
+#endif
+
+
+ChainedFixups::ChainedFixups(std::span<const Fixup::BindTarget> bindTargets,
+ std::span<const SegmentFixupsInfo> segments,
+ uint64_t preferredLoadAddress,
+ const PointerFormat& pointerFormat, uint32_t pageSize, bool setDataChains)
+{
+ buildFixups(bindTargets, segments, preferredLoadAddress, pointerFormat, pageSize, setDataChains);
+}
+
+template<typename T, typename U>
+void atomic_min(std::atomic<T>& location, U value, const T defaultValue = nullptr) {
+ // If we manage to swap with the default value, then no other thread had set the value, and we're done
+ T expected = defaultValue;
+ while ( !location.compare_exchange_weak(expected, value, std::memory_order::release, std::memory_order_relaxed) ) {
+ // Value change before the store, if new value is smaller (but not null) then there's no need to store
+ if ( expected != defaultValue && expected <= value )
+ break;
+ }
+}
+
+template<typename T, typename U>
+void atomic_max(std::atomic<T>& location, U value) {
+ // If we manage to swap with nullptr, then no other thread had set the value, and we're done
+ T expected = nullptr;
+ while ( !location.compare_exchange_weak(expected, value, std::memory_order::release, std::memory_order_relaxed) ) {
+ // Value change before the store, if new value is larger then there's no need to store
+ if ( expected >= value )
+ break;
+ }
+}
+
+
+void ChainedFixups::buildFixups(std::span<const Fixup::BindTarget> bindTargets,
+ std::span<const SegmentFixupsInfo> segments,
+ uint64_t preferredLoadAddress,
+ const PointerFormat& pointerFormat, uint32_t pageSize, bool setDataChains)
+{
+ // scan binds to figure out which imports table format to use
+ uint16_t imFormat;
+ size_t stringPoolSize;
+ _buildError = importsFormat(bindTargets, imFormat, stringPoolSize);
+ if ( _buildError.hasError() )
+ return;
+
+
+ // build imports table
+ std::vector<char> stringPool;
+ size_t importsTableSize = 0;
+ const void* importsTableStart = nullptr;
+ std::vector<dyld_chained_import> imports ;
+ std::vector<dyld_chained_import_addend> importsAddend;
+ std::vector<dyld_chained_import_addend64> importsAddend64;
+ stringPool.reserve(stringPoolSize);
+ stringPool.push_back('\0'); // so that zero is never a legal string offset
+ if ( imFormat == DYLD_CHAINED_IMPORT_ADDEND64 ) {
+ importsAddend64.reserve(bindTargets.size());
+ for (const Fixup::BindTarget& bind : bindTargets) {
+ importsAddend64.push_back({(uint16_t)bind.libOrdinal, bind.weakImport, 0, addSymbolString(bind.symbolName, stringPool), (uint64_t)bind.addend});
+ }
+ importsTableSize = sizeof(dyld_chained_import_addend64) * importsAddend64.size();
+ if ( !importsAddend64.empty() )
+ importsTableStart = &importsAddend64[0];
+ }
+ else if ( imFormat == DYLD_CHAINED_IMPORT_ADDEND ) {
+ importsAddend.reserve(bindTargets.size());
+ for (const Fixup::BindTarget& bind : bindTargets) {
+ importsAddend.push_back({(uint8_t)bind.libOrdinal, bind.weakImport, addSymbolString(bind.symbolName, stringPool), (int32_t)bind.addend});
+ }
+ importsTableSize = sizeof(dyld_chained_import_addend) * importsAddend.size();
+ if ( !importsAddend.empty() )
+ importsTableStart = &importsAddend[0];
+ }
+ else {
+ // can use most compact imports encoding
+ imports.reserve(bindTargets.size());
+ for (const Fixup::BindTarget& bind : bindTargets) {
+ imports.push_back({(uint8_t)bind.libOrdinal, bind.weakImport, addSymbolString(bind.symbolName, stringPool)});
+ }
+ importsTableSize = sizeof(dyld_chained_import) * imports.size();
+ if ( !imports.empty() )
+ importsTableStart = &imports[0];
+ }
+
+ // for 32-bit archs, compute maxRebaseAddress value
+ uint64_t maxRebaseAddress = 0;
+ if ( !pointerFormat.is64() ) {
+ for ( const SegmentFixupsInfo& segment : segments ) {
+ const MappedSegment& seg = segment.mappedSegment;
+ if ( seg.segName == "__LINKEDIT" ) {
+ uint64_t baseAddress = preferredLoadAddress;
+ if ( baseAddress == 0x4000 )
+ baseAddress = 0; // 32-bit main executables have rebase targets that are zero based
+ maxRebaseAddress = (seg.runtimeOffset + 0x00100000-1) & -0x00100000; // align to 1MB
+ }
+ }
+ }
+
+ // allocate space in _bytes for full dyld_chained_fixups data structure
+ size_t maxBytesNeeded = linkeditSize(bindTargets, segments, pageSize);
+ _bytes.resize(maxBytesNeeded, 0); // ensure alignment padding is zeroed out
+
+ // build dyld_chained_fixups data structure
+ dyld_chained_fixups_header* header = (dyld_chained_fixups_header*)(&_bytes[0]);
+ header->fixups_version = 0; // version 0
+ header->starts_offset = (uint32_t)align8(sizeof(dyld_chained_fixups_header)); // 8-byte align dyld_chained_starts_in_image
+ header->imports_offset = 0; // filled in later
+ header->symbols_offset = 0; // filled in later
+ header->imports_count = (uint32_t)bindTargets.size();
+ header->imports_format = imFormat;
+ header->symbols_format = 0; // raw strings
+ dyld_chained_starts_in_image* startsInfo = (dyld_chained_starts_in_image*)(&_bytes[header->starts_offset]);
+ startsInfo->seg_count = (uint32_t)segments.size();
+
+ // create dyld_chained_starts_in_segment for each segment
+ {
+ uint32_t segInfoOffset = (uint32_t)align8(offsetof(dyld_chained_starts_in_image,seg_info_offset[segments.size()]));
+ for ( uint32_t segIndex = 0; segIndex != segments.size(); ++segIndex ) {
+ const MappedSegment& segment = segments[segIndex].mappedSegment;
+ const std::span<const Fixup> fixupsInSegment = segments[segIndex].fixups;
+
+ // don't make dyld_chained_starts_in_segment for segments with no fixups
+ if ( !segment.writable || (segment.runtimeSize == 0) || fixupsInSegment.empty() ) {
+ startsInfo->seg_info_offset[segIndex] = 0;
+ continue;
+ }
+
+ startsInfo->seg_info_offset[segIndex] = segInfoOffset;
+ dyld_chained_starts_in_segment* segInfo = (dyld_chained_starts_in_segment*)(&_bytes[header->starts_offset+segInfoOffset]);
+ segInfo->size = 0; // filled in later
+ segInfo->page_size = pageSize;
+ segInfo->pointer_format = pointerFormat.value();
+ segInfo->segment_offset = segment.runtimeOffset;
+ segInfo->max_valid_pointer = (uint32_t)maxRebaseAddress;
+ segInfo->page_count = 0; // fill in later, may be trailing pages with no fixups
+ segInfo->page_start[0] = DYLD_CHAINED_PTR_START_NONE;
+
+ uint64_t lastFixupSegmentOffset = (uint64_t)fixupsInSegment.back().location - (uint64_t)segment.content;
+ uint64_t lastFixupPage = (lastFixupSegmentOffset / pageSize) + 1;
+
+ segInfo->page_count = lastFixupPage;
+ segInfo->size = (uint32_t)offsetof(dyld_chained_starts_in_segment, page_start[segInfo->page_count]);
+
+ // adjust segment size info to include overflow entries
+ segInfo->size += segments[segIndex].numPageExtras * sizeof(uint16_t);
+
+ segInfoOffset += segInfo->size;
+ segInfoOffset = align8(segInfoOffset);
+ }
+
+ header->imports_offset = align8(header->starts_offset + segInfoOffset);
+ header->symbols_offset = (uint32_t)align8(header->imports_offset + importsTableSize);
+ }
+
+ // For segments, we're going to try do each page in parallel when possible
+ // First this means computing the range of fixups for every page. We can do that in parallel
+ // Then walk those ranges in parallel.
+ // For segments with pageExtras, its too hard to do pages in parallel so we'll go serially
+ for ( uint32_t segIndex = 0; segIndex != segments.size(); ++segIndex ) {
+ uint32_t segInfoOffset = startsInfo->seg_info_offset[segIndex];
+ if ( segInfoOffset == 0 )
+ continue;
+
+ const dyld_chained_starts_in_segment* segInfo = (dyld_chained_starts_in_segment*)(&_bytes[header->starts_offset + segInfoOffset]);
+
+ const MappedSegment& segment = segments[segIndex].mappedSegment;
+ const std::span<const Fixup> segFixups = segments[segIndex].fixups;
+ uint32_t segExtras = segments[segIndex].numPageExtras;
+
+ std::span<uint16_t> pageStarts = { (uint16_t*)&segInfo->page_start[0], segInfo->page_count };
+ const uint32_t minNext = pointerFormat.minNext();
+
+ if ( segExtras != 0 ) {
+ // Segment has extras. Take the slow path
+ std::span<uint16_t> extras = { (uint16_t*)&segInfo->page_start[segInfo->page_count], segExtras };
+
+ int curPageIndex = -1;
+ int curExtrasIndex = -1;
+ const Fixup* prevFixup = nullptr;
+ for ( const Fixup& fixup : segFixups ) {
+ uint64_t segOffset = (uint8_t*)fixup.location - (uint8_t*)segment.content;
+ int pageIndex = (int)(segOffset/pageSize);
+ if ( pageIndex != curPageIndex ) {
+ // End the previous chain if we have one
+ if ( prevFixup != nullptr ) {
+ if ( (pageStarts[curPageIndex] & DYLD_CHAINED_PTR_START_MULTI) != 0 ) {
+ // Mark the end of this extras chain
+ extras[curExtrasIndex] |= DYLD_CHAINED_PTR_START_LAST;
+ }
+
+ if ( setDataChains ) {
+ // set end of chain for this page
+ pointerFormat.writeChainEntry(*prevFixup, nullptr, preferredLoadAddress);
+ }
+ }
+ while (curPageIndex < pageIndex) {
+ ++curPageIndex;
+ pageStarts[curPageIndex] = DYLD_CHAINED_PTR_START_NONE;
+ }
+ pageStarts[curPageIndex] = (segOffset - (curPageIndex*pageSize));
+ prevFixup = nullptr;
+ }
+
+ // Found a previous fixup on this page, so make a chain from it to this fixup
+ if ( prevFixup != nullptr ) {
+ uint8_t* chain = (uint8_t*)fixup.location;
+ intptr_t delta = chain - (uint8_t*)(prevFixup->location);
+ if ( delta <= pointerFormat.maxNext() ) {
+ if ( (delta % minNext) != 0 ) {
+ _buildError = Error("pointer not %d-byte aligned at %.*s+0x%llX, fix alignment or disable chained fixups",
+ minNext, (int)segment.segName.size(), segment.segName.data(), segOffset);
+ break;
+ }
+ else if ( setDataChains ) {
+ pointerFormat.writeChainEntry(*prevFixup, chain, preferredLoadAddress);
+ }
+ }
+ else {
+ // prev/next are too far apart for chain to span, instead terminate chain at prevFixup
+ if ( setDataChains )
+ pointerFormat.writeChainEntry(*prevFixup, nullptr, preferredLoadAddress);
+ // then start new overflow chain
+ if ( (pageStarts[curPageIndex] & DYLD_CHAINED_PTR_START_MULTI) == 0 ) {
+ ++curExtrasIndex;
+ // move first start to overflow array
+ extras[curExtrasIndex] = pageStarts[curPageIndex];
+ // change first page start to point into overflow array
+ pageStarts[curPageIndex] = DYLD_CHAINED_PTR_START_MULTI | (segInfo->page_count + curExtrasIndex);
+ }
+ uint16_t pageOffset = segOffset % pageSize;
+ ++curExtrasIndex;
+ extras[curExtrasIndex] = pageOffset;
+ }
+ }
+ prevFixup = &fixup;
+ }
+ // if this page required multiple starts, mark last one
+ if ( (pageStarts[curPageIndex] & DYLD_CHAINED_PTR_START_MULTI) != 0 ) {
+ extras[curExtrasIndex] |= DYLD_CHAINED_PTR_START_LAST;
+ }
+ if ( setDataChains && (prevFixup != nullptr) ) {
+ // set end of chain
+ pointerFormat.writeChainEntry(*prevFixup, nullptr, preferredLoadAddress);
+ }
+ } else {
+ // No extras, so use parallelism
+ typedef std::pair<std::atomic<const Fixup*>, std::atomic<const Fixup*>> FixupRange;
+ // use up to 128kb on stack, main thread has 8mb large stack by default
+ STACK_ALLOC_OVERFLOW_SAFE_ARRAY(FixupRange, fixupRangesStorage, 0x2000);
+ fixupRangesStorage.resize(segInfo->page_count);
+ // array ::resize doesn't initialize new elements, so do it here
+ bzero(&fixupRangesStorage[0], sizeof(FixupRange) * segInfo->page_count);
+ std::span<FixupRange> fixupRanges = { &fixupRangesStorage[0], segInfo->page_count };
+
+ // Walk all fixups and get the range for each page
+ mapReduce(segFixups, ^(size_t, int&, std::span<const Fixup> fixups) {
+
+ int curPageIndex = -1;
+ const Fixup* endFixup = nullptr;
+
+ // The very first fixup we process might be the first on its page, or might be
+ // somewhere in the middle. So it needs as atomic min to make sure its safe with other threads
+ {
+ const Fixup& fixup = fixups[0];
+ uint64_t segOffset = (uint8_t*)fixup.location - (uint8_t*)segment.content;
+ int pageIndex = (int)(segOffset/pageSize);
+ atomic_min(fixupRanges[pageIndex].first, &fixup);
+
+ curPageIndex = pageIndex;
+ endFixup = &fixup;
+ }
+
+ fixups = fixups.subspan(1);
+
+ for ( const Fixup& fixup : fixups ) {
+ uint64_t segOffset = (uint8_t*)fixup.location - (uint8_t*)segment.content;
+ int pageIndex = (int)(segOffset/pageSize);
+
+ if ( pageIndex != curPageIndex ) {
+ // Crossing in to a new page. As fixups are sorted, we know for sure the
+ // last fixup we processed must be on the end of its page
+ fixupRanges[curPageIndex].second.store(endFixup, std::memory_order_relaxed);
+
+ // Also the new fixup we have must be the first on its page
+ fixupRanges[pageIndex].first.store(&fixup, std::memory_order_relaxed);
+
+ curPageIndex = pageIndex;
+ }
+
+ endFixup = &fixup;
+ }
+
+ // The last fixup we have is somewhere in a page, but we don't know if its the end
+ // of that page or not. Try set it as the max
+ atomic_max(fixupRanges[curPageIndex].second, endFixup);
+ });
+
+ // If there's an unaligned fixup, this will store if offset in the segment
+ std::atomic<uint64_t> unalignedFixupOffset = ~0ULL;
+ std::atomic<uint64_t>& unalignedFixupOffsetRef = unalignedFixupOffset;
+
+ // Now process all pages in parallel
+ mapReduce(fixupRanges, std::max(fixupRanges.size() / 64, 32ul), ^(size_t, int&, std::span<FixupRange> ranges) {
+ for ( const FixupRange& fixupRange : ranges ) {
+ size_t pageIndex = &fixupRange - fixupRanges.data();
+ const Fixup* start = fixupRange.first.load(std::memory_order_relaxed);
+ const Fixup* end = fixupRange.second.load(std::memory_order_relaxed);
+ if ( start == nullptr ) {
+ assert(end == nullptr);
+ pageStarts[pageIndex] = DYLD_CHAINED_PTR_START_NONE;
+ continue;
+ }
+
+ assert(end != nullptr);
+ assert(start <= end);
+ uint64_t startSegOffset = (uint8_t*)start->location - (uint8_t*)segment.content;
+ pageStarts[pageIndex] = (startSegOffset - (pageIndex * pageSize));
+
+ if ( setDataChains ) {
+ const Fixup* fixup = start;
+ while ( fixup != end ) {
+ const Fixup* prev = fixup;
+ ++fixup;
+ uint8_t* chain = (uint8_t*)fixup->location;
+ intptr_t delta = chain - (uint8_t*)(prev->location);
+ if ( (delta % minNext) != 0 ) {
+ uint64_t segOffset = (uint8_t*)fixup->location - (uint8_t*)segment.content;
+ atomic_min(unalignedFixupOffsetRef, segOffset, ~0ULL);
+ break;
+ }
+ pointerFormat.writeChainEntry(*prev, chain, preferredLoadAddress);
+ }
+
+ // set end of chain
+ pointerFormat.writeChainEntry(*end, nullptr, preferredLoadAddress);
+ }
+ }
+ });
+
+ uint64_t segOffset = unalignedFixupOffset.load(std::memory_order_relaxed);
+ if ( (segOffset != ~0ULL) && !_buildError.hasError() ) {
+ _buildError = Error("pointer not %d-byte aligned at %.*s+0x%llX, fix alignment or disable chained fixups",
+ minNext, (int)segment.segName.size(), segment.segName.data(), segOffset);
+ }
+ }
+ }
+
+ // append import table and string pool
+ memcpy(&_bytes[header->imports_offset], importsTableStart, importsTableSize);
+ memcpy(&_bytes[header->symbols_offset], &stringPool[0], stringPool.size());
+
+ _fixupsHeader = (dyld_chained_fixups_header*)(&_bytes[0]);
+ _fixupsSize = _bytes.size();
+}
+
+
+uint32_t ChainedFixups::addSymbolString(CString symbolName, std::vector<char>& pool)
+{
+ uint32_t symbolOffset = (uint32_t)pool.size();
+ // end+1 to copy also the null-terminator
+ pool.insert(pool.end(), symbolName.begin(), symbolName.end()+1);
+ return symbolOffset;
+}
+
+
+#endif
//
@@ -420,14 +929,14 @@
int32_t bindMinEmbeddableAddend(bool authenticated) const override { return (authenticated ? 0 : -0x3FFFF); }
const void* nextLocation(const void* loc) const override {
- const unaligned_dyld_chained_ptr_arm64e_rebase* ptr = (unaligned_dyld_chained_ptr_arm64e_rebase*)loc;
+ const dyld_chained_ptr_arm64e_rebase* ptr = (dyld_chained_ptr_arm64e_rebase*)loc;
if ( ptr->next == 0 )
return nullptr;
return (void*)((uint8_t*)loc + ptr->next * stride());
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
- if ( ((unaligned_dyld_chained_ptr_arm64e_rebase*)loc)->bind ) {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
+ if ( ((dyld_chained_ptr_arm64e_rebase*)loc)->bind ) {
if ( bindBitCount() == 24 ) {
const dyld_chained_ptr_arm64e_auth_bind24* authBind24Ptr = (dyld_chained_ptr_arm64e_auth_bind24*)loc;
const dyld_chained_ptr_arm64e_bind24* bind24Ptr = (dyld_chained_ptr_arm64e_bind24*)loc;
@@ -446,8 +955,8 @@
}
}
else {
- const unaligned_dyld_chained_ptr_arm64e_auth_rebase* authRebasePtr = (unaligned_dyld_chained_ptr_arm64e_auth_rebase*)loc;
- const dyld_chained_ptr_arm64e_rebase* rebasePtr = (dyld_chained_ptr_arm64e_rebase*)loc;
+ const dyld_chained_ptr_arm64e_auth_rebase* authRebasePtr = (dyld_chained_ptr_arm64e_auth_rebase*)loc;
+ const dyld_chained_ptr_arm64e_rebase* rebasePtr = (dyld_chained_ptr_arm64e_rebase*)loc;
if ( authRebasePtr->auth )
return Fixup(loc, seg, authRebasePtr->target, authRebasePtr->key, authRebasePtr->addrDiv, authRebasePtr->diversity);
else if ( unauthRebaseIsVmAddr() )
@@ -456,26 +965,8 @@
return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | rebasePtr->target);
}
}
-
- static int64_t signExtendedAddend(dyld_chained_ptr_arm64e_bind24* bind)
- {
- uint64_t addend19 = bind->addend;
- if ( addend19 & 0x40000 )
- return addend19 | 0xFFFFFFFFFFFC0000ULL;
- else
- return addend19;
- }
-
- static int64_t signExtendedAddend(dyld_chained_ptr_arm64e_bind* bind)
- {
- uint64_t addend27 = bind->addend;
- uint64_t top8Bits = addend27 & 0x00007F80000ULL;
- uint64_t bottom19Bits = addend27 & 0x0000007FFFFULL;
- uint64_t newValue = (top8Bits << 13) | (((uint64_t)(bottom19Bits << 37) >> 37) & 0x00FFFFFFFFFFFFFF);
- return newValue;
- }
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
if ( fixup.isBind ) {
if ( bindBitCount() == 24 ) {
@@ -489,13 +980,9 @@
authBind24Ptr->diversity = fixup.auth.diversity;
authBind24Ptr->zero = 0;
authBind24Ptr->ordinal = fixup.bind.bindOrdinal;
- // validate things fit into bit fields
- if ( authBind24Ptr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( authBind24Ptr->ordinal != fixup.bind.bindOrdinal )
- return badBindOrdinal(fixup);
- if ( fixup.bind.embeddedAddend != 0 )
- return badAddend(fixup, fixup.bind.embeddedAddend);
+ assert(authBind24Ptr->next*stride() == delta);
+ assert(authBind24Ptr->ordinal == fixup.bind.bindOrdinal);
+ assert(fixup.bind.embeddedAddend == 0);
}
else {
dyld_chained_ptr_arm64e_bind24* bind24Ptr = (dyld_chained_ptr_arm64e_bind24*)fixup.location;
@@ -505,12 +992,9 @@
bind24Ptr->addend = fixup.bind.embeddedAddend;
bind24Ptr->zero = 0;
bind24Ptr->ordinal = fixup.bind.bindOrdinal;
- if ( signExtendedAddend(bind24Ptr) != fixup.bind.embeddedAddend )
- return badAddend(fixup, fixup.bind.embeddedAddend);
- if ( bind24Ptr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( bind24Ptr->ordinal != fixup.bind.bindOrdinal )
- return badBindOrdinal(fixup);
+ assert(bind24Ptr->addend == fixup.bind.embeddedAddend);
+ assert(bind24Ptr->next*stride() == delta);
+ assert(bind24Ptr->ordinal == fixup.bind.bindOrdinal);
}
}
else {
@@ -524,12 +1008,9 @@
authBindPtr->diversity = fixup.auth.diversity;
authBindPtr->zero = 0;
authBindPtr->ordinal = fixup.bind.bindOrdinal;
- if ( authBindPtr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( authBindPtr->ordinal != fixup.bind.bindOrdinal )
- return badBindOrdinal(fixup);
- if ( fixup.bind.embeddedAddend != 0 )
- return badAddend(fixup, fixup.bind.embeddedAddend);
+ assert(authBindPtr->next*stride() == delta);
+ assert(authBindPtr->ordinal == fixup.bind.bindOrdinal);
+ assert(fixup.bind.embeddedAddend == 0);
}
else {
dyld_chained_ptr_arm64e_bind* bindPtr = (dyld_chained_ptr_arm64e_bind*)fixup.location;
@@ -539,18 +1020,15 @@
bindPtr->addend = fixup.bind.embeddedAddend;
bindPtr->zero = 0;
bindPtr->ordinal = fixup.bind.bindOrdinal;
- if ( signExtendedAddend(bindPtr) != fixup.bind.embeddedAddend )
- return badAddend(fixup, fixup.bind.embeddedAddend);
- if ( bindPtr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( bindPtr->ordinal != fixup.bind.bindOrdinal )
- return badBindOrdinal(fixup);
+ assert(bindPtr->addend == fixup.bind.embeddedAddend);
+ assert(bindPtr->next*stride() == delta);
+ assert(bindPtr->ordinal == fixup.bind.bindOrdinal);
}
}
}
else {
if ( fixup.authenticated ) {
- unaligned_dyld_chained_ptr_arm64e_auth_rebase* authRebasePtr = (unaligned_dyld_chained_ptr_arm64e_auth_rebase*)fixup.location;
+ dyld_chained_ptr_arm64e_auth_rebase* authRebasePtr = (dyld_chained_ptr_arm64e_auth_rebase*)fixup.location;
authRebasePtr->auth = true;
authRebasePtr->bind = false;
authRebasePtr->next = delta/stride();
@@ -558,13 +1036,11 @@
authRebasePtr->addrDiv = fixup.auth.usesAddrDiversity;
authRebasePtr->diversity = fixup.auth.diversity;
authRebasePtr->target = fixup.rebase.targetVmOffset;
- if ( authRebasePtr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( authRebasePtr->target != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- }
+ assert(authRebasePtr->next*stride() == delta);
+ assert(authRebasePtr->target == fixup.rebase.targetVmOffset);
+ }
else {
- unaligned_dyld_chained_ptr_arm64e_rebase* rebasePtr = (unaligned_dyld_chained_ptr_arm64e_rebase*)fixup.location;
+ dyld_chained_ptr_arm64e_rebase* rebasePtr = (dyld_chained_ptr_arm64e_rebase*)fixup.location;
uint8_t high8 = (fixup.rebase.targetVmOffset >> 56);
uint64_t low56 = (fixup.rebase.targetVmOffset & 0x00FFFFFFFFFFFFFFULL);
rebasePtr->auth = false;
@@ -572,18 +1048,12 @@
rebasePtr->next = delta/stride();
rebasePtr->high8 = high8;
rebasePtr->target = low56 + (this->unauthRebaseIsVmAddr() ? preferedLoadAddress : 0);
- if ( rebasePtr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != (low56 + (this->unauthRebaseIsVmAddr() ? preferedLoadAddress : 0)) ) {
- if ( this->unauthRebaseIsVmAddr() )
- return badVmAddr(fixup, preferedLoadAddress);
- else
- return badVmOffset(fixup);
- }
- }
- }
- return Error::none();
- }
+ assert(rebasePtr->next*stride() == delta);
+ assert(rebasePtr->target == (low56 + (this->unauthRebaseIsVmAddr() ? preferedLoadAddress : 0)));
+ }
+ }
+ }
+#endif
protected:
virtual uint32_t bindBitCount() const = 0;
@@ -600,7 +1070,6 @@
uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E; }
const char* name() const override { return "DYLD_CHAINED_PTR_ARM64E"; }
const char* description() const override { return "authenticated arm64e, 8-byte stride, target vmadddr"; }
- uint32_t ptrAlignmentSize() const override { return 8; } // arm64e userspace requires 8-byte ptr alignment
protected:
uint32_t bindBitCount() const override { return 16; }
uint32_t stride() const override { return 8; }
@@ -611,7 +1080,7 @@
//
// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL ---
//
-class VIS_HIDDEN __attribute__((__packed__)) PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL : public PointerFormat_Generic_arm64e
+class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL : public PointerFormat_Generic_arm64e
{
public:
uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_KERNEL; }
@@ -634,7 +1103,6 @@
uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_USERLAND; }
const char* name() const override { return "DYLD_CHAINED_PTR_ARM64E_USERLAND"; }
const char* description() const override { return "authenticated arm64e, 8-byte stride, target vmoffset"; }
- uint32_t ptrAlignmentSize() const override { return 8; } // arm64e userspace requires 8-byte ptr alignment
protected:
uint32_t bindBitCount() const override { return 16; }
uint32_t stride() const override { return 8; }
@@ -651,7 +1119,6 @@
uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_USERLAND24; }
const char* name() const override { return "DYLD_CHAINED_PTR_ARM64E_USERLAND24"; }
const char* description() const override { return "authenticated arm64e, 8-byte stride, target vmoffset"; }
- uint32_t ptrAlignmentSize() const override { return 8; } // arm64e userspace requires 8-byte ptr alignment
protected:
uint32_t bindBitCount() const override { return 24; }
uint32_t stride() const override { return 8; }
@@ -667,188 +1134,13 @@
public:
uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_FIRMWARE; }
const char* name() const override { return "DYLD_CHAINED_PTR_ARM64E_FIRMWARE"; }
- const char* description() const override { return "authenticated arm64e, 4-byte stride, target vmaddr"; }
+ const char* description() const override { return "authenticated arm64e, 4-byte stride, target vmoffset"; }
bool is64() const override { return true; }
protected:
uint32_t bindBitCount() const override { return 16; }
uint32_t stride() const override { return 4; }
bool unauthRebaseIsVmAddr() const override { return true; }
};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE : public PointerFormat_Generic_arm64e
-{
-public:
- bool supportsBinds() const override { return false; }
- uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE; }
- const char* name() const override { return "PointerFormat_DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE"; }
- const char* description() const override { return "arm64e shared cache, 8-byte stride, target vmoffset"; }
- uint32_t ptrAlignmentSize() const override { return 8; } // arm64e userspace requires 8-byte ptr alignment
- uint64_t maxRebaseTargetOffset(bool auth) const override { return 0x3FFFFFFFFULL; }
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override;
-protected:
- uint32_t bindBitCount() const override { return 0; }
- uint32_t stride() const override { return 8; }
- bool unauthRebaseIsVmAddr() const override { return false; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_arm64e_shared_cache_rebase* ptr = (dyld_chained_ptr_arm64e_shared_cache_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * stride());
- }
-
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
- const dyld_chained_ptr_arm64e_shared_cache_auth_rebase* authRebasePtr = (dyld_chained_ptr_arm64e_shared_cache_auth_rebase*)loc;
- const dyld_chained_ptr_arm64e_shared_cache_rebase* rebasePtr = (dyld_chained_ptr_arm64e_shared_cache_rebase*)loc;
- if ( authRebasePtr->auth ) {
- uint8_t key = (authRebasePtr->keyIsData ? ptrauth_key_asda : ptrauth_key_asia);
- return Fixup(loc, seg, authRebasePtr->runtimeOffset, key, authRebasePtr->addrDiv, authRebasePtr->diversity);
- }
- else {
- return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | rebasePtr->runtimeOffset);
- }
- }
-
-};
-
-Error PointerFormat_DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE::writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const
-{
- if ( fixup.isBind )
- return Error ("shared cache fixup formate does not support binds");
- intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
- if ( fixup.authenticated ) {
- dyld_chained_ptr_arm64e_shared_cache_auth_rebase* authRebasePtr = (dyld_chained_ptr_arm64e_shared_cache_auth_rebase*)fixup.location;
- authRebasePtr->auth = 1;
- authRebasePtr->next = (uint32_t)(delta/8);
- authRebasePtr->keyIsData = (fixup.auth.key == ptrauth_key_asia ? 0 : 1);
- authRebasePtr->addrDiv = fixup.auth.usesAddrDiversity;
- authRebasePtr->diversity = fixup.auth.diversity;
- authRebasePtr->runtimeOffset = (fixup.rebase.targetVmOffset & 0x3FFFFFFFFULL);
- if ( authRebasePtr->next*8 != delta )
- return badChainDistance(fixup, delta);
- if ( authRebasePtr->runtimeOffset != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- }
- else {
- dyld_chained_ptr_arm64e_shared_cache_rebase* rebasePtr = (dyld_chained_ptr_arm64e_shared_cache_rebase*)fixup.location;
- rebasePtr->auth = 0;
- rebasePtr->next = (uint32_t)(delta/8);
- rebasePtr->unused = 0;
- rebasePtr->high8 = ((fixup.rebase.targetVmOffset >> 56) & 0xFF);
- rebasePtr->runtimeOffset = (fixup.rebase.targetVmOffset & 0x3FFFFFFFFULL);
- if ( rebasePtr->next*8 != delta )
- return badChainDistance(fixup, delta);
- uint64_t targetFromEncoding = (rebasePtr->runtimeOffset | ((uint64_t)rebasePtr->high8 << 56));
- if ( targetFromEncoding != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- }
- return Error::none();
-}
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_SEGMENTED ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E_SEGMENTED : public PointerFormat_Generic_arm64e
-{
-public:
- bool supportsBinds() const override { return false; }
- uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_SEGMENTED; }
- const char* name() const override { return "DYLD_CHAINED_PTR_ARM64E_SEGMENTED"; }
- const char* description() const override { return "authenticated arm64e, 8-byte stride, target segIndex/offset8"; }
- bool is64() const override { return true; }
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override;
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override;
- const void* nextLocation(const void* loc) const override;
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0x0FFFFFFF; }
-protected:
- uint32_t bindBitCount() const override { return 0; }
- uint32_t stride() const override { return 4; }
- bool unauthRebaseIsVmAddr() const override { return true; }
-};
-
-const void* PointerFormat_DYLD_CHAINED_PTR_ARM64E_SEGMENTED::nextLocation(const void* loc) const
-{
- const dyld_chained_ptr_arm64e_segmented_rebase* ptr = (dyld_chained_ptr_arm64e_segmented_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * stride());
-}
-
-Fixup PointerFormat_DYLD_CHAINED_PTR_ARM64E_SEGMENTED::parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const
-{
- const dyld_chained_ptr_arm64e_auth_segmented_rebase* authSegRebasePtr = (dyld_chained_ptr_arm64e_auth_segmented_rebase*)loc;
- const dyld_chained_ptr_arm64e_segmented_rebase* segRebasePtr = (dyld_chained_ptr_arm64e_segmented_rebase*)loc;
- if ( authSegRebasePtr->auth ) {
- uint64_t targetVMOffset = segOffsetTable[authSegRebasePtr->targetSegIndex] + authSegRebasePtr->targetSegOffset;
- return Fixup(loc, seg, targetVMOffset, authSegRebasePtr->key, authSegRebasePtr->addrDiv, authSegRebasePtr->diversity);
- }
- else {
- uint64_t targetVMOffset = segOffsetTable[segRebasePtr->targetSegIndex] + segRebasePtr->targetSegOffset;
- return Fixup(loc, seg, targetVMOffset);
- }
-}
-
-static bool findSegIndexAndOffset(std::span<const MappedSegment*> segments, uint64_t vmOffset, uint8_t& segIndex, uint64_t& segOffset)
-{
- int index=0;
- for (const MappedSegment* seg : segments) {
- if ( (seg->runtimeOffset <= vmOffset) && (vmOffset <= (seg->runtimeOffset+seg->runtimeSize)) ) {
- segIndex = index;
- segOffset = vmOffset - seg->runtimeOffset;
- return true;
- }
- ++index;
- }
- return false;
-}
-
-
-Error PointerFormat_DYLD_CHAINED_PTR_ARM64E_SEGMENTED::writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*> segments) const
-{
- intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
- if ( fixup.isBind )
- return Error("firmware format does not support binds");
- uint8_t segIndex;
- uint64_t segOffset;
- bool found = findSegIndexAndOffset(segments, fixup.rebase.targetVmOffset, segIndex, segOffset);
- if ( !found )
- return Error("target vm address not in any segment");
-
- if ( fixup.authenticated ) {
- //fprintf(stderr, "key=%d, addr=%d, div=0x%04X\n", fixup.auth.key, fixup.auth.usesAddrDiversity, fixup.auth.diversity);
- dyld_chained_ptr_arm64e_auth_segmented_rebase* authRebasePtr = (dyld_chained_ptr_arm64e_auth_segmented_rebase*)fixup.location;
- authRebasePtr->auth = true;
- authRebasePtr->next = (uint32_t)(delta/stride());
- authRebasePtr->key = fixup.auth.key;
- authRebasePtr->addrDiv = fixup.auth.usesAddrDiversity;
- authRebasePtr->diversity = fixup.auth.diversity;
- authRebasePtr->targetSegIndex = segIndex;
- authRebasePtr->targetSegOffset = (uint32_t)segOffset;
- if ( authRebasePtr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( (authRebasePtr->targetSegIndex != segIndex) || (authRebasePtr->targetSegOffset != segOffset) )
- return badSegIndexOrOffset(fixup, segIndex, segOffset);
- }
- else {
- //fprintf(stderr, "segIndex=%d, segOffset=0x%0llX\n", segIndex, segOffset);
- dyld_chained_ptr_arm64e_segmented_rebase* rebasePtr = (dyld_chained_ptr_arm64e_segmented_rebase*)fixup.location;
- rebasePtr->auth = false;
- rebasePtr->next = (uint32_t)(delta/stride());
- rebasePtr->padding = 0;
- rebasePtr->targetSegIndex = segIndex;
- rebasePtr->targetSegOffset = (uint32_t)segOffset;
- if ( rebasePtr->next*stride() != delta )
- return badChainDistance(fixup, delta);
- if ( (rebasePtr->targetSegIndex != segIndex) || (rebasePtr->targetSegOffset != segOffset) )
- return badSegIndexOrOffset(fixup, segIndex, segOffset);
- }
- return Error::none();
-}
//
@@ -877,7 +1169,7 @@
return (void*)((uint8_t*)loc + ptr->next * 4);
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
const dyld_chained_ptr_64_rebase* rebasePtr = (dyld_chained_ptr_64_rebase*)loc;
const dyld_chained_ptr_64_bind* bindPtr = (dyld_chained_ptr_64_bind*)loc;
if ( bindPtr->bind )
@@ -887,8 +1179,8 @@
else
return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | rebasePtr->target);
}
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
if ( fixup.isBind ) {
dyld_chained_ptr_64_bind* bindPtr = (dyld_chained_ptr_64_bind*)fixup.location;
@@ -897,12 +1189,9 @@
bindPtr->reserved = 0;
bindPtr->addend = fixup.bind.embeddedAddend;
bindPtr->ordinal = fixup.bind.bindOrdinal;
- if ( bindPtr->addend != fixup.bind.embeddedAddend )
- return badAddend(fixup, fixup.bind.embeddedAddend);
- if ( bindPtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( bindPtr->ordinal != fixup.bind.bindOrdinal )
- return badBindOrdinal(fixup);
+ assert(bindPtr->addend == fixup.bind.embeddedAddend);
+ assert(bindPtr->next*4 == delta);
+ assert(bindPtr->ordinal == fixup.bind.bindOrdinal);
}
else if ( unauthRebaseIsVmAddr() ) {
dyld_chained_ptr_64_rebase* rebasePtr = (dyld_chained_ptr_64_rebase*)fixup.location;
@@ -913,11 +1202,9 @@
rebasePtr->reserved = 0;
rebasePtr->high8 = high8;
rebasePtr->target = low56+preferedLoadAddress;
- if ( rebasePtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != (low56+preferedLoadAddress) )
- return badVmAddr(fixup, preferedLoadAddress);
- }
+ assert(rebasePtr->next*4 == delta);
+ assert(rebasePtr->target == (low56+preferedLoadAddress));
+ }
else {
dyld_chained_ptr_64_rebase* rebasePtr = (dyld_chained_ptr_64_rebase*)fixup.location;
uint8_t high8 = (fixup.rebase.targetVmOffset >> 56);
@@ -927,15 +1214,11 @@
rebasePtr->reserved = 0;
rebasePtr->high8 = high8;
rebasePtr->target = low56;
- if ( rebasePtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- uint64_t targetFromEncoding = (low56 | ((uint64_t)rebasePtr->high8 << 56));
- if ( targetFromEncoding != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- }
- return Error::none();
- }
-
+ assert(rebasePtr->next*4 == delta);
+ assert(rebasePtr->target == low56);
+ }
+ }
+#endif
protected:
virtual bool unauthRebaseIsVmAddr() const { return true; }
};
@@ -967,7 +1250,7 @@
return (void*)((uint8_t*)loc + ptr->next * 4);
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
const dyld_chained_ptr_32_rebase* rebasePtr = (dyld_chained_ptr_32_rebase*)loc;
const dyld_chained_ptr_32_bind* bindPtr = (dyld_chained_ptr_32_bind*)loc;
if ( bindPtr->bind )
@@ -975,8 +1258,8 @@
else
return Fixup(loc, seg, rebasePtr->target);
}
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
if ( fixup.isBind ) {
dyld_chained_ptr_32_bind* bindPtr = (dyld_chained_ptr_32_bind*)fixup.location;
@@ -984,12 +1267,9 @@
bindPtr->next = (uint32_t)(delta/4);
bindPtr->addend = fixup.bind.embeddedAddend;
bindPtr->ordinal = fixup.bind.bindOrdinal;
- if ( bindPtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( bindPtr->addend != fixup.bind.embeddedAddend )
- return badAddend(fixup, fixup.bind.embeddedAddend);
- if ( bindPtr->ordinal != fixup.bind.bindOrdinal )
- return badBindOrdinal(fixup);
+ assert(bindPtr->next*4 == delta);
+ assert(bindPtr->addend == fixup.bind.embeddedAddend);
+ assert(bindPtr->ordinal == fixup.bind.bindOrdinal);
}
else {
dyld_chained_ptr_32_rebase* rebasePtr = (dyld_chained_ptr_32_rebase*)fixup.location;
@@ -997,14 +1277,11 @@
rebasePtr->next = (uint32_t)(delta/4);
uint64_t target = fixup.rebase.targetVmOffset+preferedLoadAddress;
rebasePtr->target = (uint32_t)target;
- if ( rebasePtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != target )
- return badVmOffset(fixup);
- }
- return Error::none();
- }
-
+ assert(rebasePtr->next*4 == delta);
+ assert(rebasePtr->target == target);
+ }
+ }
+#endif
};
@@ -1034,22 +1311,20 @@
return (void*)((uint8_t*)loc + ptr->next * 4);
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
const dyld_chained_ptr_32_cache_rebase* rebasePtr = (dyld_chained_ptr_32_cache_rebase*)loc;
return Fixup(loc, seg, rebasePtr->target);
}
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
dyld_chained_ptr_32_cache_rebase* rebasePtr = (dyld_chained_ptr_32_cache_rebase*)fixup.location;
rebasePtr->next = (uint32_t)(delta/4);
rebasePtr->target = (uint32_t)fixup.rebase.targetVmOffset;
- if ( rebasePtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- return Error::none();
- }
+ assert(rebasePtr->next*4 == delta);
+ assert(rebasePtr->target == fixup.rebase.targetVmOffset);
+ }
+#endif
};
@@ -1080,22 +1355,20 @@
return (void*)((uint8_t*)loc + ptr->next * 4);
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
const dyld_chained_ptr_32_firmware_rebase* rebasePtr = (dyld_chained_ptr_32_firmware_rebase*)loc;
- return Fixup(loc, seg, rebasePtr->target - preferedLoadAddress);
- }
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+ return Fixup(loc, seg, rebasePtr->target);
+ }
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
dyld_chained_ptr_32_firmware_rebase* rebasePtr = (dyld_chained_ptr_32_firmware_rebase*)fixup.location;
rebasePtr->next = (uint32_t)(delta/4);
rebasePtr->target = (uint32_t)fixup.rebase.targetVmOffset;
- if ( rebasePtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- return Error::none();
- }
+ assert(rebasePtr->next*4 == delta);
+ assert(rebasePtr->target == fixup.rebase.targetVmOffset);
+ }
+#endif
};
@@ -1139,7 +1412,7 @@
return (void*)((uint8_t*)loc + ptr->next * 4);
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
const dyld_chained_ptr_64_kernel_cache_rebase* rebasePtr = (dyld_chained_ptr_64_kernel_cache_rebase*)loc;
if ( rebasePtr->isAuth )
return Fixup(loc, seg, rebasePtr->target, rebasePtr->key, rebasePtr->addrDiv, rebasePtr->diversity);
@@ -1147,11 +1420,11 @@
return Fixup(loc, seg, rebasePtr->target);
}
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
dyld_chained_ptr_64_kernel_cache_rebase* rebasePtr = (dyld_chained_ptr_64_kernel_cache_rebase*)fixup.location;
-
+
rebasePtr->isAuth = fixup.authenticated ;
rebasePtr->next = delta/4;
rebasePtr->key = fixup.auth.key;
@@ -1159,12 +1432,10 @@
rebasePtr->diversity = fixup.auth.diversity;
rebasePtr->cacheLevel = 0; // FIXME
rebasePtr->target = fixup.rebase.targetVmOffset;
- if ( rebasePtr->next*4 != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- return Error::none();
- }
+ assert(rebasePtr->next*4 == delta);
+ assert(rebasePtr->target == fixup.rebase.targetVmOffset);
+ }
+#endif
};
@@ -1194,7 +1465,7 @@
return (void*)((uint8_t*)loc + ptr->next);
}
- Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress, std::span<const uint64_t> segOffsetTable) const override {
+ Fixup parseChainEntry(const void* loc, const MappedSegment* seg, uint64_t preferedLoadAddress=0) const override {
const dyld_chained_ptr_64_kernel_cache_rebase* rebasePtr = (dyld_chained_ptr_64_kernel_cache_rebase*)loc;
if ( rebasePtr->isAuth )
return Fixup(loc, seg, rebasePtr->target, rebasePtr->key, rebasePtr->addrDiv, rebasePtr->diversity);
@@ -1202,8 +1473,8 @@
return Fixup(loc, seg, rebasePtr->target);
}
-
- Error writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress, std::span<const MappedSegment*>) const override {
+#if BUILDING_MACHO_WRITER
+ void writeChainEntry(const Fixup& fixup, const void* nextLoc, uint64_t preferedLoadAddress) const override {
intptr_t delta = (nextLoc == nullptr) ? 0 : ((uint8_t*)nextLoc - (uint8_t*)fixup.location);
dyld_chained_ptr_64_kernel_cache_rebase* rebasePtr = (dyld_chained_ptr_64_kernel_cache_rebase*)fixup.location;
@@ -1214,86 +1485,34 @@
rebasePtr->diversity = 0;
rebasePtr->cacheLevel = 0; // FIXME
rebasePtr->target = fixup.rebase.targetVmOffset;
- if ( rebasePtr->next != delta )
- return badChainDistance(fixup, delta);
- if ( rebasePtr->target != fixup.rebase.targetVmOffset )
- return badVmOffset(fixup);
- return Error::none();
- }
+ assert(rebasePtr->next == delta);
+ assert(rebasePtr->target == fixup.rebase.targetVmOffset);
+ }
+#endif
};
-Error ChainedFixups::PointerFormat::badChainDistance(const Fixup& fixup, intptr_t delta) const
-{
- return Error("distance between fixups (%ld) is not encodable in chain for fixup at %.*s+0x%0lX",
- delta, (int)fixup.segment->segName.size(), fixup.segment->segName.data(),
- (uintptr_t)fixup.location - (uintptr_t)fixup.segment->content);
-}
-
-Error ChainedFixups::PointerFormat::badBindOrdinal(const Fixup& fixup) const
-{
- return Error("bind ordinal (%u) too large in fixup at %.*s+0x%0lX",
- fixup.bind.bindOrdinal, (int)fixup.segment->segName.size(), fixup.segment->segName.data(),
- (uintptr_t)fixup.location - (uintptr_t)fixup.segment->content);
-}
-
-Error ChainedFixups::PointerFormat::badVmOffset(const Fixup& fixup) const
-{
- return Error("vmOffset (0x%0llX) cannot fit in fixup at %.*s+0x%0lX",
- fixup.rebase.targetVmOffset, (int)fixup.segment->segName.size(), fixup.segment->segName.data(),
- (uintptr_t)fixup.location - (uintptr_t)fixup.segment->content);
-}
-
-Error ChainedFixups::PointerFormat::badVmAddr(const Fixup& fixup, uint64_t baseAddress) const
-{
- return Error("vmAddress (0x%0llX) cannot fit in fixup at %.*s+0x%0lX",
- fixup.rebase.targetVmOffset+baseAddress, (int)fixup.segment->segName.size(), fixup.segment->segName.data(),
- (uintptr_t)fixup.location - (uintptr_t)fixup.segment->content);
-}
-
-Error ChainedFixups::PointerFormat::badAddend(const Fixup& fixup, int64_t addend) const
-{
- return Error("addend (%lld) cannot fit in fixup at %.*s+0x%0lX",
- addend, (int)fixup.segment->segName.size(), fixup.segment->segName.data(),
- (uintptr_t)fixup.location - (uintptr_t)fixup.segment->content);
-}
-
-Error ChainedFixups::PointerFormat::badSegIndexOrOffset(const Fixup& fixup, uint8_t segIndex, uint64_t segOffset) const
-{
- return Error("segIndex (%d) and segOffset (0x%0llX) cannot fit in fixup at %.*s+0x%0lX",
- segIndex, segOffset, (int)fixup.segment->segName.size(), fixup.segment->segName.data(),
- (uintptr_t)fixup.location - (uintptr_t)fixup.segment->content);
-}
-
bool ChainedFixups::PointerFormat::valid(uint16_t pointer_format)
{
- return (pointer_format <= DYLD_CHAINED_PTR_ARM64E_SEGMENTED);
-}
-
-uint32_t ChainedFixups::PointerFormat::ptrAlignmentSize() const
-{
- // most formats, including 64-bit, allow a 4-byte pointer alignment
- return 4;
-}
-
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E p1;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_64 p2;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_32 p3;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_32_CACHE p4;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_32_FIRMWARE p5;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_64_OFFSET p6;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL p7;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_64_KERNEL_CACHE p8;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND p9;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E_FIRMWARE p10;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE p11;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND24 p12;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE p13;
-static const constinit PointerFormat_DYLD_CHAINED_PTR_ARM64E_SEGMENTED p14;
+ return (pointer_format <= DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE);
+}
const ChainedFixups::PointerFormat& ChainedFixups::PointerFormat::make(uint16_t pointer_format)
{
+ static const PointerFormat_DYLD_CHAINED_PTR_ARM64E p1;
+ static const PointerFormat_DYLD_CHAINED_PTR_64 p2;
+ static const PointerFormat_DYLD_CHAINED_PTR_32 p3;
+ static const PointerFormat_DYLD_CHAINED_PTR_32_CACHE p4;
+ static const PointerFormat_DYLD_CHAINED_PTR_32_FIRMWARE p5;
+ static const PointerFormat_DYLD_CHAINED_PTR_64_OFFSET p6;
+ static const PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL p7;
+ static const PointerFormat_DYLD_CHAINED_PTR_64_KERNEL_CACHE p8;
+ static const PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND p9;
+ static const PointerFormat_DYLD_CHAINED_PTR_ARM64E_FIRMWARE p10;
+ static const PointerFormat_DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE p11;
+ static const PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND24 p12;
+
switch (pointer_format) {
case DYLD_CHAINED_PTR_ARM64E:
return p1;
@@ -1319,13 +1538,10 @@
return p11;
case DYLD_CHAINED_PTR_ARM64E_USERLAND24:
return p12;
- case DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE:
- return p13;
- case DYLD_CHAINED_PTR_ARM64E_SEGMENTED:
- return p14;
}
assert("unknown pointer format");
return p1;
}
+
} // namespace mach_o