diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -775,16 +775,27 @@ case R_PPC64_GOT_TLSLD16_LO: writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13, 0 break; - case R_PPC64_TLSLD: - write32(loc, 0x60000000); // nop - write32(loc + 4, 0x38631000); // addi r3, r3, 4096 + case R_PPC64_GOT_TLSLD_PCREL34: + writePrefixedInstruction(loc, 0x06000000386d1000); // paddi 3, 13, 0x1000 + break; + case R_PPC64_TLSLD: { + const uintptr_t locAsInt = reinterpret_cast(loc); + if (locAsInt % 4 == 0) { + write32(loc, 0x60000000); // NOP + write32(loc + 4, 0x38631000); // addi r3, r3, 4096 + } else if (locAsInt % 4 == 1) + write32(loc - 1, 0x60000000); // NOP + else + error("R_PPC64_TLSLD has unexpected byte alignment"); break; + } case R_PPC64_DTPREL16: case R_PPC64_DTPREL16_HA: case R_PPC64_DTPREL16_HI: case R_PPC64_DTPREL16_DS: case R_PPC64_DTPREL16_LO: case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_DTPREL34: relocate(loc, rel, val); break; default: @@ -962,6 +973,8 @@ case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_LO: return R_TLSLD_GOT; + case R_PPC64_GOT_TLSLD_PCREL34: + return R_TLSLD_PC; case R_PPC64_GOT_TPREL16_HA: case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_DS: @@ -995,6 +1008,7 @@ case R_PPC64_DTPREL16_LO: case R_PPC64_DTPREL16_LO_DS: case R_PPC64_DTPREL64: + case R_PPC64_DTPREL34: return R_DTPREL; case R_PPC64_TLSGD: return R_TLSDESC_CALL; @@ -1270,7 +1284,8 @@ write64(loc, val - dynamicThreadPointerOffset); break; case R_PPC64_PCREL34: - case R_PPC64_GOT_TLSGD_PCREL34: { + case R_PPC64_GOT_TLSGD_PCREL34: + case R_PPC64_GOT_TLSLD_PCREL34: { const uint64_t si0Mask = 0x00000003ffff0000; const uint64_t si1Mask = 0x000000000000ffff; const uint64_t fullMask = 0x0003ffff0000ffff; @@ -1283,7 +1298,8 @@ } case R_PPC64_GOT_PCREL34: case R_PPC64_GOT_TPREL_PCREL34: - case R_PPC64_TPREL34: { + case R_PPC64_TPREL34: + case R_PPC64_DTPREL34: { const uint64_t si0Mask = 0x00000003ffff0000; const uint64_t si1Mask = 0x000000000000ffff; const uint64_t fullMask = 0x0003ffff0000ffff; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1325,15 +1325,16 @@ cast(sym).section->name == ".toc") ppc64noTocRelax.insert({&sym, addend}); - if (type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) { + if ((type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) || + (type == R_PPC64_TLSLD && expr == R_TLSLD_HINT)) { if (i == end) { - error("R_PPC64_TLSGD may not be the last relocation" + + error("R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last relocation" + getLocation(sec, sym, offset)); return; } if ((offset%4) != 0) { - error("R_PPC64_TLSGD must be 4 byte aligned" + + error("R_PPC64_TLSGD/R_PPC64_TLSLD must be 4 byte aligned" + getLocation(sec, sym, offset)); return; } diff --git a/lld/test/ELF/ppc64-tls-pcrel-ld.s b/lld/test/ELF/ppc64-tls-pcrel-ld.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc64-tls-pcrel-ld.s @@ -0,0 +1,137 @@ +# REQUIRES: ppc +# RUN: echo 'SECTIONS { \ +# RUN: .text_addr 0x1001000 : { *(.text_addr) } \ +# RUN: .text_val 0x1002000 : { *(.text_val) } \ +# RUN: .text_twoval 0x1003000 : { *(.text_twoval) } \ +# RUN: .text_incrval 0x1004000 : { *(.text_incrval) } \ +# RUN: }' > %t.script + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o +# RUN: ld.lld -T %t.script --shared %t.o -o %t-ld.so +# RUN: ld.lld -T %t.script %t.o -o %t-ldtole + +# RUN: llvm-readelf -r %t-ld.so | FileCheck %s --check-prefix=LD-RELOC +# RUN: llvm-readelf -s %t-ld.so | FileCheck %s --check-prefix=LD-SYM +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-ld.so | FileCheck %s --check-prefix=LD + +# RUN: llvm-readelf -r %t-ldtole | FileCheck %s --check-prefix=LDTOLE-RELOC +# RUN: llvm-readelf -s %t-ldtole | FileCheck %s --check-prefix=LDTOLE-SYM +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-ldtole | FileCheck %s --check-prefix=LDTOLE + +## This test checks the Local Dynamic PC Relative TLS implementation for lld. +## LD - Local Dynamic with no relaxation possible +## LDTOLE - Local Dynamic relaxed to Local Exec + +# LD-RELOC: Relocation section '.rela.dyn' at offset 0x10078 contains 1 entries: +# LD-RELOC: 0000000001004158 0000000000000044 R_PPC64_DTPMOD64 0 + +# LD-SYM: Symbol table '.symtab' contains 10 entries: +# LD-SYM: 5: 0000000000000000 0 TLS LOCAL DEFAULT 13 x +# LD-SYM-NEXT: 6: 0000000000000004 0 TLS LOCAL DEFAULT 13 y + +# LDTOLE-RELOC: There are no relocations in this file. + +# LDTOLE-SYM: Symbol table '.symtab' contains 8 entries: +# LDTOLE-SYM: 5: 0000000000000000 0 TLS LOCAL DEFAULT 6 x +# LDTOLE-SYM-NEXT: 6: 0000000000000004 0 TLS LOCAL DEFAULT 6 y + +# LD-LABEL: : +# LD: paddi 3, 0, 12632, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 3, 3, 0, 0 +# LD-NEXT: blr +# LDTOLE-LABEL: : +# LDTOLE: paddi 3, 13, 4096, 0 +# LDTOLE-NEXT: nop +# LDTOLE-NEXT: paddi 3, 3, 0, 0 +# LDTOLE-NEXT: blr +.section .text_addr, "ax", %progbits +LDAddr: + paddi 3, 0, x@got@tlsld@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsld) + paddi 3, 3, x@dtprel, 0 + blr + +# LD-LABEL: : +# LD: paddi 3, 0, 8536, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 3, 3, 0, 0 +# LD-NEXT: lwz 3, 0(3) +# LD-NEXT: blr +# LDTOLE-LABEL: : +# LDTOLE: paddi 3, 13, 4096, 0 +# LDTOLE-NEXT: nop +# LDTOLE-NEXT: paddi 3, 3, 0, 0 +# LDTOLE-NEXT: lwz 3, 0(3) +# LDTOLE-NEXT: blr +.section .text_val, "ax", %progbits +LDVal: + paddi 3, 0, x@got@tlsld@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsld) + paddi 3, 3, x@dtprel, 0 + lwz 3, 0(3) + blr + +# LD-LABEL: : +# LD: paddi 3, 0, 4440, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 3, 3, 0, 0 +# LD-NEXT: lwz 2, 0(3) +# LD-NEXT: paddi 3, 3, 4, 0 +# LD-NEXT: lwz 3, 0(3) +# LD-NEXT: add 3, 3, 2 +# LD-NEXT: blr +# LDTOLE-LABEL: : +# LDTOLE: paddi 3, 13, 4096, 0 +# LDTOLE-NEXT: nop +# LDTOLE-NEXT: paddi 3, 3, 0, 0 +# LDTOLE-NEXT: lwz 2, 0(3) +# LDTOLE-NEXT: paddi 3, 3, 4, 0 +# LDTOLE-NEXT: lwz 3, 0(3) +# LDTOLE-NEXT: add 3, 3, 2 +# LDTOLE-NEXT: blr +.section .text_twoval, "ax", %progbits +LDTwoVal: + paddi 3, 0, x@got@tlsld@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsld) + paddi 3, 3, x@dtprel, 0 + lwz 2, 0(3) + paddi 3, 3, y@dtprel, 0 + lwz 3, 0(3) + add 3, 3, 2 + blr + +# LD-LABEL: : +# LD: paddi 3, 0, 344, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 9, 3, 4, 0 +# LD-NEXT: lwz 4, 0(9) +# LD-NEXT: addi 5, 4, 1 +# LD-NEXT: clrldi 3, 5, 32 +# LD-NEXT: stw 5, 0(9) +# LD-NEXT: blr +# LDTOLE-LABEL: : +# LDTOLE: paddi 3, 13, 4096, 0 +# LDTOLE-NEXT: nop +# LDTOLE-NEXT: paddi 9, 3, 4, 0 +# LDTOLE-NEXT: lwz 4, 0(9) +# LDTOLE-NEXT: addi 5, 4, 1 +# LDTOLE-NEXT: clrldi 3, 5, 32 +# LDTOLE-NEXT: stw 5, 0(9) +# LDTOLE-NEXT: blr +.section .text_incrval, "ax", %progbits +LDIncrementVal: + paddi 3, 0, y@got@tlsld@pcrel, 1 + bl __tls_get_addr@notoc(y@tlsld) + paddi 9, 3, y@dtprel, 0 + lwz 4, 0(9) + addi 5, 4, 1 + clrldi 3, 5, 32 + stw 5, 0(9) + blr + +.section .tbss,"awT",@nobits +x: + .long 0 +y: + .long 0