Index: lld/trunk/ELF/Arch/PPC64.cpp =================================================================== --- lld/trunk/ELF/Arch/PPC64.cpp +++ lld/trunk/ELF/Arch/PPC64.cpp @@ -230,6 +230,11 @@ case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_TPREL16_HI: return R_GOT_OFF; + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_DS: + case R_PPC64_GOT_DTPREL16_HI: + return R_TLSLD_GOT_OFF; case R_PPC64_TPREL16: case R_PPC64_TPREL16_HA: case R_PPC64_TPREL16_LO: @@ -312,15 +317,18 @@ return {R_PPC64_ADDR16, TocBiasedVal}; case R_PPC64_TOC16_DS: case R_PPC64_GOT_TPREL16_DS: + case R_PPC64_GOT_DTPREL16_DS: return {R_PPC64_ADDR16_DS, TocBiasedVal}; case R_PPC64_GOT_TLSGD16_HA: case R_PPC64_GOT_TLSLD16_HA: case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, TocBiasedVal}; case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TPREL16_HI: + case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, TocBiasedVal}; case R_PPC64_GOT_TLSGD16_LO: @@ -329,6 +337,7 @@ return {R_PPC64_ADDR16_LO, TocBiasedVal}; case R_PPC64_TOC16_LO_DS: case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: return {R_PPC64_ADDR16_LO_DS, TocBiasedVal}; // Dynamic Thread pointer biased relocation types. @@ -434,6 +443,9 @@ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } + case R_PPC64_DTPREL64: + write64(Loc, Val - DynamicThreadPointerOffset); + break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -503,6 +503,7 @@ case R_GOT_FROM_END: case R_RELAX_TLS_GD_TO_IE_END: return Sym.getGotOffset() + A - InX::Got->getSize(); + case R_TLSLD_GOT_OFF: case R_GOT_OFF: case R_RELAX_TLS_GD_TO_IE_GOT_OFF: return Sym.getGotOffset() + A; Index: lld/trunk/ELF/Relocations.h =================================================================== --- lld/trunk/ELF/Relocations.h +++ lld/trunk/ELF/Relocations.h @@ -81,8 +81,9 @@ R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, R_TLSGD_PC, - R_TLSLD_GOT_FROM_END, R_TLSLD_GOT, + R_TLSLD_GOT_FROM_END, + R_TLSLD_GOT_OFF, R_TLSLD_PC, }; Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -209,6 +209,23 @@ return 1; } + // Local-Dynamic sequence where offset of tls variable relative to dynamic + // thread pointer is stored in the got. + if (Expr == R_TLSLD_GOT_OFF) { + // Local-Dynamic relocs can be relaxed to local-exec + if (!Config->Shared) { + C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); + return 1; + } + if (!Sym.isInGot()) { + InX::Got->addEntry(Sym); + uint64_t Off = Sym.getGotOffset(); + InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); + } + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return 1; + } + if (isRelExprOneOf(Expr)) { if (Config->Shared) { @@ -335,12 +352,13 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant - if (isRelExprOneOf(E)) + if (isRelExprOneOf< + R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, + R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, + R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, + R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, + R_TLSGD_PC, 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/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -633,7 +633,6 @@ // whereas InputSectionBase::relocateAlloc() expects its argument // to point to the start of the output section. Target->writeGotHeader(Buf); - Buf += Target->GotHeaderEntriesNum * Target->GotEntrySize; relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size); } Index: lld/trunk/test/ELF/ppc64-dtprel.s =================================================================== --- lld/trunk/test/ELF/ppc64-dtprel.s +++ lld/trunk/test/ELF/ppc64-dtprel.s @@ -5,12 +5,14 @@ // 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 -D %t.so | FileCheck --check-prefix=Dis %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisLE %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 -D %t.so | FileCheck --check-prefix=Dis %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisBE %s .text .abiversion 2 @@ -95,6 +97,15 @@ mtlr 0 blr + .globl test_got_dtprel + .p2align 4 + .type test_got_dtprel,@function +test_got_dtprel: + addis 3, 2, i@got@dtprel@ha + ld 3, i@got@dtprel@l(3) + addis 3, 2, i@got@dtprel@h + addi 3, 2, i@got@dtprel + .section .debug_addr,"",@progbits .quad i@dtprel+32768 @@ -126,6 +137,10 @@ // InputRelocs: R_PPC64_DTPREL16_HIGHER {{[0-9a-f]+}} k + 0 // InputRelocs: R_PPC64_DTPREL16_HI {{[0-9a-f]+}} k + 0 // InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_HA {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_HI {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_DS {{[0-9a-f]+}} i + 0 // InputRelocs: Relocation section '.rela.debug_addr' // InputRelocs: R_PPC64_DTPREL64 {{[0-9a-f]+}} i + 8000 @@ -161,3 +176,29 @@ // Dis: ori 4, 4, 0 // Dis: oris 4, 4, 63 // Dis: ori 4, 4, 33796 + +// Check for GOT entry for i. There should be a got entry which holds the offset +// of i relative to the dynamic thread pointer. +// i@dtprel -> (1024 - 0x8000) = 0xffff8400 +// GotDisBE: Disassembly of section .got: +// GotDisBE: 4204f8: 00 00 00 00 +// GotDisBE: 4204fc: 00 42 84 f8 +// GotDisBE: 420510: ff ff ff ff +// GotDisBE: 420514: ff ff 84 00 + +// GotDisLE: Disassembly of section .got: +// GotDisLE: 4204f8: f8 84 42 00 +// GotDisLE: 420510: 00 84 ff ff +// GotDisLE: 420514: ff ff ff ff + +// Check that we have the correct offset to the got entry for i@got@dtprel +// The got entry for i is 0x420510, and the TOC pointer is 0x4284f8. +// #ha(i@got@dtprel) --> ((0x420510 - 0x4284f8 + 0x8000) >> 16) & 0xffff = 0 +// #lo(i@got@dtprel) --> (0x420510 - 0x4284f8) & 0xffff = -32744 +// #hi(i@got@dtprel) --> ((0x420510 - 0x4284f8) >> 16) & 0xffff = -1 +// i@got@dtprel --> 0x420510 - 0x4284f8 = -32744 +// Dis: test_got_dtprel: +// Dis: addis 3, 2, 0 +// Dis: ld 3, -32744(3) +// Dis: addis 3, 2, -1 +// Dis: addi 3, 2, -32744