Loading...
--- dyld/dyld-1241.17/mach_o/ChainedFixups.cpp
+++ /dev/null
@@ -1,1585 +0,0 @@
-/*
- * Copyright (c) 2021 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <sys/types.h>
-#include <assert.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#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 {
-
-
-
-//
-// MARK: --- ChainedFixups inspection methods ---
-//
-
-ChainedFixups::ChainedFixups(const dyld_chained_fixups_header* start, size_t size)
-: _fixupsHeader(start), _fixupsSize(size)
-{
-}
-
-const dyld_chained_fixups_header* ChainedFixups::bytes(size_t& size) const
-{
- size = _fixupsSize;
- return _fixupsHeader;
-}
-
-void ChainedFixups::forEachBindTarget(void (^callback)(const Fixup::BindTarget&, bool& stop)) const
-{
- (void)this->forEachBindTarget(^(int libOrdinal, const char* symbolName, int64_t addend, bool weakImport, bool& stop) {
- Fixup::BindTarget target = { symbolName, libOrdinal, weakImport, addend };
- callback(target, stop);
- });
-}
-
-uint32_t ChainedFixups::pageSize() const
-{
- const dyld_chained_starts_in_image* imageStarts = (dyld_chained_starts_in_image*)((uint8_t*)_fixupsHeader + _fixupsHeader->starts_offset);
- for (int i=0; i < imageStarts->seg_count; ++i) {
- const dyld_chained_starts_in_segment* segStarts = this->startsForSegment(i);
- if ( segStarts->page_size != 0 )
- return segStarts->page_size;
- }
- return 0x1000;
-}
-
-Error ChainedFixups::forEachBindTarget(void (^callback)(int libOrdinal, const char* symbolName, int64_t addend, bool weakImport, bool& stop)) const
-{
- if ( _fixupsHeader->imports_offset > _fixupsSize )
- return Error("malformed import table, imports_offset too large");
- if ( _fixupsHeader->symbols_offset > _fixupsSize )
- return Error("malformed import table, symbols_offset too large");
-
- const char* symbolsPool = (char*)_fixupsHeader + _fixupsHeader->symbols_offset;
- size_t maxSymbolOffset = _fixupsSize - _fixupsHeader->symbols_offset;
- int libOrdinal;
- bool stop = false;
- const dyld_chained_import* imports;
- const dyld_chained_import_addend* importsA32;
- const dyld_chained_import_addend64* importsA64;
- switch (_fixupsHeader->imports_format) {
- case DYLD_CHAINED_IMPORT:
- imports = (dyld_chained_import*)((uint8_t*)_fixupsHeader + _fixupsHeader->imports_offset);
- for (uint32_t i=0; i < _fixupsHeader->imports_count && !stop; ++i) {
- const char* symbolName = &symbolsPool[imports[i].name_offset];
- if ( imports[i].name_offset > maxSymbolOffset )
- return Error("malformed import table, imports[%d].name_offset (%d) out of range", i, imports[i].name_offset);
- uint8_t libVal = imports[i].lib_ordinal;
- if ( libVal > 0xF0 )
- libOrdinal = (int8_t)libVal;
- else
- libOrdinal = libVal;
- callback(libOrdinal, symbolName, 0, imports[i].weak_import, stop);
- }
- break;
- case DYLD_CHAINED_IMPORT_ADDEND:
- importsA32 = (dyld_chained_import_addend*)((uint8_t*)_fixupsHeader + _fixupsHeader->imports_offset);
- for (uint32_t i=0; i < _fixupsHeader->imports_count && !stop; ++i) {
- const char* symbolName = &symbolsPool[importsA32[i].name_offset];
- if ( importsA32[i].name_offset > maxSymbolOffset )
- return Error("malformed import table, imports[%d].name_offset (%d) out of range", i, importsA32[i].name_offset);
- uint8_t libVal = importsA32[i].lib_ordinal;
- if ( libVal > 0xF0 )
- libOrdinal = (int8_t)libVal;
- else
- libOrdinal = libVal;
- callback(libOrdinal, symbolName, importsA32[i].addend, importsA32[i].weak_import, stop);
- }
- break;
- case DYLD_CHAINED_IMPORT_ADDEND64:
- importsA64 = (dyld_chained_import_addend64*)((uint8_t*)_fixupsHeader + _fixupsHeader->imports_offset);
- for (uint32_t i=0; i < _fixupsHeader->imports_count && !stop; ++i) {
- const char* symbolName = &symbolsPool[importsA64[i].name_offset];
- if ( importsA64[i].name_offset > maxSymbolOffset )
- return Error("malformed import table, imports[%d].name_offset (%d) out of range", i, importsA64[i].name_offset);
- uint16_t libVal = importsA64[i].lib_ordinal;
- if ( libVal > 0xFFF0 )
- libOrdinal = (int16_t)libVal;
- else
- libOrdinal = libVal;
- callback(libOrdinal, symbolName, importsA64[i].addend, importsA64[i].weak_import, stop);
- }
- break;
- default:
- return Error("unknown imports format %d", _fixupsHeader->imports_format);
- }
- return Error::none();
-}
-
-const dyld_chained_starts_in_segment* ChainedFixups::startsForSegment(uint32_t segIndex) const
-{
- const dyld_chained_starts_in_image* imageStarts = (dyld_chained_starts_in_image*)((uint8_t*)_fixupsHeader + _fixupsHeader->starts_offset);
- if ( segIndex >= imageStarts->seg_count )
- return nullptr;
- uint32_t segInfoOffset = imageStarts->seg_info_offset[segIndex];
- if ( segInfoOffset == 0 )
- return nullptr;
- 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, const PointerFormat&, bool& stop)) const
-{
- bool stop = false;
- for (uint32_t segIndex=0; segIndex < segments.size(); ++segIndex) {
- if ( const dyld_chained_starts_in_segment* segStarts = this->startsForSegment(segIndex) ) {
- const PointerFormat& pf = PointerFormat::make(segStarts->pointer_format);
- for (uint32_t pageIndex=0; pageIndex < segStarts->page_count; ++pageIndex) {
- uint16_t offsetInPage = segStarts->page_start[pageIndex];
- if ( offsetInPage == DYLD_CHAINED_PTR_START_NONE )
- continue;
- if ( offsetInPage & DYLD_CHAINED_PTR_START_MULTI ) {
- // some fixups in the page are too far apart, so page has multiple starts
- uint32_t overflowIndex = offsetInPage & ~DYLD_CHAINED_PTR_START_MULTI;
- 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, pf, stop);
- ++overflowIndex;
- }
- }
- else {
- const uint8_t* chainStart = ((uint8_t*)(segments[segIndex].content)) + pageIndex * segStarts->page_size + offsetInPage;
- callback(chainStart, segIndex, pf, stop);
- }
- if ( stop )
- return;
- }
- }
- }
-}
-
-
-Error ChainedFixups::valid(uint64_t preferredLoadAddress, 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);
- if ( _fixupsHeader->starts_offset >= _fixupsSize )
- return Error("chained fixups, starts_offset exceeds LC_DYLD_CHAINED_FIXUPS size");
- if ( _fixupsHeader->imports_offset > _fixupsSize)
- return Error("chained fixups, imports_offset exceeds LC_DYLD_CHAINED_FIXUPS size");
- uint32_t formatEntrySize;
- switch ( _fixupsHeader->imports_format ) {
- case DYLD_CHAINED_IMPORT:
- formatEntrySize = sizeof(dyld_chained_import);
- break;
- case DYLD_CHAINED_IMPORT_ADDEND:
- formatEntrySize = sizeof(dyld_chained_import_addend);
- break;
- case DYLD_CHAINED_IMPORT_ADDEND64:
- formatEntrySize = sizeof(dyld_chained_import_addend64);
- break;
- default:
- return Error("chained fixups, unknown imports_format (%d)", _fixupsHeader->imports_format);
- }
- if ( greaterThanAddOrOverflow(_fixupsHeader->imports_offset, (formatEntrySize * _fixupsHeader->imports_count), _fixupsHeader->symbols_offset) )
- return Error("chained fixups, imports array overlaps symbols");
- if ( _fixupsHeader->symbols_format != 0 )
- return Error("chained fixups, symbols_format unknown (%d)", _fixupsHeader->symbols_format);
-
-
- // validate dyld_chained_starts_in_image
- const dyld_chained_starts_in_image* startsInfo = (dyld_chained_starts_in_image*)((uint8_t*)_fixupsHeader + _fixupsHeader->starts_offset);
- if ( startsInfo->seg_count != segments.size() ) {
- // We can have fewer segments than the count, so long as those we are missing have no relocs
- // This can happen because __CTF is inserted by ctf_insert after linking, and between __DATA and __LINKEDIT, but has no relocs
- // ctf_insert updates the load commands to put __CTF between __DATA and __LINKEDIT, but doesn't update the chained fixups data structures
- if ( startsInfo->seg_count > segments.size() )
- return Error("chained fixups, seg_count exceeds number of segments");
-
- // We can have fewer segments than the count, so long as those we are missing have no relocs
- const MappedSegment& lastSegInfo = segments.back();
- if ( lastSegInfo.segName != "__CTF" )
- return Error("chained fixups, seg_count does not match number of segments");
- }
-
- uint32_t maxValidPointerSeen = 0;
- uint16_t pointer_format_for_all = 0;
- bool pointer_format_found = false;
- const uint8_t* endOfStarts = (uint8_t*)_fixupsHeader + _fixupsHeader->imports_offset;
- for (uint32_t i=0; i < startsInfo->seg_count; ++i) {
- uint32_t segInfoOffset = startsInfo->seg_info_offset[i];
- // 0 offset means this segment has no fixups
- if ( segInfoOffset == 0 )
- continue;
- const dyld_chained_starts_in_segment* segInfo = (dyld_chained_starts_in_segment*)((uint8_t*)startsInfo + segInfoOffset);
- if ( segInfo->size > (endOfStarts - (uint8_t*)segInfo) )
- return Error("chained fixups, dyld_chained_starts_in_segment for segment #%d overruns imports table", i);
-
- // validate dyld_chained_starts_in_segment
- if ( (segInfo->page_size != 0x1000) && (segInfo->page_size != 0x4000) )
- return Error("chained fixups, page_size not 4KB or 16KB in segment #%d", i);
- if ( !PointerFormat::valid(segInfo->pointer_format) )
- return Error("chained fixups, unknown pointer_format in segment #%d", i);
- if ( !pointer_format_found ) {
- pointer_format_for_all = segInfo->pointer_format;
- pointer_format_found = true;
- }
- if ( segInfo->pointer_format != pointer_format_for_all )
- return Error("chained fixups, pointer_format not same for all segments %d and %d", segInfo->pointer_format, pointer_format_for_all);
- if ( segInfo->max_valid_pointer != 0 ) {
- if ( maxValidPointerSeen == 0 ) {
- // record max_valid_pointer values seen
- maxValidPointerSeen = segInfo->max_valid_pointer;
- }
- else if ( maxValidPointerSeen != segInfo->max_valid_pointer ) {
- return Error("chained fixups, different max_valid_pointer values seen in different segments");
- }
- }
- // validate starts table in segment
- if ( offsetof(dyld_chained_starts_in_segment, page_start[segInfo->page_count]) > segInfo->size )
- return Error("chained fixups, page_start array overflows size");
- uint32_t maxOverflowIndex = (uint32_t)(segInfo->size - offsetof(dyld_chained_starts_in_segment, page_start[0]))/sizeof(uint16_t);
- for (int pageIndex=0; pageIndex < segInfo->page_count; ++pageIndex) {
- uint16_t offsetInPage = segInfo->page_start[pageIndex];
- if ( offsetInPage == DYLD_CHAINED_PTR_START_NONE )
- continue;
- if ( (offsetInPage & DYLD_CHAINED_PTR_START_MULTI) == 0 ) {
- // this is the offset into the page where the first fixup is
- if ( offsetInPage > segInfo->page_size ) {
- return Error("chained fixups, in segment #%d page_start[%d]=0x%04X exceeds page size", i, pageIndex, offsetInPage);
- }
- }
- else {
- // this is actually an index into chain_starts[]
- uint32_t overflowIndex = offsetInPage & ~DYLD_CHAINED_PTR_START_MULTI;
- // now verify all starts are within the page and in ascending order
- uint16_t lastOffsetInPage = 0;
- do {
- if ( overflowIndex > maxOverflowIndex )
- return Error("chain overflow index out of range %d (max=%d) in segment #%d", overflowIndex, maxOverflowIndex, i);
- offsetInPage = (segInfo->page_start[overflowIndex] & ~DYLD_CHAINED_PTR_START_LAST);
- if ( offsetInPage > segInfo->page_size )
- return Error("chained fixups, in segment #%d overflow page_start[%d]=0x%04X exceeds page size", i, overflowIndex, offsetInPage);
- if ( (offsetInPage <= lastOffsetInPage) && (lastOffsetInPage != 0) )
- return Error("chained fixups, in segment #%d overflow page_start[%d]=0x%04X is before previous at 0x%04X\n", i, overflowIndex, offsetInPage, lastOffsetInPage);
- lastOffsetInPage = offsetInPage;
- ++overflowIndex;
- } while ( (segInfo->page_start[overflowIndex] & DYLD_CHAINED_PTR_START_LAST) == 0 );
- }
- }
-
- }
- // validate import table size can fit
- uint32_t maxBindOrdinal = PointerFormat::make(pointer_format_for_all).maxBindOrdinal(false);
- 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);
- }
- return Error::none();
-}
-
-
-const char* ChainedFixups::importsFormatName(uint32_t format)
-{
- switch (format) {
- case DYLD_CHAINED_IMPORT:
- return "DYLD_CHAINED_IMPORT";
- case DYLD_CHAINED_IMPORT_ADDEND:
- return "DYLD_CHAINED_IMPORT_ADDEND";
- case DYLD_CHAINED_IMPORT_ADDEND64:
- return "DYLD_CHAINED_IMPORT_ADDEND64";
- }
- return "unknown";
-}
-
-const char* ChainedFixups::importsFormatName() const
-{
- return importsFormatName(_fixupsHeader->imports_format);
-}
-
-void ChainedFixups::PointerFormat::forEachFixupLocationInChain(const void* chainStartLoc, uint64_t prefLoadAddr, const MappedSegment* seg,
- 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 (set runtime pointer)
- nextLoc = this->nextLocation(fixupLoc);
- 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.resize(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 max valid pointer value
- uint64_t maxValidPointer = 0;
- if ( !pointerFormat.is64() ) {
- uint64_t lastDataSegmentIndex = segments.size() - (segments.back().mappedSegment.segName == "__LINKEDIT" ? 2 : 1);
- const MappedSegment& lastDataSegment = segments[lastDataSegmentIndex].mappedSegment;
- // for 32-bit binaries rebase targets are 0 based, so load address needs to be included in max pointer computation
- uint64_t lastDataSegmentLastVMAddr = preferredLoadAddress + lastDataSegment.runtimeOffset + lastDataSegment.runtimeSize;
- maxValidPointer = (lastDataSegmentLastVMAddr + 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)maxValidPointer;
- 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
-
-
-// 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
-};
-
-
-//
-// MARK: --- PointerFormat_Generic_arm64e ---
-//
-class VIS_HIDDEN PointerFormat_Generic_arm64e : public ChainedFixups::PointerFormat
-{
-public:
- bool is64() const override { return true; }
- bool supportsAuth() const override { return true; }
- uint32_t minNext() const override { return stride(); }
- uint32_t maxNext() const override { return stride()*0x7FF; } // 11-bits
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return (authenticated ? 0xFFFFFFFF : 0x7FFFFFFFFFFULL); }
- bool supportsBinds() const override { return true; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return (1 << bindBitCount()) - 1; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return (authenticated ? 0 : 0x3FFFF); }
- 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;
- 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=0) const override {
- if ( ((unaligned_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;
- if ( authBind24Ptr->auth )
- return Fixup(loc, seg, authBind24Ptr->ordinal, 0, authBind24Ptr->key, authBind24Ptr->addrDiv, authBind24Ptr->diversity);
- else
- return Fixup(loc, seg, bind24Ptr->ordinal, bind24Ptr->addend);
- }
- else {
- const dyld_chained_ptr_arm64e_auth_bind* authBindPtr = (dyld_chained_ptr_arm64e_auth_bind*)loc;
- const dyld_chained_ptr_arm64e_bind* bindPtr = (dyld_chained_ptr_arm64e_bind*)loc;
- if ( authBindPtr->auth )
- return Fixup(loc, seg, authBindPtr->ordinal, 0, authBindPtr->key, authBindPtr->addrDiv, authBindPtr->diversity);
- else
- return Fixup(loc, seg, bindPtr->ordinal, bindPtr->addend);
- }
- }
- 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;
- if ( authRebasePtr->auth )
- return Fixup(loc, seg, authRebasePtr->target, authRebasePtr->key, authRebasePtr->addrDiv, authRebasePtr->diversity);
- else if ( unauthRebaseIsVmAddr() )
- return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | (rebasePtr->target - preferedLoadAddress));
- else
- return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | rebasePtr->target);
- }
- }
-#if BUILDING_MACHO_WRITER
- 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;
- }
-
- 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 ) {
- if ( fixup.authenticated ) {
- dyld_chained_ptr_arm64e_auth_bind24* authBind24Ptr = (dyld_chained_ptr_arm64e_auth_bind24*)fixup.location;
- authBind24Ptr->auth = true;
- authBind24Ptr->bind = true;
- authBind24Ptr->next = delta/stride();
- authBind24Ptr->key = fixup.auth.key;
- authBind24Ptr->addrDiv = fixup.auth.usesAddrDiversity;
- authBind24Ptr->diversity = fixup.auth.diversity;
- authBind24Ptr->zero = 0;
- authBind24Ptr->ordinal = fixup.bind.bindOrdinal;
- 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;
- bind24Ptr->auth = false;
- bind24Ptr->bind = true;
- bind24Ptr->next = delta/stride();
- bind24Ptr->addend = fixup.bind.embeddedAddend;
- bind24Ptr->zero = 0;
- bind24Ptr->ordinal = fixup.bind.bindOrdinal;
- assert(signExtendedAddend(bind24Ptr) == fixup.bind.embeddedAddend);
- assert(bind24Ptr->next*stride() == delta);
- assert(bind24Ptr->ordinal == fixup.bind.bindOrdinal);
- }
- }
- else {
- if ( fixup.authenticated ) {
- dyld_chained_ptr_arm64e_auth_bind* authBindPtr = (dyld_chained_ptr_arm64e_auth_bind*)fixup.location;
- authBindPtr->auth = true;
- authBindPtr->bind = true;
- authBindPtr->next = delta/stride();
- authBindPtr->key = fixup.auth.key;
- authBindPtr->addrDiv = fixup.auth.usesAddrDiversity;
- authBindPtr->diversity = fixup.auth.diversity;
- authBindPtr->zero = 0;
- authBindPtr->ordinal = fixup.bind.bindOrdinal;
- 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;
- bindPtr->auth = false;
- bindPtr->bind = true;
- bindPtr->next = delta/stride();
- bindPtr->addend = fixup.bind.embeddedAddend;
- bindPtr->zero = 0;
- bindPtr->ordinal = fixup.bind.bindOrdinal;
- assert(signExtendedAddend(bindPtr) == fixup.bind.embeddedAddend);
- assert(bindPtr->next*stride() == delta);
- assert(bindPtr->ordinal == fixup.bind.bindOrdinal);
- }
- }
- }
- else {
- if ( fixup.authenticated ) {
- 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();
- authRebasePtr->key = fixup.auth.key;
- authRebasePtr->addrDiv = fixup.auth.usesAddrDiversity;
- authRebasePtr->diversity = fixup.auth.diversity;
- authRebasePtr->target = fixup.rebase.targetVmOffset;
- assert(authRebasePtr->next*stride() == delta);
- assert(authRebasePtr->target == fixup.rebase.targetVmOffset);
- }
- else {
- 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;
- rebasePtr->bind = false;
- rebasePtr->next = delta/stride();
- rebasePtr->high8 = high8;
- rebasePtr->target = low56 + (this->unauthRebaseIsVmAddr() ? preferedLoadAddress : 0);
- assert(rebasePtr->next*stride() == delta);
- assert(rebasePtr->target == (low56 + (this->unauthRebaseIsVmAddr() ? preferedLoadAddress : 0)));
- }
- }
- }
-#endif
-
-protected:
- virtual uint32_t bindBitCount() const = 0;
- virtual uint32_t stride() const = 0;
- virtual bool unauthRebaseIsVmAddr() const = 0;
-};
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E : public PointerFormat_Generic_arm64e
-{
-public:
- 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"; }
-protected:
- uint32_t bindBitCount() const override { return 16; }
- uint32_t stride() const override { return 8; }
- bool unauthRebaseIsVmAddr() const override { return true; }
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL ---
-//
-class VIS_HIDDEN __attribute__((__packed__)) PointerFormat_DYLD_CHAINED_PTR_ARM64E_KERNEL : public PointerFormat_Generic_arm64e
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_ARM64E_KERNEL; }
- const char* name() const override { return "DYLD_CHAINED_PTR_ARM64E_KERNEL"; }
- const char* description() const override { return "authenticated arm64e, 4-byte stride, target vmoffset"; }
-protected:
- uint32_t bindBitCount() const override { return 16; }
- uint32_t stride() const override { return 4; }
- bool unauthRebaseIsVmAddr() const override { return false; }
-};
-
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND : public PointerFormat_Generic_arm64e
-{
-public:
- 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"; }
-protected:
- uint32_t bindBitCount() const override { return 16; }
- uint32_t stride() const override { return 8; }
- bool unauthRebaseIsVmAddr() const override { return false; }
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND24 ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E_USERLAND24 : public PointerFormat_Generic_arm64e
-{
-public:
- 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"; }
-protected:
- uint32_t bindBitCount() const override { return 24; }
- uint32_t stride() const override { return 8; }
- bool unauthRebaseIsVmAddr() const override { return false; }
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_ARM64E_FIRMWARE ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_ARM64E_FIRMWARE : public PointerFormat_Generic_arm64e
-{
-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"; }
- 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_64 ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_64 : public ChainedFixups::PointerFormat
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_64; }
- const char* name() const override { return "DYLD_CHAINED_PTR_64"; }
- const char* description() const override { return "generic 64-bit, 4-byte stride, target vmadddr"; }
- bool is64() const override { return true; }
- bool supportsAuth() const override { return false; }
- uint32_t minNext() const override { return 4; }
- uint32_t maxNext() const override { return 4*0xFFF; }
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0xFFFFFFFFFULL; }
- bool supportsBinds() const override { return true; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return 0x00FFFFFF; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return 255; }
- int32_t bindMinEmbeddableAddend(bool authenticated) const override { return 0; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_64_rebase* ptr = (dyld_chained_ptr_64_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * 4);
- }
-
- 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 )
- return Fixup(loc, seg, bindPtr->ordinal, bindPtr->addend);
- else if ( unauthRebaseIsVmAddr() )
- return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | (rebasePtr->target-preferedLoadAddress));
- else
- return Fixup(loc, seg, ((uint64_t)(rebasePtr->high8) << 56) | 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);
- if ( fixup.isBind ) {
- dyld_chained_ptr_64_bind* bindPtr = (dyld_chained_ptr_64_bind*)fixup.location;
- bindPtr->bind = true;
- bindPtr->next = delta/4;
- bindPtr->reserved = 0;
- bindPtr->addend = fixup.bind.embeddedAddend;
- bindPtr->ordinal = fixup.bind.bindOrdinal;
- 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;
- uint8_t high8 = (fixup.rebase.targetVmOffset >> 56);
- uint64_t low56 = (fixup.rebase.targetVmOffset & 0x00FFFFFFFFFFFFFFULL);
- rebasePtr->bind = false;
- rebasePtr->next = delta/4;
- rebasePtr->reserved = 0;
- rebasePtr->high8 = high8;
- rebasePtr->target = low56+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);
- uint64_t low56 = (fixup.rebase.targetVmOffset & 0x00FFFFFFFFFFFFFFULL);
- rebasePtr->bind = false;
- rebasePtr->next = delta/4;
- rebasePtr->reserved = 0;
- rebasePtr->high8 = high8;
- rebasePtr->target = low56;
- assert(rebasePtr->next*4 == delta);
- assert(rebasePtr->target == low56);
- }
- }
-#endif
-protected:
- virtual bool unauthRebaseIsVmAddr() const { return true; }
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_32
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_32 : public ChainedFixups::PointerFormat
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_32; }
- const char* name() const override { return "DYLD_CHAINED_PTR_32"; }
- const char* description() const override { return "generic 32-bit, 4-byte stride"; }
- bool is64() const override { return false; }
- bool supportsAuth() const override { return false; }
- uint32_t minNext() const override { return 4; }
- uint32_t maxNext() const override { return 4*0x1F; }
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0x03FFFFFF; }
- bool supportsBinds() const override { return true; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return 0x000FFFFF; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return 63; }
- int32_t bindMinEmbeddableAddend(bool authenticated) const override { return 0; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_32_rebase* ptr = (dyld_chained_ptr_32_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * 4);
- }
-
- 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 )
- return Fixup(loc, seg, bindPtr->ordinal, bindPtr->addend);
- else
- 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);
- if ( fixup.isBind ) {
- dyld_chained_ptr_32_bind* bindPtr = (dyld_chained_ptr_32_bind*)fixup.location;
- bindPtr->bind = true;
- bindPtr->next = (uint32_t)(delta/4);
- bindPtr->addend = fixup.bind.embeddedAddend;
- bindPtr->ordinal = fixup.bind.bindOrdinal;
- 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;
- rebasePtr->bind = false;
- rebasePtr->next = (uint32_t)(delta/4);
- uint64_t target = fixup.rebase.targetVmOffset+preferedLoadAddress;
- rebasePtr->target = (uint32_t)target;
- assert(rebasePtr->next*4 == delta);
- assert(rebasePtr->target == target);
- }
- }
-#endif
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_32_CACHE
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_32_CACHE : public ChainedFixups::PointerFormat
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_32_CACHE; }
- const char* name() const override { return "DYLD_CHAINED_PTR_32_CACHE"; }
- const char* description() const override { return "generic 32-bit, 4-byte stride"; }
- bool is64() const override { return false; }
- bool supportsAuth() const override { return false; }
- uint32_t minNext() const override { return 4; }
- uint32_t maxNext() const override { return 4*3; }
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0x3FFFFFFF; }
- bool supportsBinds() const override { return false; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return 0; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return 0; }
- int32_t bindMinEmbeddableAddend(bool authenticated) const override { return 0; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_32_cache_rebase* ptr = (dyld_chained_ptr_32_cache_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * 4);
- }
-
- 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);
- }
-#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;
- assert(rebasePtr->next*4 == delta);
- assert(rebasePtr->target == fixup.rebase.targetVmOffset);
- }
-#endif
-};
-
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_32_FIRMWARE
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_32_FIRMWARE : public ChainedFixups::PointerFormat
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_32_FIRMWARE; }
- const char* name() const override { return "DYLD_CHAINED_PTR_32_FIRMWARE"; }
- const char* description() const override { return "generic 32-bit, 4-byte stride"; }
- bool is64() const override { return false; }
- bool supportsAuth() const override { return false; }
- uint32_t minNext() const override { return 4; }
- uint32_t maxNext() const override { return 4*0x1F; }
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0x03FFFFFF; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return 0x000FFFFF; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return 0; }
- int32_t bindMinEmbeddableAddend(bool authenticated) const override { return 0; }
- bool supportsBinds() const override { return false; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_32_firmware_rebase* ptr = (dyld_chained_ptr_32_firmware_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * 4);
- }
-
- 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);
- }
-#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;
- assert(rebasePtr->next*4 == delta);
- assert(rebasePtr->target == fixup.rebase.targetVmOffset);
- }
-#endif
-};
-
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_64_OFFSET ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_64_OFFSET : public PointerFormat_DYLD_CHAINED_PTR_64
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_64_OFFSET; }
- const char* name() const override { return "DYLD_CHAINED_PTR_64_OFFSET"; }
- const char* description() const override { return "generic 64-bit, 4-byte stride, target vmoffset"; }
- bool unauthRebaseIsVmAddr() const override { return false; }
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_64_KERNEL_CACHE ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_64_KERNEL_CACHE : public ChainedFixups::PointerFormat
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_64_KERNEL_CACHE; }
- const char* name() const override { return "DYLD_CHAINED_PTR_64_KERNEL_CACHE"; }
- const char* description() const override { return "authenticated arm64e, 4-byte stride, for kernel cache"; }
- bool is64() const override { return true; }
- bool supportsAuth() const override { return true; }
- uint32_t minNext() const override { return 4; }
- uint32_t maxNext() const override { return 4*0xFFF; } // 12-bits
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0x3FFFFFFF; }
- bool supportsBinds() const override { return false; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return 0; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return 0; }
- int32_t bindMinEmbeddableAddend(bool authenticated) const override { return 0; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_64_kernel_cache_rebase* ptr = (dyld_chained_ptr_64_kernel_cache_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next * 4);
- }
-
- 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);
- else
- 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_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;
- rebasePtr->addrDiv = fixup.auth.usesAddrDiversity;
- rebasePtr->diversity = fixup.auth.diversity;
- rebasePtr->cacheLevel = 0; // FIXME
- rebasePtr->target = fixup.rebase.targetVmOffset;
- assert(rebasePtr->next*4 == delta);
- assert(rebasePtr->target == fixup.rebase.targetVmOffset);
- }
-#endif
-};
-
-
-//
-// MARK: --- PointerFormat_DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE ---
-//
-class VIS_HIDDEN PointerFormat_DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE : public ChainedFixups::PointerFormat
-{
-public:
- uint16_t value() const override { return DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE; }
- const char* name() const override { return "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE"; }
- const char* description() const override { return "1-byte stride, for x86_64 kernel cache"; }
- bool is64() const override { return true; }
- bool supportsAuth() const override { return true; }
- uint32_t minNext() const override { return 1; }
- uint32_t maxNext() const override { return 1*0xFFF; } // 12-bits
- uint64_t maxRebaseTargetOffset(bool authenticated) const override { return 0x3FFFFFFF; }
- bool supportsBinds() const override { return false; }
- uint32_t maxBindOrdinal(bool authenticated) const override { return 0; }
- int32_t bindMaxEmbeddableAddend(bool authenticated) const override { return 0; }
- int32_t bindMinEmbeddableAddend(bool authenticated) const override { return 0; }
-
- const void* nextLocation(const void* loc) const override {
- const dyld_chained_ptr_64_kernel_cache_rebase* ptr = (dyld_chained_ptr_64_kernel_cache_rebase*)loc;
- if ( ptr->next == 0 )
- return nullptr;
- return (void*)((uint8_t*)loc + ptr->next);
- }
-
- 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);
- else
- 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_64_kernel_cache_rebase* rebasePtr = (dyld_chained_ptr_64_kernel_cache_rebase*)fixup.location;
-
- rebasePtr->isAuth = false;
- rebasePtr->next = delta;
- rebasePtr->key = 0;
- rebasePtr->addrDiv = 0;
- rebasePtr->diversity = 0;
- rebasePtr->cacheLevel = 0; // FIXME
- rebasePtr->target = fixup.rebase.targetVmOffset;
- assert(rebasePtr->next == delta);
- assert(rebasePtr->target == fixup.rebase.targetVmOffset);
- }
-#endif
-};
-
-
-bool ChainedFixups::PointerFormat::valid(uint16_t pointer_format)
-{
- return (pointer_format <= DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE);
-}
-
-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;
-
-
-const ChainedFixups::PointerFormat& ChainedFixups::PointerFormat::make(uint16_t pointer_format)
-{
- switch (pointer_format) {
- case DYLD_CHAINED_PTR_ARM64E:
- return p1;
- case DYLD_CHAINED_PTR_64 :
- return p2;
- case DYLD_CHAINED_PTR_32:
- return p3;
- case DYLD_CHAINED_PTR_32_CACHE:
- return p4;
- case DYLD_CHAINED_PTR_32_FIRMWARE:
- return p5;
- case DYLD_CHAINED_PTR_64_OFFSET:
- return p6;
- case DYLD_CHAINED_PTR_ARM64E_KERNEL:
- return p7;
- case DYLD_CHAINED_PTR_ARM64E_USERLAND:
- return p8;
- case DYLD_CHAINED_PTR_64_KERNEL_CACHE:
- return p9;
- case DYLD_CHAINED_PTR_ARM64E_FIRMWARE:
- return p10;
- case DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE:
- return p11;
- case DYLD_CHAINED_PTR_ARM64E_USERLAND24:
- return p12;
- }
- assert("unknown pointer format");
- return p1;
-}
-
-} // namespace mach_o