[compiler-rt] d0767e9 - [JITLink] Add TLS support for SystemZ (#171559)

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 11 03:11:54 PST 2025


Author: anoopkg6
Date: 2025-12-11T12:11:50+01:00
New Revision: d0767e96f9c1f46de60ae6c592459f830af05cca

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

LOG: [JITLink] Add TLS support for SystemZ (#171559)

This patch adds TLS support for SystemZ on top of orc-runtime support. A
separate orc-runtime support #171062 has been created from earlier TLS
support #[170706](https://github.com/llvm/llvm-project/pull/170706).

See conversations in
[#170706](https://github.com/llvm/llvm-project/pull/170706)

---------

Co-authored-by: anoopkg6 <anoopkg6 at github.com>

Added: 
    compiler-rt/lib/orc/elfnix_tls.systemz.S
    compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S

Modified: 
    compiler-rt/lib/orc/CMakeLists.txt
    llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
    llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
    llvm/lib/ExecutionEngine/JITLink/systemz.cpp
    llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt
index b8d1b03b788c9..649d988d9d608 100644
--- a/compiler-rt/lib/orc/CMakeLists.txt
+++ b/compiler-rt/lib/orc/CMakeLists.txt
@@ -119,6 +119,7 @@ else() # not Apple
       elfnix_tls.x86-64.S
       elfnix_tls.aarch64.S
       elfnix_tls.ppc64.S
+      elfnix_tls.systemz.S
       sysv_reenter.arm64.S
       sysv_reenter.x86-64.S
       )

diff  --git a/compiler-rt/lib/orc/elfnix_tls.systemz.S b/compiler-rt/lib/orc/elfnix_tls.systemz.S
new file mode 100644
index 0000000000000..4e116c92a5a88
--- /dev/null
+++ b/compiler-rt/lib/orc/elfnix_tls.systemz.S
@@ -0,0 +1,42 @@
+//===-- orc_rt_elfnix_tls_systemz.s -------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The special thing about the s390 TLS ABI is that we do not have the
+// standard __tls_get_addr function but the __tls_get_offset function
+// which 
diff ers in two important aspects:
+// 1) __tls_get_offset gets a got offset instead of a pointer to the
+//    tls_index structure
+// 2) __tls_get_offset returns the offset of the requested variable to
+//    the thread descriptor instead of a pointer to the variable.
+
+// The content of this file is systemz-only
+
+#if defined(__s390x__)
+
+	.text
+	// returns offset of TLV from TP in %r2.
+	.globl	___orc_rt_elfnix_tls_get_offset
+___orc_rt_elfnix_tls_get_offset:
+	stmg	%r14, %r15, 112(%r15)
+	aghi	%r15, -160
+	// Pass pointer to tls_index.
+	la 	%r2, 0(%r2, %r12)
+	brasl	%r14, __orc_rt_elfnix_tls_get_addr_impl
+	// Return offset from TP.
+	ear 	%r0, %a0
+	sllg	%r0, %r0, 32
+	ear 	%r0, %a1
+	sgr 	%r2, %r0
+	lmg 	%r14, %r15, 272(%r15)
+	br	%r14
+
+#endif // defined(__s390x__)

diff  --git a/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S
new file mode 100644
index 0000000000000..4bf1c578bd1d7
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S
@@ -0,0 +1,67 @@
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t
+//
+// Test that basic ELF TLS work by adding together TLSs with values
+// 0, 1, and -1, and returning the result (0 for success). This setup
+// tests both zero-initialized (.tbss) and non-zero-initialized
+// (.tdata) sections.
+
+        .section        .data.rel.ro,"aw", at progbits
+        .p2align        3, 0x0
+.LCPI0_0:
+        .quad   x at TLSGD
+.LCPI0_1:
+        .quad   y at TLSGD
+.LCPI0_2:
+        .quad   z at TLSGD
+
+        .text
+        .globl  main
+        .p2align        4
+        .type   main, at function
+main:
+        stmg    %r10, %r15, 80(%r15)
+        aghi    %r15, -160
+        lgrl    %r2, .LCPI0_0
+        larl    %r12, _GLOBAL_OFFSET_TABLE_
+        brasl   %r14, __tls_get_offset at PLT:tls_gdcall:x
+        lgr     %r13, %r2
+        lgrl    %r2, .LCPI0_1
+        brasl   %r14, __tls_get_offset at PLT:tls_gdcall:y
+        ear     %r0, %a0
+        sllg    %r11, %r0, 32
+        ear     %r11, %a1
+        l       %r10, 0(%r2,%r11)
+        lgrl    %r2, .LCPI0_2
+        a       %r10, 0(%r13,%r11)
+        brasl   %r14, __tls_get_offset at PLT:tls_gdcall:z
+        a       %r10, 0(%r2,%r11)
+        lgfr    %r2, %r10
+        lmg     %r10, %r15, 240(%r15)
+        br      %r14
+.Lfunc_end0:
+        .size   main, .Lfunc_end0-main
+
+
+        .type   x, at object                       # @x
+        .section        .tbss,"awT", at nobits
+        .globl  x
+        .p2align        2, 0x0
+x:
+        .long   0                               # 0x0
+        .size   x, 4
+
+        .type   y, at object                       # @y
+        .section        .tdata,"awT", at progbits
+        .globl  y
+        .p2align        2, 0x0
+y:
+        .long   1                               # 0x1
+        .size   y, 4
+
+        .type   z, at object                       # @z
+        .globl  z
+        .p2align        2, 0x0
+z:
+        .long   4294967295                      # 0xffffffff
+        .size   z, 4

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index 09ec56db6826f..bfd22ec753074 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -507,6 +507,21 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   RequestGOTAndTransformToDelta32dbl,
 
+  /// A TLSInfo entry getter/constructor, transformed to Delta64FromGOT.
+  ///
+  /// Indicates that this edge should be transformed into a Delta64FromGOT
+  /// targeting the TLSInfo entry for the edge's current target. A TLSInfo
+  /// entry for the target should be created if one does not already exist.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
+  ///
+  RequestTLSDescInGOTAndTransformToDelta64FromGOT,
+
   /// A 32-bit Delta to GOT base.
   ///
   /// Fixup expression:

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 29eeecceea766..50acd6ea2e542 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -27,12 +27,67 @@ using namespace llvm::jitlink;
 namespace {
 
 constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
+constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
+
+// TLS Info Builder.
+class TLSInfoTableManager_ELF_systemz
+    : public TableManager<TLSInfoTableManager_ELF_systemz> {
+public:
+  static StringRef getSectionName() { return ELFTLSInfoSectionName; }
+
+  static const uint8_t TLSInfoEntryContent[16];
+
+  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+    if (E.getKind() ==
+        systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT) {
+      LLVM_DEBUG({
+        dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
+               << formatv("{0:x}", B->getFixupAddress(E)) << " ("
+               << formatv("{0:x}", B->getAddress()) << " + "
+               << formatv("{0:x}", E.getOffset()) << ")\n";
+      });
+      E.setKind(systemz::Delta64FromGOT);
+      E.setTarget(getEntryForTarget(G, E.getTarget()));
+      return true;
+    }
+    return false;
+  }
+
+  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+    // the TLS Info entry's key value will be written by the fixTLVSectionByName
+    // pass, so create mutable content.
+    auto &TLSInfoEntry = G.createMutableContentBlock(
+        getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
+        orc::ExecutorAddr(), 8, 0);
+    TLSInfoEntry.addEdge(systemz::Pointer64, 8, Target, 0);
+    return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
+  }
+
+private:
+  Section &getTLSInfoSection(LinkGraph &G) {
+    if (!TLSInfoTable)
+      TLSInfoTable = &G.createSection(getSectionName(), orc::MemProt::Read);
+    return *TLSInfoTable;
+  }
+
+  ArrayRef<char> getTLSInfoEntryContent() const {
+    return {reinterpret_cast<const char *>(TLSInfoEntryContent),
+            sizeof(TLSInfoEntryContent)};
+  }
+
+  Section *TLSInfoTable = nullptr;
+};
+
+const uint8_t TLSInfoTableManager_ELF_systemz::TLSInfoEntryContent[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
 Error buildTables_ELF_systemz(LinkGraph &G) {
   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
   systemz::GOTTableManager GOT;
   systemz::PLTTableManager PLT(GOT);
-  visitExistingEdges(G, GOT, PLT);
+  TLSInfoTableManager_ELF_systemz TLSInfo;
+  visitExistingEdges(G, GOT, PLT, TLSInfo);
   return Error::success();
 }
 
@@ -329,6 +384,15 @@ class ELFLinkGraphBuilder_systemz
       Kind = systemz::Delta32dblGOTBase;
       break;
     }
+    // Tag for function call in general dynamic TLS code.
+    case ELF::R_390_TLS_GDCALL: {
+      break;
+    }
+    // Direct 64 bit for general dynamic thread local data.
+    case ELF::R_390_TLS_GD64: {
+      Kind = systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT;
+      break;
+    }
     default:
       return make_error<JITLinkError>(
           "In " + G->getName() + ": Unsupported systemz relocation type " +

diff  --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index f6cc29fa6e6a1..dbb924c3f9291 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -104,6 +104,8 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "RequestGOTAndTransformToDelta12FromGOT";
   case RequestGOTAndTransformToDelta32dbl:
     return "RequestGOTAndTransformToDelta32dbl";
+  case RequestTLSDescInGOTAndTransformToDelta64FromGOT:
+    return "RequestTLSDescInGOTAndTransformToDelta64FromGOT";
   default:
     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
   }

diff  --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index 7dc1ae520f132..0a761290373aa 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -988,6 +988,7 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
     jitlink::LinkGraph &G, JITDylib &JD) {
   auto TLSGetAddrSymbolName = G.intern("__tls_get_addr");
   auto TLSDescResolveSymbolName = G.intern("__tlsdesc_resolver");
+  auto TLSGetOffsetSymbolName = G.intern("__tls_get_offset");
   for (auto *Sym : G.external_symbols()) {
     if (Sym->getName() == TLSGetAddrSymbolName) {
       auto TLSGetAddr =
@@ -997,6 +998,10 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
       auto TLSGetAddr =
           MP.getExecutionSession().intern("___orc_rt_elfnix_tlsdesc_resolver");
       Sym->setName(std::move(TLSGetAddr));
+    } else if (Sym->getName() == TLSGetOffsetSymbolName) {
+      auto TLSGetAddr =
+          MP.getExecutionSession().intern("___orc_rt_elfnix_tls_get_offset");
+      Sym->setName(std::move(TLSGetAddr));
     }
   }
 


        


More information about the llvm-commits mailing list