[lld] 7912286 - [LLD][PowerPC] Add support for R_PPC64_GOT_TLSGD_PCREL34 used in TLS General Dynamic

Stefan Pintilie via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 11:01:03 PDT 2020


Author: Stefan Pintilie
Date: 2020-10-01T13:00:37-05:00
New Revision: 79122868f9a3909cfd94d51e9bfe960917a1be05

URL: https://github.com/llvm/llvm-project/commit/79122868f9a3909cfd94d51e9bfe960917a1be05
DIFF: https://github.com/llvm/llvm-project/commit/79122868f9a3909cfd94d51e9bfe960917a1be05.diff

LOG: [LLD][PowerPC] Add support for R_PPC64_GOT_TLSGD_PCREL34 used in TLS General Dynamic

Add Thread Local Storage support for the 34 bit relocation R_PPC64_GOT_TLSGD_PCREL34 used in General Dynamic.

The compiler will produce code that looks like:
```
pla r3, x at got@tlsgd at pcrel            R_PPC64_GOT_TLSGD_PCREL34
bl __tls_get_addr at notoc(x at tlsgd)     R_PPC64_TLSGD
                                     R_PPC64_REL24_NOTOC
```
LLD should be able to correctly compute the relocation for  R_PPC64_GOT_TLSGD_PCREL34 as well as do the following two relaxations where possible:
General Dynamic to Local Exec:
```
paddi r3, r13, x at tprel
nop
```
and General Dynamic to Initial Exec:
```
pld r3, x at got@tprel at pcrel
add r3, r3, r13
```
Note:
This patch adds support for the PC Relative (no TOC) version of General Dynamic on top of the existing support for the TOC version of General Dynamic.
The ABI does not provide any way to tell by looking only at the relocation `R_PPC64_TLSGD` when it is being used in a TOC instruction sequence or and when it is being used in a no TOC sequence. The TOC sequence should always be 4 byte aligned. This patch adds one to the offset of the relocation when it is being used in a no TOC sequence. In this way LLD can tell by looking at the alignment of the offset of `R_PPC64_TLSGD` whether or not it is being used as part of a TOC or no TOC sequence.

Reviewed By: NeHuang, sfertile, MaskRay

Differential Revision: https://reviews.llvm.org/D87318

Added: 
    lld/test/ELF/ppc64-tls-pcrel-gd.s

Modified: 
    lld/ELF/Arch/PPC64.cpp
    lld/ELF/Relocations.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index 06dd863f31b2..2e7b20d46cb0 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -727,15 +727,38 @@ void PPC64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
     writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13
     relocateNoSym(loc, R_PPC64_TPREL16_HA, val);
     break;
-  case R_PPC64_TLSGD:
-    write32(loc, 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:
+    // Relax from paddi r3, 0, x at got@tlsgd at pcrel, 1 to
+    //            paddi r3, r13, x at tprel, 0
+    writePrefixedInstruction(loc, 0x06000000386d0000);
+    relocateNoSym(loc, R_PPC64_TPREL34, val);
+    break;
+  case R_PPC64_TLSGD: {
+    // PC Relative Relaxation:
+    // Relax from bl __tls_get_addr at notoc(x at tlsgd) to
+    //            nop
+    // TOC Relaxation:
+    // Relax from bl __tls_get_addr(x at tlsgd)
+    //            nop
+    // to
+    //            nop
+    //            addi r3, r3, x at tprel@l
+    const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
+    if (locAsInt % 4 == 0) {
+      write32(loc, NOP);            // 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, NOP);
+    } else {
+      errorOrWarn("R_PPC64_TLSGD has unexpected byte alignment");
+    }
     break;
+  }
   default:
     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
   }
@@ -947,6 +970,8 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s,
   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:
@@ -1261,6 +1286,7 @@ void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
     break;
   case R_PPC64_PCREL34:
   case R_PPC64_GOT_PCREL34:
+  case R_PPC64_GOT_TLSGD_PCREL34:
   case R_PPC64_GOT_TPREL_PCREL34:
   case R_PPC64_TPREL34: {
     const uint64_t si0Mask = 0x00000003ffff0000;
@@ -1340,7 +1366,8 @@ RelExpr PPC64::adjustRelaxExpr(RelType type, const uint8_t *data,
     if ((readPrefixedInstruction(data) & 0xfc000000) == 0xe4000000)
       return R_PPC64_RELAX_GOT_PC;
   }
-  if (expr == R_RELAX_TLS_GD_TO_IE)
+
+  if (type != R_PPC64_GOT_TLSGD_PCREL34 && expr == R_RELAX_TLS_GD_TO_IE)
     return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
   if (expr == R_RELAX_TLS_LD_TO_LE)
     return R_RELAX_TLS_LD_TO_LE_ABS;
@@ -1381,10 +1408,35 @@ void PPC64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
     relocateNoSym(loc, R_PPC64_GOT_TPREL16_LO_DS, val);
     return;
   }
