[lld] [lld][ELF] Add basic TLSDESC support for LoongArch (PR #94451)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 5 02:45:50 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld-elf

Author: wanglei (wangleiat)

<details>
<summary>Changes</summary>

LoongArch does not yet implemented TLSDESC transition of DESC to LE/IE.
So a TLSDESC dynamic relocation needs to be generated for each desc,
which is ultimately handled by the dynamic linker.


---
Full diff: https://github.com/llvm/llvm-project/pull/94451.diff


6 Files Affected:

- (modified) lld/ELF/Arch/LoongArch.cpp (+40) 
- (modified) lld/ELF/InputSection.cpp (+2) 
- (modified) lld/ELF/Relocations.cpp (+13) 
- (modified) lld/ELF/Relocations.h (+1) 
- (added) lld/test/ELF/loongarch-tlsdesc-gd-mixed.s (+23) 
- (added) lld/test/ELF/loongarch-tlsdesc.s (+134) 


``````````diff
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 2c5d5df922c0f..c6ee73f23d471 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -98,11 +98,13 @@ uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type) {
   case R_LARCH_PCALA64_LO20:
   case R_LARCH_GOT64_PC_LO20:
   case R_LARCH_TLS_IE64_PC_LO20:
+  case R_LARCH_TLS_DESC64_PC_LO20:
     pcalau12i_pc = pc - 8;
     break;
   case R_LARCH_PCALA64_HI12:
   case R_LARCH_GOT64_PC_HI12:
   case R_LARCH_TLS_IE64_PC_HI12:
+  case R_LARCH_TLS_DESC64_PC_HI12:
     pcalau12i_pc = pc - 12;
     break;
   default:
@@ -190,11 +192,13 @@ LoongArch::LoongArch() {
     tlsModuleIndexRel = R_LARCH_TLS_DTPMOD64;
     tlsOffsetRel = R_LARCH_TLS_DTPREL64;
     tlsGotRel = R_LARCH_TLS_TPREL64;
+    tlsDescRel = R_LARCH_TLS_DESC64;
   } else {
     symbolicRel = R_LARCH_32;
     tlsModuleIndexRel = R_LARCH_TLS_DTPMOD32;
     tlsOffsetRel = R_LARCH_TLS_DTPREL32;
     tlsGotRel = R_LARCH_TLS_TPREL32;
+    tlsDescRel = R_LARCH_TLS_DESC32;
   }
 
   gotRel = symbolicRel;
@@ -294,6 +298,10 @@ int64_t LoongArch::getImplicitAddend(const uint8_t *buf, RelType type) const {
   case R_LARCH_JUMP_SLOT:
     // These relocations are defined as not having an implicit addend.
     return 0;
+  case R_LARCH_TLS_DESC32:
+    return read32le(buf + 4);
+  case R_LARCH_TLS_DESC64:
+    return read64le(buf + 8);
   }
 }
 
@@ -486,6 +494,19 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
     return config->relax ? R_RELAX_HINT : R_NONE;
   case R_LARCH_ALIGN:
     return R_RELAX_HINT;
+  case R_LARCH_TLS_DESC_PC_HI20:
+  case R_LARCH_TLS_DESC64_PC_LO20:
+  case R_LARCH_TLS_DESC64_PC_HI12:
+    return R_LOONGARCH_TLSDESC_PAGE_PC;
+  case R_LARCH_TLS_DESC_PC_LO12:
+  case R_LARCH_TLS_DESC_LD:
+  case R_LARCH_TLS_DESC_HI20:
+  case R_LARCH_TLS_DESC_LO12:
+  case R_LARCH_TLS_DESC64_LO20:
+  case R_LARCH_TLS_DESC64_HI12:
+    return R_TLSDESC;
+  case R_LARCH_TLS_DESC_CALL:
+    return R_TLSDESC_CALL;
 
   // Other known relocs that are explicitly unimplemented:
   //
@@ -510,6 +531,8 @@ bool LoongArch::usesOnlyLowPageBits(RelType type) const {
   case R_LARCH_GOT_LO12:
   case R_LARCH_GOT_PC_LO12:
   case R_LARCH_TLS_IE_PC_LO12:
+  case R_LARCH_TLS_DESC_LO12:
+  case R_LARCH_TLS_DESC_PC_LO12:
     return true;
   }
 }
