Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -33,7 +33,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, @@ -51,6 +51,10 @@ void resolveMIPSRelocation(const SectionEntry &Section, uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend); + void resolveMIPS64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + SID SectionID); + void resolvePPC64Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); @@ -91,18 +95,37 @@ void updateGOTEntries(StringRef Name, uint64_t Addr) override; + int32_t findMIPSGOTEntryOffset(uint64_t LoadAddr, uint64_t Offset, + SID GOTSectionID); + + void addMips64RelocationForSection(const RelocationEntry &RE, unsigned SectionID); + + void addMips64RelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName); + + void resolveMips64Relocations(); // Relocation entries for symbols whose position-independent offset is // updated in a global offset table. typedef SmallVector GOTRelocations; GOTRelocations GOTEntries; // List of entries requiring finalization. SmallVector, 8> GOTs; // Allocated tables. + SmallVector, 64> Mips64Relocations; // 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. SmallVector UnregisteredEHFrameSections; SmallVector RegisteredEHFrameSections; + // A map from section to a GOT section that has entries for section's GOT + // relocations. + std::map SectionToGOTMap; + + int64_t calculatedValue; + + bool applyRelocation; + + bool useCalculatedValue; + public: RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} @@ -122,6 +145,8 @@ static std::unique_ptr createObjectImage(std::unique_ptr InputBuffer); static ObjectImage *createObjectImageFromFile(std::unique_ptr Obj); + + void resolveRelocations() override; }; } // end namespace llvm Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MutexGuard.h" using namespace llvm; using namespace llvm::object; @@ -614,6 +615,206 @@ } } +void RuntimeDyldELF::resolveMIPS64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + SID SectionID) { + uint32_t *Placeholder = + reinterpret_cast(Section.ObjAddress + Offset); + if (useCalculatedValue) + Addend = calculatedValue; + + DEBUG(dbgs() << "resolveMips64Relocation, LocalAddress: " + << Section.Address + Offset << " FinalAddress: " + << format("%p", Section.LoadAddress + Offset) << " Value: " + << format("%x", Value) << " Type: " << format("%d", Type) + << " Addend: " << format("%x", Addend) << "\n"); + + switch (Type) { + default: + llvm_unreachable("Not implemented relocation type!"); + break; + case ELF::R_MIPS_NONE: + break; + case ELF::R_MIPS_32: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = Value + Addend; + if (applyRelocation) + *TargetPtr = calculatedValue; + break; + } + case ELF::R_MIPS_64: { + uint64_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = Value + Addend; + if (applyRelocation) + *TargetPtr = calculatedValue; + break; + } + case ELF::R_MIPS_26: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = ((Value + Addend) & 0x0fffffff) >> 2; + if (applyRelocation) + *TargetPtr = ((*Placeholder) & 0xfc000000) | calculatedValue; + break; + } + case ELF::R_MIPS_GPREL16: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); + calculatedValue = Value + Addend - (GOTAddr + 0x7ff0); + if (applyRelocation) + *TargetPtr = ((*Placeholder) & 0xffff0000) | (calculatedValue & 0xffff); + break; + } + case ELF::R_MIPS_SUB: { + uint64_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = Value - Addend; + if (applyRelocation) + *TargetPtr = calculatedValue; + break; + } + case ELF::R_MIPS_HI16: { + // Get the higher 16-bits. Also add 1 if bit 15 is 1. + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = ((Value + Addend + 0x8000) >> 16) & 0xffff; + if (applyRelocation) + *TargetPtr = + ((*Placeholder) & 0xffff0000) | calculatedValue; + break; + } + case ELF::R_MIPS_LO16: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = (Value + Addend) & 0xffff; + if (applyRelocation) + *TargetPtr = ((*Placeholder) & 0xffff0000) | calculatedValue; + break; + } + case ELF::R_MIPS_CALL16: + case ELF::R_MIPS_GOT_DISP: + case ELF::R_MIPS_GOT_PAGE: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + int32_t GOTOffset; + GOTOffset = findMIPSGOTEntryOffset(Value, Addend, + SectionToGOTMap[SectionID]); + GOTOffset -= 0x7ff0; + calculatedValue = GOTOffset; + if (applyRelocation) + *TargetPtr = ((*Placeholder) & 0xffff0000) | (calculatedValue & 0xffff); + break; + } + case ELF::R_MIPS_GOT_OFST: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = (Value + Addend) & 0xffff; + if (applyRelocation) + *TargetPtr = ((*Placeholder) & 0xffff0000) | calculatedValue; + break; + } + case ELF::R_MIPS_GPREL32: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); + calculatedValue = Value + Addend - (GOTAddr + 0x7ff0); + if (applyRelocation) + *TargetPtr = calculatedValue; + break; + } + } +} + +void RuntimeDyldELF::resolveRelocations() { + // MIPS64 is specific in resolving relocations since there are three + // relocation types in a single entry. + // Call MIPS64 specific routine that is aware of this. + if (Arch == Triple::mips64el || Arch == Triple::mips64) + resolveMips64Relocations(); + else + RuntimeDyldImpl::resolveRelocations(); +} + +void RuntimeDyldELF::resolveMips64Relocations() { + MutexGuard locked(lock); + + applyRelocation = true; + for (unsigned i = 0; i != Mips64Relocations.size(); ++i) { + unsigned SectionID = Mips64Relocations[i].first; + const RelocationEntry &RE = Mips64Relocations[i].second; + + if (RE.RelType == ELF::R_MIPS_NONE) + continue; + if (i + 1 != Mips64Relocations.size()) { + const RelocationEntry &REnext = Mips64Relocations[i + 1].second; + useCalculatedValue = !applyRelocation; + applyRelocation = (REnext.RelType == ELF::R_MIPS_NONE) || + (REnext.SectionID != RE.SectionID || REnext.Offset != RE.Offset); + } + + if (SectionID != -1U) { + uint64_t Addr = Sections[SectionID].LoadAddress; + resolveRelocation(RE, Addr); + } else { + StringRef Name = RE.SymbolName; + if (Name.size() == 0) { + // This is an absolute symbol, use an address of zero. + DEBUG(dbgs() << "Resolving absolute relocations." + << "\n"); + resolveRelocation(RE, 0); + } else { + uint64_t Addr = 0; + SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(Name); + if (Loc == GlobalSymbolTable.end()) { + // This is an external symbol, try to get its address from + // MemoryManager. + Addr = MemMgr->getSymbolAddress(Name.data()); + } else { + // We found the symbol in our global table. It was probably in a + // Module that we loaded previously. + SymbolLoc SymLoc = Loc->second; + Addr = getSectionLoadAddress(SymLoc.first) + SymLoc.second; + } + // FIXME: Implement error handling that doesn't kill the host program! + if (!Addr) + report_fatal_error("Program used external function '" + Name + + "' which could not be resolved!"); + + updateGOTEntries(Name, Addr); + DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t" + << format("0x%lx", Addr) << "\n"); + resolveRelocation(RE, Addr); + } + } + } + Mips64Relocations.clear(); +} + +void RuntimeDyldELF::addMips64RelocationForSection(const RelocationEntry &RE, + unsigned SectionID) { + Mips64Relocations.push_back(std::make_pair(SectionID, RE)); +} + +void RuntimeDyldELF::addMips64RelocationForSymbol(const RelocationEntry &RE, + StringRef SymbolName) { + // Relocation by symbol. If the symbol is found in the global symbol table, + // create an appropriate section relocation. Otherwise, add it to + // ExternalSymbolRelocations. + SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(SymbolName); + if (Loc == GlobalSymbolTable.end()) { + Mips64Relocations.push_back(std::make_pair(-1U, RE)); + } else { + // Copy the RE since we want to modify its addend. + RelocationEntry RECopy = RE; + RECopy.Addend += Loc->second.second; + Mips64Relocations.push_back(std::make_pair(Loc->second.first, RECopy)); + } +} + // Return the .TOC. section and offset. void RuntimeDyldELF::findPPC64TOCSection(ObjectImage &Obj, ObjSectionToIDMap &LocalSections, @@ -891,13 +1092,13 @@ 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); @@ -922,6 +1123,10 @@ resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; + case Triple::mips64: + case Triple::mips64el: + resolveMIPS64Relocation(Section, Offset, Value, Type, Addend, SectionID); + break; case Triple::ppc64: // Fall through. case Triple::ppc64le: resolvePPC64Relocation(Section, Offset, Value, Type, Addend); @@ -962,6 +1167,7 @@ Value.SectionID = lsi->second.first; Value.Offset = lsi->second.second; Value.Addend = lsi->second.second + Addend; + Value.IsLocal = !(Symbol->getFlags() & SymbolRef::SF_Global); } else { // Search for the symbol in the global symbol table SymbolTableMap::const_iterator gsi = GlobalSymbolTable.end(); @@ -971,6 +1177,7 @@ Value.SectionID = gsi->second.first; Value.Offset = gsi->second.second; Value.Addend = gsi->second.second + Addend; + Value.IsLocal = false; } else { switch (SymType) { case SymbolRef::ST_Debug: { @@ -1131,6 +1338,25 @@ addRelocationForSection(RE, SectionID); Section.StubOffset += getMaxStubSize(); } + } else if (Arch == Triple::mips64el || Arch == Triple::mips64) { + uint64_t r_type = RelType & 0xff; + uint64_t r_type2 = (RelType & 0xff00) >> 8; + uint64_t r_type3 = (RelType & 0xff0000) >> 16; + + if (r_type == ELF::R_MIPS_CALL16 || r_type == ELF::R_MIPS_GOT_PAGE + || r_type == ELF::R_MIPS_GOT_DISP) + GOTEntries.push_back(Value); + + RelocationEntry RE1(SectionID, Offset, r_type, Value.Addend, TargetName); + if (Value.SymbolName) + addMips64RelocationForSymbol(RE1, Value.SymbolName); + else + addMips64RelocationForSection(RE1, Value.SectionID); + + RelocationEntry RE2(SectionID, Offset, r_type2, Value.Addend, StringRef()); + addMips64RelocationForSymbol(RE2, StringRef()); + RelocationEntry RE3(SectionID, Offset, r_type3, Value.Addend, StringRef()); + addMips64RelocationForSymbol(RE3, StringRef()); } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { if (RelType == ELF::R_PPC64_REL24) { // Determine ABI variant in use for this object. @@ -1426,6 +1652,8 @@ case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: + case Triple::mips64el: + case Triple::mips64: Result = sizeof(uint64_t); break; case Triple::x86: @@ -1495,6 +1723,70 @@ return 0; } +int32_t RuntimeDyldELF::findMIPSGOTEntryOffset(uint64_t LoadAddress, + uint64_t Offset, + SID GOTSectionID) { + const size_t GOTEntrySize = getGOTEntrySize(); + + SmallVectorImpl>::const_iterator it; + SmallVectorImpl>::const_iterator end = + GOTs.end(); + + int GOTIndex = -1; + bool IsPageEntry = false; + for (it = GOTs.begin(); it != end; ++it) { + if (it->first != GOTSectionID) + continue; + + const GOTRelocations &GOTEntries = it->second; + + // Find the matching entry in our vector. + uint64_t SymbolOffset = 0; + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { + if (!GOTEntries[i].SymbolName) { + if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress && + GOTEntries[i].Offset == Offset) { + GOTIndex = i; + SymbolOffset = GOTEntries[i].Offset; + IsPageEntry = GOTEntries[i].IsLocal; + break; + } + } else { + // GOT entries for external symbols use the addend as the address when + // the external symbol has been resolved. + if (GOTEntries[i].Offset == LoadAddress) { + GOTIndex = i; + // Don't use the Addend here. The relocation handler will use it. + break; + } + } + } + + if (GOTIndex != -1) { + uint64_t Value = LoadAddress + SymbolOffset; + if (IsPageEntry) { + // Create GOT page entry value. + Value = (Value + 0x8000) & 0xffffffffffff0000; + } + if (GOTEntrySize == sizeof(uint64_t)) { + uint64_t *LocalGOTAddr = (uint64_t *)getSectionAddress(GOTSectionID); + // Fill in this entry with the address of the symbol being referenced. + LocalGOTAddr[GOTIndex] = Value; + } else { + uint32_t *LocalGOTAddr = (uint32_t *)getSectionAddress(GOTSectionID); + // Fill in this entry with the address of the symbol being referenced. + LocalGOTAddr[GOTIndex] = (uint32_t)(Value); + } + + return GOTIndex * GOTEntrySize; + } + } + + assert(GOTIndex != -1 && "Unable to find requested GOT entry."); + return 0; +} + + void RuntimeDyldELF::finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) { // If necessary, allocate the global offset table @@ -1515,6 +1807,20 @@ // 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 (Arch == Triple::mips64el || Arch == Triple::mips64) { + // To correctly resolve Mips GOT relocations, we need a mapping from + // object's sections to GOTs. + GOTEntries.clear(); + for (section_iterator SI = ObjImg.begin_sections(), SE = ObjImg.end_sections(); + 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] = SectionID; + } + } + } } } else { report_fatal_error("Unable to allocate memory for GOT!"); Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -109,29 +109,37 @@ /// The size of this relocation (MachO specific). unsigned Size; + /// Symbol name (for target defined symbols). + StringRef SymbolName; + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(false), Size(0) {} + SymOffset(0), IsPCRel(false), Size(0), SymbolName() {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, uint64_t symoffset) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(symoffset), IsPCRel(false), Size(0) {} + SymOffset(symoffset), IsPCRel(false), Size(0), SymbolName() {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, bool IsPCRel, unsigned Size) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} + SymOffset(0), IsPCRel(IsPCRel), Size(Size), SymbolName() {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, uint64_t SectionBOffset, bool IsPCRel, unsigned Size) : SectionID(id), Offset(offset), RelType(type), Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), - Size(Size) { + Size(Size), SymbolName() { Sections.SectionA = SectionA; Sections.SectionB = SectionB; } + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + StringRef symname) + : SectionID(id), Offset(offset), RelType(type), Addend(addend), SymOffset(0), + IsPCRel(false), Size(0), SymbolName(symname) {} }; class RelocationValueRef { @@ -140,8 +148,11 @@ uint64_t Offset; int64_t Addend; const char *SymbolName; + // Mips GOT relocations need to know whether the symbol originally was local. + bool IsLocal; + RelocationValueRef() : SectionID(0), Offset(0), Addend(0), - SymbolName(nullptr) {} + SymbolName(nullptr), IsLocal(false) {} inline bool operator==(const RelocationValueRef &Other) const { return SectionID == Other.SectionID && Offset == Other.Offset && @@ -396,7 +407,7 @@ return getSectionLoadAddress(Loc.first) + Loc.second; } - void resolveRelocations(); + virtual void resolveRelocations(); void reassignSectionAddress(unsigned SectionID, uint64_t Addr); Index: lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp =================================================================== --- lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp +++ lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp @@ -23,9 +23,9 @@ /*HasJIT=*/true> Y(TheMipselTarget, "mipsel", "Mipsel"); RegisterTarget A(TheMips64Target, "mips64", "Mips64 [experimental]"); + /*HasJIT=*/true> A(TheMips64Target, "mips64", "Mips64 [experimental]"); RegisterTarget B(TheMips64elTarget, + /*HasJIT=*/true> B(TheMips64elTarget, "mips64el", "Mips64el [experimental]"); }