You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
@ -1,215 +0,0 @@
|
||||
//===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// COFF x86 support for MC-JIT runtime dynamic linker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
|
||||
|
||||
#include "../RuntimeDyldCOFF.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
|
||||
public:
|
||||
RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldCOFF(MM, Resolver) {}
|
||||
|
||||
unsigned getMaxStubSize() override {
|
||||
return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad
|
||||
}
|
||||
|
||||
unsigned getStubAlignment() override { return 1; }
|
||||
|
||||
Expected<relocation_iterator>
|
||||
processRelocationRef(unsigned SectionID,
|
||||
relocation_iterator RelI,
|
||||
const ObjectFile &Obj,
|
||||
ObjSectionToIDMap &ObjSectionToID,
|
||||
StubMap &Stubs) override {
|
||||
|
||||
auto Symbol = RelI->getSymbol();
|
||||
if (Symbol == Obj.symbol_end())
|
||||
report_fatal_error("Unknown symbol in relocation");
|
||||
|
||||
Expected<StringRef> TargetNameOrErr = Symbol->getName();
|
||||
if (!TargetNameOrErr)
|
||||
return TargetNameOrErr.takeError();
|
||||
StringRef TargetName = *TargetNameOrErr;
|
||||
|
||||
auto SectionOrErr = Symbol->getSection();
|
||||
if (!SectionOrErr)
|
||||
return SectionOrErr.takeError();
|
||||
auto Section = *SectionOrErr;
|
||||
|
||||
uint64_t RelType = RelI->getType();
|
||||
uint64_t Offset = RelI->getOffset();
|
||||
|
||||
// Determine the Addend used to adjust the relocation value.
|
||||
uint64_t Addend = 0;
|
||||
SectionEntry &AddendSection = Sections[SectionID];
|
||||
uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
|
||||
uint8_t *Displacement = (uint8_t *)ObjTarget;
|
||||
|
||||
switch (RelType) {
|
||||
case COFF::IMAGE_REL_I386_DIR32:
|
||||
case COFF::IMAGE_REL_I386_DIR32NB:
|
||||
case COFF::IMAGE_REL_I386_SECREL:
|
||||
case COFF::IMAGE_REL_I386_REL32: {
|
||||
Addend = readBytesUnaligned(Displacement, 4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
SmallString<32> RelTypeName;
|
||||
RelI->getTypeName(RelTypeName);
|
||||
#endif
|
||||
DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
|
||||
<< " RelType: " << RelTypeName << " TargetName: " << TargetName
|
||||
<< " Addend " << Addend << "\n");
|
||||
|
||||
unsigned TargetSectionID = -1;
|
||||
if (Section == Obj.section_end()) {
|
||||
RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
|
||||
addRelocationForSymbol(RE, TargetName);
|
||||
} else {
|
||||
if (auto TargetSectionIDOrErr =
|
||||
findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
|
||||
TargetSectionID = *TargetSectionIDOrErr;
|
||||
else
|
||||
return TargetSectionIDOrErr.takeError();
|
||||
|
||||
switch (RelType) {
|
||||
case COFF::IMAGE_REL_I386_ABSOLUTE:
|
||||
// This relocation is ignored.
|
||||
break;
|
||||
case COFF::IMAGE_REL_I386_DIR32:
|
||||
case COFF::IMAGE_REL_I386_DIR32NB:
|
||||
case COFF::IMAGE_REL_I386_REL32: {
|
||||
RelocationEntry RE =
|
||||
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
|
||||
getSymbolOffset(*Symbol), 0, 0, false, 0);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_I386_SECTION: {
|
||||
RelocationEntry RE =
|
||||
RelocationEntry(TargetSectionID, Offset, RelType, 0);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_I386_SECREL: {
|
||||
RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
|
||||
getSymbolOffset(*Symbol) + Addend);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation type");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
||||
const auto Section = Sections[RE.SectionID];
|
||||
uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
|
||||
|
||||
switch (RE.RelType) {
|
||||
case COFF::IMAGE_REL_I386_ABSOLUTE:
|
||||
// This relocation is ignored.
|
||||
break;
|
||||
case COFF::IMAGE_REL_I386_DIR32: {
|
||||
// The target's 32-bit VA.
|
||||
uint64_t Result =
|
||||
RE.Sections.SectionA == static_cast<uint32_t>(-1)
|
||||
? Value
|
||||
: Sections[RE.Sections.SectionA].getLoadAddressWithOffset(
|
||||
RE.Addend);
|
||||
assert(Result <= UINT32_MAX && "relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_I386_DIR32"
|
||||
<< " TargetSection: " << RE.Sections.SectionA
|
||||
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
|
||||
writeBytesUnaligned(Result, Target, 4);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_I386_DIR32NB: {
|
||||
// The target's 32-bit RVA.
|
||||
// NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
|
||||
uint64_t Result =
|
||||
Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) -
|
||||
Sections[0].getLoadAddress();
|
||||
assert(Result <= UINT32_MAX && "relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_I386_DIR32NB"
|
||||
<< " TargetSection: " << RE.Sections.SectionA
|
||||
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
|
||||
writeBytesUnaligned(Result, Target, 4);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_I386_REL32: {
|
||||
// 32-bit relative displacement to the target.
|
||||
uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1)
|
||||
? Value
|
||||
: Sections[RE.Sections.SectionA].getLoadAddress();
|
||||
Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset;
|
||||
assert(static_cast<int64_t>(Result) <= INT32_MAX &&
|
||||
"relocation overflow");
|
||||
assert(static_cast<int64_t>(Result) >= INT32_MIN &&
|
||||
"relocation underflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_I386_REL32"
|
||||
<< " TargetSection: " << RE.Sections.SectionA
|
||||
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
|
||||
writeBytesUnaligned(Result, Target, 4);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_I386_SECTION:
|
||||
// 16-bit section index of the section that contains the target.
|
||||
assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
|
||||
"relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_I386_SECTION Value: " << RE.SectionID
|
||||
<< '\n');
|
||||
writeBytesUnaligned(RE.SectionID, Target, 2);
|
||||
break;
|
||||
case COFF::IMAGE_REL_I386_SECREL:
|
||||
// 32-bit offset of the target from the beginning of its section.
|
||||
assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
|
||||
"relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_I386_SECREL Value: " << RE.Addend
|
||||
<< '\n');
|
||||
writeBytesUnaligned(RE.Addend, Target, 4);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation type");
|
||||
}
|
||||
}
|
||||
|
||||
void registerEHFrames() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,310 +0,0 @@
|
||||
//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// COFF thumb support for MC-JIT runtime dynamic linker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
|
||||
|
||||
#include "../RuntimeDyldCOFF.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
static bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj,
|
||||
section_iterator Section) {
|
||||
Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType();
|
||||
if (!SymTypeOrErr) {
|
||||
std::string Buf;
|
||||
raw_string_ostream OS(Buf);
|
||||
logAllUnhandledErrors(SymTypeOrErr.takeError(), OS, "");
|
||||
OS.flush();
|
||||
report_fatal_error(Buf);
|
||||
}
|
||||
|
||||
if (*SymTypeOrErr != SymbolRef::ST_Function)
|
||||
return false;
|
||||
|
||||
// We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell
|
||||
// if it's thumb or not
|
||||
return cast<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics &
|
||||
COFF::IMAGE_SCN_MEM_16BIT;
|
||||
}
|
||||
|
||||
class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
|
||||
public:
|
||||
RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldCOFF(MM, Resolver) {}
|
||||
|
||||
unsigned getMaxStubSize() override {
|
||||
return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
|
||||
}
|
||||
|
||||
unsigned getStubAlignment() override { return 1; }
|
||||
|
||||
Expected<relocation_iterator>
|
||||
processRelocationRef(unsigned SectionID,
|
||||
relocation_iterator RelI,
|
||||
const ObjectFile &Obj,
|
||||
ObjSectionToIDMap &ObjSectionToID,
|
||||
StubMap &Stubs) override {
|
||||
auto Symbol = RelI->getSymbol();
|
||||
if (Symbol == Obj.symbol_end())
|
||||
report_fatal_error("Unknown symbol in relocation");
|
||||
|
||||
Expected<StringRef> TargetNameOrErr = Symbol->getName();
|
||||
if (!TargetNameOrErr)
|
||||
return TargetNameOrErr.takeError();
|
||||
StringRef TargetName = *TargetNameOrErr;
|
||||
|
||||
auto SectionOrErr = Symbol->getSection();
|
||||
if (!SectionOrErr)
|
||||
return SectionOrErr.takeError();
|
||||
auto Section = *SectionOrErr;
|
||||
|
||||
uint64_t RelType = RelI->getType();
|
||||
uint64_t Offset = RelI->getOffset();
|
||||
|
||||
// Determine the Addend used to adjust the relocation value.
|
||||
uint64_t Addend = 0;
|
||||
SectionEntry &AddendSection = Sections[SectionID];
|
||||
uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
|
||||
uint8_t *Displacement = (uint8_t *)ObjTarget;
|
||||
|
||||
switch (RelType) {
|
||||
case COFF::IMAGE_REL_ARM_ADDR32:
|
||||
case COFF::IMAGE_REL_ARM_ADDR32NB:
|
||||
case COFF::IMAGE_REL_ARM_SECREL:
|
||||
Addend = readBytesUnaligned(Displacement, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
SmallString<32> RelTypeName;
|
||||
RelI->getTypeName(RelTypeName);
|
||||
#endif
|
||||
DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
|
||||
<< " RelType: " << RelTypeName << " TargetName: " << TargetName
|
||||
<< " Addend " << Addend << "\n");
|
||||
|
||||
unsigned TargetSectionID = -1;
|
||||
if (Section == Obj.section_end()) {
|
||||
RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
|
||||
addRelocationForSymbol(RE, TargetName);
|
||||
} else {
|
||||
if (auto TargetSectionIDOrErr =
|
||||
findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
|
||||
TargetSectionID = *TargetSectionIDOrErr;
|
||||
else
|
||||
return TargetSectionIDOrErr.takeError();
|
||||
|
||||
// We need to find out if the relocation is relative to a thumb function
|
||||
// so that we include the ISA selection bit when resolve the relocation
|
||||
bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
|
||||
|
||||
switch (RelType) {
|
||||
default: llvm_unreachable("unsupported relocation type");
|
||||
case COFF::IMAGE_REL_ARM_ABSOLUTE:
|
||||
// This relocation is ignored.
|
||||
break;
|
||||
case COFF::IMAGE_REL_ARM_ADDR32: {
|
||||
RelocationEntry RE = RelocationEntry(
|
||||
SectionID, Offset, RelType, Addend, TargetSectionID,
|
||||
getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_ADDR32NB: {
|
||||
RelocationEntry RE =
|
||||
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
|
||||
getSymbolOffset(*Symbol), 0, 0, false, 0);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_SECTION: {
|
||||
RelocationEntry RE =
|
||||
RelocationEntry(TargetSectionID, Offset, RelType, 0);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_SECREL: {
|
||||
RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
|
||||
getSymbolOffset(*Symbol) + Addend);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_MOV32T: {
|
||||
RelocationEntry RE = RelocationEntry(
|
||||
SectionID, Offset, RelType, Addend, TargetSectionID,
|
||||
getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_BRANCH20T:
|
||||
case COFF::IMAGE_REL_ARM_BRANCH24T:
|
||||
case COFF::IMAGE_REL_ARM_BLX23T: {
|
||||
RelocationEntry RE =
|
||||
RelocationEntry(SectionID, Offset, RelType,
|
||||
getSymbolOffset(*Symbol) + Addend, true, 0);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
||||
const auto Section = Sections[RE.SectionID];
|
||||
uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
|
||||
int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
|
||||
|
||||
switch (RE.RelType) {
|
||||
default: llvm_unreachable("unsupported relocation type");
|
||||
case COFF::IMAGE_REL_ARM_ABSOLUTE:
|
||||
// This relocation is ignored.
|
||||
break;
|
||||
case COFF::IMAGE_REL_ARM_ADDR32: {
|
||||
// The target's 32-bit VA.
|
||||
uint64_t Result =
|
||||
RE.Sections.SectionA == static_cast<uint32_t>(-1)
|
||||
? Value
|
||||
: Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
|
||||
Result |= ISASelectionBit;
|
||||
assert(Result <= UINT32_MAX && "relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_ADDR32"
|
||||
<< " TargetSection: " << RE.Sections.SectionA
|
||||
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
|
||||
writeBytesUnaligned(Result, Target, 4);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_ADDR32NB: {
|
||||
// The target's 32-bit RVA.
|
||||
// NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
|
||||
uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
|
||||
Sections[0].getLoadAddress() + RE.Addend;
|
||||
assert(Result <= UINT32_MAX && "relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_ADDR32NB"
|
||||
<< " TargetSection: " << RE.Sections.SectionA
|
||||
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
|
||||
Result |= ISASelectionBit;
|
||||
writeBytesUnaligned(Result, Target, 4);
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_SECTION:
|
||||
// 16-bit section index of the section that contains the target.
|
||||
assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
|
||||
"relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_SECTION Value: " << RE.SectionID
|
||||
<< '\n');
|
||||
writeBytesUnaligned(RE.SectionID, Target, 2);
|
||||
break;
|
||||
case COFF::IMAGE_REL_ARM_SECREL:
|
||||
// 32-bit offset of the target from the beginning of its section.
|
||||
assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
|
||||
"relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
|
||||
<< '\n');
|
||||
writeBytesUnaligned(RE.Addend, Target, 2);
|
||||
break;
|
||||
case COFF::IMAGE_REL_ARM_MOV32T: {
|
||||
// 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
|
||||
uint64_t Result =
|
||||
Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
|
||||
assert(Result <= UINT32_MAX && "relocation overflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_MOV32T"
|
||||
<< " TargetSection: " << RE.Sections.SectionA
|
||||
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
|
||||
|
||||
// MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
|
||||
// imm32 = zext imm4:i:imm3:imm8
|
||||
// MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
|
||||
// imm16 = imm4:i:imm3:imm8
|
||||
|
||||
auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) {
|
||||
Bytes[0] |= ((Immediate & 0xf000) >> 12);
|
||||
Bytes[1] |= ((Immediate & 0x0800) >> 11);
|
||||
Bytes[2] |= ((Immediate & 0x00ff) >> 0);
|
||||
Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);
|
||||
};
|
||||
|
||||
EncodeImmediate(&Target[0],
|
||||
(static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
|
||||
EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
|
||||
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_BRANCH20T: {
|
||||
// The most significant 20-bits of the signed 21-bit relative displacement
|
||||
uint64_t Value =
|
||||
RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
|
||||
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
|
||||
"relocation overflow");
|
||||
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
|
||||
"relocation underflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_BRANCH20T"
|
||||
<< " Value: " << static_cast<int32_t>(Value) << '\n');
|
||||
static_cast<void>(Value);
|
||||
llvm_unreachable("unimplemented relocation");
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_BRANCH24T: {
|
||||
// The most significant 24-bits of the signed 25-bit relative displacement
|
||||
uint64_t Value =
|
||||
RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
|
||||
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
|
||||
"relocation overflow");
|
||||
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
|
||||
"relocation underflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_BRANCH24T"
|
||||
<< " Value: " << static_cast<int32_t>(Value) << '\n');
|
||||
static_cast<void>(Value);
|
||||
llvm_unreachable("unimplemented relocation");
|
||||
break;
|
||||
}
|
||||
case COFF::IMAGE_REL_ARM_BLX23T: {
|
||||
// The most significant 24-bits of the signed 25-bit relative displacement
|
||||
uint64_t Value =
|
||||
RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
|
||||
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
|
||||
"relocation overflow");
|
||||
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
|
||||
"relocation underflow");
|
||||
DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
|
||||
<< " RelType: IMAGE_REL_ARM_BLX23T"
|
||||
<< " Value: " << static_cast<int32_t>(Value) << '\n');
|
||||
static_cast<void>(Value);
|
||||
llvm_unreachable("unimplemented relocation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void registerEHFrames() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,219 +0,0 @@
|
||||
//===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 specific code ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// COFF x86_x64 support for MC-JIT runtime dynamic linker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
|
||||
|
||||
#include "../RuntimeDyldCOFF.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF {
|
||||
|
||||
private:
|
||||
// When a module is loaded we save the SectionID of the unwind
|
||||
// sections in a table until we receive a request to register all
|
||||
// unregisteredEH frame sections with the memory manager.
|
||||
SmallVector<SID, 2> UnregisteredEHFrameSections;
|
||||
SmallVector<SID, 2> RegisteredEHFrameSections;
|
||||
|
||||
public:
|
||||
RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldCOFF(MM, Resolver) {}
|
||||
|
||||
unsigned getMaxStubSize() override {
|
||||
return 6; // 2-byte jmp instruction + 32-bit relative address
|
||||
}
|
||||
|
||||
// The target location for the relocation is described by RE.SectionID and
|
||||
// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
|
||||
// SectionEntry has three members describing its location.
|
||||
// SectionEntry::Address is the address at which the section has been loaded
|
||||
// into memory in the current (host) process. SectionEntry::LoadAddress is
|
||||
// the address that the section will have in the target process.
|
||||
// SectionEntry::ObjAddress is the address of the bits for this section in the
|
||||
// original emitted object image (also in the current address space).
|
||||
//
|
||||
// Relocations will be applied as if the section were loaded at
|
||||
// SectionEntry::LoadAddress, but they will be applied at an address based
|
||||
// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer
|
||||
// to Target memory contents if they are required for value calculations.
|
||||
//
|
||||
// The Value parameter here is the load address of the symbol for the
|
||||
// relocation to be applied. For relocations which refer to symbols in the
|
||||
// current object Value will be the LoadAddress of the section in which
|
||||
// the symbol resides (RE.Addend provides additional information about the
|
||||
// symbol location). For external symbols, Value will be the address of the
|
||||
// symbol in the target address space.
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
|
||||
|
||||
switch (RE.RelType) {
|
||||
|
||||
case COFF::IMAGE_REL_AMD64_REL32:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_1:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_2:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_3:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_4:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_5: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
|
||||
// Delta is the distance from the start of the reloc to the end of the
|
||||
// instruction with the reloc.
|
||||
uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32);
|
||||
Value -= FinalAddress + Delta;
|
||||
uint64_t Result = Value + RE.Addend;
|
||||
assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow");
|
||||
assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow");
|
||||
writeBytesUnaligned(Result, Target, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case COFF::IMAGE_REL_AMD64_ADDR32NB: {
|
||||
// Note ADDR32NB requires a well-established notion of
|
||||
// image base. This address must be less than or equal
|
||||
// to every section's load address, and all sections must be
|
||||
// within a 32 bit offset from the base.
|
||||
//
|
||||
// For now we just set these to zero.
|
||||
writeBytesUnaligned(0, Target, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case COFF::IMAGE_REL_AMD64_ADDR64: {
|
||||
writeBytesUnaligned(Value + RE.Addend, Target, 8);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
llvm_unreachable("Relocation type not implemented yet!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Expected<relocation_iterator>
|
||||
processRelocationRef(unsigned SectionID,
|
||||
relocation_iterator RelI,
|
||||
const ObjectFile &Obj,
|
||||
ObjSectionToIDMap &ObjSectionToID,
|
||||
StubMap &Stubs) override {
|
||||
// If possible, find the symbol referred to in the relocation,
|
||||
// and the section that contains it.
|
||||
symbol_iterator Symbol = RelI->getSymbol();
|
||||
if (Symbol == Obj.symbol_end())
|
||||
report_fatal_error("Unknown symbol in relocation");
|
||||
auto SectionOrError = Symbol->getSection();
|
||||
if (!SectionOrError)
|
||||
return SectionOrError.takeError();
|
||||
section_iterator SecI = *SectionOrError;
|
||||
// If there is no section, this must be an external reference.
|
||||
const bool IsExtern = SecI == Obj.section_end();
|
||||
|
||||
// Determine the Addend used to adjust the relocation value.
|
||||
uint64_t RelType = RelI->getType();
|
||||
uint64_t Offset = RelI->getOffset();
|
||||
uint64_t Addend = 0;
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
uintptr_t ObjTarget = Section.getObjAddress() + Offset;
|
||||
|
||||
switch (RelType) {
|
||||
|
||||
case COFF::IMAGE_REL_AMD64_REL32:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_1:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_2:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_3:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_4:
|
||||
case COFF::IMAGE_REL_AMD64_REL32_5:
|
||||
case COFF::IMAGE_REL_AMD64_ADDR32NB: {
|
||||
uint8_t *Displacement = (uint8_t *)ObjTarget;
|
||||
Addend = readBytesUnaligned(Displacement, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case COFF::IMAGE_REL_AMD64_ADDR64: {
|
||||
uint8_t *Displacement = (uint8_t *)ObjTarget;
|
||||
Addend = readBytesUnaligned(Displacement, 8);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Expected<StringRef> TargetNameOrErr = Symbol->getName();
|
||||
if (!TargetNameOrErr)
|
||||
return TargetNameOrErr.takeError();
|
||||
StringRef TargetName = *TargetNameOrErr;
|
||||
|
||||
DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
|
||||
<< " RelType: " << RelType << " TargetName: " << TargetName
|
||||
<< " Addend " << Addend << "\n");
|
||||
|
||||
if (IsExtern) {
|
||||
RelocationEntry RE(SectionID, Offset, RelType, Addend);
|
||||
addRelocationForSymbol(RE, TargetName);
|
||||
} else {
|
||||
bool IsCode = SecI->isText();
|
||||
unsigned TargetSectionID;
|
||||
if (auto TargetSectionIDOrErr =
|
||||
findOrEmitSection(Obj, *SecI, IsCode, ObjSectionToID))
|
||||
TargetSectionID = *TargetSectionIDOrErr;
|
||||
else
|
||||
return TargetSectionIDOrErr.takeError();
|
||||
uint64_t TargetOffset = getSymbolOffset(*Symbol);
|
||||
RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
|
||||
addRelocationForSection(RE, TargetSectionID);
|
||||
}
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
unsigned getStubAlignment() override { return 1; }
|
||||
void registerEHFrames() override {
|
||||
for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
|
||||
uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
|
||||
uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress();
|
||||
size_t EHFrameSize = Sections[EHFrameSID].getSize();
|
||||
MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
|
||||
RegisteredEHFrameSections.push_back(EHFrameSID);
|
||||
}
|
||||
UnregisteredEHFrameSections.clear();
|
||||
}
|
||||
Error finalizeLoad(const ObjectFile &Obj,
|
||||
ObjSectionToIDMap &SectionMap) override {
|
||||
// Look for and record the EH frame section IDs.
|
||||
for (const auto &SectionPair : SectionMap) {
|
||||
const SectionRef &Section = SectionPair.first;
|
||||
StringRef Name;
|
||||
if (auto EC = Section.getName(Name))
|
||||
return errorCodeToError(EC);
|
||||
// Note unwind info is split across .pdata and .xdata, so this
|
||||
// may not be sufficiently general for all users.
|
||||
if (Name == ".xdata") {
|
||||
UnregisteredEHFrameSections.push_back(SectionPair.second);
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
@ -1,321 +0,0 @@
|
||||
//===-- RuntimeDyldELFMips.cpp ---- ELF/Mips specific code. -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RuntimeDyldELFMips.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE,
|
||||
uint64_t Value) {
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
if (IsMipsO32ABI)
|
||||
resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
|
||||
else if (IsMipsN32ABI) {
|
||||
resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
|
||||
RE.SymOffset, RE.SectionID);
|
||||
} else if (IsMipsN64ABI)
|
||||
resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
|
||||
RE.SymOffset, RE.SectionID);
|
||||
else
|
||||
llvm_unreachable("Mips ABI not handled");
|
||||
}
|
||||
|
||||
uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE,
|
||||
uint64_t Value,
|
||||
uint64_t Addend) {
|
||||
if (IsMipsN32ABI) {
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType,
|
||||
Addend, RE.SymOffset, RE.SectionID);
|
||||
return Value;
|
||||
}
|
||||
llvm_unreachable("Not reachable");
|
||||
}
|
||||
|
||||
void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE,
|
||||
uint64_t Value) {
|
||||
if (IsMipsN32ABI) {
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value,
|
||||
RE.RelType);
|
||||
return;
|
||||
}
|
||||
llvm_unreachable("Not reachable");
|
||||
}
|
||||
|
||||
int64_t
|
||||
RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section,
|
||||
uint64_t Offset, uint64_t Value,
|
||||
uint32_t Type) {
|
||||
|
||||
DEBUG(dbgs() << "evaluateMIPS32Relocation, LocalAddress: 0x"
|
||||
<< format("%llx", Section.getAddressWithOffset(Offset))
|
||||
<< " FinalAddress: 0x"
|
||||
<< format("%llx", Section.getLoadAddressWithOffset(Offset))
|
||||
<< " Value: 0x" << format("%llx", Value) << " Type: 0x"
|
||||
<< format("%x", Type) << "\n");
|
||||
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("Unknown relocation type!");
|
||||
return Value;
|
||||
case ELF::R_MIPS_32:
|
||||
return Value;
|
||||
case ELF::R_MIPS_26:
|
||||
return Value >> 2;
|
||||
case ELF::R_MIPS_HI16:
|
||||
// Get the higher 16-bits. Also add 1 if bit 15 is 1.
|
||||
return (Value + 0x8000) >> 16;
|
||||
case ELF::R_MIPS_LO16:
|
||||
return Value;
|
||||
case ELF::R_MIPS_PC32: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return Value - FinalAddress;
|
||||
}
|
||||
case ELF::R_MIPS_PC16: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return (Value - FinalAddress) >> 2;
|
||||
}
|
||||
case ELF::R_MIPS_PC19_S2: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return (Value - (FinalAddress & ~0x3)) >> 2;
|
||||
}
|
||||
case ELF::R_MIPS_PC21_S2: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return (Value - FinalAddress) >> 2;
|
||||
}
|
||||
case ELF::R_MIPS_PC26_S2: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return (Value - FinalAddress) >> 2;
|
||||
}
|
||||
case ELF::R_MIPS_PCHI16: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return (Value - FinalAddress + 0x8000) >> 16;
|
||||
}
|
||||
case ELF::R_MIPS_PCLO16: {
|
||||
uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return Value - FinalAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t RuntimeDyldELFMips::evaluateMIPS64Relocation(
|
||||
const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
|
||||
int64_t Addend, uint64_t SymOffset, SID SectionID) {
|
||||
|
||||
DEBUG(dbgs() << "evaluateMIPS64Relocation, LocalAddress: 0x"
|
||||
<< format("%llx", Section.getAddressWithOffset(Offset))
|
||||
<< " FinalAddress: 0x"
|
||||
<< format("%llx", Section.getLoadAddressWithOffset(Offset))
|
||||
<< " Value: 0x" << format("%llx", Value) << " Type: 0x"
|
||||
<< format("%x", Type) << " Addend: 0x" << format("%llx", Addend)
|
||||
<< " Offset: " << format("%llx" PRIx64, Offset)
|
||||
<< " SID: " << format("%d", SectionID)
|
||||
<< " SymOffset: " << format("%x", SymOffset) << "\n");
|
||||
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("Not implemented relocation type!");
|
||||
break;
|
||||
case ELF::R_MIPS_JALR:
|
||||
case ELF::R_MIPS_NONE:
|
||||
break;
|
||||
case ELF::R_MIPS_32:
|
||||
case ELF::R_MIPS_64:
|
||||
return Value + Addend;
|
||||
case ELF::R_MIPS_26:
|
||||
return ((Value + Addend) >> 2) & 0x3ffffff;
|
||||
case ELF::R_MIPS_GPREL16: {
|
||||
uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
|
||||
return Value + Addend - (GOTAddr + 0x7ff0);
|
||||
}
|
||||
case ELF::R_MIPS_SUB:
|
||||
return Value - Addend;
|
||||
case ELF::R_MIPS_HI16:
|
||||
// Get the higher 16-bits. Also add 1 if bit 15 is 1.
|
||||
return ((Value + Addend + 0x8000) >> 16) & 0xffff;
|
||||
case ELF::R_MIPS_LO16:
|
||||
return (Value + Addend) & 0xffff;
|
||||
case ELF::R_MIPS_HIGHER:
|
||||
return ((Value + Addend + 0x80008000) >> 32) & 0xffff;
|
||||
case ELF::R_MIPS_HIGHEST:
|
||||
return ((Value + Addend + 0x800080008000) >> 48) & 0xffff;
|
||||
case ELF::R_MIPS_CALL16:
|
||||
case ELF::R_MIPS_GOT_DISP:
|
||||
case ELF::R_MIPS_GOT_PAGE: {
|
||||
uint8_t *LocalGOTAddr =
|
||||
getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset;
|
||||
uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize());
|
||||
|
||||
Value += Addend;
|
||||
if (Type == ELF::R_MIPS_GOT_PAGE)
|
||||
Value = (Value + 0x8000) & ~0xffff;
|
||||
|
||||
if (GOTEntry)
|
||||
assert(GOTEntry == Value &&
|
||||
"GOT entry has two different addresses.");
|
||||
else
|
||||
writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize());
|
||||
|
||||
return (SymOffset - 0x7ff0) & 0xffff;
|
||||
}
|
||||
case ELF::R_MIPS_GOT_OFST: {
|
||||
int64_t page = (Value + Addend + 0x8000) & ~0xffff;
|
||||
return (Value + Addend - page) & 0xffff;
|
||||
}
|
||||
case ELF::R_MIPS_GPREL32: {
|
||||
uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
|
||||
return Value + Addend - (GOTAddr + 0x7ff0);
|
||||
}
|
||||
case ELF::R_MIPS_PC16: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return ((Value + Addend - FinalAddress) >> 2) & 0xffff;
|
||||
}
|
||||
case ELF::R_MIPS_PC32: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return Value + Addend - FinalAddress;
|
||||
}
|
||||
case ELF::R_MIPS_PC18_S3: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff;
|
||||
}
|
||||
case ELF::R_MIPS_PC19_S2: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff;
|
||||
}
|
||||
case ELF::R_MIPS_PC21_S2: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff;
|
||||
}
|
||||
case ELF::R_MIPS_PC26_S2: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff;
|
||||
}
|
||||
case ELF::R_MIPS_PCHI16: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff;
|
||||
}
|
||||
case ELF::R_MIPS_PCLO16: {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
|
||||
return (Value + Addend - FinalAddress) & 0xffff;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value,
|
||||
uint32_t Type) {
|
||||
uint32_t Insn = readBytesUnaligned(TargetPtr, 4);
|
||||
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("Unknown relocation type!");
|
||||
break;
|
||||
case ELF::R_MIPS_GPREL16:
|
||||
case ELF::R_MIPS_HI16:
|
||||
case ELF::R_MIPS_LO16:
|
||||
case ELF::R_MIPS_HIGHER:
|
||||
case ELF::R_MIPS_HIGHEST:
|
||||
case ELF::R_MIPS_PC16:
|
||||
case ELF::R_MIPS_PCHI16:
|
||||
case ELF::R_MIPS_PCLO16:
|
||||
case ELF::R_MIPS_CALL16:
|
||||
case ELF::R_MIPS_GOT_DISP:
|
||||
case ELF::R_MIPS_GOT_PAGE:
|
||||
case ELF::R_MIPS_GOT_OFST:
|
||||
Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff);
|
||||
writeBytesUnaligned(Insn, TargetPtr, 4);
|
||||
break;
|
||||
case ELF::R_MIPS_PC18_S3:
|
||||
Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff);
|
||||
writeBytesUnaligned(Insn, TargetPtr, 4);
|
||||
break;
|
||||
case ELF::R_MIPS_PC19_S2:
|
||||
Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff);
|
||||
writeBytesUnaligned(Insn, TargetPtr, 4);
|
||||
break;
|
||||
case ELF::R_MIPS_PC21_S2:
|
||||
Insn = (Insn & 0xffe00000) | (Value & 0x001fffff);
|
||||
writeBytesUnaligned(Insn, TargetPtr, 4);
|
||||
break;
|
||||
case ELF::R_MIPS_26:
|
||||
case ELF::R_MIPS_PC26_S2:
|
||||
Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff);
|
||||
writeBytesUnaligned(Insn, TargetPtr, 4);
|
||||
break;
|
||||
case ELF::R_MIPS_32:
|
||||
case ELF::R_MIPS_GPREL32:
|
||||
case ELF::R_MIPS_PC32:
|
||||
writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4);
|
||||
break;
|
||||
case ELF::R_MIPS_64:
|
||||
case ELF::R_MIPS_SUB:
|
||||
writeBytesUnaligned(Value, TargetPtr, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeDyldELFMips::resolveMIPSN32Relocation(
|
||||
const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
|
||||
int64_t Addend, uint64_t SymOffset, SID SectionID) {
|
||||
int64_t CalculatedValue = evaluateMIPS64Relocation(
|
||||
Section, Offset, Value, Type, Addend, SymOffset, SectionID);
|
||||
applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
|
||||
Type);
|
||||
}
|
||||
|
||||
void RuntimeDyldELFMips::resolveMIPSN64Relocation(
|
||||
const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
|
||||
int64_t Addend, uint64_t SymOffset, SID SectionID) {
|
||||
uint32_t r_type = Type & 0xff;
|
||||
uint32_t r_type2 = (Type >> 8) & 0xff;
|
||||
uint32_t r_type3 = (Type >> 16) & 0xff;
|
||||
|
||||
// RelType is used to keep information for which relocation type we are
|
||||
// applying relocation.
|
||||
uint32_t RelType = r_type;
|
||||
int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value,
|
||||
RelType, Addend,
|
||||
SymOffset, SectionID);
|
||||
if (r_type2 != ELF::R_MIPS_NONE) {
|
||||
RelType = r_type2;
|
||||
CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
|
||||
CalculatedValue, SymOffset,
|
||||
SectionID);
|
||||
}
|
||||
if (r_type3 != ELF::R_MIPS_NONE) {
|
||||
RelType = r_type3;
|
||||
CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
|
||||
CalculatedValue, SymOffset,
|
||||
SectionID);
|
||||
}
|
||||
applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
|
||||
RelType);
|
||||
}
|
||||
|
||||
void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section,
|
||||
uint64_t Offset,
|
||||
uint32_t Value, uint32_t Type,
|
||||
int32_t Addend) {
|
||||
uint8_t *TargetPtr = Section.getAddressWithOffset(Offset);
|
||||
Value += Addend;
|
||||
|
||||
DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: "
|
||||
<< Section.getAddressWithOffset(Offset) << " FinalAddress: "
|
||||
<< format("%p", Section.getLoadAddressWithOffset(Offset))
|
||||
<< " Value: " << format("%x", Value)
|
||||
<< " Type: " << format("%x", Type)
|
||||
<< " Addend: " << format("%x", Addend)
|
||||
<< " SymOffset: " << format("%x", Offset) << "\n");
|
||||
|
||||
Value = evaluateMIPS32Relocation(Section, Offset, Value, Type);
|
||||
|
||||
applyMIPSRelocation(TargetPtr, Value, Type);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
//===-- RuntimeDyldELFMips.h ---- ELF/Mips specific code. -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDELFMIPS_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDELFMIPS_H
|
||||
|
||||
#include "../RuntimeDyldELF.h"
|
||||
#include <string>
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RuntimeDyldELFMips : public RuntimeDyldELF {
|
||||
public:
|
||||
|
||||
typedef uint64_t TargetPtrT;
|
||||
|
||||
RuntimeDyldELFMips(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldELF(MM, Resolver) {}
|
||||
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override;
|
||||
|
||||
protected:
|
||||
void resolveMIPSO32Relocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint32_t Value, uint32_t Type, int32_t Addend);
|
||||
void resolveMIPSN32Relocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint64_t Value, uint32_t Type, int64_t Addend,
|
||||
uint64_t SymOffset, SID SectionID);
|
||||
void resolveMIPSN64Relocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint64_t Value, uint32_t Type, int64_t Addend,
|
||||
uint64_t SymOffset, SID SectionID);
|
||||
|
||||
private:
|
||||
/// \brief A object file specific relocation resolver
|
||||
/// \param RE The relocation to be resolved
|
||||
/// \param Value Target symbol address to apply the relocation action
|
||||
uint64_t evaluateRelocation(const RelocationEntry &RE, uint64_t Value,
|
||||
uint64_t Addend);
|
||||
|
||||
/// \brief A object file specific relocation resolver
|
||||
/// \param RE The relocation to be resolved
|
||||
/// \param Value Target symbol address to apply the relocation action
|
||||
void applyRelocation(const RelocationEntry &RE, uint64_t Value);
|
||||
|
||||
int64_t evaluateMIPS32Relocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint64_t Value, uint32_t Type);
|
||||
int64_t evaluateMIPS64Relocation(const SectionEntry &Section,
|
||||
uint64_t Offset, uint64_t Value,
|
||||
uint32_t Type, int64_t Addend,
|
||||
uint64_t SymOffset, SID SectionID);
|
||||
|
||||
void applyMIPSRelocation(uint8_t *TargetPtr, int64_t CalculatedValue,
|
||||
uint32_t Type);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
@ -1,467 +0,0 @@
|
||||
//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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() override { return 8; }
|
||||
|
||||
unsigned getStubAlignment() override { return 8; }
|
||||
|
||||
/// Extract the addend encoded in the instruction / memory location.
|
||||
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:
|
||||
llvm_unreachable("Unsupported relocation type!");
|
||||
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 (RE.RelType) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported relocation type!");
|
||||
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 the expected branch instruction.
|
||||
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
|
||||
assert((*p & 0xFC000000) == 0x14000000 && "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_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_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 && "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));
|
||||
RE.Addend = decodeAddend(RE);
|
||||
|
||||
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 (!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)
|
||||
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 {
|
||||
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_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_POINTER_TO_GOT:
|
||||
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.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;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
@ -1,410 +0,0 @@
|
||||
//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
|
||||
|
||||
#include "../RuntimeDyldMachO.h"
|
||||
#include <string>
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RuntimeDyldMachOARM
|
||||
: public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
|
||||
private:
|
||||
typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;
|
||||
|
||||
public:
|
||||
|
||||
typedef uint32_t TargetPtrT;
|
||||
|
||||
RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldMachOCRTPBase(MM, Resolver) {}
|
||||
|
||||
unsigned getMaxStubSize() override { return 8; }
|
||||
|
||||
unsigned getStubAlignment() override { return 4; }
|
||||
|
||||
JITSymbolFlags getJITSymbolFlags(const BasicSymbolRef &SR) override {
|
||||
auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);
|
||||
Flags.getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR);
|
||||
return Flags;
|
||||
}
|
||||
|
||||
uint64_t modifyAddressBasedOnFlags(uint64_t Addr,
|
||||
JITSymbolFlags Flags) const override {
|
||||
if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb)
|
||||
Addr |= 0x1;
|
||||
return Addr;
|
||||
}
|
||||
|
||||
Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
||||
|
||||
switch (RE.RelType) {
|
||||
default:
|
||||
return memcpyAddend(RE);
|
||||
case MachO::ARM_RELOC_BR24: {
|
||||
uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
|
||||
Temp &= 0x00ffffff; // Mask out the opcode.
|
||||
// Now we've got the shifted immediate, shift by 2, sign extend and ret.
|
||||
return SignExtend32<26>(Temp << 2);
|
||||
}
|
||||
|
||||
case MachO::ARM_THUMB_RELOC_BR22: {
|
||||
// This is a pair of instructions whose operands combine to provide 22
|
||||
// bits of displacement:
|
||||
// Encoding for high bits 1111 0XXX XXXX XXXX
|
||||
// Encoding for low bits 1111 1XXX XXXX XXXX
|
||||
uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);
|
||||
if ((HighInsn & 0xf800) != 0xf000)
|
||||
return make_error<StringError>("Unrecognized thumb branch encoding "
|
||||
"(BR22 high bits)",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);
|
||||
if ((LowInsn & 0xf800) != 0xf800)
|
||||
return make_error<StringError>("Unrecognized thumb branch encoding "
|
||||
"(BR22 low bits)",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
return SignExtend64<23>(((HighInsn & 0x7ff) << 12) |
|
||||
((LowInsn & 0x7ff) << 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
|
||||
|
||||
// Set to true for thumb functions in this (or previous) TUs.
|
||||
// Will be used to set the TargetIsThumbFunc member on the relocation entry.
|
||||
bool TargetIsLocalThumbFunc = false;
|
||||
if (Obj.getPlainRelocationExternal(RelInfo)) {
|
||||
auto Symbol = RelI->getSymbol();
|
||||
StringRef TargetName;
|
||||
if (auto TargetNameOrErr = Symbol->getName())
|
||||
TargetName = *TargetNameOrErr;
|
||||
else
|
||||
return TargetNameOrErr.takeError();
|
||||
|
||||
// If the target is external but the value doesn't have a name then we've
|
||||
// converted the value to a section/offset pair, but we still need to set
|
||||
// the IsTargetThumbFunc bit, so look the value up in the globla symbol table.
|
||||
auto EntryItr = GlobalSymbolTable.find(TargetName);
|
||||
if (EntryItr != GlobalSymbolTable.end()) {
|
||||
TargetIsLocalThumbFunc =
|
||||
EntryItr->second.getFlags().getTargetFlags() &
|
||||
ARMJITSymbolFlags::Thumb;
|
||||
}
|
||||
}
|
||||
|
||||
if (Obj.isRelocationScattered(RelInfo)) {
|
||||
if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
|
||||
return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
|
||||
ObjSectionToID);
|
||||
else if (RelType == MachO::GENERIC_RELOC_VANILLA)
|
||||
return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID,
|
||||
TargetIsLocalThumbFunc);
|
||||
else
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
// Sanity check relocation type.
|
||||
switch (RelType) {
|
||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR);
|
||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
|
||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
|
||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);
|
||||
UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);
|
||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
|
||||
default:
|
||||
if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)
|
||||
return make_error<RuntimeDyldError>(("MachO ARM relocation type " +
|
||||
Twine(RelType) +
|
||||
" is out of range").str());
|
||||
break;
|
||||
}
|
||||
|
||||
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
|
||||
if (auto AddendOrErr = decodeAddend(RE))
|
||||
RE.Addend = *AddendOrErr;
|
||||
else
|
||||
return AddendOrErr.takeError();
|
||||
RE.IsTargetThumbFunc = TargetIsLocalThumbFunc;
|
||||
|
||||
RelocationValueRef Value;
|
||||
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
|
||||
Value = *ValueOrErr;
|
||||
else
|
||||
return ValueOrErr.takeError();
|
||||
|
||||
// If this is a branch from a thumb function (BR22) then make sure we mark
|
||||
// the value as being a thumb stub: we don't want to mix it up with an ARM
|
||||
// stub targeting the same function.
|
||||
if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
|
||||
Value.IsStubThumb = TargetIsLocalThumbFunc;
|
||||
|
||||
if (RE.IsPCRel)
|
||||
makeValueAddendPCRel(Value, RelI,
|
||||
(RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8);
|
||||
|
||||
if (RE.RelType == MachO::ARM_RELOC_BR24 ||
|
||||
RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
|
||||
processBranchRelocation(RE, Value, Stubs);
|
||||
else {
|
||||
RE.Addend = Value.Offset;
|
||||
if (Value.SymbolName)
|
||||
addRelocationForSymbol(RE, Value.SymbolName);
|
||||
else
|
||||
addRelocationForSection(RE, Value.SectionID);
|
||||
}
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
||||
DEBUG(dumpRelocationToResolve(RE, Value));
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
||||
|
||||
// If the relocation is PC-relative, the value to be encoded is the
|
||||
// pointer difference.
|
||||
if (RE.IsPCRel) {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
|
||||
Value -= FinalAddress;
|
||||
// ARM PCRel relocations have an effective-PC offset of two instructions
|
||||
// (four bytes in Thumb mode, 8 bytes in ARM mode).
|
||||
Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8;
|
||||
}
|
||||
|
||||
switch (RE.RelType) {
|
||||
case MachO::ARM_THUMB_RELOC_BR22: {
|
||||
Value += RE.Addend;
|
||||
uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);
|
||||
assert((HighInsn & 0xf800) == 0xf000 &&
|
||||
"Unrecognized thumb branch encoding (BR22 high bits)");
|
||||
HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff);
|
||||
|
||||
uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);
|
||||
assert((LowInsn & 0xf800) != 0xf8000 &&
|
||||
"Unrecognized thumb branch encoding (BR22 low bits)");
|
||||
LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff);
|
||||
|
||||
writeBytesUnaligned(HighInsn, LocalAddress, 2);
|
||||
writeBytesUnaligned(LowInsn, LocalAddress + 2, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
case MachO::ARM_RELOC_VANILLA:
|
||||
if (RE.IsTargetThumbFunc)
|
||||
Value |= 0x01;
|
||||
writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
|
||||
break;
|
||||
case MachO::ARM_RELOC_BR24: {
|
||||
// Mask the value into the target address. We know instructions are
|
||||
// 32-bit aligned, so we can do it all at once.
|
||||
Value += RE.Addend;
|
||||
// The low two bits of the value are not encoded.
|
||||
Value >>= 2;
|
||||
// Mask the value to 24 bits.
|
||||
uint64_t FinalValue = Value & 0xffffff;
|
||||
// FIXME: If the destination is a Thumb function (and the instruction
|
||||
// is a non-predicated BL instruction), we need to change it to a BLX
|
||||
// instruction instead.
|
||||
|
||||
// Insert the value into the instruction.
|
||||
uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
|
||||
writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);
|
||||
|
||||
break;
|
||||
}
|
||||
case MachO::ARM_RELOC_HALF_SECTDIFF: {
|
||||
uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
|
||||
uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
|
||||
assert((Value == SectionABase || Value == SectionBBase) &&
|
||||
"Unexpected HALFSECTDIFF relocation value.");
|
||||
Value = SectionABase - SectionBBase + RE.Addend;
|
||||
if (RE.Size & 0x1) // :upper16:
|
||||
Value = (Value >> 16);
|
||||
|
||||
bool IsThumb = RE.Size & 0x2;
|
||||
|
||||
Value &= 0xffff;
|
||||
|
||||
uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
|
||||
|
||||
if (IsThumb)
|
||||
Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) |
|
||||
((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) |
|
||||
((Value & 0x00ff) << 16);
|
||||
else
|
||||
Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
|
||||
writeBytesUnaligned(Insn, LocalAddress, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
llvm_unreachable("Invalid relocation type");
|
||||
}
|
||||
}
|
||||
|
||||
Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
|
||||
const SectionRef &Section) {
|
||||
StringRef Name;
|
||||
Section.getName(Name);
|
||||
|
||||
if (Name == "__nl_symbol_ptr")
|
||||
return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
|
||||
Section, SectionID);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void processBranchRelocation(const RelocationEntry &RE,
|
||||
const RelocationValueRef &Value,
|
||||
StubMap &Stubs) {
|
||||
// This is an ARM branch relocation, need to use a stub function.
|
||||
// Look up for existing stub.
|
||||
SectionEntry &Section = Sections[RE.SectionID];
|
||||
RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
|
||||
uint8_t *Addr;
|
||||
if (i != Stubs.end()) {
|
||||
Addr = Section.getAddressWithOffset(i->second);
|
||||
} else {
|
||||
// Create a new stub function.
|
||||
assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub");
|
||||
Stubs[Value] = Section.getStubOffset();
|
||||
uint32_t StubOpcode = 0;
|
||||
if (RE.RelType == MachO::ARM_RELOC_BR24)
|
||||
StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4]
|
||||
else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
|
||||
StubOpcode = 0xf000f8df; // ldr pc, [pc]
|
||||
else
|
||||
llvm_unreachable("Unrecognized relocation");
|
||||
Addr = Section.getAddressWithOffset(Section.getStubOffset());
|
||||
writeBytesUnaligned(StubOpcode, Addr, 4);
|
||||
uint8_t *StubTargetAddr = Addr + 4;
|
||||
RelocationEntry StubRE(
|
||||
RE.SectionID, StubTargetAddr - Section.getAddress(),
|
||||
MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
|
||||
StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc;
|
||||
if (Value.SymbolName)
|
||||
addRelocationForSymbol(StubRE, Value.SymbolName);
|
||||
else
|
||||
addRelocationForSection(StubRE, Value.SectionID);
|
||||
Section.advanceStubOffset(getMaxStubSize());
|
||||
}
|
||||
RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
|
||||
RE.IsPCRel, RE.Size);
|
||||
resolveRelocation(TargetRE, (uint64_t)Addr);
|
||||
}
|
||||
|
||||
Expected<relocation_iterator>
|
||||
processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
|
||||
const ObjectFile &BaseTObj,
|
||||
ObjSectionToIDMap &ObjSectionToID) {
|
||||
const MachOObjectFile &MachO =
|
||||
static_cast<const MachOObjectFile&>(BaseTObj);
|
||||
MachO::any_relocation_info RE =
|
||||
MachO.getRelocation(RelI->getRawDataRefImpl());
|
||||
|
||||
// For a half-diff relocation the length bits actually record whether this
|
||||
// is a movw/movt, and whether this is arm or thumb.
|
||||
// Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
|
||||
// Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
|
||||
unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
|
||||
bool IsThumb = HalfDiffKindBits & 0x2;
|
||||
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
uint32_t RelocType = MachO.getAnyRelocationType(RE);
|
||||
bool IsPCRel = MachO.getAnyRelocationPCRel(RE);
|
||||
uint64_t Offset = RelI->getOffset();
|
||||
uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
|
||||
int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
|
||||
|
||||
if (IsThumb)
|
||||
Immediate = ((Immediate & 0x0000000f) << 12) |
|
||||
((Immediate & 0x00000400) << 1) |
|
||||
((Immediate & 0x70000000) >> 20) |
|
||||
((Immediate & 0x00ff0000) >> 16);
|
||||
else
|
||||
Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
|
||||
|
||||
++RelI;
|
||||
MachO::any_relocation_info RE2 =
|
||||
MachO.getRelocation(RelI->getRawDataRefImpl());
|
||||
uint32_t AddrA = MachO.getScatteredRelocationValue(RE);
|
||||
section_iterator SAI = getSectionByAddress(MachO, AddrA);
|
||||
assert(SAI != MachO.section_end() && "Can't find section for address A");
|
||||
uint64_t SectionABase = SAI->getAddress();
|
||||
uint64_t SectionAOffset = AddrA - SectionABase;
|
||||
SectionRef SectionA = *SAI;
|
||||
bool IsCode = SectionA.isText();
|
||||
uint32_t SectionAID = ~0U;
|
||||
if (auto SectionAIDOrErr =
|
||||
findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))
|
||||
SectionAID = *SectionAIDOrErr;
|
||||
else
|
||||
return SectionAIDOrErr.takeError();
|
||||
|
||||
uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);
|
||||
section_iterator SBI = getSectionByAddress(MachO, AddrB);
|
||||
assert(SBI != MachO.section_end() && "Can't find section for address B");
|
||||
uint64_t SectionBBase = SBI->getAddress();
|
||||
uint64_t SectionBOffset = AddrB - SectionBBase;
|
||||
SectionRef SectionB = *SBI;
|
||||
uint32_t SectionBID = ~0U;
|
||||
if (auto SectionBIDOrErr =
|
||||
findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))
|
||||
SectionBID = *SectionBIDOrErr;
|
||||
else
|
||||
return SectionBIDOrErr.takeError();
|
||||
|
||||
uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;
|
||||
unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
|
||||
uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
|
||||
int64_t Addend = FullImmVal - (AddrA - AddrB);
|
||||
|
||||
// addend = Encoded - Expected
|
||||
// = Encoded - (AddrA - AddrB)
|
||||
|
||||
DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
|
||||
<< ", Addend: " << Addend << ", SectionA ID: " << SectionAID
|
||||
<< ", SectionAOffset: " << SectionAOffset
|
||||
<< ", SectionB ID: " << SectionBID
|
||||
<< ", SectionBOffset: " << SectionBOffset << "\n");
|
||||
RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
|
||||
SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
|
||||
HalfDiffKindBits);
|
||||
|
||||
addRelocationForSection(R, SectionAID);
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
@ -1,249 +0,0 @@
|
||||
//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H
|
||||
|
||||
#include "../RuntimeDyldMachO.h"
|
||||
#include <string>
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RuntimeDyldMachOI386
|
||||
: public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> {
|
||||
public:
|
||||
|
||||
typedef uint32_t TargetPtrT;
|
||||
|
||||
RuntimeDyldMachOI386(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldMachOCRTPBase(MM, Resolver) {}
|
||||
|
||||
unsigned getMaxStubSize() override { return 0; }
|
||||
|
||||
unsigned getStubAlignment() override { return 1; }
|
||||
|
||||
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());
|
||||
uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
|
||||
|
||||
if (Obj.isRelocationScattered(RelInfo)) {
|
||||
if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
|
||||
RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
|
||||
return processSECTDIFFRelocation(SectionID, RelI, Obj,
|
||||
ObjSectionToID);
|
||||
else if (RelType == MachO::GENERIC_RELOC_VANILLA)
|
||||
return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
|
||||
return make_error<RuntimeDyldError>(("Unhandled I386 scattered relocation "
|
||||
"type: " + Twine(RelType)).str());
|
||||
}
|
||||
|
||||
switch (RelType) {
|
||||
UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PAIR);
|
||||
UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PB_LA_PTR);
|
||||
UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_TLV);
|
||||
default:
|
||||
if (RelType > MachO::GENERIC_RELOC_TLV)
|
||||
return make_error<RuntimeDyldError>(("MachO I386 relocation type " +
|
||||
Twine(RelType) +
|
||||
" is out of range").str());
|
||||
break;
|
||||
}
|
||||
|
||||
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
|
||||
RE.Addend = memcpyAddend(RE);
|
||||
RelocationValueRef Value;
|
||||
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
|
||||
Value = *ValueOrErr;
|
||||
else
|
||||
return ValueOrErr.takeError();
|
||||
|
||||
// Addends for external, PC-rel relocations on i386 point back to the zero
|
||||
// offset. Calculate the final offset from the relocation target instead.
|
||||
// This allows us to use the same logic for both external and internal
|
||||
// relocations in resolveI386RelocationRef.
|
||||
// bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
|
||||
// if (IsExtern && RE.IsPCRel) {
|
||||
// uint64_t RelocAddr = 0;
|
||||
// RelI->getAddress(RelocAddr);
|
||||
// Value.Addend += RelocAddr + 4;
|
||||
// }
|
||||
if (RE.IsPCRel)
|
||||
makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
|
||||
|
||||
RE.Addend = Value.Offset;
|
||||
|
||||
if (Value.SymbolName)
|
||||
addRelocationForSymbol(RE, Value.SymbolName);
|
||||
else
|
||||
addRelocationForSection(RE, Value.SectionID);
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
||||
DEBUG(dumpRelocationToResolve(RE, Value));
|
||||
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
||||
|
||||
if (RE.IsPCRel) {
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
|
||||
Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
|
||||
}
|
||||
|
||||
switch (RE.RelType) {
|
||||
case MachO::GENERIC_RELOC_VANILLA:
|
||||
writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
|
||||
break;
|
||||
case MachO::GENERIC_RELOC_SECTDIFF:
|
||||
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
|
||||
uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
|
||||
uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
|
||||
assert((Value == SectionABase || Value == SectionBBase) &&
|
||||
"Unexpected SECTDIFF relocation value.");
|
||||
Value = SectionABase - SectionBBase + RE.Addend;
|
||||
writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Invalid relocation type!");
|
||||
}
|
||||
}
|
||||
|
||||
Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
|
||||
const SectionRef &Section) {
|
||||
StringRef Name;
|
||||
Section.getName(Name);
|
||||
|
||||
if (Name == "__jump_table")
|
||||
return populateJumpTable(cast<MachOObjectFile>(Obj), Section, SectionID);
|
||||
else if (Name == "__pointers")
|
||||
return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
|
||||
Section, SectionID);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
Expected<relocation_iterator>
|
||||
processSECTDIFFRelocation(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());
|
||||
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
uint32_t RelocType = Obj.getAnyRelocationType(RE);
|
||||
bool IsPCRel = Obj.getAnyRelocationPCRel(RE);
|
||||
unsigned Size = Obj.getAnyRelocationLength(RE);
|
||||
uint64_t Offset = RelI->getOffset();
|
||||
uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
|
||||
unsigned NumBytes = 1 << Size;
|
||||
uint64_t Addend = readBytesUnaligned(LocalAddress, NumBytes);
|
||||
|
||||
++RelI;
|
||||
MachO::any_relocation_info RE2 =
|
||||
Obj.getRelocation(RelI->getRawDataRefImpl());
|
||||
|
||||
uint32_t AddrA = Obj.getScatteredRelocationValue(RE);
|
||||
section_iterator SAI = getSectionByAddress(Obj, AddrA);
|
||||
assert(SAI != Obj.section_end() && "Can't find section for address A");
|
||||
uint64_t SectionABase = SAI->getAddress();
|
||||
uint64_t SectionAOffset = AddrA - SectionABase;
|
||||
SectionRef SectionA = *SAI;
|
||||
bool IsCode = SectionA.isText();
|
||||
uint32_t SectionAID = ~0U;
|
||||
if (auto SectionAIDOrErr =
|
||||
findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID))
|
||||
SectionAID = *SectionAIDOrErr;
|
||||
else
|
||||
return SectionAIDOrErr.takeError();
|
||||
|
||||
uint32_t AddrB = Obj.getScatteredRelocationValue(RE2);
|
||||
section_iterator SBI = getSectionByAddress(Obj, AddrB);
|
||||
assert(SBI != Obj.section_end() && "Can't find section for address B");
|
||||
uint64_t SectionBBase = SBI->getAddress();
|
||||
uint64_t SectionBOffset = AddrB - SectionBBase;
|
||||
SectionRef SectionB = *SBI;
|
||||
uint32_t SectionBID = ~0U;
|
||||
if (auto SectionBIDOrErr =
|
||||
findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID))
|
||||
SectionBID = *SectionBIDOrErr;
|
||||
else
|
||||
return SectionBIDOrErr.takeError();
|
||||
|
||||
// Compute the addend 'C' from the original expression 'A - B + C'.
|
||||
Addend -= AddrA - AddrB;
|
||||
|
||||
DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
|
||||
<< ", Addend: " << Addend << ", SectionA ID: " << SectionAID
|
||||
<< ", SectionAOffset: " << SectionAOffset
|
||||
<< ", SectionB ID: " << SectionBID
|
||||
<< ", SectionBOffset: " << SectionBOffset << "\n");
|
||||
RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
|
||||
SectionAOffset, SectionBID, SectionBOffset,
|
||||
IsPCRel, Size);
|
||||
|
||||
addRelocationForSection(R, SectionAID);
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
// Populate stubs in __jump_table section.
|
||||
Error populateJumpTable(const MachOObjectFile &Obj,
|
||||
const SectionRef &JTSection,
|
||||
unsigned JTSectionID) {
|
||||
MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
|
||||
MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
|
||||
uint32_t JTSectionSize = Sec32.size;
|
||||
unsigned FirstIndirectSymbol = Sec32.reserved1;
|
||||
unsigned JTEntrySize = Sec32.reserved2;
|
||||
unsigned NumJTEntries = JTSectionSize / JTEntrySize;
|
||||
uint8_t *JTSectionAddr = getSectionAddress(JTSectionID);
|
||||
unsigned JTEntryOffset = 0;
|
||||
|
||||
if (JTSectionSize % JTEntrySize != 0)
|
||||
return make_error<RuntimeDyldError>("Jump-table section does not contain "
|
||||
"a whole number of stubs?");
|
||||
|
||||
for (unsigned i = 0; i < NumJTEntries; ++i) {
|
||||
unsigned SymbolIndex =
|
||||
Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
|
||||
symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
|
||||
Expected<StringRef> IndirectSymbolName = SI->getName();
|
||||
if (!IndirectSymbolName)
|
||||
return IndirectSymbolName.takeError();
|
||||
uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset;
|
||||
createStubFunction(JTEntryAddr);
|
||||
RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
|
||||
MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
|
||||
addRelocationForSymbol(RE, *IndirectSymbolName);
|
||||
JTEntryOffset += JTEntrySize;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
@ -1,240 +0,0 @@
|
||||
//===-- RuntimeDyldMachOX86_64.h ---- MachO/X86_64 specific code. -*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H
|
||||
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H
|
||||
|
||||
#include "../RuntimeDyldMachO.h"
|
||||
#include <string>
|
||||
|
||||
#define DEBUG_TYPE "dyld"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RuntimeDyldMachOX86_64
|
||||
: public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> {
|
||||
public:
|
||||
|
||||
typedef uint64_t TargetPtrT;
|
||||
|
||||
RuntimeDyldMachOX86_64(RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver)
|
||||
: RuntimeDyldMachOCRTPBase(MM, Resolver) {}
|
||||
|
||||
unsigned getMaxStubSize() override { return 8; }
|
||||
|
||||
unsigned getStubAlignment() override { return 1; }
|
||||
|
||||
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());
|
||||
uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
|
||||
|
||||
if (RelType == MachO::X86_64_RELOC_SUBTRACTOR)
|
||||
return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
|
||||
|
||||
assert(!Obj.isRelocationScattered(RelInfo) &&
|
||||
"Scattered relocations not supported on X86_64");
|
||||
|
||||
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
|
||||
RE.Addend = memcpyAddend(RE);
|
||||
RelocationValueRef Value;
|
||||
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
|
||||
Value = *ValueOrErr;
|
||||
else
|
||||
return ValueOrErr.takeError();
|
||||
|
||||
bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
|
||||
if (!IsExtern && RE.IsPCRel)
|
||||
makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
|
||||
|
||||
switch (RelType) {
|
||||
UNIMPLEMENTED_RELOC(MachO::X86_64_RELOC_TLV);
|
||||
default:
|
||||
if (RelType > MachO::X86_64_RELOC_TLV)
|
||||
return make_error<RuntimeDyldError>(("MachO X86_64 relocation type " +
|
||||
Twine(RelType) +
|
||||
" is out of range").str());
|
||||
break;
|
||||
}
|
||||
|
||||
if (RE.RelType == MachO::X86_64_RELOC_GOT ||
|
||||
RE.RelType == MachO::X86_64_RELOC_GOT_LOAD)
|
||||
processGOTRelocation(RE, Value, Stubs);
|
||||
else {
|
||||
RE.Addend = Value.Offset;
|
||||
if (Value.SymbolName)
|
||||
addRelocationForSymbol(RE, Value.SymbolName);
|
||||
else
|
||||
addRelocationForSection(RE, Value.SectionID);
|
||||
}
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
|
||||
DEBUG(dumpRelocationToResolve(RE, Value));
|
||||
const SectionEntry &Section = Sections[RE.SectionID];
|
||||
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
||||
|
||||
// If the relocation is PC-relative, the value to be encoded is the
|
||||
// pointer difference.
|
||||
if (RE.IsPCRel) {
|
||||
// FIXME: It seems this value needs to be adjusted by 4 for an effective
|
||||
// PC address. Is that expected? Only for branches, perhaps?
|
||||
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
|
||||
Value -= FinalAddress + 4;
|
||||
}
|
||||
|
||||
switch (RE.RelType) {
|
||||
default:
|
||||
llvm_unreachable("Invalid relocation type!");
|
||||
case MachO::X86_64_RELOC_SIGNED_1:
|
||||
case MachO::X86_64_RELOC_SIGNED_2:
|
||||
case MachO::X86_64_RELOC_SIGNED_4:
|
||||
case MachO::X86_64_RELOC_SIGNED:
|
||||
case MachO::X86_64_RELOC_UNSIGNED:
|
||||
case MachO::X86_64_RELOC_BRANCH:
|
||||
writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
|
||||
break;
|
||||
case MachO::X86_64_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
|
||||
const SectionRef &Section) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
void processGOTRelocation(const RelocationEntry &RE,
|
||||
RelocationValueRef &Value, StubMap &Stubs) {
|
||||
SectionEntry &Section = Sections[RE.SectionID];
|
||||
assert(RE.IsPCRel);
|
||||
assert(RE.Size == 2);
|
||||
Value.Offset -= RE.Addend;
|
||||
RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
|
||||
uint8_t *Addr;
|
||||
if (i != Stubs.end()) {
|
||||
Addr = Section.getAddressWithOffset(i->second);
|
||||
} else {
|
||||
Stubs[Value] = Section.getStubOffset();
|
||||
uint8_t *GOTEntry = Section.getAddressWithOffset(Section.getStubOffset());
|
||||
RelocationEntry GOTRE(RE.SectionID, Section.getStubOffset(),
|
||||
MachO::X86_64_RELOC_UNSIGNED, Value.Offset, false,
|
||||
3);
|
||||
if (Value.SymbolName)
|
||||
addRelocationForSymbol(GOTRE, Value.SymbolName);
|
||||
else
|
||||
addRelocationForSection(GOTRE, Value.SectionID);
|
||||
Section.advanceStubOffset(8);
|
||||
Addr = GOTEntry;
|
||||
}
|
||||
RelocationEntry TargetRE(RE.SectionID, RE.Offset,
|
||||
MachO::X86_64_RELOC_UNSIGNED, RE.Addend, true, 2);
|
||||
resolveRelocation(TargetRE, (uint64_t)Addr);
|
||||
}
|
||||
|
||||
Expected<relocation_iterator>
|
||||
processSubtractRelocation(unsigned SectionID, relocation_iterator RelI,
|
||||
const MachOObjectFile &BaseObj,
|
||||
ObjSectionToIDMap &ObjSectionToID) {
|
||||
const MachOObjectFile &Obj =
|
||||
static_cast<const MachOObjectFile&>(BaseObj);
|
||||
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;
|
||||
int64_t Addend =
|
||||
SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8);
|
||||
|
||||
unsigned SectionBID = ~0U;
|
||||
uint64_t SectionBOffset = 0;
|
||||
|
||||
MachO::any_relocation_info RelInfo =
|
||||
Obj.getRelocation(RelI->getRawDataRefImpl());
|
||||
|
||||
bool AIsExternal = BaseObj.getPlainRelocationExternal(RelInfo);
|
||||
|
||||
if (AIsExternal) {
|
||||
Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName();
|
||||
if (!SubtrahendNameOrErr)
|
||||
return SubtrahendNameOrErr.takeError();
|
||||
auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr);
|
||||
SectionBID = SubtrahendI->second.getSectionID();
|
||||
SectionBOffset = SubtrahendI->second.getOffset();
|
||||
} else {
|
||||
SectionRef SecB = Obj.getAnyRelocationSection(RelInfo);
|
||||
bool IsCode = SecB.isText();
|
||||
Expected<unsigned> SectionBIDOrErr =
|
||||
findOrEmitSection(Obj, SecB, IsCode, ObjSectionToID);
|
||||
if (!SectionBIDOrErr)
|
||||
return SectionBIDOrErr.takeError();
|
||||
SectionBID = *SectionBIDOrErr;
|
||||
Addend += SecB.getAddress();
|
||||
}
|
||||
|
||||
++RelI;
|
||||
|
||||
unsigned SectionAID = ~0U;
|
||||
uint64_t SectionAOffset = 0;
|
||||
|
||||
RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
|
||||
|
||||
bool BIsExternal = BaseObj.getPlainRelocationExternal(RelInfo);
|
||||
if (BIsExternal) {
|
||||
Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName();
|
||||
if (!MinuendNameOrErr)
|
||||
return MinuendNameOrErr.takeError();
|
||||
auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr);
|
||||
SectionAID = MinuendI->second.getSectionID();
|
||||
SectionAOffset = MinuendI->second.getOffset();
|
||||
} else {
|
||||
SectionRef SecA = Obj.getAnyRelocationSection(RelInfo);
|
||||
bool IsCode = SecA.isText();
|
||||
Expected<unsigned> SectionAIDOrErr =
|
||||
findOrEmitSection(Obj, SecA, IsCode, ObjSectionToID);
|
||||
if (!SectionAIDOrErr)
|
||||
return SectionAIDOrErr.takeError();
|
||||
SectionAID = *SectionAIDOrErr;
|
||||
Addend -= SecA.getAddress();
|
||||
}
|
||||
|
||||
RelocationEntry R(SectionID, Offset, MachO::X86_64_RELOC_SUBTRACTOR, (uint64_t)Addend,
|
||||
SectionAID, SectionAOffset, SectionBID, SectionBOffset,
|
||||
false, Size);
|
||||
|
||||
addRelocationForSection(R, SectionAID);
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user