Loading...
--- dyld/dyld-1340/mach_o/RebaseOpcodes.cpp
+++ /dev/null
@@ -1,295 +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>
-
-#include "RebaseOpcodes.h"
-#include "Misc.h"
-#include "Image.h"
-
-namespace mach_o {
-
-//
-// MARK: --- RebaseOpcodes inspection methods ---
-//
-
-RebaseOpcodes::RebaseOpcodes(const uint8_t* start, size_t size, bool is64)
- : _opcodesStart(start), _opcodesEnd(start+size), _pointerSize(is64 ? 8 : 4)
-{
-}
-
-
-Error RebaseOpcodes::valid(std::span<const MappedSegment> segments, bool allowTextFixups, bool onlyFixupsInWritableSegments) const
-{
- __block Error locError;
- Error opcodeErr = this->forEachRebase(^(const char* opcodeName, int type, bool segIndexSet, uint8_t segmentIndex, uint64_t segmentOffset, bool& stop) {
- if ( !segIndexSet ) {
- locError = Error("%s missing preceding REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB", opcodeName);
- stop = true;
- }
- else if ( segmentIndex >= segments.size() ) {
- locError = Error("%s segment index %d too large", opcodeName, segmentIndex);
- stop = true;
- }
- else if ( segmentOffset > (segments[segmentIndex].runtimeSize-_pointerSize) ) {
- locError = Error("%s segment offset 0x%08llX beyond segment '%.*s' size (0x%08llX)", opcodeName, segmentOffset,
- (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data(),
- segments[segmentIndex].runtimeSize);
- stop = true;
- }
- else {
- switch ( type ) {
- case REBASE_TYPE_POINTER:
- if ( !segments[segmentIndex].writable && onlyFixupsInWritableSegments ) {
- locError = Error("%s pointer rebase is in non-writable segment '%.*s'", opcodeName,
- (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
- stop = true;
- }
- else if ( segments[segmentIndex].executable && onlyFixupsInWritableSegments ) {
- locError = Error("%s pointer rebase is in executable segment '%.*s'", opcodeName,
- (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
- stop = true;
- }
- break;
- case REBASE_TYPE_TEXT_ABSOLUTE32:
- case REBASE_TYPE_TEXT_PCREL32:
- if ( !allowTextFixups ) {
- locError = Error("%s text rebase not supported for architecture", opcodeName);
- stop = true;
- }
- else if ( segments[segmentIndex].writable ) {
- locError = Error("%s text rebase is in writable segment '%.*s'", opcodeName,
- (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
- stop = true;
- }
- else if ( !segments[segmentIndex].executable ) {
- locError = Error("%s text rebase is in non-executable segment '%.*s'", opcodeName,
- (int)segments[segmentIndex].segName.size(), segments[segmentIndex].segName.data());
- stop = true;
- }
- break;
- default:
- locError = Error("%s unknown rebase type", opcodeName);
- stop = true;
- }
- }
- });
- if ( opcodeErr )
- return opcodeErr;
- return std::move(locError);
-}
-
-Error RebaseOpcodes::forEachRebase(void (^handler)(const char* opcodeName, int type, bool segIndexSet, uint8_t segmentIndex, uint64_t segmentOffset, bool& stop)) const
-{
- const uint8_t* p = _opcodesStart;
- int type = 0;
- int segIndex = 0;
- uint64_t segOffset = 0;
- bool segIndexSet = false;
- bool stop = false;
- bool malformed = false;
- uint64_t count;
- uint64_t skip;
- while ( !stop && !malformed && (p < _opcodesEnd) ) {
- uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
- uint8_t opcode = *p & REBASE_OPCODE_MASK;
- ++p;
- switch (opcode) {
- case REBASE_OPCODE_DONE:
- // Allow some padding, in case rebases were somehow aligned to 16-bytes in size
- if ( (_opcodesEnd - p) > 15 )
- return Error("rebase opcodes terminated early at offset %d of %d", (int)(p-_opcodesStart), (int)(_opcodesEnd-_opcodesStart));
- break;
- case REBASE_OPCODE_SET_TYPE_IMM:
- switch ( immediate ) {
- case REBASE_TYPE_POINTER:
- case REBASE_TYPE_TEXT_ABSOLUTE32:
- case REBASE_TYPE_TEXT_PCREL32:
- type = immediate;
- break;
- default:
- type = 0;
- break;
- }
- break;
- case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
- segIndex = immediate;
- segOffset = read_uleb128(p, _opcodesEnd, malformed);
- segIndexSet = true;
- break;
- case REBASE_OPCODE_ADD_ADDR_ULEB:
- segOffset += read_uleb128(p, _opcodesEnd, malformed);
- break;
- case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
- segOffset += immediate*_pointerSize;
- break;
- case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
- for (int i=0; i < immediate; ++i) {
- handler("REBASE_OPCODE_DO_REBASE_IMM_TIMES", type, segIndexSet, segIndex, segOffset, stop);
- segOffset += _pointerSize;
- if ( stop )
- break;
- }
- break;
- case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
- count = read_uleb128(p, _opcodesEnd, malformed);
- if ( malformed )
- break;
- for (uint32_t i=0; i < count; ++i) {
- handler("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB", type, segIndexSet, segIndex, segOffset, stop);
- segOffset += _pointerSize;
- if ( stop )
- break;
- }
- break;
- case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
- handler("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB", type, segIndexSet, segIndex, segOffset, stop);
- segOffset += read_uleb128(p, _opcodesEnd, malformed) + _pointerSize;
- break;
- case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
- count = read_uleb128(p, _opcodesEnd, malformed);
- if ( malformed )
- break;
- skip = read_uleb128(p, _opcodesEnd, malformed);
- if ( malformed )
- break;
- for (uint32_t i=0; i < count; ++i) {
- handler("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB", type, segIndexSet, segIndex, segOffset, stop);
- segOffset += skip + _pointerSize;
- if ( stop )
- break;
- }
- break;
- default:
- return Error("unknown rebase opcode 0x%02X", opcode);
- }
- }
- if ( malformed )
- return Error("malformed uleb128");
- else
- return Error::none();
-}
-
-void RebaseOpcodes::forEachRebaseLocation(void (^callback)(uint32_t segIndex, uint64_t segOffset, bool& stop)) const
-{
- (void)forEachRebase(^(const char* opcodeName, int type, bool segIndexSet, uint8_t segmentIndex, uint64_t segmentOffset, bool& stop) {
- callback(segmentIndex, segmentOffset, stop);
- });
-}
-
-void RebaseOpcodes::forEachRebaseLocation(std::span<const MappedSegment> segments, uint64_t prefLoadAdder, void (^callback)(const Fixup& fixup, bool& stop)) const
-{
- const bool is64 = (_pointerSize == 8);
- (void)forEachRebase(^(const char* opcodeName, int type, bool segIndexSet, uint8_t segIndex, uint64_t segOffset, bool& stop) {
- uint8_t* loc = (uint8_t*)(segments[segIndex].content) + segOffset;
- uint64_t targetVmOffset;
- if ( is64 ) {
- targetVmOffset = *((uint64_t*)loc) - prefLoadAdder;
- }
- else {
- // for i386, there may be "text relocations" which are not 4-byte aligned
- uint32_t value;
- memcpy(&value, loc, 4);
- targetVmOffset = (uint64_t)value - prefLoadAdder;
- }
- Fixup fixup(loc, &segments[segIndex], targetVmOffset);
- callback(fixup, stop);
- });
-}
-
-const uint8_t* RebaseOpcodes::bytes(size_t& size) const
-{
- size = (_opcodesEnd - _opcodesStart);
- return _opcodesStart;
-}
-
-void RebaseOpcodes::printOpcodes(FILE* output, int indentCount) const
-{
- uint8_t type = 0;
- uint64_t count;
- uint64_t skip;
- uint32_t segmentIndex;
- uint64_t segOffset;
- bool done = false;
- bool malformed = false;
- char indent[indentCount+1];
- const uint8_t* p = _opcodesStart;
- for (int i=0; i < indentCount; ++i)
- indent[i] = ' ';
- indent[indentCount] = '\0';
- while ( !done && !malformed && (p < _opcodesEnd) ) {
- uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
- uint8_t opcode = *p & REBASE_OPCODE_MASK;
- long opcodeOffset = p - _opcodesStart;
- ++p;
- switch (opcode) {
- case REBASE_OPCODE_DONE:
- done = true;
- fprintf(output, "%s0x%04lX REBASE_OPCODE_DONE()\n", indent, opcodeOffset);
- break;
- case REBASE_OPCODE_SET_TYPE_IMM:
- type = immediate;
- fprintf(output, "%s0x%04lX REBASE_OPCODE_SET_TYPE_IMM(%d)\n", indent, opcodeOffset, type);
- break;
- case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
- segmentIndex = immediate;
- segOffset = read_uleb128(p, _opcodesEnd, malformed);
- fprintf(output, "%s0x%04lX REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", indent, opcodeOffset, segmentIndex, segOffset);
- break;
- case REBASE_OPCODE_ADD_ADDR_ULEB:
- segOffset = read_uleb128(p, _opcodesEnd, malformed);
- fprintf(output, "%s0x%04lX REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", indent, opcodeOffset, segOffset);
- break;
- case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
- segOffset = immediate * _pointerSize;
- fprintf(output, "%s0x%04lX REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", indent, opcodeOffset, segOffset);
- break;
- case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
- fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", indent, opcodeOffset, immediate);
- break;
- case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
- count = read_uleb128(p, _opcodesEnd, malformed);
- fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", indent, opcodeOffset, count);
- break;
- case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
- skip = read_uleb128(p, _opcodesEnd, malformed) + _pointerSize;
- fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%lld)\n", indent, opcodeOffset, skip);
- break;
- case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
- count = read_uleb128(p, _opcodesEnd, malformed);
- skip = read_uleb128(p, _opcodesEnd, malformed);
- fprintf(output, "%s0x%04lX REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", indent, opcodeOffset, count, skip);
- break;
- default:
- fprintf(output, "%sunknown rebase opcode 0x%02X\n", indent, *p);
- }
- }
-}
-
-} // namespace mach_o