mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-22 13:29:44 +00:00
PowerPC: Initial support for PowerPC64 MCJIT
This patch adds initial support for MCJIT for PPC64-elf-abi. The TOC relocation and ODP handling is implemented. It fixes the following ExecutionEngine testcases: ExecutionEngine/2003-01-04-ArgumentBug.ll ExecutionEngine/2003-01-04-LoopTest.ll ExecutionEngine/2003-01-04-PhiTest.ll ExecutionEngine/2003-01-09-SARTest.ll ExecutionEngine/2003-01-10-FUCOM.ll ExecutionEngine/2003-01-15-AlignmentTest.ll ExecutionEngine/2003-05-11-PHIRegAllocBug.ll ExecutionEngine/2003-06-04-bzip2-bug.ll ExecutionEngine/2003-06-05-PHIBug.ll ExecutionEngine/2003-08-15-AllocaAssertion.ll ExecutionEngine/2003-08-21-EnvironmentTest.ll ExecutionEngine/2003-08-23-RegisterAllocatePhysReg.ll ExecutionEngine/2003-10-18-PHINode-ConstantExpr-CondCode-Failure.ll ExecutionEngine/simplesttest.ll ExecutionEngine/simpletest.ll ExecutionEngine/stubs.ll ExecutionEngine/test-arith.ll ExecutionEngine/test-branch.ll ExecutionEngine/test-call-no-external-funcs.ll ExecutionEngine/test-cast.ll ExecutionEngine/test-common-symbols.ll ExecutionEngine/test-constantexpr.ll ExecutionEngine/test-fp-no-external-funcs.ll ExecutionEngine/test-fp.ll ExecutionEngine/test-global-init-nonzero.ll ExecutionEngine/test-global.ll ExecutionEngine/test-loadstore.ll ExecutionEngine/test-local.ll ExecutionEngine/test-logical.ll ExecutionEngine/test-loop.ll ExecutionEngine/test-phi.ll ExecutionEngine/test-ret.ll ExecutionEngine/test-return.ll ExecutionEngine/test-setcond-fp.ll ExecutionEngine/test-setcond-int.ll ExecutionEngine/test-shift.ll git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166678 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
aa71428378
commit
6e8946c528
@ -190,7 +190,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
|
|||||||
if (!Addr)
|
if (!Addr)
|
||||||
report_fatal_error("Unable to allocate memory for common symbols!");
|
report_fatal_error("Unable to allocate memory for common symbols!");
|
||||||
uint64_t Offset = 0;
|
uint64_t Offset = 0;
|
||||||
Sections.push_back(SectionEntry(Addr, TotalSize, TotalSize, 0));
|
Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, TotalSize, 0));
|
||||||
memset(Addr, 0, TotalSize);
|
memset(Addr, 0, TotalSize);
|
||||||
|
|
||||||
DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID
|
DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID
|
||||||
@ -233,10 +233,12 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
|
|||||||
bool IsVirtual;
|
bool IsVirtual;
|
||||||
bool IsZeroInit;
|
bool IsZeroInit;
|
||||||
uint64_t DataSize;
|
uint64_t DataSize;
|
||||||
|
StringRef Name;
|
||||||
Check(Section.isRequiredForExecution(IsRequired));
|
Check(Section.isRequiredForExecution(IsRequired));
|
||||||
Check(Section.isVirtual(IsVirtual));
|
Check(Section.isVirtual(IsVirtual));
|
||||||
Check(Section.isZeroInit(IsZeroInit));
|
Check(Section.isZeroInit(IsZeroInit));
|
||||||
Check(Section.getSize(DataSize));
|
Check(Section.getSize(DataSize));
|
||||||
|
Check(Section.getName(Name));
|
||||||
|
|
||||||
unsigned Allocate;
|
unsigned Allocate;
|
||||||
unsigned SectionID = Sections.size();
|
unsigned SectionID = Sections.size();
|
||||||
@ -264,6 +266,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
|
|||||||
memcpy(Addr, pData, DataSize);
|
memcpy(Addr, pData, DataSize);
|
||||||
|
|
||||||
DEBUG(dbgs() << "emitSection SectionID: " << SectionID
|
DEBUG(dbgs() << "emitSection SectionID: " << SectionID
|
||||||
|
<< " Name: " << Name
|
||||||
<< " obj addr: " << format("%p", pData)
|
<< " obj addr: " << format("%p", pData)
|
||||||
<< " new addr: " << format("%p", Addr)
|
<< " new addr: " << format("%p", Addr)
|
||||||
<< " DataSize: " << DataSize
|
<< " DataSize: " << DataSize
|
||||||
@ -279,6 +282,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
|
|||||||
Allocate = 0;
|
Allocate = 0;
|
||||||
Addr = 0;
|
Addr = 0;
|
||||||
DEBUG(dbgs() << "emitSection SectionID: " << SectionID
|
DEBUG(dbgs() << "emitSection SectionID: " << SectionID
|
||||||
|
<< " Name: " << Name
|
||||||
<< " obj addr: " << format("%p", data.data())
|
<< " obj addr: " << format("%p", data.data())
|
||||||
<< " new addr: 0"
|
<< " new addr: 0"
|
||||||
<< " DataSize: " << DataSize
|
<< " DataSize: " << DataSize
|
||||||
@ -287,7 +291,8 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
|
|||||||
<< "\n");
|
<< "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
Sections.push_back(SectionEntry(Addr, Allocate, DataSize,(uintptr_t)pData));
|
Sections.push_back(SectionEntry(Name, Addr, Allocate, DataSize,
|
||||||
|
(uintptr_t)pData));
|
||||||
return SectionID;
|
return SectionID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,6 +357,24 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
|
|||||||
*StubAddr = JrT9Instr;
|
*StubAddr = JrT9Instr;
|
||||||
StubAddr++;
|
StubAddr++;
|
||||||
*StubAddr = NopInstr;
|
*StubAddr = NopInstr;
|
||||||
|
return Addr;
|
||||||
|
} else if (Arch == Triple::ppc64) {
|
||||||
|
// PowerPC64 stub: the address points to a function descriptor
|
||||||
|
// instead of the function itself. Load the function address
|
||||||
|
// on r11 and sets it to control register. Also loads the function
|
||||||
|
// TOC in r2 and environment pointer to r11.
|
||||||
|
writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr)
|
||||||
|
writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr)
|
||||||
|
writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32
|
||||||
|
writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr)
|
||||||
|
writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr)
|
||||||
|
writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1)
|
||||||
|
writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12)
|
||||||
|
writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12)
|
||||||
|
writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11
|
||||||
|
writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2)
|
||||||
|
writeInt32BE(Addr+40, 0x4E800420); // bctr
|
||||||
|
|
||||||
return Addr;
|
return Addr;
|
||||||
}
|
}
|
||||||
return Addr;
|
return Addr;
|
||||||
|
@ -30,6 +30,14 @@ using namespace llvm::object;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static inline
|
||||||
|
error_code check(error_code Err) {
|
||||||
|
if (Err) {
|
||||||
|
report_fatal_error(Err.message());
|
||||||
|
}
|
||||||
|
return Err;
|
||||||
|
}
|
||||||
|
|
||||||
template<support::endianness target_endianness, bool is64Bits>
|
template<support::endianness target_endianness, bool is64Bits>
|
||||||
class DyldELFObject : public ELFObjectFile<target_endianness, is64Bits> {
|
class DyldELFObject : public ELFObjectFile<target_endianness, is64Bits> {
|
||||||
LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
|
LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
|
||||||
@ -340,6 +348,179 @@ void RuntimeDyldELF::resolveMIPSRelocation(uint8_t *LocalAddress,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the .TOC. section address to R_PPC64_TOC relocations.
|
||||||
|
uint64_t RuntimeDyldELF::findPPC64TOC() const {
|
||||||
|
// The TOC consists of sections .got, .toc, .tocbss, .plt in that
|
||||||
|
// order. The TOC starts where the first of these sections starts.
|
||||||
|
SectionList::const_iterator it = Sections.begin();
|
||||||
|
SectionList::const_iterator ite = Sections.end();
|
||||||
|
for (; it != ite; ++it) {
|
||||||
|
if (it->Name == ".got" ||
|
||||||
|
it->Name == ".toc" ||
|
||||||
|
it->Name == ".tocbss" ||
|
||||||
|
it->Name == ".plt")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (it == ite) {
|
||||||
|
// This may happen for
|
||||||
|
// * references to TOC base base (sym@toc, .odp relocation) without
|
||||||
|
// a .toc directive.
|
||||||
|
// In this case just use the first section (which is usually
|
||||||
|
// the .odp) since the code won't reference the .toc base
|
||||||
|
// directly.
|
||||||
|
it = Sections.begin();
|
||||||
|
}
|
||||||
|
assert (it != ite);
|
||||||
|
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
|
||||||
|
// thus permitting a full 64 Kbytes segment.
|
||||||
|
return it->LoadAddress + 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the sections and offset associated with the ODP entry referenced
|
||||||
|
// by Symbol.
|
||||||
|
void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
|
||||||
|
ObjSectionToIDMap &LocalSections,
|
||||||
|
RelocationValueRef &Rel) {
|
||||||
|
// Get the ELF symbol value (st_value) to compare with Relocation offset in
|
||||||
|
// .opd entries
|
||||||
|
|
||||||
|
error_code err;
|
||||||
|
for (section_iterator si = Obj.begin_sections(),
|
||||||
|
se = Obj.end_sections(); si != se; si.increment(err)) {
|
||||||
|
StringRef SectionName;
|
||||||
|
check(si->getName(SectionName));
|
||||||
|
if (SectionName != ".opd")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (relocation_iterator i = si->begin_relocations(),
|
||||||
|
e = si->end_relocations(); i != e;) {
|
||||||
|
check(err);
|
||||||
|
|
||||||
|
// The R_PPC64_ADDR64 relocation indicates the first field
|
||||||
|
// of a .opd entry
|
||||||
|
uint64_t TypeFunc;
|
||||||
|
check(i->getType(TypeFunc));
|
||||||
|
if (TypeFunc != ELF::R_PPC64_ADDR64) {
|
||||||
|
i.increment(err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolRef TargetSymbol;
|
||||||
|
uint64_t TargetSymbolOffset;
|
||||||
|
int64_t TargetAdditionalInfo;
|
||||||
|
check(i->getSymbol(TargetSymbol));
|
||||||
|
check(i->getOffset(TargetSymbolOffset));
|
||||||
|
check(i->getAdditionalInfo(TargetAdditionalInfo));
|
||||||
|
|
||||||
|
i = i.increment(err);
|
||||||
|
if (i == e)
|
||||||
|
break;
|
||||||
|
check(err);
|
||||||
|
|
||||||
|
// Just check if following relocation is a R_PPC64_TOC
|
||||||
|
uint64_t TypeTOC;
|
||||||
|
check(i->getType(TypeTOC));
|
||||||
|
if (TypeTOC != ELF::R_PPC64_TOC)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Finally compares the Symbol value and the target symbol offset
|
||||||
|
// to check if this .opd entry refers to the symbol the relocation
|
||||||
|
// points to.
|
||||||
|
if (Rel.Addend != (intptr_t)TargetSymbolOffset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
section_iterator tsi(Obj.end_sections());
|
||||||
|
check(TargetSymbol.getSection(tsi));
|
||||||
|
Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections);
|
||||||
|
Rel.Addend = (intptr_t)TargetAdditionalInfo;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
llvm_unreachable("Attempting to get address of ODP entry!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relocation masks following the #lo(value), #hi(value), #higher(value),
|
||||||
|
// and #highest(value) macros defined in section 4.5.1. Relocation Types
|
||||||
|
// in PPC-elf64abi document.
|
||||||
|
//
|
||||||
|
static inline
|
||||||
|
uint16_t applyPPClo (uint64_t value)
|
||||||
|
{
|
||||||
|
return value & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint16_t applyPPChi (uint64_t value)
|
||||||
|
{
|
||||||
|
return (value >> 16) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint16_t applyPPChigher (uint64_t value)
|
||||||
|
{
|
||||||
|
return (value >> 32) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint16_t applyPPChighest (uint64_t value)
|
||||||
|
{
|
||||||
|
return (value >> 48) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeDyldELF::resolvePPC64Relocation(uint8_t *LocalAddress,
|
||||||
|
uint64_t FinalAddress,
|
||||||
|
uint64_t Value,
|
||||||
|
uint32_t Type,
|
||||||
|
int64_t Addend) {
|
||||||
|
switch (Type) {
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Relocation type not implemented yet!");
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_ADDR16_LO :
|
||||||
|
writeInt16BE(LocalAddress, applyPPClo (Value + Addend));
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_ADDR16_HI :
|
||||||
|
writeInt16BE(LocalAddress, applyPPChi (Value + Addend));
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_ADDR16_HIGHER :
|
||||||
|
writeInt16BE(LocalAddress, applyPPChigher (Value + Addend));
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_ADDR16_HIGHEST :
|
||||||
|
writeInt16BE(LocalAddress, applyPPChighest (Value + Addend));
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_ADDR14 : {
|
||||||
|
assert(((Value + Addend) & 3) == 0);
|
||||||
|
// Preserve the AA/LK bits in the branch instruction
|
||||||
|
uint8_t aalk = *(LocalAddress+3);
|
||||||
|
writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc));
|
||||||
|
} break;
|
||||||
|
case ELF::R_PPC64_REL24 : {
|
||||||
|
int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend);
|
||||||
|
if (SignExtend32<24>(delta) != delta)
|
||||||
|
llvm_unreachable("Relocation R_PPC64_REL24 overflow");
|
||||||
|
// Generates a 'bl <address>' instruction
|
||||||
|
writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC));
|
||||||
|
} break;
|
||||||
|
case ELF::R_PPC64_ADDR64 :
|
||||||
|
writeInt64BE(LocalAddress, Value + Addend);
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_TOC :
|
||||||
|
writeInt64BE(LocalAddress, findPPC64TOC());
|
||||||
|
break;
|
||||||
|
case ELF::R_PPC64_TOC16 : {
|
||||||
|
uint64_t TOCStart = findPPC64TOC();
|
||||||
|
Value = applyPPClo((Value + Addend) - TOCStart);
|
||||||
|
writeInt16BE(LocalAddress, applyPPClo(Value));
|
||||||
|
} break;
|
||||||
|
case ELF::R_PPC64_TOC16_DS : {
|
||||||
|
uint64_t TOCStart = findPPC64TOC();
|
||||||
|
Value = ((Value + Addend) - TOCStart);
|
||||||
|
writeInt16BE(LocalAddress, applyPPClo(Value));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
|
void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
|
||||||
uint64_t FinalAddress,
|
uint64_t FinalAddress,
|
||||||
uint64_t Value,
|
uint64_t Value,
|
||||||
@ -366,6 +547,9 @@ void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
|
|||||||
(uint32_t)(Value & 0xffffffffL), Type,
|
(uint32_t)(Value & 0xffffffffL), Type,
|
||||||
(uint32_t)(Addend & 0xffffffffL));
|
(uint32_t)(Addend & 0xffffffffL));
|
||||||
break;
|
break;
|
||||||
|
case Triple::ppc64:
|
||||||
|
resolvePPC64Relocation(LocalAddress, FinalAddress, Value, Type, Addend);
|
||||||
|
break;
|
||||||
default: llvm_unreachable("Unsupported CPU type!");
|
default: llvm_unreachable("Unsupported CPU type!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,6 +574,8 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
|
|||||||
RelocationValueRef Value;
|
RelocationValueRef Value;
|
||||||
// First search for the symbol in the local symbol table
|
// First search for the symbol in the local symbol table
|
||||||
SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
|
SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
|
||||||
|
SymbolRef::Type SymType;
|
||||||
|
Symbol.getType(SymType);
|
||||||
if (lsi != Symbols.end()) {
|
if (lsi != Symbols.end()) {
|
||||||
Value.SectionID = lsi->second.first;
|
Value.SectionID = lsi->second.first;
|
||||||
Value.Addend = lsi->second.second;
|
Value.Addend = lsi->second.second;
|
||||||
@ -401,8 +587,6 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
|
|||||||
Value.SectionID = gsi->second.first;
|
Value.SectionID = gsi->second.first;
|
||||||
Value.Addend = gsi->second.second;
|
Value.Addend = gsi->second.second;
|
||||||
} else {
|
} else {
|
||||||
SymbolRef::Type SymType;
|
|
||||||
Symbol.getType(SymType);
|
|
||||||
switch (SymType) {
|
switch (SymType) {
|
||||||
case SymbolRef::ST_Debug: {
|
case SymbolRef::ST_Debug: {
|
||||||
// TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously
|
// TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously
|
||||||
@ -516,6 +700,93 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
|
|||||||
Section.StubOffset, RelType, 0);
|
Section.StubOffset, RelType, 0);
|
||||||
Section.StubOffset += getMaxStubSize();
|
Section.StubOffset += getMaxStubSize();
|
||||||
}
|
}
|
||||||
|
} else if (Arch == Triple::ppc64) {
|
||||||
|
if (RelType == ELF::R_PPC64_REL24) {
|
||||||
|
// A PPC branch relocation will need a stub function if the target is
|
||||||
|
// an external symbol (Symbol::ST_Unknown) or if the target address
|
||||||
|
// is not within the signed 24-bits branch address.
|
||||||
|
SectionEntry &Section = Sections[Rel.SectionID];
|
||||||
|
uint8_t *Target = Section.Address + Rel.Offset;
|
||||||
|
bool RangeOverflow = false;
|
||||||
|
if (SymType != SymbolRef::ST_Unknown) {
|
||||||
|
// A function call may points to the .opd entry, so the final symbol value
|
||||||
|
// in calculated based in the relocation values in .opd section.
|
||||||
|
findOPDEntrySection(Obj, ObjSectionToID, Value);
|
||||||
|
uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend;
|
||||||
|
int32_t delta = static_cast<int32_t>(Target - RelocTarget);
|
||||||
|
// If it is within 24-bits branch range, just set the branch target
|
||||||
|
if (SignExtend32<24>(delta) == delta) {
|
||||||
|
RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
|
||||||
|
if (Value.SymbolName)
|
||||||
|
addRelocationForSymbol(RE, Value.SymbolName);
|
||||||
|
else
|
||||||
|
addRelocationForSection(RE, Value.SectionID);
|
||||||
|
} else {
|
||||||
|
RangeOverflow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SymType == SymbolRef::ST_Unknown || RangeOverflow == true) {
|
||||||
|
// It is an external symbol (SymbolRef::ST_Unknown) or within a range
|
||||||
|
// larger than 24-bits.
|
||||||
|
StubMap::const_iterator i = Stubs.find(Value);
|
||||||
|
if (i != Stubs.end()) {
|
||||||
|
// Symbol function stub already created, just relocate to it
|
||||||
|
resolveRelocation(Target, (uint64_t)Target, (uint64_t)Section.Address
|
||||||
|
+ i->second, RelType, 0);
|
||||||
|
DEBUG(dbgs() << " Stub function found\n");
|
||||||
|
} else {
|
||||||
|
// Create a new stub function.
|
||||||
|
DEBUG(dbgs() << " Create a new stub function\n");
|
||||||
|
Stubs[Value] = Section.StubOffset;
|
||||||
|
uint8_t *StubTargetAddr = createStubFunction(Section.Address +
|
||||||
|
Section.StubOffset);
|
||||||
|
RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address,
|
||||||
|
ELF::R_PPC64_ADDR64, Value.Addend);
|
||||||
|
|
||||||
|
// Generates the 64-bits address loads as exemplified in section
|
||||||
|
// 4.5.1 in PPC64 ELF ABI.
|
||||||
|
RelocationEntry REhst(Rel.SectionID,
|
||||||
|
StubTargetAddr - Section.Address + 2,
|
||||||
|
ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend);
|
||||||
|
RelocationEntry REhr(Rel.SectionID,
|
||||||
|
StubTargetAddr - Section.Address + 6,
|
||||||
|
ELF::R_PPC64_ADDR16_HIGHER, Value.Addend);
|
||||||
|
RelocationEntry REh(Rel.SectionID,
|
||||||
|
StubTargetAddr - Section.Address + 14,
|
||||||
|
ELF::R_PPC64_ADDR16_HI, Value.Addend);
|
||||||
|
RelocationEntry REl(Rel.SectionID,
|
||||||
|
StubTargetAddr - Section.Address + 18,
|
||||||
|
ELF::R_PPC64_ADDR16_LO, Value.Addend);
|
||||||
|
|
||||||
|
if (Value.SymbolName) {
|
||||||
|
addRelocationForSymbol(REhst, Value.SymbolName);
|
||||||
|
addRelocationForSymbol(REhr, Value.SymbolName);
|
||||||
|
addRelocationForSymbol(REh, Value.SymbolName);
|
||||||
|
addRelocationForSymbol(REl, Value.SymbolName);
|
||||||
|
} else {
|
||||||
|
addRelocationForSection(REhst, Value.SectionID);
|
||||||
|
addRelocationForSection(REhr, Value.SectionID);
|
||||||
|
addRelocationForSection(REh, Value.SectionID);
|
||||||
|
addRelocationForSection(REl, Value.SectionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveRelocation(Target, (uint64_t)Target, (uint64_t)Section.Address
|
||||||
|
+ Section.StubOffset, RelType, 0);
|
||||||
|
if (SymType == SymbolRef::ST_Unknown)
|
||||||
|
// Restore the TOC for external calls
|
||||||
|
writeInt32BE(Target+4, 0xE8410028); // ld r2,40(r1)
|
||||||
|
Section.StubOffset += getMaxStubSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
|
||||||
|
// Extra check to avoid relocation againt empty symbols (usually
|
||||||
|
// the R_PPC64_TOC).
|
||||||
|
if (Value.SymbolName && !TargetName.empty())
|
||||||
|
addRelocationForSymbol(RE, Value.SymbolName);
|
||||||
|
else
|
||||||
|
addRelocationForSection(RE, Value.SectionID);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
|
RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
|
||||||
if (Value.SymbolName)
|
if (Value.SymbolName)
|
||||||
|
@ -46,6 +46,12 @@ protected:
|
|||||||
uint32_t Type,
|
uint32_t Type,
|
||||||
int32_t Addend);
|
int32_t Addend);
|
||||||
|
|
||||||
|
void resolvePPC64Relocation(uint8_t *LocalAddress,
|
||||||
|
uint64_t FinalAddress,
|
||||||
|
uint64_t Value,
|
||||||
|
uint32_t Type,
|
||||||
|
int64_t Addend);
|
||||||
|
|
||||||
virtual void resolveRelocation(uint8_t *LocalAddress,
|
virtual void resolveRelocation(uint8_t *LocalAddress,
|
||||||
uint64_t FinalAddress,
|
uint64_t FinalAddress,
|
||||||
uint64_t Value,
|
uint64_t Value,
|
||||||
@ -60,6 +66,11 @@ protected:
|
|||||||
|
|
||||||
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
|
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
|
||||||
|
|
||||||
|
uint64_t findPPC64TOC() const;
|
||||||
|
void findOPDEntrySection(ObjectImage &Obj,
|
||||||
|
ObjSectionToIDMap &LocalSections,
|
||||||
|
RelocationValueRef &Rel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RuntimeDyldELF(RTDyldMemoryManager *mm)
|
RuntimeDyldELF(RTDyldMemoryManager *mm)
|
||||||
: RuntimeDyldImpl(mm) {}
|
: RuntimeDyldImpl(mm) {}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/Support/Format.h"
|
#include "llvm/Support/Format.h"
|
||||||
|
#include "llvm/Support/Host.h"
|
||||||
|
#include "llvm/Support/SwapByteOrder.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Support/system_error.h"
|
#include "llvm/Support/system_error.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -41,6 +43,9 @@ class Twine;
|
|||||||
/// linker.
|
/// linker.
|
||||||
class SectionEntry {
|
class SectionEntry {
|
||||||
public:
|
public:
|
||||||
|
/// Name - section name.
|
||||||
|
StringRef Name;
|
||||||
|
|
||||||
/// Address - address in the linker's memory where the section resides.
|
/// Address - address in the linker's memory where the section resides.
|
||||||
uint8_t *Address;
|
uint8_t *Address;
|
||||||
|
|
||||||
@ -61,9 +66,9 @@ public:
|
|||||||
/// for calculating relocations in some object formats (like MachO).
|
/// for calculating relocations in some object formats (like MachO).
|
||||||
uintptr_t ObjAddress;
|
uintptr_t ObjAddress;
|
||||||
|
|
||||||
SectionEntry(uint8_t *address, size_t size, uintptr_t stubOffset,
|
SectionEntry(StringRef name, uint8_t *address, size_t size,
|
||||||
uintptr_t objAddress)
|
uintptr_t stubOffset, uintptr_t objAddress)
|
||||||
: Address(address), Size(size), LoadAddress((uintptr_t)address),
|
: Name(name), Address(address), Size(size), LoadAddress((uintptr_t)address),
|
||||||
StubOffset(stubOffset), ObjAddress(objAddress) {}
|
StubOffset(stubOffset), ObjAddress(objAddress) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -163,6 +168,8 @@ protected:
|
|||||||
return 8; // 32-bit instruction and 32-bit address
|
return 8; // 32-bit instruction and 32-bit address
|
||||||
else if (Arch == Triple::mipsel)
|
else if (Arch == Triple::mipsel)
|
||||||
return 16;
|
return 16;
|
||||||
|
else if (Arch == Triple::ppc64)
|
||||||
|
return 44;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -185,6 +192,35 @@ protected:
|
|||||||
return (uint8_t*)Sections[SectionID].Address;
|
return (uint8_t*)Sections[SectionID].Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeInt16BE(uint8_t *Addr, uint16_t Value) {
|
||||||
|
if (sys::isLittleEndianHost())
|
||||||
|
Value = sys::SwapByteOrder(Value);
|
||||||
|
*Addr = (Value >> 8) & 0xFF;
|
||||||
|
*(Addr+1) = Value & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeInt32BE(uint8_t *Addr, uint32_t Value) {
|
||||||
|
if (sys::isLittleEndianHost())
|
||||||
|
Value = sys::SwapByteOrder(Value);
|
||||||
|
*Addr = (Value >> 24) & 0xFF;
|
||||||
|
*(Addr+1) = (Value >> 16) & 0xFF;
|
||||||
|
*(Addr+2) = (Value >> 8) & 0xFF;
|
||||||
|
*(Addr+3) = Value & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeInt64BE(uint8_t *Addr, uint64_t Value) {
|
||||||
|
if (sys::isLittleEndianHost())
|
||||||
|
Value = sys::SwapByteOrder(Value);
|
||||||
|
*Addr = (Value >> 56) & 0xFF;
|
||||||
|
*(Addr+1) = (Value >> 48) & 0xFF;
|
||||||
|
*(Addr+2) = (Value >> 40) & 0xFF;
|
||||||
|
*(Addr+3) = (Value >> 32) & 0xFF;
|
||||||
|
*(Addr+4) = (Value >> 24) & 0xFF;
|
||||||
|
*(Addr+5) = (Value >> 16) & 0xFF;
|
||||||
|
*(Addr+6) = (Value >> 8) & 0xFF;
|
||||||
|
*(Addr+7) = Value & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Given the common symbols discovered in the object file, emit a
|
/// \brief Given the common symbols discovered in the object file, emit a
|
||||||
/// new section for them and update the symbol mappings in the object and
|
/// new section for them and update the symbol mappings in the object and
|
||||||
/// symbol table.
|
/// symbol table.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user