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: { + uint64_t si0Mask = 0x00000003FFFF0000; + uint64_t si1Mask = 0x000000000000FFFF; + 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-pcrel34-reloc.s =================================================================== --- /dev/null +++ lld/test/ELF/ppc64-pcrel34-reloc.s @@ -0,0 +1,48 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o +# RUN: ld.lld %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.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 +.globl _start +_start: +# CHECK-LABEL: Disassembly of section .GLOB_INT_PCREL +# CHECK: 10010180: plwa 3, 12(0), 1 +# SYMBOL: 1001018c 4 NOTYPE LOCAL DEFAULT 2 glob_int +.section .GLOB_INT_PCREL,"ax",@progbits + plwa 3, glob_int@PCREL(0), 1 + blr +glob_int: + .long 0 + .size glob_int, 4 + + +# CHECK-LABEL: Disassembly of section .GLOB_INT_PCREL_OFFSET +# CHECK: 100101c0: plwa 3, 16(0), 1 +# SYMBOL: 100101cc 8 NOTYPE LOCAL DEFAULT 3 glob_int8 +.section .GLOB_INT_PCREL_OFFSET,"ax",@progbits + plwa 3, glob_int8@PCREL+4(0), 1 + blr +glob_int8: + .long 0 + .size glob_int8, 8 + + +# CHECK-LABEL: Disassembly of section .GLOB_INT_PCREL_BIGOFFSET +# CHECK: 10010200: plwa 3, 500016(0), 1 +# SYMBOL: 1008a32c 8 NOTYPE LOCAL DEFAULT 4 glob_int8_big +.section .GLOB_INT_PCREL_BIGOFFSET,"ax",@progbits + plwa 3, glob_int8_big@PCREL+4(0), 1 + blr +.space 500000 +glob_int8_big: + .long 0 + .size glob_int8_big, 8