diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h --- a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h @@ -23,16 +23,33 @@ enum EdgeKind_ppc64 : Edge::Kind { Pointer64 = Edge::FirstRelocation, Pointer32, + Pointer16, + Pointer16DS, + Pointer16HA, + Pointer16HI, + Pointer16HIGH, + Pointer16HIGHA, + Pointer16HIGHER, + Pointer16HIGHERA, + Pointer16HIGHEST, + Pointer16HIGHESTA, + Pointer16LO, + Pointer16LODS, + Pointer14, Delta64, Delta34, Delta32, NegDelta32, Delta16, Delta16HA, + Delta16HI, Delta16LO, + TOC, + TOCDelta16, + TOCDelta16DS, TOCDelta16HA, + TOCDelta16HI, TOCDelta16LO, - TOCDelta16DS, TOCDelta16LODS, CallBranchDelta, // Need to restore r2 after the bl, suggesting the bl is followed by a nop. @@ -228,9 +245,19 @@ /// only. const char *getEdgeKindName(Edge::Kind K); -inline static uint16_t ha16(uint64_t x) { return (x + 0x8000) >> 16; } - -inline static uint16_t lo16(uint64_t x) { return x & 0xffff; } +inline static uint16_t ha(uint64_t x) { return (x + 0x8000) >> 16; } +inline static uint64_t lo(uint64_t x) { return x & 0xffff; } +inline static uint16_t hi(uint64_t x) { return x >> 16; } +inline static uint64_t high(uint64_t x) { return (x >> 16) & 0xffff; } +inline static uint64_t higha(uint64_t x) { + return ((x + 0x8000) >> 16) & 0xffff; +} +inline static uint64_t higher(uint64_t x) { return (x >> 32) & 0xffff; } +inline static uint64_t highera(uint64_t x) { + return ((x + 0x8000) >> 32) & 0xffff; +} +inline static uint16_t highest(uint64_t x) { return x >> 48; } +inline static uint16_t highesta(uint64_t x) { return (x + 0x8000) >> 48; } // Prefixed instruction introduced in ISAv3.1 consists of two 32-bit words, // prefix word and suffix word, i.e., prefixed_instruction = concat(prefix_word, @@ -252,6 +279,63 @@ support::endian::write64(Loc, Inst); } +template +inline Error relocateHalf16(char *FixupPtr, int64_t Value, Edge::Kind K) { + switch (K) { + case Delta16: + case Pointer16: + case TOCDelta16: + support::endian::write16(FixupPtr, Value); + break; + case Pointer16DS: + case TOCDelta16DS: + support::endian::write16(FixupPtr, Value & ~3); + break; + case Delta16HA: + case Pointer16HA: + case TOCDelta16HA: + support::endian::write16(FixupPtr, ha(Value)); + break; + case Delta16HI: + case Pointer16HI: + case TOCDelta16HI: + support::endian::write16(FixupPtr, hi(Value)); + break; + case Pointer16HIGH: + support::endian::write16(FixupPtr, high(Value)); + break; + case Pointer16HIGHA: + support::endian::write16(FixupPtr, higha(Value)); + break; + case Pointer16HIGHER: + support::endian::write16(FixupPtr, higher(Value)); + break; + case Pointer16HIGHERA: + support::endian::write16(FixupPtr, highera(Value)); + break; + case Pointer16HIGHEST: + support::endian::write16(FixupPtr, highest(Value)); + break; + case Pointer16HIGHESTA: + support::endian::write16(FixupPtr, highesta(Value)); + break; + case Delta16LO: + case Pointer16LO: + case TOCDelta16LO: + support::endian::write16(FixupPtr, lo(Value)); + break; + case Pointer16LODS: + case TOCDelta16LODS: + support::endian::write16(FixupPtr, lo(Value) & ~3); + break; + default: + return make_error( + StringRef(getEdgeKindName(K)) + + " relocation does not write at half16 field"); + } + return Error::success(); +} + /// Apply fixup expression for edge to block content. template inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, @@ -278,41 +362,60 @@ support::endian::write64(FixupPtr, Value); break; } + case Delta16: case Delta16HA: + case Delta16HI: case Delta16LO: { int64_t Value = S + A - P; if (LLVM_UNLIKELY(!isInt<32>(Value))) { return makeTargetOutOfRangeError(G, B, E); } - if (K == Delta16LO) - support::endian::write16(FixupPtr, lo16(Value)); - else - support::endian::write16(FixupPtr, ha16(Value)); - break; + return relocateHalf16(FixupPtr, Value, K); } - case TOCDelta16HA: - case TOCDelta16LO: { - int64_t Value = S + A - TOCBase; + case TOC: + support::endian::write64(FixupPtr, TOCBase); + break; + case Pointer16: + case Pointer16DS: + case Pointer16HA: + case Pointer16HI: + case Pointer16HIGH: + case Pointer16HIGHA: + case Pointer16HIGHER: + case Pointer16HIGHERA: + case Pointer16HIGHEST: + case Pointer16HIGHESTA: + case Pointer16LO: + case Pointer16LODS: { + uint64_t Value = S + A; if (LLVM_UNLIKELY(!isInt<32>(Value))) { return makeTargetOutOfRangeError(G, B, E); } - if (K == TOCDelta16LO) - support::endian::write16(FixupPtr, lo16(Value)); - else - support::endian::write16(FixupPtr, ha16(Value)); + return relocateHalf16(FixupPtr, Value, K); + } + case Pointer14: { + static const uint32_t Low14Mask = 0xfffc; + uint64_t Value = S + A; + assert((Value & 3) == 0 && "Pointer14 requires 4-byte alignment"); + if (LLVM_UNLIKELY(!isInt<16>(Value))) { + return makeTargetOutOfRangeError(G, B, E); + } + uint32_t Inst = support::endian::read32(FixupPtr); + support::endian::write32(FixupPtr, (Inst & ~Low14Mask) | + (Value & Low14Mask)); break; } + case TOCDelta16: case TOCDelta16DS: + case TOCDelta16HA: + case TOCDelta16HI: + case TOCDelta16LO: case TOCDelta16LODS: { int64_t Value = S + A - TOCBase; if (LLVM_UNLIKELY(!isInt<32>(Value))) { return makeTargetOutOfRangeError(G, B, E); } - if (K == TOCDelta16LODS) - support::endian::write16(FixupPtr, lo16(Value) & ~3); - else - support::endian::write16(FixupPtr, Value & ~3); - break; + return relocateHalf16(FixupPtr, Value, K); } case CallBranchDeltaRestoreTOC: case CallBranchDelta: { diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp @@ -266,9 +266,57 @@ case ELF::R_PPC64_ADDR32: Kind = ppc64::Pointer32; break; + case ELF::R_PPC64_ADDR16: + Kind = ppc64::Pointer16; + break; + case ELF::R_PPC64_ADDR16_DS: + Kind = ppc64::Pointer16DS; + break; + case ELF::R_PPC64_ADDR16_HA: + Kind = ppc64::Pointer16HA; + break; + case ELF::R_PPC64_ADDR16_HI: + Kind = ppc64::Pointer16HI; + break; + case ELF::R_PPC64_ADDR16_HIGH: + Kind = ppc64::Pointer16HIGH; + break; + case ELF::R_PPC64_ADDR16_HIGHA: + Kind = ppc64::Pointer16HIGHA; + break; + case ELF::R_PPC64_ADDR16_HIGHER: + Kind = ppc64::Pointer16HIGHER; + break; + case ELF::R_PPC64_ADDR16_HIGHERA: + Kind = ppc64::Pointer16HIGHERA; + break; + case ELF::R_PPC64_ADDR16_HIGHEST: + Kind = ppc64::Pointer16HIGHEST; + break; + case ELF::R_PPC64_ADDR16_HIGHESTA: + Kind = ppc64::Pointer16HIGHESTA; + break; + case ELF::R_PPC64_ADDR16_LO: + Kind = ppc64::Pointer16LO; + break; + case ELF::R_PPC64_ADDR16_LO_DS: + Kind = ppc64::Pointer16LODS; + break; + case ELF::R_PPC64_ADDR14: + Kind = ppc64::Pointer14; + break; + case ELF::R_PPC64_TOC: + Kind = ppc64::TOC; + break; + case ELF::R_PPC64_TOC16: + Kind = ppc64::TOCDelta16; + break; case ELF::R_PPC64_TOC16_HA: Kind = ppc64::TOCDelta16HA; break; + case ELF::R_PPC64_TOC16_HI: + Kind = ppc64::TOCDelta16HI; + break; case ELF::R_PPC64_TOC16_DS: Kind = ppc64::TOCDelta16DS; break; @@ -284,6 +332,9 @@ case ELF::R_PPC64_REL16_HA: Kind = ppc64::Delta16HA; break; + case ELF::R_PPC64_REL16_HI: + Kind = ppc64::Delta16HI; + break; case ELF::R_PPC64_REL16_LO: Kind = ppc64::Delta16LO; break; diff --git a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp @@ -64,6 +64,32 @@ return "Pointer64"; case Pointer32: return "Pointer32"; + case Pointer16: + return "Pointer16"; + case Pointer16DS: + return "Pointer16DS"; + case Pointer16HA: + return "Pointer16HA"; + case Pointer16HI: + return "Pointer16HI"; + case Pointer16HIGH: + return "Pointer16HIGH"; + case Pointer16HIGHA: + return "Pointer16HIGHA"; + case Pointer16HIGHER: + return "Pointer16HIGHER"; + case Pointer16HIGHERA: + return "Pointer16HIGHERA"; + case Pointer16HIGHEST: + return "Pointer16HIGHEST"; + case Pointer16HIGHESTA: + return "Pointer16HIGHESTA"; + case Pointer16LO: + return "Pointer16LO"; + case Pointer16LODS: + return "Pointer16LODS"; + case Pointer14: + return "Pointer14"; case Delta64: return "Delta64"; case Delta34: @@ -76,14 +102,22 @@ return "Delta16"; case Delta16HA: return "Delta16HA"; + case Delta16HI: + return "Delta16HI"; case Delta16LO: return "Delta16LO"; + case TOC: + return "TOC"; + case TOCDelta16: + return "TOCDelta16"; + case TOCDelta16DS: + return "TOCDelta16DS"; case TOCDelta16HA: return "TOCDelta16HA"; + case TOCDelta16HI: + return "TOCDelta16HI"; case TOCDelta16LO: return "TOCDelta16LO"; - case TOCDelta16DS: - return "TOCDelta16DS"; case TOCDelta16LODS: return "TOCDelta16LODS"; case CallBranchDelta: