Skip to content

Commit

Permalink
[Mips64] Add support for MCJIT for MIPS64r2 and MIPS64r6
Browse files Browse the repository at this point in the history
Add support for resolving MIPS64r2 and MIPS64r6 relocations in MCJIT.

Patch by Vladimir Radosavljevic.

Differential Revision: http://reviews.llvm.org/D9667

llvm-svn: 238424
  • Loading branch information
petar-jovanovic committed May 28, 2015
1 parent fb7d5b8 commit 9720283
Show file tree
Hide file tree
Showing 32 changed files with 469 additions and 33 deletions.
3 changes: 2 additions & 1 deletion llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
// Save information about our target
Arch = (Triple::ArchType)Obj.getArch();
IsTargetLittleEndian = Obj.isLittleEndian();
setMipsABI(Obj);

// Compute the memory size required to load all sections to be loaded
// and pass this information to the memory manager
Expand Down Expand Up @@ -689,7 +690,7 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr,
// and stubs for branches Thumb - ARM and ARM - Thumb.
writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc,<label>
return Addr + 4;
} else if (Arch == Triple::mipsel || Arch == Triple::mips) {
} else if (IsMipsO32ABI) {
// 0: 3c190000 lui t9,%hi(addr).
// 4: 27390000 addiu t9,t9,%lo(addr).
// 8: 03200008 jr t9.
Expand Down
253 changes: 247 additions & 6 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,199 @@ void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section,
}
}

void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) {
if (!StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) {
IsMipsO32ABI = false;
IsMipsN64ABI = false;
return;
}
unsigned AbiVariant;
Obj.getPlatformFlags(AbiVariant);
IsMipsO32ABI = AbiVariant & ELF::EF_MIPS_ABI_O32;
IsMipsN64ABI = Obj.getFileFormatName().equals("ELF64-mips");
if (AbiVariant & ELF::EF_MIPS_ABI2)
llvm_unreachable("Mips N32 ABI is not supported yet");
}

void RuntimeDyldELF::resolveMIPS64Relocation(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);
}
applyMIPS64Relocation(Section.Address + Offset, CalculatedValue, RelType);
}

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.Address + Offset)
<< " FinalAddress: 0x"
<< format("%llx", Section.LoadAddress + 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, 8);

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, 8);

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.LoadAddress + Offset);
return ((Value + Addend - FinalAddress - 4) >> 2) & 0xffff;
}
case ELF::R_MIPS_PC18_S3: {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
return ((Value + Addend - ((FinalAddress | 7) ^ 7)) >> 3) & 0x3ffff;
}
case ELF::R_MIPS_PC19_S2: {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
return ((Value + Addend - FinalAddress) >> 2) & 0x7ffff;
}
case ELF::R_MIPS_PC21_S2: {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff;
}
case ELF::R_MIPS_PC26_S2: {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff;
}
case ELF::R_MIPS_PCHI16: {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff;
}
case ELF::R_MIPS_PCLO16: {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
return (Value + Addend - FinalAddress) & 0xffff;
}
}
return 0;
}

void RuntimeDyldELF::applyMIPS64Relocation(uint8_t *TargetPtr,
int64_t CalculatedValue,
uint32_t Type) {
uint32_t Insn = readBytesUnaligned(TargetPtr, 4);

switch (Type) {
default:
break;
case ELF::R_MIPS_32:
case ELF::R_MIPS_GPREL32:
writeBytesUnaligned(CalculatedValue & 0xffffffff, TargetPtr, 4);
break;
case ELF::R_MIPS_64:
case ELF::R_MIPS_SUB:
writeBytesUnaligned(CalculatedValue, TargetPtr, 8);
break;
case ELF::R_MIPS_26:
case ELF::R_MIPS_PC26_S2:
Insn = (Insn & 0xfc000000) | CalculatedValue;
writeBytesUnaligned(Insn, TargetPtr, 4);
break;
case ELF::R_MIPS_GPREL16:
Insn = (Insn & 0xffff0000) | (CalculatedValue & 0xffff);
writeBytesUnaligned(Insn, TargetPtr, 4);
break;
case ELF::R_MIPS_HI16:
case ELF::R_MIPS_LO16:
case ELF::R_MIPS_PCHI16:
case ELF::R_MIPS_PCLO16:
case ELF::R_MIPS_PC16:
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) | CalculatedValue;
writeBytesUnaligned(Insn, TargetPtr, 4);
break;
case ELF::R_MIPS_PC18_S3:
Insn = (Insn & 0xfffc0000) | CalculatedValue;
writeBytesUnaligned(Insn, TargetPtr, 4);
break;
case ELF::R_MIPS_PC19_S2:
Insn = (Insn & 0xfff80000) | CalculatedValue;
writeBytesUnaligned(Insn, TargetPtr, 4);
break;
case ELF::R_MIPS_PC21_S2:
Insn = (Insn & 0xffe00000) | CalculatedValue;
writeBytesUnaligned(Insn, TargetPtr, 4);
break;
}
}

// Return the .TOC. section and offset.
void RuntimeDyldELF::findPPC64TOCSection(const ObjectFile &Obj,
ObjSectionToIDMap &LocalSections,
Expand Down Expand Up @@ -784,13 +977,13 @@ void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE,
uint64_t Value) {
const SectionEntry &Section = Sections[RE.SectionID];
return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
RE.SymOffset);
RE.SymOffset, RE.SectionID);
}