@@ -594,6 +617,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_TLS_LE_LO12:
   case R_LARCH_TLS_IE_PC_LO12:
   case R_LARCH_TLS_IE_LO12:
+  case R_LARCH_TLS_DESC_PC_LO12:
+  case R_LARCH_TLS_DESC_LO12:
     write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
     return;
 
@@ -609,6 +634,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_TLS_LD_HI20:
   case R_LARCH_TLS_GD_PC_HI20:
   case R_LARCH_TLS_GD_HI20:
+  case R_LARCH_TLS_DESC_PC_HI20:
+  case R_LARCH_TLS_DESC_HI20:
     write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
     return;
 
@@ -620,6 +647,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_TLS_LE64_LO20:
   case R_LARCH_TLS_IE64_PC_LO20:
   case R_LARCH_TLS_IE64_LO20:
+  case R_LARCH_TLS_DESC64_PC_LO20:
+  case R_LARCH_TLS_DESC64_LO20:
     write32le(loc, setJ20(read32le(loc), extractBits(val, 51, 32)));
     return;
 
@@ -631,6 +660,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_TLS_LE64_HI12:
   case R_LARCH_TLS_IE64_PC_HI12:
   case R_LARCH_TLS_IE64_HI12:
+  case R_LARCH_TLS_DESC64_PC_HI12:
+  case R_LARCH_TLS_DESC64_HI12:
     write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52)));
     return;
 
@@ -679,6 +710,15 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
   case R_LARCH_RELAX:
     return; // Ignored (for now)
 
+  case R_LARCH_TLS_DESC_LD:
+    return; // nothing to do.
+  case R_LARCH_TLS_DESC32:
+    write32le(loc + 4, val);
+    return;
+  case R_LARCH_TLS_DESC64:
+    write64le(loc + 8, val);
+    return;
+
   default:
     llvm_unreachable("unknown relocation");
   }
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index e6c5996c0b392..03a66552d075b 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -877,6 +877,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
     return in.got->getTlsDescAddr(sym) + a - in.gotPlt->getVA();
   case R_AARCH64_TLSDESC_PAGE:
     return getAArch64Page(in.got->getTlsDescAddr(sym) + a) - getAArch64Page(p);
+  case R_LOONGARCH_TLSDESC_PAGE_PC:
+    return getLoongArchPageDelta(in.got->getTlsDescAddr(sym) + a, p, type);
   case R_TLSGD_GOT:
     return in.got->getGlobalDynOffset(sym) + a;
   case R_TLSGD_GOTPLT:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 2c02c2e572bfd..b6a4a6d7953b1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1303,6 +1303,19 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
 
   if (config->emachine == EM_MIPS)
     return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
+
+  // LoongArch does not yet implemented TLSDESC transition of DESC to LE/IE.
+  // Generates TLSDESC dynamic relocation for the symbol that is handled by the
+  // dynamic linker.
+  if (config->emachine == EM_LOONGARCH &&
+      oneof<R_LOONGARCH_TLSDESC_PAGE_PC, R_TLSDESC, R_TLSDESC_CALL>(expr)) {
+    if (expr != R_TLSDESC_CALL) {
+      sym.setFlags(NEEDS_TLSDESC);
+      c.addReloc({expr, type, offset, addend, &sym});
+    }
+    return 1;
+  }
+
   bool isRISCV = config->emachine == EM_RISCV;
 
   if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index b7b9c09e1b892..e299d23dd7db3 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -116,6 +116,7 @@ enum RelExpr {
   R_LOONGARCH_GOT,
   R_LOONGARCH_GOT_PAGE_PC,
   R_LOONGARCH_TLSGD_PAGE_PC,
+  R_LOONGARCH_TLSDESC_PAGE_PC,
 };
 
 // Architecture-neutral representation of relocation.
