Index: lld/ELF/Arch/PPC64.cpp =================================================================== --- lld/ELF/Arch/PPC64.cpp +++ lld/ELF/Arch/PPC64.cpp @@ -376,6 +376,19 @@ return read32(config->isLE ? loc : loc - 2); } +// The prefix is always in lower memory than the instruction (regardless of +// endianness). So on little endian machines, we have to load/store the +// pieces separately and assemble/disassemble them accordingly. +static void writePrefixedInstruction(uint8_t *loc, uint64_t insn) { + insn = config->isLE ? insn << 32 | insn >> 32 : insn; + write64(loc, insn); +} + +static uint64_t readPrefixedInstruction(const uint8_t *loc) { + uint64_t fullInstr = read64(loc); + return config->isLE ? (fullInstr << 32 | fullInstr >> 32) : fullInstr; +} + PPC64::PPC64() { copyRel = R_PPC64_COPY; gotRel = R_PPC64_GLOB_DAT; @@ -670,6 +683,7 @@ case R_PPC64_REL16_HI: case R_PPC64_REL32: case R_PPC64_REL64: + case R_PPC64_PCREL34: return R_PC; case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_HA: @@ -986,6 +1000,19 @@ case R_PPC64_DTPREL64: write64(loc, val - dynamicThreadPointerOffset); break; + case R_PPC64_PCREL34: { + const uint64_t si0Mask = 0x00000003ffff0000; + const uint64_t si1Mask = 0x000000000000ffff; + const uint64_t fullMask = 0x0003ffff0000ffff; + checkInt(loc, val, 34, rel); + + uint64_t si0 = (val & si0Mask) << 16; + uint64_t si1 = (val & si1Mask); + uint64_t instr = readPrefixedInstruction(loc) & ~fullMask; + + writePrefixedInstruction(loc, instr | si0 | si1); + break; + } default: llvm_unreachable("unknown relocation"); } Index: lld/test/ELF/ppc64-reloc-pcrel34.s =================================================================== --- /dev/null +++ lld/test/ELF/ppc64-reloc-pcrel34.s @@ -0,0 +1,52 @@ +# REQUIRES: ppc +# RUN: echo 'SECTIONS { \ +# RUN: .text_low 0x10010000: { *(.text_low) } \ +# RUN: .text_high 0x10080000 : { *(.text_high) } \ +# RUN: }' > %t.script + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o +# RUN: ld.lld -T %t.script %t.o -o %t +# RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=SYMBOL +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=future %t | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t.o +# RUN: ld.lld -T %t.script %t.o -o %t +# RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=SYMBOL +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=future %t | FileCheck %s + + +.text +.section .text_low, "ax", %progbits +# CHECK-LABEL: : +# CHECK-NEXT: 10010000: plwa 3, 12(0), 1 +# SYMBOL: 1001000c 4 NOTYPE LOCAL DEFAULT 1 glob_int +GlobIntPCRel: + plwa 3, glob_int@PCREL(0), 1 + blr +glob_int: + .long 0 + .size glob_int, 4 + + +# CHECK-LABEL: : +# CHECK-NEXT: 10010010: plwa 3, 16(0), 1 +# SYMBOL: 1001001c 8 NOTYPE LOCAL DEFAULT 1 glob_int8 +GlobIntPCRelOffset: + plwa 3, glob_int8@PCREL+4(0), 1 + blr +glob_int8: + .long 0 + .size glob_int8, 8 + + +# CHECK-LABEL: : +# CHECK-NEXT: 10010020: plwa 3, 458724(0), 1 +# SYMBOL: 10080000 8 NOTYPE LOCAL DEFAULT 2 glob_int8_big +GlobIntPCRelBigOffset: + plwa 3, glob_int8_big@PCREL+4(0), 1 + blr + +.section .text_high, "ax", %progbits +glob_int8_big: + .long 0 + .size glob_int8_big, 8