-  case R_PPC64_TLSGD:
-    write32(loc, NOP);            // bl __tls_get_addr(sym at tlsgd) --> nop
-    write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+  case R_PPC64_GOT_TLSGD_PCREL34: {
+    // Relax from paddi r3, 0, sym at got@tlsgd at pcrel, 1 to
+    //            pld r3, sym at got@tprel at pcrel
+    writePrefixedInstruction(loc, 0x04100000e4600000);
+    relocateNoSym(loc, R_PPC64_GOT_TPREL_PCREL34, val);
+    return;
+  }
+  case R_PPC64_TLSGD: {
+    // PC Relative Relaxation:
+    // Relax from bl __tls_get_addr at notoc(x at tlsgd) to
+    //            nop
+    // TOC Relaxation:
+    // Relax from bl __tls_get_addr(x at tlsgd)
+    //            nop
+    // to
+    //            nop
+    //            add r3, r3, r13
+    const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
+    if (locAsInt % 4 == 0) {
+      write32(loc, NOP);            // bl __tls_get_addr(sym at tlsgd) --> nop
+      write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+    } else if (locAsInt % 4 == 1) {
+      // bl __tls_get_addr(sym at tlsgd) --> add r3, r3, r13
+      write32(loc - 1, 0x7c636a14);
+    } else {
+      errorOrWarn("R_PPC64_TLSGD has unexpected byte alignment");
+    }
     return;
+  }
   default:
     llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
   }

diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 4c6a70d9034e..ea6aa3c6a12a 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1357,6 +1357,19 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
     if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) &&
         cast<Defined>(sym).section->name == ".toc")
       ppc64noTocRelax.insert({&sym, addend});
+
+    if (type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) {
+      if (i == end) {
+        errorOrWarn("R_PPC64_TLSGD may not be the last relocation" +
+                    getLocation(sec, sym, offset));
+        return;
+      }
+
+      // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case,
+      // so we can discern it later from the toc-case.
+      if (i->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC)
+        ++offset;
+    }
   }
 
   // Relax relocations.

diff  --git a/lld/test/ELF/ppc64-tls-pcrel-gd.s b/lld/test/ELF/ppc64-tls-pcrel-gd.s
new file mode 100644
index 000000000000..2220d91fe798
--- /dev/null
+++ b/lld/test/ELF/ppc64-tls-pcrel-gd.s
@@ -0,0 +1,94 @@
+# REQUIRES: ppc
+# RUN: split-file %s %t
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/asm -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/defs -o %t-defs.o
+# RUN: ld.lld --shared %t-defs.o -o %t-defs.so
+# RUN: ld.lld -T %t/lds --shared %t.o -o %t-gd.so
+# RUN: ld.lld -T %t/lds %t.o %t-defs.so -o %t-gdtoie
+# RUN: ld.lld -T %t/lds %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
+
+#--- lds
+SECTIONS {
+  .text_addr 0x1001000 : { *(.text_addr) }
+}
+
+#--- defs
+.section .tbss,"awT", at nobits
+.globl  x
+x:
+  .long 0
+.globl  y
+y:
+  .long 0
+
+#--- asm
+
+# GD-RELOC: Relocation section '.rela.dyn' at offset 0x100b8 contains 4 entries:
+# GD-RELOC: 0000000001001160  0000000200000044 R_PPC64_DTPMOD64       0000000000000000 x + 0
+# GD-RELOC: 0000000001001168  000000020000004e R_PPC64_DTPREL64       0000000000000000 x + 0
+# GD-RELOC: 0000000001001170  0000000300000044 R_PPC64_DTPMOD64       0000000000000000 y + 0
+# GD-RELOC: 0000000001001178  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: 00000000010010e0  0000000200000049 R_PPC64_TPREL64        0000000000000000 x + 0
+# GDTOIE-RELOC: 00000000010010e8  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 5 entries:
+# GDTOLE-SYM: 3: 0000000000000000     0 TLS     GLOBAL DEFAULT     3 x
+# GDTOLE-SYM: 4: 0000000000000004     0 TLS     GLOBAL DEFAULT     3 y
+
+# GD-LABEL: <GDTwoVal>:
+# GD-NEXT:    paddi 3, 0, 352, 1
+# GD-NEXT:    bl
+# GD-NEXT:    paddi 3, 0, 356, 1
+# GD-NEXT:    bl
+# GD-NEXT:    blr
+# GDTOIE-LABEL: <GDTwoVal>:
+# GDTOIE-NEXT:    pld 3, 224(0), 1
+# GDTOIE-NEXT:    add 3, 3, 13
+# GDTOIE-NEXT:    pld 3, 220(0), 1
+# GDTOIE-NEXT:    add 3, 3, 13
+# GDTOIE-NEXT:    blr
+# GDTOLE-LABEL: <GDTwoVal>:
+# GDTOLE-NEXT:    paddi 3, 13, -28672, 0
+# GDTOLE-NEXT:    nop
+# GDTOLE-NEXT:    paddi 3, 13, -28668, 0
+# GDTOLE-NEXT:    nop
+# GDTOLE-NEXT:    blr
+.section .text_addr, "ax", %progbits
+GDTwoVal:
+  paddi 3, 0, x at got@tlsgd at pcrel, 1
+  bl __tls_get_addr at notoc(x at tlsgd)
+  paddi 3, 0, y at got@tlsgd at pcrel, 1
+  bl __tls_get_addr at notoc(y at tlsgd)
+  blr


        


More information about the llvm-commits mailing list