diff --git a/lld/test/ELF/loongarch-tlsdesc-gd-mixed.s b/lld/test/ELF/loongarch-tlsdesc-gd-mixed.s
new file mode 100644
index 0000000000000..16f8d288b1898
--- /dev/null
+++ b/lld/test/ELF/loongarch-tlsdesc-gd-mixed.s
@@ -0,0 +1,23 @@
+# REQUIRES: loongarch
+# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so
+
+## Both TLSDESC and DTPMOD64/DTPREL64 should be present.
+# RELA:      .rela.dyn {
+# RELA-NEXT:   0x[[#%X,ADDR:]] R_LARCH_TLS_DESC64   a 0x0
+# RELA-NEXT:   0x[[#ADDR+16]]  R_LARCH_TLS_DTPMOD64 a 0x0
+# RELA-NEXT:   0x[[#ADDR+24]]  R_LARCH_TLS_DTPREL64 a 0x0
+# RELA-NEXT: }
+
+  la.tls.gd $a0,a
+  bl %plt(__tls_get_addr)
+
+  la.tls.desc $a0, a
+  add.d $a1, $a0, $tp
+
+.section .tbss,"awT", at nobits
+.globl a
+.zero 8
+a:
+.zero 4
diff --git a/lld/test/ELF/loongarch-tlsdesc.s b/lld/test/ELF/loongarch-tlsdesc.s
new file mode 100644
index 0000000000000..3d3c309ea73c2
--- /dev/null
+++ b/lld/test/ELF/loongarch-tlsdesc.s
@@ -0,0 +1,134 @@
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=loongarch64 a.s -o a.64.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch64 c.s -o c.64.o
+# RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 a.s -o a.32.o
+# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 c.s -o c.32.o
+# RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so
+
+# RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so
+# RUN: llvm-readobj -r -x .got a.64.so | FileCheck --check-prefix=GD64-RELA %s
+# RUN: llvm-objdump --no-show-raw-insn -h -d a.64.so | FileCheck %s --check-prefix=GD64
+
+# RUN: ld.lld -shared -z now a.64.o c.64.o -o rel.64.so -z rel
+# RUN: llvm-readobj -r -x .got rel.64.so | FileCheck --check-prefix=GD64-REL %s
+
+## FIXME: The transition frome TLSDESC to IE/LE has not yet been implemented.
+## Keep the dynamic relocations and hand them over to dynamic linker.
+
+# RUN: ld.lld -e 0 -z now a.64.o c.64.o -o a.64.le
+# RUN: llvm-readobj -r -x .got a.64.le | FileCheck --check-prefix=LE64-RELA %s
+
+# RUN: ld.lld -e 0 -z now a.64.o c.64.so -o a.64.ie
+# RUN: llvm-readobj -r -x .got a.64.ie | FileCheck --check-prefix=IE64-RELA %s
+
+## 32-bit code is mostly the same. We only test a few variants.
+
+# RUN: ld.lld -shared -z now a.32.o c.32.o -o rel.32.so -z rel
+# RUN: llvm-readobj -r -x .got rel.32.so | FileCheck --check-prefix=GD32-REL %s
+
+# GD64-RELA:      .rela.dyn {
+# GD64-RELA-NEXT:   0x20400 R_LARCH_TLS_DESC64 - 0x7FF
+# GD64-RELA-NEXT:   0x203E0 R_LARCH_TLS_DESC64 a 0x0
+# GD64-RELA-NEXT:   0x203F0 R_LARCH_TLS_DESC64 c 0x0
+# GD64-RELA-NEXT: }
+# GD64-RELA:      Hex dump of section '.got':
+# GD64-RELA-NEXT: 0x000203e0 00000000 00000000 00000000 00000000 .
+# GD64-RELA-NEXT: 0x000203f0 00000000 00000000 00000000 00000000 .
+# GD64-RELA-NEXT: 0x00020400 00000000 00000000 00000000 00000000 .
+
+# GD64-REL:      .rel.dyn {
+# GD64-REL-NEXT:   0x203E8 R_LARCH_TLS_DESC64 -
+# GD64-REL-NEXT:   0x203C8 R_LARCH_TLS_DESC64 a
+# GD64-REL-NEXT:   0x203D8 R_LARCH_TLS_DESC64 c
+# GD64-REL-NEXT: }
+# GD64-REL:      Hex dump of section '.got':
+# GD64-REL-NEXT: 0x000203c8 00000000 00000000 00000000 00000000 .
+# GD64-REL-NEXT: 0x000203d8 00000000 00000000 00000000 00000000 .
+# GD64-REL-NEXT: 0x000203e8 00000000 00000000 ff070000 00000000 .
+
+# GD64:      .got     00000030 00000000000203e0
+
+## &.got[a]-. = 0x203e0 - 0x102e0: 0x10 pages, page offset 0x3e0
+# GD64:        102e0: pcalau12i $a0, 16
+# GD64-NEXT:          addi.d $a0, $a0, 992
+# GD64-NEXT:          ld.d $ra, $a0, 0
+# GD64-NEXT:          jirl $ra, $ra, 0
+# GD64-NEXT:          add.d $a1, $a0, $tp
+
+## &.got[b]-. = 0x203e0+32 - 0x102f4: 0x10 pages, page offset 0x400
+# GD64:        102f4: pcalau12i $a0, 16
+# GD64-NEXT:          addi.d $a0, $a0, 1024
+# GD64-NEXT:          ld.d $ra, $a0, 0
+# GD64-NEXT:          jirl $ra, $ra, 0
+# GD64-NEXT:          add.d $a2, $a0, $tp
+
+## &.got[c]-. = 0x23e0+16 - 0x10308: 0x10 pages, page offset 0x3f0
+# GD64:        10308: pcalau12i $a0, 16
+# GD64-NEXT:          addi.d $a0, $a0, 1008
+# GD64-NEXT:          ld.d $ra, $a0, 0
+# GD64-NEXT:          jirl $ra, $ra, 0
+# GD64-NEXT:          add.d $a3, $a0, $tp
+
+# LE64-RELA:      .rela.dyn {
+# LE64-RELA-NEXT:   0x30250 R_LARCH_TLS_DESC64 - 0x8
+# LE64-RELA-NEXT:   0x30260 R_LARCH_TLS_DESC64 - 0x800
+# LE64-RELA-NEXT:   0x30270 R_LARCH_TLS_DESC64 - 0x7FF
+# LE64-RELA-NEXT: }
+# LE64-RELA:      Hex dump of section '.got':
+# LE64-RELA-NEXT: 0x00030250 00000000 00000000 00000000 00000000 .
+# LE64-RELA-NEXT: 0x00030260 00000000 00000000 00000000 00000000 .
+# LE64-RELA-NEXT: 0x00030270 00000000 00000000 00000000 00000000 .
+
+# IE64-RELA:      .rela.dyn {
+# IE64-RELA-NEXT:   0x303D8 R_LARCH_TLS_DESC64 - 0x8
+# IE64-RELA-NEXT:   0x303F8 R_LARCH_TLS_DESC64 - 0x7FF
+# IE64-RELA-NEXT:   0x303E8 R_LARCH_TLS_DESC64 c 0x0
+# IE64-RELA-NEXT: }
+# IE64-RELA:      Hex dump of section '.got':
+# IE64-RELA-NEXT: 0x000303d8 00000000 00000000 00000000 00000000 .
+# IE64-RELA-NEXT: 0x000303e8 00000000 00000000 00000000 00000000 .
+# IE64-RELA-NEXT: 0x000303f8 00000000 00000000 00000000 00000000 .
+
+# GD32-REL:      .rel.dyn {
+# GD32-REL-NEXT:    0x20270 R_LARCH_TLS_DESC32 -
+# GD32-REL-NEXT:    0x20260 R_LARCH_TLS_DESC32 a
+# GD32-REL-NEXT:    0x20268 R_LARCH_TLS_DESC32 c
+# GD32-REL-NEXT: }
+# GD32-REL:      Hex dump of section '.got':
+# GD32-REL-NEXT: 0x00020260 00000000 00000000 00000000 00000000 .
+# GD32-REL-NEXT: 0x00020270 00000000 ff070000                   .
+
+#--- a.s
+.macro add dst, src1, src2
+.ifdef ELF32
+add.w \dst, \src1, \src2
+.else
+add.d \dst, \src1, \src2
+.endif
+.endm
+
+la.tls.desc $a0, a
+add $a1, $a0, $tp
+
+la.tls.desc $a0, b
+add $a2, $a0, $tp
+
+la.tls.desc $a0, c
+add $a3, $a0, $tp
+
+#.section .tbss
+.section .tbss,"awT", at nobits
+.globl a
+.zero 8
+a:
+.zero 2039  ## Place b at 0x7ff
+b:
+.zero 1
+
+#--- c.s
+.section .tbss,"awT", at nobits
+#.tbss
+.globl c
+c: .zero 4

``````````

</details>


https://github.com/llvm/llvm-project/pull/94451


More information about the llvm-commits mailing list