Index: lld/trunk/ELF/Arch/PPC64.cpp =================================================================== --- lld/trunk/ELF/Arch/PPC64.cpp +++ lld/trunk/ELF/Arch/PPC64.cpp @@ -80,6 +80,9 @@ PltHeaderSize = 60; NeedsThunks = true; + TlsModuleIndexRel = R_PPC64_DTPMOD64; + TlsOffsetRel = R_PPC64_DTPREL64; + // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). DefaultMaxPageSize = 65536; @@ -167,6 +170,13 @@ case R_PPC64_REL32: case R_PPC64_REL64: return R_PC; + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSGD16_LO: + return R_TLSGD_GOT; + case R_PPC64_TLSGD: + return R_HINT; default: return R_ABS; } @@ -210,14 +220,18 @@ static std::pair toAddr16Rel(RelType Type, uint64_t Val) { uint64_t V = Val - PPC64TocOffset; switch (Type) { + case R_PPC64_GOT_TLSGD16: case R_PPC64_TOC16: return {R_PPC64_ADDR16, V}; case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V}; + case R_PPC64_GOT_TLSGD16_HA: case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V}; + case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V}; + case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V}; case R_PPC64_TOC16_LO_DS: Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -633,6 +633,8 @@ getAArch64Page(P); case R_TLSGD: return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize(); + case R_TLSGD_GOT: + return InX::Got->getGlobalDynOffset(Sym) + A; case R_TLSGD_PC: return InX::Got->getGlobalDynAddr(Sym) + A - P; case R_TLSLD: Index: lld/trunk/ELF/Relocations.h =================================================================== --- lld/trunk/ELF/Relocations.h +++ lld/trunk/ELF/Relocations.h @@ -78,6 +78,7 @@ R_TLSDESC_CALL, R_TLSDESC_PAGE, R_TLSGD, + R_TLSGD_GOT, R_TLSGD_PC, R_TLSLD, R_TLSLD_PC, Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -219,7 +219,7 @@ } if (isRelExprOneOf(Expr)) { + R_TLSGD_GOT, R_TLSGD_PC>(Expr)) { if (Config->Shared) { if (InX::Got->addDynTlsEntry(Sym)) { uint64_t Off = InX::Got->getGlobalDynOffset(Sym); @@ -347,9 +347,9 @@ if (isRelExprOneOf(E)) + R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, + R_TLSGD_PC, R_TLSGD, R_PPC_CALL_PLT, R_TLSDESC_CALL, + R_TLSDESC_PAGE, R_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if Index: lld/trunk/test/ELF/ppc64-general-dynamic-tls.s =================================================================== --- lld/trunk/test/ELF/ppc64-general-dynamic-tls.s +++ lld/trunk/test/ELF/ppc64-general-dynamic-tls.s @@ -0,0 +1,112 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s + + .text + .abiversion 2 + .globl test + .p2align 4 + .type test,@function +test: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry test, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 31, -8(1) + std 0, 16(1) + stdu 1, -48(1) + mr 31, 1 + std 30, 32(31) + addis 3, 2, i@got@tlsgd@ha + addi 3, 3, i@got@tlsgd@l + bl __tls_get_addr(i@tlsgd) + nop + lwz 30, 0(3) + extsw 3, 30 + ld 30, 32(31) + addi 1, 1, 48 + ld 0, 16(1) + ld 31, -8(1) + mtlr 0 + blr + + +test_hi: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry test2, .Lfunc_lep1-.Lfunc_gep1 + addis 3, 0, j@got@tlsgd@h + blr + +test_16: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry test16, .Lfunc_lep2-.Lfunc_gep2 + addi 3, 0, k@got@tlsgd + blr + +// Verify that the input has every general-dynamic tls relocation type. +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} i + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} i + 0 +// InputRelocs: R_PPC64_TLSGD {{0+}} i + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16_HI {{0+}} j + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16 {{0+}} k + 0 + +// There is 2 got entries for each tls variable that is accessed with the +// general-dynamic model. The entries can be though of as a structure to be +// filled in by the dynamic linker: +// typedef struct { +// unsigned long int ti_module; --> R_PPC64_DTPMOD64 +// unsigned long int ti_offset; --> R_PPC64_DTPREL64 +//} tls_index; +// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 6 entries: +// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} i + 0 +// OutputRelocs: R_PPC64_DTPREL64 {{0+}} i + 0 +// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} j + 0 +// OutputRelocs: R_PPC64_DTPREL64 {{0+}} j + 0 +// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} k + 0 +// OutputRelocs: R_PPC64_DTPREL64 {{0+}} k + 0 + +// Check that the got has 7 entires. (1 for the TOC and 3 structures of +// 2 entries for the tls variables). Also verify the address so we can check +// the offsets we calculated for each relocation type. +// CheckGot: got 00000038 00000000000200f0 + +// got starts at 0x200f0, so .TOC. will be 0x280f0. + +// We are building the address of the first tls_index in the got which starts at +// 0x200f8 (got[1]). +// #ha(i@got@tlsgd) --> (0x200f8 - 0x280f0 + 0x8000) >> 16 = 0 +// #lo(i@got@tlsgd) --> (0x200f8 - 0x280f0) & 0xFFFF = -7ff8 = -32760 +// Dis: test: +// Dis: addis 3, 2, 0 +// Dis: addi 3, 3, -32760 + +// Second tls_index starts at got[3]. +// #hi(j@got@tlsgd) --> (0x20108 - 0x280f0) >> 16 = -1 +// Dis: test_hi: +// Dis: lis 3, -1 + +// Third tls index is at got[5]. +// k@got@tlsgd --> (0x20118 - 0x280f0) = -0x7fd8 = -32728 +// Dis: test_16: +// Dis: li 3, -32728