542 lines
22 KiB
C++
542 lines
22 KiB
C++
//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
|
|
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
|
|
|
|
#include "../RuntimeDyldMachO.h"
|
|
#include "llvm/Support/Endian.h"
|
|
|
|
#define DEBUG_TYPE "dyld"
|
|
|
|
namespace llvm {
|
|
|
|
class RuntimeDyldMachOAArch64
|
|
: public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
|
|
public:
|
|
|
|
typedef uint64_t TargetPtrT;
|
|
|
|
RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM,
|
|
JITSymbolResolver &Resolver)
|
|
: RuntimeDyldMachOCRTPBase(MM, Resolver) {}
|
|
|
|
unsigned getMaxStubSize() const override { return 8; }
|
|
|
|
unsigned getStubAlignment() override { return 8; }
|
|
|
|
/// Extract the addend encoded in the instruction / memory location.
|
|
Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
|
|
const SectionEntry &Section = Sections[RE.SectionID];
|
|
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
|
unsigned NumBytes = 1 << RE.Size;
|
|
int64_t Addend = 0;
|
|
// Verify that the relocation has the correct size and alignment.
|
|
switch (RE.RelType) {
|
|
default: {
|
|
std::string ErrMsg;
|
|
{
|
|
raw_string_ostream ErrStream(ErrMsg);
|
|
ErrStream << "Unsupported relocation type: "
|
|
<< getRelocName(RE.RelType);
|
|
}
|
|
return make_error<StringError>(std::move(ErrMsg),
|
|
inconvertibleErrorCode());
|
|
}
|
|
case MachO::ARM64_RELOC_POINTER_TO_GOT:
|
|
case MachO::ARM64_RELOC_UNSIGNED: {
|
|
if (NumBytes != 4 && NumBytes != 8) {
|
|
std::string ErrMsg;
|
|
{
|
|
raw_string_ostream ErrStream(ErrMsg);
|
|
ErrStream << "Invalid relocation size for relocation "
|
|
<< getRelocName(RE.RelType);
|
|
}
|
|
return make_error<StringError>(std::move(ErrMsg),
|
|
inconvertibleErrorCode());
|
|
}
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_BRANCH26:
|
|
case MachO::ARM64_RELOC_PAGE21:
|
|
case MachO::ARM64_RELOC_PAGEOFF12:
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
|
assert(NumBytes == 4 && "Invalid relocation size.");
|
|
assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
|
|
"Instruction address is not aligned to 4 bytes.");
|
|
break;
|
|
}
|
|
|
|
switch (RE.RelType) {
|
|
default:
|
|
llvm_unreachable("Unsupported relocation type!");
|
|
case MachO::ARM64_RELOC_POINTER_TO_GOT:
|
|
case MachO::ARM64_RELOC_UNSIGNED:
|
|
// This could be an unaligned memory location.
|
|
if (NumBytes == 4)
|
|
Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress);
|
|
else
|
|
Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
|
|
break;
|
|
case MachO::ARM64_RELOC_BRANCH26: {
|
|
// Verify that the relocation points to a B/BL instruction.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
assert(((*p & 0xFC000000) == 0x14000000 ||
|
|
(*p & 0xFC000000) == 0x94000000) &&
|
|
"Expected branch instruction.");
|
|
|
|
// Get the 26 bit addend encoded in the branch instruction and sign-extend
|
|
// to 64 bit. The lower 2 bits are always zeros and are therefore implicit
|
|
// (<< 2).
|
|
Addend = (*p & 0x03FFFFFF) << 2;
|
|
Addend = SignExtend64(Addend, 28);
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
|
case MachO::ARM64_RELOC_PAGE21: {
|
|
// Verify that the relocation points to the expected adrp instruction.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
|
|
|
|
// Get the 21 bit addend encoded in the adrp instruction and sign-extend
|
|
// to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are
|
|
// therefore implicit (<< 12).
|
|
Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12;
|
|
Addend = SignExtend64(Addend, 33);
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
|
|
// Verify that the relocation points to one of the expected load / store
|
|
// instructions.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
(void)p;
|
|
assert((*p & 0x3B000000) == 0x39000000 &&
|
|
"Only expected load / store instructions.");
|
|
LLVM_FALLTHROUGH;
|
|
}
|
|
case MachO::ARM64_RELOC_PAGEOFF12: {
|
|
// Verify that the relocation points to one of the expected load / store
|
|
// or add / sub instructions.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
assert((((*p & 0x3B000000) == 0x39000000) ||
|
|
((*p & 0x11C00000) == 0x11000000) ) &&
|
|
"Expected load / store or add/sub instruction.");
|
|
|
|
// Get the 12 bit addend encoded in the instruction.
|
|
Addend = (*p & 0x003FFC00) >> 10;
|
|
|
|
// Check which instruction we are decoding to obtain the implicit shift
|
|
// factor of the instruction.
|
|
int ImplicitShift = 0;
|
|
if ((*p & 0x3B000000) == 0x39000000) { // << load / store
|
|
// For load / store instructions the size is encoded in bits 31:30.
|
|
ImplicitShift = ((*p >> 30) & 0x3);
|
|
if (ImplicitShift == 0) {
|
|
// Check if this a vector op to get the correct shift value.
|
|
if ((*p & 0x04800000) == 0x04800000)
|
|
ImplicitShift = 4;
|
|
}
|
|
}
|
|
// Compensate for implicit shift.
|
|
Addend <<= ImplicitShift;
|
|
break;
|
|
}
|
|
}
|
|
return Addend;
|
|
}
|
|
|
|
/// Extract the addend encoded in the instruction.
|
|
void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes,
|
|
MachO::RelocationInfoType RelType, int64_t Addend) const {
|
|
// Verify that the relocation has the correct alignment.
|
|
switch (RelType) {
|
|
default:
|
|
llvm_unreachable("Unsupported relocation type!");
|
|
case MachO::ARM64_RELOC_POINTER_TO_GOT:
|
|
case MachO::ARM64_RELOC_UNSIGNED:
|
|
assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
|
|
break;
|
|
case MachO::ARM64_RELOC_BRANCH26:
|
|
case MachO::ARM64_RELOC_PAGE21:
|
|
case MachO::ARM64_RELOC_PAGEOFF12:
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
|
assert(NumBytes == 4 && "Invalid relocation size.");
|
|
assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
|
|
"Instruction address is not aligned to 4 bytes.");
|
|
break;
|
|
}
|
|
|
|
switch (RelType) {
|
|
default:
|
|
llvm_unreachable("Unsupported relocation type!");
|
|
case MachO::ARM64_RELOC_POINTER_TO_GOT:
|
|
case MachO::ARM64_RELOC_UNSIGNED:
|
|
// This could be an unaligned memory location.
|
|
if (NumBytes == 4)
|
|
*reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend;
|
|
else
|
|
*reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend;
|
|
break;
|
|
case MachO::ARM64_RELOC_BRANCH26: {
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
// Verify that the relocation points to the expected branch instruction.
|
|
assert(((*p & 0xFC000000) == 0x14000000 ||
|
|
(*p & 0xFC000000) == 0x94000000) &&
|
|
"Expected branch instruction.");
|
|
|
|
// Verify addend value.
|
|
assert((Addend & 0x3) == 0 && "Branch target is not aligned");
|
|
assert(isInt<28>(Addend) && "Branch target is out of range.");
|
|
|
|
// Encode the addend as 26 bit immediate in the branch instruction.
|
|
*p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
|
case MachO::ARM64_RELOC_PAGE21: {
|
|
// Verify that the relocation points to the expected adrp instruction.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
|
|
|
|
// Check that the addend fits into 21 bits (+ 12 lower bits).
|
|
assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
|
|
assert(isInt<33>(Addend) && "Invalid page reloc value.");
|
|
|
|
// Encode the addend into the instruction.
|
|
uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000;
|
|
uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0;
|
|
*p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
|
|
// Verify that the relocation points to one of the expected load / store
|
|
// instructions.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
assert((*p & 0x3B000000) == 0x39000000 &&
|
|
"Only expected load / store instructions.");
|
|
(void)p;
|
|
LLVM_FALLTHROUGH;
|
|
}
|
|
case MachO::ARM64_RELOC_PAGEOFF12: {
|
|
// Verify that the relocation points to one of the expected load / store
|
|
// or add / sub instructions.
|
|
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
|
assert((((*p & 0x3B000000) == 0x39000000) ||
|
|
((*p & 0x11C00000) == 0x11000000) ) &&
|
|
"Expected load / store or add/sub instruction.");
|
|
|
|
// Check which instruction we are decoding to obtain the implicit shift
|
|
// factor of the instruction and verify alignment.
|
|
int ImplicitShift = 0;
|
|
if ((*p & 0x3B000000) == 0x39000000) { // << load / store
|
|
// For load / store instructions the size is encoded in bits 31:30.
|
|
ImplicitShift = ((*p >> 30) & 0x3);
|
|
switch (ImplicitShift) {
|
|
case 0:
|
|
// Check if this a vector op to get the correct shift value.
|
|
if ((*p & 0x04800000) == 0x04800000) {
|
|
ImplicitShift = 4;
|
|
assert(((Addend & 0xF) == 0) &&
|
|
"128-bit LDR/STR not 16-byte aligned.");
|
|
}
|
|
break;
|
|
case 1:
|
|
assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
|
|
break;
|
|
case 2:
|
|
assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
|
|
break;
|
|
case 3:
|
|
assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
|
|
break;
|
|
}
|
|
}
|
|
// Compensate for implicit shift.
|
|
Addend >>= ImplicitShift;
|
|
assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
|
|
|
|
// Encode the addend into the instruction.
|
|
*p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Expected<relocation_iterator>
|
|
processRelocationRef(unsigned SectionID, relocation_iterator RelI,
|
|
const ObjectFile &BaseObjT,
|
|
ObjSectionToIDMap &ObjSectionToID,
|
|
StubMap &Stubs) override {
|
|
const MachOObjectFile &Obj =
|
|
static_cast<const MachOObjectFile &>(BaseObjT);
|
|
MachO::any_relocation_info RelInfo =
|
|
Obj.getRelocation(RelI->getRawDataRefImpl());
|
|
|
|
if (Obj.isRelocationScattered(RelInfo))
|
|
return make_error<RuntimeDyldError>("Scattered relocations not supported "
|
|
"for MachO AArch64");
|
|
|
|
// ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit
|
|
// addend for the following relocation. If found: (1) store the associated
|
|
// addend, (2) consume the next relocation, and (3) use the stored addend to
|
|
// override the addend.
|
|
int64_t ExplicitAddend = 0;
|
|
if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) {
|
|
assert(!Obj.getPlainRelocationExternal(RelInfo));
|
|
assert(!Obj.getAnyRelocationPCRel(RelInfo));
|
|
assert(Obj.getAnyRelocationLength(RelInfo) == 2);
|
|
int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
|
|
// Sign-extend the 24-bit to 64-bit.
|
|
ExplicitAddend = SignExtend64(RawAddend, 24);
|
|
++RelI;
|
|
RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
|
|
}
|
|
|
|
if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR)
|
|
return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
|
|
|
|
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
|
|
|
|
if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
|
|
bool Valid =
|
|
(RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel);
|
|
if (!Valid)
|
|
return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports "
|
|
"32-bit pc-rel or 64-bit absolute only",
|
|
inconvertibleErrorCode());
|
|
}
|
|
|
|
if (auto Addend = decodeAddend(RE))
|
|
RE.Addend = *Addend;
|
|
else
|
|
return Addend.takeError();
|
|
|
|
assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
|
|
"ARM64_RELOC_ADDEND and embedded addend in the instruction.");
|
|
if (ExplicitAddend)
|
|
RE.Addend = ExplicitAddend;
|
|
|
|
RelocationValueRef Value;
|
|
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
|
|
Value = *ValueOrErr;
|
|
else
|
|
return ValueOrErr.takeError();
|
|
|
|
bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
|
|
if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
|
|
// We'll take care of the offset in processGOTRelocation.
|
|
Value.Offset = 0;
|
|
} else if (!IsExtern && RE.IsPCRel)
|
|
makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
|
|
|
|
RE.Addend = Value.Offset;
|
|
|
|
if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
|
|
RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 ||
|
|
RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT)
|
|
processGOTRelocation(RE, Value, Stubs);
|
|
else {
|
|
if (Value.SymbolName)
|
|
addRelocationForSymbol(RE, Value.SymbolName);
|
|
else
|
|
addRelocationForSection(RE, Value.SectionID);
|
|
}
|
|
|
|
return ++RelI;
|
|
}
|
|
|
|
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
|
LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
|
|
|
|
const SectionEntry &Section = Sections[RE.SectionID];
|
|
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
|
MachO::RelocationInfoType RelType =
|
|
static_cast<MachO::RelocationInfoType>(RE.RelType);
|
|
|
|
switch (RelType) {
|
|
default:
|
|
llvm_unreachable("Invalid relocation type!");
|
|
case MachO::ARM64_RELOC_UNSIGNED: {
|
|
assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
|
|
// Mask in the target value a byte at a time (we don't have an alignment
|
|
// guarantee for the target address, so this is safest).
|
|
if (RE.Size < 2)
|
|
llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
|
|
|
|
encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
|
|
break;
|
|
}
|
|
|
|
case MachO::ARM64_RELOC_POINTER_TO_GOT: {
|
|
assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) &&
|
|
"ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit "
|
|
"absolute");
|
|
// Addend is the GOT entry address and RE.Offset the target of the
|
|
// relocation.
|
|
uint64_t Result =
|
|
RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend);
|
|
encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result);
|
|
break;
|
|
}
|
|
|
|
case MachO::ARM64_RELOC_BRANCH26: {
|
|
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
|
|
// Check if branch is in range.
|
|
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
|
|
int64_t PCRelVal = Value - FinalAddress + RE.Addend;
|
|
encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
|
|
case MachO::ARM64_RELOC_PAGE21: {
|
|
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
|
|
// Adjust for PC-relative relocation and offset.
|
|
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
|
|
int64_t PCRelVal =
|
|
((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
|
|
encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
|
|
case MachO::ARM64_RELOC_PAGEOFF12: {
|
|
assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
|
|
// Add the offset from the symbol.
|
|
Value += RE.Addend;
|
|
// Mask out the page address and only use the lower 12 bits.
|
|
Value &= 0xFFF;
|
|
encodeAddend(LocalAddress, /*Size=*/4, RelType, Value);
|
|
break;
|
|
}
|
|
case MachO::ARM64_RELOC_SUBTRACTOR: {
|
|
uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
|
|
uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
|
|
assert((Value == SectionABase || Value == SectionBBase) &&
|
|
"Unexpected SUBTRACTOR relocation value.");
|
|
Value = SectionABase - SectionBBase + RE.Addend;
|
|
writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
|
|
break;
|
|
}
|
|
|
|
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
|
|
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
|
|
llvm_unreachable("Relocation type not yet implemented!");
|
|
case MachO::ARM64_RELOC_ADDEND:
|
|
llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
|
|
"processRelocationRef!");
|
|
}
|
|
}
|
|
|
|
Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
|
|
const SectionRef &Section) {
|
|
return Error::success();
|
|
}
|
|
|
|
private:
|
|
void processGOTRelocation(const RelocationEntry &RE,
|
|
RelocationValueRef &Value, StubMap &Stubs) {
|
|
assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT &&
|
|
(RE.Size == 2 || RE.Size == 3)) ||
|
|
RE.Size == 2);
|
|
SectionEntry &Section = Sections[RE.SectionID];
|
|
StubMap::const_iterator i = Stubs.find(Value);
|
|
int64_t Offset;
|
|
if (i != Stubs.end())
|
|
Offset = static_cast<int64_t>(i->second);
|
|
else {
|
|
// FIXME: There must be a better way to do this then to check and fix the
|
|
// alignment every time!!!
|
|
uintptr_t BaseAddress = uintptr_t(Section.getAddress());
|
|
uintptr_t StubAlignment = getStubAlignment();
|
|
uintptr_t StubAddress =
|
|
(BaseAddress + Section.getStubOffset() + StubAlignment - 1) &
|
|
-StubAlignment;
|
|
unsigned StubOffset = StubAddress - BaseAddress;
|
|
Stubs[Value] = StubOffset;
|
|
assert(((StubAddress % getStubAlignment()) == 0) &&
|
|
"GOT entry not aligned");
|
|
RelocationEntry GOTRE(RE.SectionID, StubOffset,
|
|
MachO::ARM64_RELOC_UNSIGNED, Value.Offset,
|
|
/*IsPCRel=*/false, /*Size=*/3);
|
|
if (Value.SymbolName)
|
|
addRelocationForSymbol(GOTRE, Value.SymbolName);
|
|
else
|
|
addRelocationForSection(GOTRE, Value.SectionID);
|
|
Section.advanceStubOffset(getMaxStubSize());
|
|
Offset = static_cast<int64_t>(StubOffset);
|
|
}
|
|
RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset,
|
|
RE.IsPCRel, RE.Size);
|
|
addRelocationForSection(TargetRE, RE.SectionID);
|
|
}
|
|
|
|
Expected<relocation_iterator>
|
|
processSubtractRelocation(unsigned SectionID, relocation_iterator RelI,
|
|
const ObjectFile &BaseObjT,
|
|
ObjSectionToIDMap &ObjSectionToID) {
|
|
const MachOObjectFile &Obj =
|
|
static_cast<const MachOObjectFile&>(BaseObjT);
|
|
MachO::any_relocation_info RE =
|
|
Obj.getRelocation(RelI->getRawDataRefImpl());
|
|
|
|
unsigned Size = Obj.getAnyRelocationLength(RE);
|
|
uint64_t Offset = RelI->getOffset();
|
|
uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset);
|
|
unsigned NumBytes = 1 << Size;
|
|
|
|
Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName();
|
|
if (!SubtrahendNameOrErr)
|
|
return SubtrahendNameOrErr.takeError();
|
|
auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr);
|
|
unsigned SectionBID = SubtrahendI->second.getSectionID();
|
|
uint64_t SectionBOffset = SubtrahendI->second.getOffset();
|
|
int64_t Addend =
|
|
SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8);
|
|
|
|
++RelI;
|
|
Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName();
|
|
if (!MinuendNameOrErr)
|
|
return MinuendNameOrErr.takeError();
|
|
auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr);
|
|
unsigned SectionAID = MinuendI->second.getSectionID();
|
|
uint64_t SectionAOffset = MinuendI->second.getOffset();
|
|
|
|
RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend,
|
|
SectionAID, SectionAOffset, SectionBID, SectionBOffset,
|
|
false, Size);
|
|
|
|
addRelocationForSection(R, SectionAID);
|
|
|
|
return ++RelI;
|
|
}
|
|
|
|
static const char *getRelocName(uint32_t RelocType) {
|
|
switch (RelocType) {
|
|
case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED";
|
|
case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR";
|
|
case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26";
|
|
case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21";
|
|
case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12";
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21";
|
|
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12";
|
|
case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT";
|
|
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21";
|
|
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12";
|
|
case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND";
|
|
}
|
|
return "Unrecognized arm64 addend";
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
#undef DEBUG_TYPE
|
|
|
|
#endif
|