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 @@ -24,6 +24,7 @@ Pointer64 = Edge::FirstRelocation, Pointer32, Delta64, + Delta34, Delta32, NegDelta32, Delta16, @@ -217,6 +218,20 @@ inline static uint16_t lo16(uint64_t x) { return x & 0xffff; } +template +inline static uint64_t readPrefixedInstruction(const char *Loc) { + constexpr bool isLE = Endianness == support::endianness::little; + uint64_t Inst = support::endian::read64(Loc); + return isLE ? (Inst << 32) | (Inst >> 32) : Inst; +} + +template +inline static void writePrefixedInstruction(char *Loc, uint64_t Inst) { + constexpr bool isLE = Endianness == support::endianness::little; + Inst = isLE ? (Inst << 32) | (Inst >> 32) : Inst; + support::endian::write64(Loc, Inst); +} + /// Apply fixup expression for edge to block content. template inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, @@ -303,6 +318,18 @@ support::endian::write64(FixupPtr, Value); break; } + case Delta34: { + int64_t Value = S + A - P; + if (!LLVM_UNLIKELY(isInt<34>(Value))) + return makeTargetOutOfRangeError(G, B, E); + static const uint64_t SI0Mask = 0x00000003ffff0000; + static const uint64_t SI1Mask = 0x000000000000ffff; + static const uint64_t FullMask = 0x0003ffff0000ffff; + uint64_t Inst = readPrefixedInstruction(FixupPtr) & ~FullMask; + writePrefixedInstruction( + FixupPtr, Inst | ((Value & SI0Mask) << 16) | (Value & SI1Mask)); + break; + } case Delta32: { int64_t Value = S + A - P; if (LLVM_UNLIKELY(!isInt<32>(Value))) { 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 @@ -237,6 +237,9 @@ case ELF::R_PPC64_REL64: Kind = ppc64::Delta64; break; + case ELF::R_PPC64_PCREL34: + Kind = ppc64::Delta34; + break; } Edge GE(Kind, Offset, *GraphSymbol, Addend); 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 @@ -66,6 +66,8 @@ return "Pointer32"; case Delta64: return "Delta64"; + case Delta34: + return "Delta34"; case Delta32: return "Delta32"; case NegDelta32: diff --git a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64le_relocations.s b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64le_relocations.s --- a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64le_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64le_relocations.s @@ -82,6 +82,23 @@ blr .size test_external_call_notoc, .-test_external_call_notoc +# Check R_PPC64_PCREL34 +# jitlink-check: (section_addr(elf_reloc.o, .rodata.str1.1) - test_pcrel34)[33:0] = \ +# jitlink-check: ((((*{4}(test_pcrel34)) & 0x3ffff) << 16) | ((*{4}(test_pcrel34 + 4)) & 0xffff))[33:0] + .global test_pcrel34 + .p2align 4 + .type test_pcrel34,@function +test_pcrel34: + paddi 3, 0, .L.str@PCREL, 1 + blr + .size test_pcrel34, .-test_pcrel34 + + .type .L.str,@object + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "Hey!" + .size .L.str, 5 + .section .toc,"aw",@progbits .LC0: .tc external_data[TC],external_data diff --git a/llvm/test/ExecutionEngine/JITLink/ppc64/ppc64le-relocs.s b/llvm/test/ExecutionEngine/JITLink/ppc64/ppc64le-relocs.s --- a/llvm/test/ExecutionEngine/JITLink/ppc64/ppc64le-relocs.s +++ b/llvm/test/ExecutionEngine/JITLink/ppc64/ppc64le-relocs.s @@ -183,6 +183,17 @@ .Lfunc_end7: .size bar, .Lfunc_end7-.Lfunc_begin7 + .global foobar + .p2align + .type foobar,@function +foobar: +.Lfunc_begin8: + .localentry foobar, 1 + paddi 3, 0, .L.str@PCREL, 1 + blr +.Lfunc_end8: + .size foobar, .Lfunc_end8-.Lfunc_end8 + .type local_var,@object .section .bss,"aw",@nobits .globl local_var