Skip to content

Commit

Permalink
[mips][rtdyld] Move MIPS relocation resolution to a subclass and impl…
Browse files Browse the repository at this point in the history
…ement N32 relocations

N32 relocations are only correct for individual relocations at the moment.
Support for relocation composition will follow in a later patch.

Patch By: Daniel Sanders

Reviwers: vkalintiris, atanasyan

Differential Revision: https://reviews.llvm.org/D27467

llvm-svn: 289532
  • Loading branch information
Simon Dardis committed Dec 13, 2016
1 parent 7209bb9 commit c97cfb6
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 306 deletions.
1 change: 1 addition & 0 deletions llvm/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt
Expand Up @@ -6,6 +6,7 @@ add_llvm_library(LLVMRuntimeDyld
RuntimeDyldCOFF.cpp
RuntimeDyldELF.cpp
RuntimeDyldMachO.cpp
Targets/RuntimeDyldELFMips.cpp

DEPENDS
intrinsics_gen
Expand Down
9 changes: 6 additions & 3 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
Expand Up @@ -1023,10 +1023,11 @@ createRuntimeDyldCOFF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
}

static std::unique_ptr<RuntimeDyldELF>
createRuntimeDyldELF(RuntimeDyld::MemoryManager &MM,
createRuntimeDyldELF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
JITSymbolResolver &Resolver, bool ProcessAllSections,
RuntimeDyldCheckerImpl *Checker) {
std::unique_ptr<RuntimeDyldELF> Dyld(new RuntimeDyldELF(MM, Resolver));
std::unique_ptr<RuntimeDyldELF> Dyld =
RuntimeDyldELF::create(Arch, MM, Resolver);
Dyld->setProcessAllSections(ProcessAllSections);
Dyld->setRuntimeDyldChecker(Checker);
return Dyld;
Expand All @@ -1048,7 +1049,9 @@ std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
RuntimeDyld::loadObject(const ObjectFile &Obj) {
if (!Dyld) {
if (Obj.isELF())
Dyld = createRuntimeDyldELF(MemMgr, Resolver, ProcessAllSections, Checker);
Dyld =
createRuntimeDyldELF(static_cast<Triple::ArchType>(Obj.getArch()),
MemMgr, Resolver, ProcessAllSections, Checker);
else if (Obj.isMachO())
Dyld = createRuntimeDyldMachO(
static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver,
Expand Down
298 changes: 16 additions & 282 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Expand Up @@ -13,6 +13,7 @@

#include "RuntimeDyldELF.h"
#include "RuntimeDyldCheckerImpl.h"
#include "Targets/RuntimeDyldELFMips.h"
#include "llvm/ADT/IntervalMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -211,6 +212,21 @@ void RuntimeDyldELF::deregisterEHFrames() {
RegisteredEHFrameSections.clear();
}

std::unique_ptr<RuntimeDyldELF>
llvm::RuntimeDyldELF::create(Triple::ArchType Arch,
RuntimeDyld::MemoryManager &MemMgr,
JITSymbolResolver &Resolver) {
switch (Arch) {
default:
return make_unique<RuntimeDyldELF>(MemMgr, Resolver);
case Triple::mips:
case Triple::mipsel:
case Triple::mips64:
case Triple::mips64el:
return make_unique<RuntimeDyldELFMips>(MemMgr, Resolver);
}
}

std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
RuntimeDyldELF::loadObject(const object::ObjectFile &O) {
if (auto ObjSectionToIDOrErr = loadObjectImpl(O))
Expand Down Expand Up @@ -498,24 +514,6 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section,
}
}

void RuntimeDyldELF::resolveMIPSRelocation(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() << "resolveMIPSRelocation, LocalAddress: "
<< Section.getAddressWithOffset(Offset) << " FinalAddress: "
<< format("%p", Section.getLoadAddressWithOffset(Offset))
<< " Value: " << format("%x", Value)
<< " Type: " << format("%x", Type)
<< " Addend: " << format("%x", Addend) << "\n");

Value = evaluateMIPS32Relocation(Section, Offset, Value, Type);

applyMIPSRelocation(TargetPtr, Value, Type);
}

void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) {
if (Arch == Triple::UnknownArch ||
!StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) {
Expand All @@ -531,254 +529,6 @@ void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) {
IsMipsN64ABI = Obj.getFileFormatName().equals("ELF64-mips");
}

void RuntimeDyldELF::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 RuntimeDyldELF::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);
}

int64_t RuntimeDyldELF::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
RuntimeDyldELF::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)
<< " 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_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 RuntimeDyldELF::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_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;
}
}

// Return the .TOC. section and offset.
Error RuntimeDyldELF::findPPC64TOCSection(const ELFObjectFileBase &Obj,
ObjSectionToIDMap &LocalSections,
Expand Down Expand Up @@ -1123,22 +873,6 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type,
(uint32_t)(Addend & 0xffffffffL));
break;
case Triple::mips: // Fall through.
case Triple::mipsel:
case Triple::mips64:
case Triple::mips64el:
if (IsMipsO32ABI)
resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL),
Type, (uint32_t)(Addend & 0xffffffffL));
else if (IsMipsN32ABI)
resolveMIPSN32Relocation(Section, Offset, Value, Type, Addend, SymOffset,
SectionID);
else if (IsMipsN64ABI)
resolveMIPSN64Relocation(Section, Offset, Value, Type, Addend, SymOffset,
SectionID);
else
llvm_unreachable("Mips ABI not handled");
break;
case Triple::ppc:
resolvePPC32Relocation(Section, Offset, Value, Type, Addend);
break;
Expand Down

0 comments on commit c97cfb6

Please sign in to comment.