void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
uint64_t Offset, uint64_t Value,
uint32_t Type, int64_t Addend,
uint64_t SymOffset) {
uint64_t SymOffset, SID SectionID) {
switch (Arch) {
case Triple::x86_64:
resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset);
Expand All @@ -812,8 +1005,16 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
break;
case Triple::mips: // Fall through.
case Triple::mipsel:
resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL),
Type, (uint32_t)(Addend & 0xffffffffL));
case Triple::mips64:
case Triple::mips64el:
if (IsMipsO32ABI)
resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL),
Type, (uint32_t)(Addend & 0xffffffffL));
else if (IsMipsN64ABI)
resolveMIPS64Relocation(Section, Offset, Value, Type, Addend, SymOffset,
SectionID);
else
llvm_unreachable("Mips ABI not handled");
break;
case Triple::ppc64: // Fall through.
case Triple::ppc64le:
Expand Down Expand Up @@ -999,7 +1200,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
}
processSimpleRelocation(SectionID, Offset, RelType, Value);
}
} else if ((Arch == Triple::mipsel || Arch == Triple::mips)) {
} else if (IsMipsO32ABI) {
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(computePlaceholderAddress(SectionID, Offset));
if (RelType == ELF::R_MIPS_26) {
// This is an Mips branch relocation, need to use a stub function.
Expand Down Expand Up @@ -1054,6 +1255,23 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
Value.Addend += *Placeholder;
processSimpleRelocation(SectionID, Offset, RelType, Value);
}
} else if (IsMipsN64ABI) {
uint32_t r_type = RelType & 0xff;
RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
if (r_type == ELF::R_MIPS_CALL16 || r_type == ELF::R_MIPS_GOT_PAGE
|| r_type == ELF::R_MIPS_GOT_DISP) {
StringMap<uint64_t>::iterator i = GOTSymbolOffsets.find(TargetName);
if (i != GOTSymbolOffsets.end())
RE.SymOffset = i->second;
else {
RE.SymOffset = allocateGOTEntries(SectionID, 1);
GOTSymbolOffsets[TargetName] = RE.SymOffset;
}
}
if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
addRelocationForSection(RE, Value.SectionID);
} else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) {
if (RelType == ELF::R_PPC64_REL24) {
// Determine ABI variant in use for this object.
Expand Down Expand Up @@ -1356,9 +1574,18 @@ size_t RuntimeDyldELF::getGOTEntrySize() {
case Triple::x86:
case Triple::arm:
case Triple::thumb:
Result = sizeof(uint32_t);
break;
case Triple::mips:
case Triple::mipsel:
Result = sizeof(uint32_t);
case Triple::mips64:
case Triple::mips64el:
if (IsMipsO32ABI)
Result = sizeof(uint32_t);
else if (IsMipsN64ABI)
Result = sizeof(uint64_t);
else
llvm_unreachable("Mips ABI not handled");
break;
default:
llvm_unreachable("Unsupported CPU type!");
Expand Down Expand Up @@ -1413,6 +1640,20 @@ void RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj,
// For now, initialize all GOT entries to zero. We'll fill them in as
// needed when GOT-based relocations are applied.
memset(Addr, 0, TotalSize);
if (IsMipsN64ABI) {
// To correctly resolve Mips GOT relocations, we need a mapping from
// object's sections to GOTs.
for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end();
SI != SE; ++SI) {
if (SI->relocation_begin() != SI->relocation_end()) {
section_iterator RelocatedSection = SI->getRelocatedSection();
ObjSectionToIDMap::iterator i = SectionMap.find(*RelocatedSection);
assert (i != SectionMap.end());
SectionToGOTMap[i->second] = GOTSectionID;
}
}
GOTSymbolOffsets.clear();
}
}

// Look for and record the EH frame section.
Expand Down
25 changes: 23 additions & 2 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RuntimeDyldELF : public RuntimeDyldImpl {

void resolveRelocation(const SectionEntry &Section, uint64_t Offset,
uint64_t Value, uint32_t Type, int64_t Addend,
uint64_t SymOffset = 0);
uint64_t SymOffset = 0, SID SectionID = 0);

void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset,
uint64_t Value, uint32_t Type, int64_t Addend,
Expand All @@ -49,12 +49,24 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset,
uint64_t Value, uint32_t Type, int64_t Addend);

void resolveMIPS64Relocation(const SectionEntry &Section, uint64_t Offset,
uint64_t Value, uint32_t Type, int64_t Addend,
uint64_t SymOffset, SID SectionID);

int64_t evaluateMIPS64Relocation(const SectionEntry &Section,
uint64_t Offset, uint64_t Value,
uint32_t Type, int64_t Addend,
uint64_t SymOffset, SID SectionID);

void applyMIPS64Relocation(uint8_t *TargetPtr, int64_t CalculatedValue,
uint32_t Type);

unsigned getMaxStubSize() override {
if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be)
return 20; // movz; movk; movk; movk; br
if (Arch == Triple::arm || Arch == Triple::thumb)
return 8; // 32-bit instruction and 32-bit address
else if (Arch == Triple::mipsel || Arch == Triple::mips)
else if (IsMipsO32ABI)
return 16;
else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
return 44;
Expand All @@ -73,6 +85,8 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
return 1;
}

void setMipsABI(const ObjectFile &Obj) override;

void findPPC64TOCSection(const ObjectFile &Obj,
ObjSectionToIDMap &LocalSections,
RelocationValueRef &Rel);
Expand Down Expand Up @@ -114,6 +128,13 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
// that consume more than one slot)
unsigned CurrentGOTIndex;

// A map from section to a GOT section that has entries for section's GOT
// relocations. (Mips64 specific)
DenseMap<SID, SID> SectionToGOTMap;

// A map to avoid duplicate got entries (Mips64 specific)
StringMap<uint64_t> GOTSymbolOffsets;

// When a module is loaded we save the SectionID of the EH frame section
// in a table until we receive a request to register all unregistered
// EH frame sections with the memory manager.
Expand Down
Loading

0 comments on commit 9720283

Please sign in to comment.