[lld] r335651 - [PPC64] Thread-local storage general-dynamic to initial-exec relaxation.
Sean Fertile via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 26 12:38:19 PDT 2018
Author: sfertile
Date: Tue Jun 26 12:38:18 2018
New Revision: 335651
URL: http://llvm.org/viewvc/llvm-project?rev=335651&view=rev
Log:
[PPC64] Thread-local storage general-dynamic to initial-exec relaxation.
Patch adds support for relaxing the general-dynamic tls sequence to
initial-exec.
the relaxation performs the following transformation:
addis r3, r2, x at got@tlsgd at ha --> addis r3, r2, x at got@tprel at ha
addi r3, r3, x at got@tlsgd at l --> ld r3, x at got@tprel at l(r3)
bl __tls_get_addr(x at tlsgd) --> nop
nop --> add r3, r3, r13
and instead of emitting a DTPMOD64/DTPREL64 pair for x, we emit a single
R_PPC64_TPREL64.
Differential Revision: https://reviews.llvm.org/D48090
Added:
lld/trunk/test/ELF/ppc64-gd-to-ie.s
Modified:
lld/trunk/ELF/Arch/PPC64.cpp
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/Relocations.h
Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=335651&r1=335650&r2=335651&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Tue Jun 26 12:38:18 2018
@@ -51,6 +51,9 @@ public:
void writeGotHeader(uint8_t *Buf) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
@@ -214,6 +217,7 @@ RelExpr PPC64::getRelExpr(RelType Type,
case R_PPC64_DTPREL64:
return R_ABS;
case R_PPC64_TLSGD:
+ return R_TLSDESC_CALL;
case R_PPC64_TLSLD:
case R_PPC64_TLS:
return R_HINT;
@@ -405,6 +409,55 @@ bool PPC64::needsThunk(RelExpr Expr, Rel
return Type == R_PPC64_REL24 && S.isInPlt();
}
+RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE)
+ return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
+ return Expr;
+}
+
+// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement.
+// The general dynamic code sequence for a global `x` uses 4 instructions.
+// Instruction Relocation Symbol
+// addis r3, r2, x at got@tlsgd at ha R_PPC64_GOT_TLSGD16_HA x
+// addi r3, r3, x at got@tlsgd at l R_PPC64_GOT_TLSGD16_LO x
+// bl __tls_get_addr(x at tlsgd) R_PPC64_TLSGD x
+// R_PPC64_REL24 __tls_get_addr
+// nop None None
+//
+// Relaxing to initial-exec entails:
+// 1) Convert the addis/addi pair that builds the address of the tls_index
+// struct for 'x' to an addis/ld pair that loads an offset from a got-entry.
+// 2) Convert the call to __tls_get_addr to a nop.
+// 3) Convert the nop following the call to an add of the loaded offset to the
+// thread pointer.
+// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is
+// used as the relaxation hint for both steps 2 and 3.
+void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ // This is relaxed from addis rT, r2, sym at got@tlsgd at ha to
+ // addis rT, r2, sym at got@tprel at ha.
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val);
+ return;
+ case R_PPC64_GOT_TLSGD16_LO: {
+ // Relax from addi r3, rA, sym at got@tlsgd at l to
+ // ld r3, sym at got@tprel at l(rA)
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16));
+ write32(Loc - EndianOffset, 0xE8600000 | InputRegister);
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
+ return;
+ }
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // bl __tls_get_addr(sym at tlsgd) --> nop
+ write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+ }
+}
+
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=335651&r1=335650&r2=335651&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Jun 26 12:38:18 2018
@@ -504,6 +504,7 @@ static uint64_t getRelocTargetVA(const I
case R_RELAX_TLS_GD_TO_IE_END:
return Sym.getGotOffset() + A - InX::Got->getSize();
case R_GOT_OFF:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return Sym.getGotOffset() + A;
case R_GOT_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
@@ -773,11 +774,18 @@ void InputSectionBase::relocateAlloc(uin
break;
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
case R_PPC_CALL:
+ // If this is a call to __tls_get_addr, it may be part of a TLS
+ // sequence that has been relaxed and turned into a nop. In this
+ // case, we don't want to handle it as a call.
+ if (read32(BufLoc) == 0x60000000) // nop
+ break;
+
// Patch a nop (0x60000000) to a ld.
if (Rel.Sym->NeedsTocRestore) {
if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=335651&r1=335650&r2=335651&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Tue Jun 26 12:38:18 2018
@@ -67,6 +67,7 @@ enum RelExpr {
R_RELAX_TLS_GD_TO_IE,
R_RELAX_TLS_GD_TO_IE_ABS,
R_RELAX_TLS_GD_TO_IE_END,
+ R_RELAX_TLS_GD_TO_IE_GOT_OFF,
R_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_RELAX_TLS_GD_TO_LE,
R_RELAX_TLS_GD_TO_LE_NEG,
Added: lld/trunk/test/ELF/ppc64-gd-to-ie.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-gd-to-ie.s?rev=335651&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-gd-to-ie.s (added)
+++ lld/trunk/test/ELF/ppc64-gd-to-ie.s Tue Jun 26 12:38:18 2018
@@ -0,0 +1,104 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t3.so
+# RUN: ld.lld %t.o %t3.so -o %t
+# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+# RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t3.so
+# RUN: ld.lld %t.o %t3.so -o %t
+# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+# RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
+
+ .text
+ .abiversion 2
+ .globl _start
+ .p2align 4
+ .type _start, at function
+_start:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0 at ha
+ addi 2, 2, .TOC.-.Lfunc_gep0 at l
+.Lfunc_lep0:
+ .localentry _start, .Lfunc_lep0-.Lfunc_gep0
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 3, 2, a at got@tlsgd at ha
+ addi 3, 3, a at got@tlsgd at l
+ bl __tls_get_addr(a at tlsgd)
+ nop
+ lwa 3, 0(3)
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+
+ .globl other_reg
+ .p2align 4
+ .type other_reg, at function
+other_reg:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1 at ha
+ addi 2, 2, .TOC.-.Lfunc_gep1 at l
+.Lfunc_lep1:
+ .localentry other_reg, .Lfunc_lep1-.Lfunc_gep1
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addis 5, 2, a at got@tlsgd at ha
+ addi 3, 5, a at got@tlsgd at l
+ bl __tls_get_addr(a at tlsgd)
+ nop
+ lwa 4, 0(3)
+ addis 30, 2, b at got@tlsgd at ha
+ addi 3, 30, b at got@tlsgd at l
+ bl __tls_get_addr(b at tlsgd)
+ nop
+ lwa 3, 0(3)
+ add 3, 4, 3
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .globl __tls_get_addr
+ .type __tls_get_addr, at function
+__tls_get_addr:
+
+
+# CheckGot: .got 00000018 00000000100200c0 DATA
+# .got is at 0x100200c0 so the toc-base is 100280c0.
+# `a` is at .got[1], we expect the offsets to be:
+# Ha(a) = ((0x100200c8 - 0x100280c0) + 0x8000) >> 16 = 0
+# Lo(a) = (0x100200c8 - 0x100280c0) = -32760
+
+# Dis-LABEL: _start
+# Dis: addis 3, 2, 0
+# Dis-NEXT: ld 3, -32760(3)
+# Dis-NEXT: nop
+# Dis-NEXT: add 3, 3, 13
+
+# Dis-LABEL: other_reg
+# Dis: addis 5, 2, 0
+# Dis-NEXT: ld 3, -32760(5)
+# Dis-NEXT: nop
+# Dis-NEXT: add 3, 3, 13
+# Dis: addis 30, 2, 0
+# Dis: ld 3, -32752(30)
+# Dis-NEXT: nop
+# Dis-NEXT: add 3, 3, 13
+
+# Verify that the only dynamic relocations we emit are TPREL ones rather then
+# the DTPMOD64/DTPREL64 pair for general-dynamic.
+# OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries:
+# OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} a + 0
+# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} b + 0
More information about the llvm-commits
mailing list