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 @@ -788,16 +788,40 @@ case R_PPC64_GOT_TLSLD16_LO: writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13, 0 break; - case R_PPC64_TLSLD: - write32(loc, NOP); - write32(loc + 4, 0x38631000); // addi r3, r3, 4096 + case R_PPC64_GOT_TLSLD_PCREL34: + // Relax from paddi r3, 0, x1@got@tlsld@pcrel, 1 to + // paddi r3, r13, 0x1000, 0 + writePrefixedInstruction(loc, 0x06000000386d1000); break; + case R_PPC64_TLSLD: { + // PC Relative Relaxation: + // Relax from bl __tls_get_addr@notoc(x@tlsld) + // to + // nop + // TOC Relaxation: + // Relax from bl __tls_get_addr(x@tlsld) + // nop + // to + // nop + // addi r3, r3, 4096 + const uintptr_t locAsInt = reinterpret_cast(loc); + if (locAsInt % 4 == 0) { + write32(loc, NOP); + write32(loc + 4, 0x38631000); // addi r3, r3, 4096 + } else if (locAsInt % 4 == 1) { + write32(loc - 1, NOP); + } else { + errorOrWarn("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: @@ -977,6 +1001,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: @@ -1010,6 +1036,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; @@ -1284,9 +1311,16 @@ case R_PPC64_DTPREL64: write64(loc, val - dynamicThreadPointerOffset); break; + case R_PPC64_DTPREL34: + // The Dynamic Thread Vector actually points 0x8000 bytes past the start + // of the TLS block. Therefore, in the case of R_PPC64_DTPREL34 we first + // need to subtract that value then fallthrough to the general case. + val -= dynamicThreadPointerOffset; + LLVM_FALLTHROUGH; case R_PPC64_PCREL34: case R_PPC64_GOT_PCREL34: case R_PPC64_GOT_TLSGD_PCREL34: + case R_PPC64_GOT_TLSLD_PCREL34: case R_PPC64_GOT_TPREL_PCREL34: case R_PPC64_TPREL34: { const uint64_t si0Mask = 0x00000003ffff0000; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1358,9 +1358,11 @@ 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) { - errorOrWarn("R_PPC64_TLSGD may not be the last relocation" + + errorOrWarn("R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last " + "relocation" + 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,145 @@ +# REQUIRES: ppc +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/asm -o %t.o +# RUN: ld.lld -T %t/lds --shared -soname=t-ld %t.o -o %t-ld.so +# RUN: ld.lld -T %t/lds %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-readelf -x .got %t-ld.so | FileCheck %s --check-prefix=LD-GOT +# 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-readelf -x .got %t-ldtole 2>&1 | FileCheck %s --check-prefix=LDTOLE-GOT +# 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 0x10080 contains 1 entries: +# LD-RELOC: 0000000001004168 0000000000000044 R_PPC64_DTPMOD64 0 + +# LD-SYM: Symbol table '.symtab' contains 11 entries: +# LD-SYM: 5: 0000000000000000 0 TLS LOCAL DEFAULT 13 x +# LD-SYM-NEXT: 6: 0000000000000004 0 TLS LOCAL DEFAULT 13 y + +# LD-GOT: section '.got': +# LD-GOT-NEXT: 0x01004160 60c10001 00000000 00000000 00000000 +# LD-GOT-NEXT: 0x01004170 00000000 00000000 + +# LDTOLE-RELOC: There are no relocations in this file. + +# LDTOLE-SYM: Symbol table '.symtab' contains 9 entries: +# LDTOLE-SYM: 5: 0000000000000000 0 TLS LOCAL DEFAULT 6 x +# LDTOLE-SYM-NEXT: 6: 0000000000000004 0 TLS LOCAL DEFAULT 6 y + +# LDTOLE-GOT: section '.got': +# LDTOLE-GOT-NEXT: 0x01004020 20c00001 00000000 + +//--- lds +SECTIONS { + .text_addr 0x1001000 : { *(.text_addr) } + .text_val 0x1002000 : { *(.text_val) } + .text_twoval 0x1003000 : { *(.text_twoval) } + .text_incrval 0x1004000 : { *(.text_incrval) } +} + +//--- asm +# LD-LABEL: : +# LD: paddi 3, 0, 12644, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 3, 3, -32768, 0 +# LD-NEXT: blr +# LDTOLE-LABEL: : +# LDTOLE: paddi 3, 13, 4096, 0 +# LDTOLE-NEXT: nop +# LDTOLE-NEXT: paddi 3, 3, -32768, 0 +# LDTOLE-NEXT: blr +.section .text_addr, "ax", %progbits +LDAddr: + # TODO: This symbol is added to to ensure that this object has a .TOC. symbol. + # In this situation we have tls references that require the GOT but a valid + # GOT will not be created unless the .TOC. symbol is present. Without the + # .TOC. the offsets in the GOT would be incorrect. + addis 2, 12, .TOC.-LDAddr@ha + 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, 8552, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 3, 3, -32768, 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, -32768, 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, 4456, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 3, 3, -32768, 0 +# LD-NEXT: lwz 2, 0(3) +# LD-NEXT: paddi 3, 3, -32764, 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, -32768, 0 +# LDTOLE-NEXT: lwz 2, 0(3) +# LDTOLE-NEXT: paddi 3, 3, -32764, 0 +# LDTOLE-NEXT: lwz 3, 0(3) +# 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) + blr + +# LD-LABEL: : +# LD: paddi 3, 0, 360, 1 +# LD-NEXT: bl 0x1001020 +# LD-NEXT: paddi 9, 3, -32764, 0 +# LD-NEXT: lwz 4, 0(9) +# 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, -32764, 0 +# LDTOLE-NEXT: lwz 4, 0(9) +# 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) + stw 5, 0(9) + blr + +.section .tbss,"awT",@nobits +x: + .long 0 +y: + .long 0