Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -774,7 +774,14 @@ // Ignore relocations for sections that were not loaded if (Sections[RE.SectionID].Address == nullptr) continue; - resolveRelocation(RE, Value); + if (Arch == Triple::mips64el || Arch == Triple::mips64) + // MIPS64 is specific in resolving relocations since there are three + // relocation types in a single entry and may be applied a number of + // relocation operations to a single instruction. + // Call MIPS64 specific routine that is aware of this. + resolveMIPS64Relocation(Relocs, Value, i); + else + resolveRelocation(RE, Value); } } Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -27,6 +27,9 @@ uint64_t Value, uint32_t Type, int64_t Addend, uint64_t SymOffset = 0); + void resolveMIPS64Relocation(const RelocationList &Relocs, uint64_t Value, + unsigned RelocIndex) override; + void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend, uint64_t SymOffset); @@ -43,6 +46,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, uint64_t SymOffset); + void resolvePPC64Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); @@ -114,6 +121,22 @@ // that consume more than one slot) unsigned CurrentGOTIndex; + // Apply relocation in instruction + bool applyRelocation; + + // True if using the result of the previous relocation type + bool useCalculatedValue; + + // The result of the previous relocation type + int64_t calculatedValue; + + // A map from section to a GOT section that has entries for section's GOT + // relocations. + DenseMap SectionToGOTMap; + + // A map to avoid duplicate got entries + StringMap 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. Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -186,8 +186,9 @@ RuntimeDyldELF::RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, RuntimeDyld::SymbolResolver &Resolver) - : RuntimeDyldImpl(MemMgr, Resolver), GOTSectionID(0), CurrentGOTIndex(0) {} -RuntimeDyldELF::~RuntimeDyldELF() {} + : RuntimeDyldImpl(MemMgr, Resolver), GOTSectionID(0), CurrentGOTIndex(0), + applyRelocation(true), useCalculatedValue(false), calculatedValue(0) {} +RuntimeDyldELF::~RuntimeDyldELF() { SectionToGOTMap.clear(); } void RuntimeDyldELF::registerEHFrames() { for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { @@ -509,6 +510,235 @@ } } +void RuntimeDyldELF::resolveMIPS64Relocation(const RelocationList &Relocs, + uint64_t Value, + unsigned RelocIndex) { + const RelocationEntry &RE = Relocs[RelocIndex]; + const SectionEntry &Section = Sections[RE.SectionID]; + + uint32_t r_type = RE.RelType & 0xff; + uint32_t r_type2 = (RE.RelType >> 8) & 0xff; + uint32_t r_type3 = (RE.RelType >> 16) & 0xff; + + // If next type is R_MIPS_NONE, apply the relocation, + // otherwise use the result of this type of relocation as addend for + // next type of the same relocation entry. + useCalculatedValue = !applyRelocation; + applyRelocation = r_type2 == ELF::R_MIPS_NONE; + resolveMIPS64Relocation(Section, RE.Offset, Value, r_type, RE.Addend, + RE.SectionID, RE.SymOffset); + + useCalculatedValue = !applyRelocation; + applyRelocation = r_type3 == ELF::R_MIPS_NONE; + resolveMIPS64Relocation(Section, RE.Offset, Value, r_type2, RE.Addend, + RE.SectionID, RE.SymOffset); + + // If the next relocation entry is not for the same instruction, + // apply the relocation, otherwise use the result as addend for + // next relocation entry + useCalculatedValue = !applyRelocation; + if (RelocIndex + 1 == Relocs.size()) + applyRelocation = true; + else { + const RelocationEntry &REnext = Relocs[RelocIndex + 1]; + applyRelocation = REnext.SectionID != RE.SectionID || + REnext.Offset != RE.Offset; + } + resolveMIPS64Relocation(Section, RE.Offset, Value, r_type3, RE.Addend, + RE.SectionID, RE.SymOffset); +} + +void RuntimeDyldELF::resolveMIPS64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + SID SectionID, + uint64_t SymOffset) { + if (useCalculatedValue) { + Addend = calculatedValue; + Value = 0; + } + + DEBUG(dbgs() << "resolveMips64Relocation, 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: { + 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 = ((*TargetPtr) & 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 = ((*TargetPtr) & 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 = ((*TargetPtr) & 0xffff0000) | calculatedValue; + break; + } + case ELF::R_MIPS_LO16: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + calculatedValue = (Value + Addend) & 0xffff; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 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); + uint64_t *LocalGOTAddr = + (uint64_t *)(getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset); + + Value += Addend; + if (Type == ELF::R_MIPS_GOT_PAGE) + Value = (Value + 0x8000) & 0xffffffffffff0000; + + if (*LocalGOTAddr) + assert(*LocalGOTAddr == Value && + "GOT entry has two different addresses."); + else + *LocalGOTAddr = Value; + + calculatedValue = SymOffset - 0x7ff0; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 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 = ((*TargetPtr) & 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; + } + case ELF::R_MIPS_PC16: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = (Value + Addend - FinalAddress - 4) >> 2; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xffff0000) | (calculatedValue & 0xffff); + break; + } + case ELF::R_MIPS_PC18_S3: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = (Value + Addend - ((FinalAddress | 7) ^ 7)) >> 3; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xfffc0000) | (calculatedValue & 0x3ffff); + break; + } + case ELF::R_MIPS_PC19_S2: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = (Value + Addend - FinalAddress) >> 2; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xfff80000) | (calculatedValue & 0x7ffff); + break; + } + case ELF::R_MIPS_PC21_S2: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = (Value + Addend - FinalAddress) >> 2; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xffe00000) | (calculatedValue & 0x1fffff); + break; + } + case ELF::R_MIPS_PC26_S2: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = (Value + Addend - FinalAddress) >> 2; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xfc000000) | (calculatedValue & 0x3ffffff); + break; + } + case ELF::R_MIPS_PCHI16: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = + ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xffff0000) | calculatedValue; + break; + } + case ELF::R_MIPS_PCLO16: { + uint32_t *TargetPtr = reinterpret_cast(Section.Address + + Offset); + uint64_t FinalAddress = (Section.LoadAddress + Offset); + calculatedValue = (Value + Addend - FinalAddress) & 0xffff; + if (applyRelocation) + *TargetPtr = ((*TargetPtr) & 0xffff0000) | calculatedValue; + break; + } + } +} + // Return the .TOC. section and offset. void RuntimeDyldELF::findPPC64TOCSection(const ObjectFile &Obj, ObjSectionToIDMap &LocalSections, @@ -1056,6 +1286,23 @@ Value.Addend += *Placeholder; processSimpleRelocation(SectionID, Offset, RelType, Value); } + } else if (Arch == Triple::mips64el || Arch == Triple::mips64) { + 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::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. @@ -1353,6 +1600,8 @@ case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: + case Triple::mips64el: + case Triple::mips64: Result = sizeof(uint64_t); break; case Triple::x86: @@ -1415,6 +1664,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. + 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. Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -417,6 +417,11 @@ void resolveRelocations(); + virtual void resolveMIPS64Relocation(const RelocationList &Relocs, + uint64_t Value, unsigned RelocId) { + llvm_unreachable("Mips64 relocations is only implemented for ELF"); + } + void reassignSectionAddress(unsigned SectionID, uint64_t Addr); void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress); 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]"); } Index: unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp =================================================================== --- unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -127,6 +127,8 @@ SupportedArchs.push_back(Triple::aarch64); SupportedArchs.push_back(Triple::arm); SupportedArchs.push_back(Triple::mips); + SupportedArchs.push_back(Triple::mips64); + SupportedArchs.push_back(Triple::mips64el); SupportedArchs.push_back(Triple::x86); SupportedArchs.push_back(Triple::x86_64); Index: unittests/ExecutionEngine/MCJIT/MCJITTestBase.h =================================================================== --- unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -298,6 +298,8 @@ SupportedArchs.push_back(Triple::arm); SupportedArchs.push_back(Triple::mips); SupportedArchs.push_back(Triple::mipsel); + SupportedArchs.push_back(Triple::mips64); + SupportedArchs.push_back(Triple::mips64el); SupportedArchs.push_back(Triple::x86); SupportedArchs.push_back(Triple::x86_64);