Index: lld/ELF/Arch/PPC64.cpp =================================================================== --- lld/ELF/Arch/PPC64.cpp +++ lld/ELF/Arch/PPC64.cpp @@ -725,15 +725,27 @@ writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13 relocateNoSym(loc, R_PPC64_TPREL16_HA, val); break; - case R_PPC64_TLSGD: - write32(loc, 0x60000000); // nop - write32(loc + 4, 0x38630000); // addi r3, r3 - // Since we are relocating a half16 type relocation and Loc + 4 points to - // the start of an instruction we need to advance the buffer by an extra - // 2 bytes on BE. - relocateNoSym(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0), - R_PPC64_TPREL16_LO, val); + case R_PPC64_GOT_TLSGD_PCREL34: + writePrefixedInstruction(loc, 0x06000000386d0000); // paddi r3, r13 + relocateNoSym(loc, R_PPC64_TPREL34, val); break; + case R_PPC64_TLSGD: { + const uintptr_t locAsInt = reinterpret_cast(loc); + if ((locAsInt % 4) == 0) { + write32(loc, 0x60000000); // nop + write32(loc + 4, 0x38630000); // addi r3, r3 + // Since we are relocating a half16 type relocation and Loc + 4 points to + // the start of an instruction we need to advance the buffer by an extra + // 2 bytes on BE. + relocateNoSym(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0), + R_PPC64_TPREL16_LO, val); + } else if ((locAsInt % 4) == 1) + write32(loc - 1, 0x60000000); // nop + else + error("R_PPC64_TLSGD has unexpected byte alignment"); + + break; + } default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } @@ -943,6 +955,8 @@ case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_LO: return R_TLSGD_GOT; + case R_PPC64_GOT_TLSGD_PCREL34: + return R_TLSGD_PC; case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16_HA: case R_PPC64_GOT_TLSLD16_HI: @@ -1255,7 +1269,8 @@ case R_PPC64_DTPREL64: write64(loc, val - dynamicThreadPointerOffset); break; - case R_PPC64_PCREL34: { + case R_PPC64_PCREL34: + case R_PPC64_GOT_TLSGD_PCREL34: { const uint64_t si0Mask = 0x00000003ffff0000; const uint64_t si1Mask = 0x000000000000ffff; const uint64_t fullMask = 0x0003ffff0000ffff; @@ -1346,6 +1361,9 @@ if ((readPrefixedInstruction(data) & 0xfc000000) == 0xe4000000) return R_PPC64_RELAX_GOT_PC; } + if (type == R_PPC64_GOT_TLSGD_PCREL34 && expr == R_RELAX_TLS_GD_TO_IE) + return R_RELAX_TLS_GD_TO_IE; + if (expr == R_RELAX_TLS_GD_TO_IE) return R_RELAX_TLS_GD_TO_IE_GOT_OFF; if (expr == R_RELAX_TLS_LD_TO_LE) @@ -1387,10 +1405,24 @@ relocateNoSym(loc, R_PPC64_GOT_TPREL16_LO_DS, val); return; } - case R_PPC64_TLSGD: - write32(loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop - write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 + case R_PPC64_GOT_TLSGD_PCREL34: { + // pld r3, sym@got@tprel@pcrel + writePrefixedInstruction(loc, 0x04100000e4600000); + relocateNoSym(loc, R_PPC64_GOT_TPREL_PCREL34, val); + break; + } + case R_PPC64_TLSGD: { + const uintptr_t locAsInt = reinterpret_cast(loc); + if ((locAsInt % 4) == 0) { + write32(loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop + write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 + } else if ((locAsInt % 4) == 1) { + // bl __tls_get_addr(sym@tlsgd) --> add r3, r3, r13 + write32(loc - 1, 0x7c636A14); + } else + error("R_PPC64_TLSGD has unexpected byte alignment"); return; + } default: llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); } Index: lld/ELF/Relocations.cpp =================================================================== --- lld/ELF/Relocations.cpp +++ lld/ELF/Relocations.cpp @@ -1324,6 +1324,27 @@ if (type == R_PPC64_TOC16_LO && sym.isSection() && isa(sym) && cast(sym).section->name == ".toc") ppc64noTocRelax.insert({&sym, addend}); + + if (type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) { + if (i == end) { + error("R_PPC64_TLSGD may not be the last relocation" + + getLocation(sec, sym, offset)); + return; + } + + if ((offset%4) != 0) { + error("R_PPC64_TLSGD must be 4 byte aligned" + + getLocation(sec, sym, offset)); + return; + } + + // Offset R_PPC64_TLSGD by one byte in the NOTOC case. + // For the TOC case the relocaiton should always be 4 byte aligned + // by adding 1 we can mark the NOTOC case as it will be one byte offset + // from the 4 byte alignment. + if (i->getType(config->isMips64EL) == R_PPC64_REL24_NOTOC) + offset++; + } } // Relax relocations. Index: lld/test/ELF/ppc64-tls-pcrel-gd.s =================================================================== --- /dev/null +++ lld/test/ELF/ppc64-tls-pcrel-gd.s @@ -0,0 +1,174 @@ +# 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: llvm-mc -filetype=obj -triple=powerpc64le %p/Inputs/ppc64-tls-vardef.s -o %t-defs.o +# RUN: ld.lld --shared %t-defs.o -o %t-defs.so +# RUN: ld.lld -T %t.script --shared %t.o -o %t-gd.so +# RUN: ld.lld -T %t.script %t.o %t-defs.so -o %t-gdtoie +# RUN: ld.lld -T %t.script %t.o %t-defs.o -o %t-gdtole + +# RUN: llvm-readelf -r %t-gd.so | FileCheck %s --check-prefix=GD-RELOC +# RUN: llvm-readelf -s %t-gd.so | FileCheck %s --check-prefix=GD-SYM +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gd.so | FileCheck %s --check-prefix=GD + +# RUN: llvm-readelf -r %t-gdtoie | FileCheck %s --check-prefix=GDTOIE-RELOC +# RUN: llvm-readelf -s %t-gdtoie | FileCheck %s --check-prefix=GDTOIE-SYM +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gdtoie | FileCheck %s --check-prefix=GDTOIE + +# RUN: llvm-readelf -r %t-gdtole | FileCheck %s --check-prefix=GDTOLE-RELOC +# RUN: llvm-readelf -s %t-gdtole | FileCheck %s --check-prefix=GDTOLE-SYM +# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gdtole | FileCheck %s --check-prefix=GDTOLE + +## This test checks the General Dynamic PC Relative TLS implementation for lld. +## GD - General Dynamic with no relaxation possible +## GDTOIE - General Dynamic relaxed to Initial Exec +## GDTOLE - General Dynamic relaxed to Local Exec + +# GD-RELOC: Relocation section '.rela.dyn' at offset 0x100b8 contains 4 entries: +# GD-RELOC: 0000000001004158 0000000200000044 R_PPC64_DTPMOD64 0000000000000000 x + 0 +# GD-RELOC: 0000000001004160 000000020000004e R_PPC64_DTPREL64 0000000000000000 x + 0 +# GD-RELOC: 0000000001004168 0000000300000044 R_PPC64_DTPMOD64 0000000000000000 y + 0 +# GD-RELOC: 0000000001004170 000000030000004e R_PPC64_DTPREL64 0000000000000000 y + 0 + +# GD-SYM: Symbol table '.dynsym' contains 4 entries: +# GD-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND x +# GD-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT UND y + + +# GDTOIE-RELOC: Relocation section '.rela.dyn' at offset 0x10118 contains 2 entries: +# GDTOIE-RELOC: 00000000010040e8 0000000200000049 R_PPC64_TPREL64 0000000000000000 x + 0 +# GDTOIE-RELOC: 00000000010040f0 0000000300000049 R_PPC64_TPREL64 0000000000000000 y + 0 + +# GDTOIE-SYM: Symbol table '.dynsym' contains 4 entries: +# GDTOIE-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND x +# GDTOIE-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT UND y + + +# GDTOLE-RELOC: There are no relocations in this file. + +# GDTOLE-SYM: Symbol table '.symtab' contains 8 entries: +# GDTOLE-SYM: 6: 0000000000000000 4 TLS GLOBAL DEFAULT 6 x +# GDTOLE-SYM: 7: 0000000000000004 4 TLS GLOBAL DEFAULT 6 y + + +# GD-LABEL: : +# GD-NEXT: paddi 3, 0, 12632, 1 +# GD-NEXT: bl +# GD-NEXT: blr +# GDTOIE-LABEL: : +# GDTOIE-NEXT: pld 3, 12520(0), 1 +# GDTOIE-NEXT: add 3, 3, 13 +# GDTOIE-NEXT: blr +# GDTOLE-LABEL: : +# GDTOLE-NEXT: paddi 3, 13, -28672, 0 +# GDTOLE-NEXT: nop +# GDTOLE-NEXT: blr +.section .text_addr, "ax", %progbits +GDAddr: + paddi 3, 0, x@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsgd) + blr + +# GD-LABEL: : +# GD-NEXT: paddi 3, 0, 8536, 1 +# GD-NEXT: bl +# GD-NEXT: lwz 3, 0(3) +# GD-NEXT: blr +# GDTOIE-LABEL: : +# GDTOIE-NEXT: pld 3, 8424(0), 1 +# GDTOIE-NEXT: add 3, 3, 13 +# GDTOIE-NEXT: lwz 3, 0(3) +# GDTOIE-NEXT: blr +# GDTOLE-LABEL: : +# GDTOLE-NEXT: paddi 3, 13, -28672, 0 +# GDTOLE-NEXT: nop +# GDTOLE-NEXT: lwz 3, 0(3) +# GDTOLE-NEXT: blr +.section .text_val, "ax", %progbits +GDVal: + paddi 3, 0, x@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsgd) + lwz 3, 0(3) + blr + +# GD-LABEL: : +# GD-NEXT: paddi 3, 0, 4440, 1 +# GD-NEXT: bl +# GD-NEXT: lwz 2, 0(3) +# GD-NEXT: paddi 3, 0, 4440, 1 +# GD-NEXT: bl +# GD-NEXT: lwz 3, 0(3) +# GD-NEXT: add 3, 3, 2 +# GD-NEXT: blr +# GDTOIE-LABEL: : +# GDTOIE-NEXT: pld 3, 4328(0), 1 +# GDTOIE-NEXT: add 3, 3, 13 +# GDTOIE-NEXT: lwz 2, 0(3) +# GDTOIE-NEXT: pld 3, 4320(0), 1 +# GDTOIE-NEXT: add 3, 3, 13 +# GDTOIE-NEXT: lwz 3, 0(3) +# GDTOIE-NEXT: add 3, 3, 2 +# GDTOIE-NEXT: blr +# GDTOLE-LABEL: : +# GDTOLE-NEXT: paddi 3, 13, -28672, 0 +# GDTOLE-NEXT: nop +# GDTOLE-NEXT: lwz 2, 0(3) +# GDTOLE-NEXT: paddi 3, 13, -28668, 0 +# GDTOLE-NEXT: nop +# GDTOLE-NEXT: lwz 3, 0(3) +# GDTOLE-NEXT: add 3, 3, 2 +# GDTOLE-NEXT: blr +.section .text_twoval, "ax", %progbits +GDTwoVal: + paddi 3, 0, x@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsgd) + lwz 2, 0(3) + paddi 3, 0, y@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(y@tlsgd) + lwz 3, 0(3) + add 3, 3, 2 + blr + +# GD-LABEL: : +# GD-NEXT: paddi 3, 0, 360, 1 +# GD-NEXT: bl +# GD-NEXT: lwz 4, 0(3) +# GD-NEXT: addi 5, 4, 1 +# GD-NEXT: clrldi 4, 5, 32 +# GD-NEXT: stw 5, 0(3) +# GD-NEXT: mr 3, 4 +# GD-NEXT: blr +# GDTOIE-LABEL: : +# GDTOIE-NEXT: pld 3, 240(0), 1 +# GDTOIE-NEXT: add 3, 3, 13 +# GDTOIE-NEXT: lwz 4, 0(3) +# GDTOIE-NEXT: addi 5, 4, 1 +# GDTOIE-NEXT: clrldi 4, 5, 32 +# GDTOIE-NEXT: stw 5, 0(3) +# GDTOIE-NEXT: mr 3, 4 +# GDTOIE-NEXT: blr +# GDTOLE-LABEL: : +# GDTOLE-NEXT: paddi 3, 13, -28668, 0 +# GDTOLE-NEXT: nop +# GDTOLE-NEXT: lwz 4, 0(3) +# GDTOLE-NEXT: addi 5, 4, 1 +# GDTOLE-NEXT: clrldi 4, 5, 32 +# GDTOLE-NEXT: stw 5, 0(3) +# GDTOLE-NEXT: mr 3, 4 +# GDTOLE-NEXT: blr +.section .text_incrval, "ax", %progbits +GDIncrementVal: + paddi 3, 0, y@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(y@tlsgd) + lwz 4, 0(3) + addi 5, 4, 1 + clrldi 4, 5, 32 + stw 5, 0(3) + mr 3, 4 + blr