diff options
Diffstat (limited to 'contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 507 |
1 files changed, 131 insertions, 376 deletions
diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 9cbdb13..05615d3 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -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" @@ -27,9 +28,34 @@ using namespace llvm; using namespace llvm::object; +using namespace llvm::support::endian; #define DEBUG_TYPE "dyld" +static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); } + +static void or32AArch64Imm(void *L, uint64_t Imm) { + or32le(L, (Imm & 0xFFF) << 10); +} + +template <class T> static void write(bool isBE, void *P, T V) { + isBE ? write<T, support::big>(P, V) : write<T, support::little>(P, V); +} + +static void write32AArch64Addr(void *L, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); +} + +// Return the bits [Start, End] from Val shifted Start bits. +// For instance, getBits(0xF0, 4, 8) returns 0xF. +static uint64_t getBits(uint64_t Val, int Start, int End) { + uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; + return (Val >> Start) & Mask; +} + namespace { template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { @@ -184,7 +210,7 @@ LoadedELFObjectInfo::getObjectForDebug(const ObjectFile &Obj) const { namespace llvm { RuntimeDyldELF::RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, - RuntimeDyld::SymbolResolver &Resolver) + JITSymbolResolver &Resolver) : RuntimeDyldImpl(MemMgr, Resolver), GOTSectionID(0), CurrentGOTIndex(0) {} RuntimeDyldELF::~RuntimeDyldELF() {} @@ -211,6 +237,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)) @@ -309,6 +350,8 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, uint32_t *TargetPtr = reinterpret_cast<uint32_t *>(Section.getAddressWithOffset(Offset)); uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + // Data should use target endian. Code should always use little endian. + bool isBE = Arch == Triple::aarch64_be; DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" << format("%llx", Section.getAddressWithOffset(Offset)) @@ -321,19 +364,19 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, default: llvm_unreachable("Relocation type not implemented yet!"); break; - case ELF::R_AARCH64_ABS64: { - uint64_t *TargetPtr = - reinterpret_cast<uint64_t *>(Section.getAddressWithOffset(Offset)); - *TargetPtr = Value + Addend; + case ELF::R_AARCH64_ABS64: + write(isBE, TargetPtr, Value + Addend); break; - } case ELF::R_AARCH64_PREL32: { uint64_t Result = Value + Addend - FinalAddress; assert(static_cast<int64_t>(Result) >= INT32_MIN && static_cast<int64_t>(Result) <= UINT32_MAX); - *TargetPtr = static_cast<uint32_t>(Result & 0xffffffffU); + write(isBE, TargetPtr, static_cast<uint32_t>(Result & 0xffffffffU)); break; } + case ELF::R_AARCH64_PREL64: + write(isBE, TargetPtr, Value + Addend - FinalAddress); + break; case ELF::R_AARCH64_CALL26: // fallthrough case ELF::R_AARCH64_JUMP26: { // Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the @@ -342,62 +385,21 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, // "Check that -2^27 <= result < 2^27". assert(isInt<28>(BranchImm)); - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xfc000000U; - // Immediate goes in bits 25:0 of B and BL. - *TargetPtr |= static_cast<uint32_t>(BranchImm & 0xffffffcU) >> 2; + or32le(TargetPtr, (BranchImm & 0x0FFFFFFC) >> 2); break; } - case ELF::R_AARCH64_MOVW_UABS_G3: { - uint64_t Result = Value + Addend; - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xffe0001fU; - // Immediate goes in bits 20:5 of MOVZ/MOVK instruction - *TargetPtr |= Result >> (48 - 5); - // Shift must be "lsl #48", in bits 22:21 - assert((*TargetPtr >> 21 & 0x3) == 3 && "invalid shift for relocation"); + case ELF::R_AARCH64_MOVW_UABS_G3: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF000000000000) >> 43); break; - } - case ELF::R_AARCH64_MOVW_UABS_G2_NC: { - uint64_t Result = Value + Addend; - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xffe0001fU; - // Immediate goes in bits 20:5 of MOVZ/MOVK instruction - *TargetPtr |= ((Result & 0xffff00000000ULL) >> (32 - 5)); - // Shift must be "lsl #32", in bits 22:21 - assert((*TargetPtr >> 21 & 0x3) == 2 && "invalid shift for relocation"); + case ELF::R_AARCH64_MOVW_UABS_G2_NC: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF00000000) >> 27); break; - } - case ELF::R_AARCH64_MOVW_UABS_G1_NC: { - uint64_t Result = Value + Addend; - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xffe0001fU; - // Immediate goes in bits 20:5 of MOVZ/MOVK instruction - *TargetPtr |= ((Result & 0xffff0000U) >> (16 - 5)); - // Shift must be "lsl #16", in bits 22:2 - assert((*TargetPtr >> 21 & 0x3) == 1 && "invalid shift for relocation"); + case ELF::R_AARCH64_MOVW_UABS_G1_NC: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF0000) >> 11); break; - } - case ELF::R_AARCH64_MOVW_UABS_G0_NC: { - uint64_t Result = Value + Addend; - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xffe0001fU; - // Immediate goes in bits 20:5 of MOVZ/MOVK instruction - *TargetPtr |= ((Result & 0xffffU) << 5); - // Shift must be "lsl #0", in bits 22:21. - assert((*TargetPtr >> 21 & 0x3) == 0 && "invalid shift for relocation"); + case ELF::R_AARCH64_MOVW_UABS_G0_NC: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF) << 5); break; - } case ELF::R_AARCH64_ADR_PREL_PG_HI21: { // Operation: Page(S+A) - Page(P) uint64_t Result = @@ -406,40 +408,30 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, // Check that -2^32 <= X < 2^32 assert(isInt<33>(Result) && "overflow check failed for relocation"); - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0x9f00001fU; // Immediate goes in bits 30:29 + 5:23 of ADRP instruction, taken // from bits 32:12 of X. - *TargetPtr |= ((Result & 0x3000U) << (29 - 12)); - *TargetPtr |= ((Result & 0x1ffffc000ULL) >> (14 - 5)); + write32AArch64Addr(TargetPtr, Result >> 12); break; } - case ELF::R_AARCH64_LDST32_ABS_LO12_NC: { + case ELF::R_AARCH64_ADD_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:0 of X + or32AArch64Imm(TargetPtr, Value + Addend); + break; + case ELF::R_AARCH64_LDST32_ABS_LO12_NC: // Operation: S + A - uint64_t Result = Value + Addend; - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xffc003ffU; // Immediate goes in bits 21:10 of LD/ST instruction, taken // from bits 11:2 of X - *TargetPtr |= ((Result & 0xffc) << (10 - 2)); + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 2, 11)); break; - } - case ELF::R_AARCH64_LDST64_ABS_LO12_NC: { + case ELF::R_AARCH64_LDST64_ABS_LO12_NC: // Operation: S + A - uint64_t Result = Value + Addend; - - // AArch64 code is emitted with .rela relocations. The data already in any - // bits affected by the relocation on entry is garbage. - *TargetPtr &= 0xffc003ffU; // Immediate goes in bits 21:10 of LD/ST instruction, taken // from bits 11:3 of X - *TargetPtr |= ((Result & 0xff8) << (10 - 3)); + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 3, 11)); break; } - } } void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, @@ -463,10 +455,15 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, case ELF::R_ARM_NONE: break; + // Write a 31bit signed offset case ELF::R_ARM_PREL31: + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0x80000000) | + ((Value - FinalAddress) & ~0x80000000); + break; case ELF::R_ARM_TARGET1: case ELF::R_ARM_ABS32: - *TargetPtr = Value; + support::ulittle32_t::ref{TargetPtr} = Value; break; // Write first 16 bit of 32 bit value to the mov instruction. // Last 4 bit should be shifted. @@ -476,9 +473,9 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, Value = Value & 0xFFFF; else if (Type == ELF::R_ARM_MOVT_ABS) Value = (Value >> 16) & 0xFFFF; - *TargetPtr &= ~0x000F0FFF; - *TargetPtr |= Value & 0xFFF; - *TargetPtr |= ((Value >> 12) & 0xF) << 16; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & ~0x000F0FFF) | (Value & 0xFFF) | + (((Value >> 12) & 0xF) << 16); break; // Write 24 bit relative value to the branch instruction. case ELF::R_ARM_PC24: // Fall through. @@ -486,298 +483,26 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, case ELF::R_ARM_JUMP24: int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); RelValue = (RelValue & 0x03FFFFFC) >> 2; - assert((*TargetPtr & 0xFFFFFF) == 0xFFFFFE); - *TargetPtr &= 0xFF000000; - *TargetPtr |= RelValue; + assert((support::ulittle32_t::ref{TargetPtr} & 0xFFFFFF) == 0xFFFFFE); + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xFF000000) | RelValue; break; } } -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"); - - uint32_t Insn = readBytesUnaligned(TargetPtr, 4); - - switch (Type) { - default: - llvm_unreachable("Not implemented relocation type!"); - break; - case ELF::R_MIPS_32: - writeBytesUnaligned(Value, TargetPtr, 4); - break; - case ELF::R_MIPS_26: - Insn &= 0xfc000000; - Insn |= (Value & 0x0fffffff) >> 2; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_HI16: - // Get the higher 16-bits. Also add 1 if bit 15 is 1. - Insn &= 0xffff0000; - Insn |= ((Value + 0x8000) >> 16) & 0xffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_LO16: - Insn &= 0xffff0000; - Insn |= Value & 0xffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_PC32: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - writeBytesUnaligned(Value - FinalAddress, (uint8_t *)TargetPtr, 4); - break; - } - case ELF::R_MIPS_PC16: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - Insn &= 0xffff0000; - Insn |= ((Value - FinalAddress) >> 2) & 0xffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - } - case ELF::R_MIPS_PC19_S2: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - Insn &= 0xfff80000; - Insn |= ((Value - (FinalAddress & ~0x3)) >> 2) & 0x7ffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - } - case ELF::R_MIPS_PC21_S2: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - Insn &= 0xffe00000; - Insn |= ((Value - FinalAddress) >> 2) & 0x1fffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - } - case ELF::R_MIPS_PC26_S2: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - Insn &= 0xfc000000; - Insn |= ((Value - FinalAddress) >> 2) & 0x3ffffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - } - case ELF::R_MIPS_PCHI16: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - Insn &= 0xffff0000; - Insn |= ((Value - FinalAddress + 0x8000) >> 16) & 0xffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - } - case ELF::R_MIPS_PCLO16: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - Insn &= 0xffff0000; - Insn |= (Value - FinalAddress) & 0xffff; - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - } - } -} - void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) { if (Arch == Triple::UnknownArch || !StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) { IsMipsO32ABI = false; + IsMipsN32ABI = false; IsMipsN64ABI = false; return; } unsigned AbiVariant; Obj.getPlatformFlags(AbiVariant); IsMipsO32ABI = AbiVariant & ELF::EF_MIPS_ABI_O32; + IsMipsN32ABI = AbiVariant & ELF::EF_MIPS_ABI2; 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.getAddressWithOffset(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.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, 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.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::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: - case ELF::R_MIPS_PC32: - 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. @@ -1124,19 +849,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 (IsMipsN64ABI) - resolveMIPS64Relocation(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; @@ -1187,6 +899,48 @@ uint32_t RuntimeDyldELF::getMatchingLoRelocation(uint32_t RelType, return ELF::R_MIPS_NONE; } +// Sometimes we don't need to create thunk for a branch. +// This typically happens when branch target is located +// in the same object file. In such case target is either +// a weak symbol or symbol in a different executable section. +// This function checks if branch target is located in the +// same object file and if distance between source and target +// fits R_AARCH64_CALL26 relocation. If both conditions are +// met, it emits direct jump to the target and returns true. +// Otherwise false is returned and thunk is created. +bool RuntimeDyldELF::resolveAArch64ShortBranch( + unsigned SectionID, relocation_iterator RelI, + const RelocationValueRef &Value) { + uint64_t Address; + if (Value.SymbolName) { + auto Loc = GlobalSymbolTable.find(Value.SymbolName); + + // Don't create direct branch for external symbols. + if (Loc == GlobalSymbolTable.end()) + return false; + + const auto &SymInfo = Loc->second; + Address = + uint64_t(Sections[SymInfo.getSectionID()].getLoadAddressWithOffset( + SymInfo.getOffset())); + } else { + Address = uint64_t(Sections[Value.SectionID].getLoadAddress()); + } + uint64_t Offset = RelI->getOffset(); + uint64_t SourceAddress = Sections[SectionID].getLoadAddressWithOffset(Offset); + + // R_AARCH64_CALL26 requires immediate to be in range -2^27 <= imm < 2^27 + // If distance between source and target is out of range then we should + // create thunk. + if (!isInt<28>(Address + Value.Addend - SourceAddress)) + return false; + + resolveRelocation(Sections[SectionID], Offset, Address, RelI->getType(), + Value.Addend); + + return true; +} + Expected<relocation_iterator> RuntimeDyldELF::processRelocationRef( unsigned SectionID, relocation_iterator RelI, const ObjectFile &O, @@ -1258,6 +1012,7 @@ RuntimeDyldELF::processRelocationRef( break; } case SymbolRef::ST_Data: + case SymbolRef::ST_Function: case SymbolRef::ST_Unknown: { Value.SymbolName = TargetName.data(); Value.Addend = Addend; @@ -1293,7 +1048,7 @@ RuntimeDyldELF::processRelocationRef( (uint64_t)Section.getAddressWithOffset(i->second), RelType, 0); DEBUG(dbgs() << " Stub function found\n"); - } else { + } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) { // Create a new stub function. DEBUG(dbgs() << " Create a new stub function\n"); Stubs[Value] = Section.getStubOffset(); @@ -1468,7 +1223,7 @@ RuntimeDyldELF::processRelocationRef( Value.Addend += SignExtend32<28>((Opcode & 0x03ffffff) << 2); processSimpleRelocation(SectionID, Offset, RelType, Value); } - } else if (IsMipsN64ABI) { + } else if (IsMipsN32ABI || 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 @@ -1805,7 +1560,7 @@ size_t RuntimeDyldELF::getGOTEntrySize() { case Triple::mipsel: case Triple::mips64: case Triple::mips64el: - if (IsMipsO32ABI) + if (IsMipsO32ABI || IsMipsN32ABI) Result = sizeof(uint32_t); else if (IsMipsN64ABI) Result = sizeof(uint64_t); @@ -1870,7 +1625,7 @@ Error 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) { + if (IsMipsN32ABI || 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(); |