Skip to content

Commit d0767e9

Browse files
anoopkg6anoopkg6
andauthored
[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](#170706). See conversations in [#170706](#170706) --------- Co-authored-by: anoopkg6 <anoopkg6@github.com>
1 parent 481ce81 commit d0767e9

File tree

7 files changed

+197
-1
lines changed

7 files changed

+197
-1
lines changed

compiler-rt/lib/orc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ else() # not Apple
119119
elfnix_tls.x86-64.S
120120
elfnix_tls.aarch64.S
121121
elfnix_tls.ppc64.S
122+
elfnix_tls.systemz.S
122123
sysv_reenter.arm64.S
123124
sysv_reenter.x86-64.S
124125
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- orc_rt_elfnix_tls_systemz.s -------------------------------*- ASM -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of the ORC runtime support library.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// The special thing about the s390 TLS ABI is that we do not have the
14+
// standard __tls_get_addr function but the __tls_get_offset function
15+
// which differs in two important aspects:
16+
// 1) __tls_get_offset gets a got offset instead of a pointer to the
17+
// tls_index structure
18+
// 2) __tls_get_offset returns the offset of the requested variable to
19+
// the thread descriptor instead of a pointer to the variable.
20+
21+
// The content of this file is systemz-only
22+
23+
#if defined(__s390x__)
24+
25+
.text
26+
// returns offset of TLV from TP in %r2.
27+
.globl ___orc_rt_elfnix_tls_get_offset
28+
___orc_rt_elfnix_tls_get_offset:
29+
stmg %r14, %r15, 112(%r15)
30+
aghi %r15, -160
31+
// Pass pointer to tls_index.
32+
la %r2, 0(%r2, %r12)
33+
brasl %r14, __orc_rt_elfnix_tls_get_addr_impl
34+
// Return offset from TP.
35+
ear %r0, %a0
36+
sllg %r0, %r0, 32
37+
ear %r0, %a1
38+
sgr %r2, %r0
39+
lmg %r14, %r15, 272(%r15)
40+
br %r14
41+
42+
#endif // defined(__s390x__)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// RUN: %clang -c -o %t %s
2+
// RUN: %llvm_jitlink %t
3+
//
4+
// Test that basic ELF TLS work by adding together TLSs with values
5+
// 0, 1, and -1, and returning the result (0 for success). This setup
6+
// tests both zero-initialized (.tbss) and non-zero-initialized
7+
// (.tdata) sections.
8+
9+
.section .data.rel.ro,"aw",@progbits
10+
.p2align 3, 0x0
11+
.LCPI0_0:
12+
.quad x@TLSGD
13+
.LCPI0_1:
14+
.quad y@TLSGD
15+
.LCPI0_2:
16+
.quad z@TLSGD
17+
18+
.text
19+
.globl main
20+
.p2align 4
21+
.type main,@function
22+
main:
23+
stmg %r10, %r15, 80(%r15)
24+
aghi %r15, -160
25+
lgrl %r2, .LCPI0_0
26+
larl %r12, _GLOBAL_OFFSET_TABLE_
27+
brasl %r14, __tls_get_offset@PLT:tls_gdcall:x
28+
lgr %r13, %r2
29+
lgrl %r2, .LCPI0_1
30+
brasl %r14, __tls_get_offset@PLT:tls_gdcall:y
31+
ear %r0, %a0
32+
sllg %r11, %r0, 32
33+
ear %r11, %a1
34+
l %r10, 0(%r2,%r11)
35+
lgrl %r2, .LCPI0_2
36+
a %r10, 0(%r13,%r11)
37+
brasl %r14, __tls_get_offset@PLT:tls_gdcall:z
38+
a %r10, 0(%r2,%r11)
39+
lgfr %r2, %r10
40+
lmg %r10, %r15, 240(%r15)
41+
br %r14
42+
.Lfunc_end0:
43+
.size main, .Lfunc_end0-main
44+
45+
46+
.type x,@object # @x
47+
.section .tbss,"awT",@nobits
48+
.globl x
49+
.p2align 2, 0x0
50+
x:
51+
.long 0 # 0x0
52+
.size x, 4
53+
54+
.type y,@object # @y
55+
.section .tdata,"awT",@progbits
56+
.globl y
57+
.p2align 2, 0x0
58+
y:
59+
.long 1 # 0x1
60+
.size y, 4
61+
62+
.type z,@object # @z
63+
.globl z
64+
.p2align 2, 0x0
65+
z:
66+
.long 4294967295 # 0xffffffff
67+
.size z, 4

llvm/include/llvm/ExecutionEngine/JITLink/systemz.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,21 @@ enum EdgeKind_systemz : Edge::Kind {
507507
///
508508
RequestGOTAndTransformToDelta32dbl,
509509

510+
/// A TLSInfo entry getter/constructor, transformed to Delta64FromGOT.
511+
///
512+
/// Indicates that this edge should be transformed into a Delta64FromGOT
513+
/// targeting the TLSInfo entry for the edge's current target. A TLSInfo
514+
/// entry for the target should be created if one does not already exist.
515+
///
516+
/// Fixup expression:
517+
/// NONE
518+
///
519+
/// Errors:
520+
/// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
521+
/// phase will result in an assert/unreachable during the fixup phase.
522+
///
523+
RequestTLSDescInGOTAndTransformToDelta64FromGOT,
524+
510525
/// A 32-bit Delta to GOT base.
511526
///
512527
/// Fixup expression:

llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,67 @@ using namespace llvm::jitlink;
2727
namespace {
2828

2929
constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
30+
constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
31+
32+
// TLS Info Builder.
33+
class TLSInfoTableManager_ELF_systemz
34+
: public TableManager<TLSInfoTableManager_ELF_systemz> {
35+
public:
36+
static StringRef getSectionName() { return ELFTLSInfoSectionName; }
37+
38+
static const uint8_t TLSInfoEntryContent[16];
39+
40+
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
41+
if (E.getKind() ==
42+
systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT) {
43+
LLVM_DEBUG({
44+
dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
45+
<< formatv("{0:x}", B->getFixupAddress(E)) << " ("
46+
<< formatv("{0:x}", B->getAddress()) << " + "
47+
<< formatv("{0:x}", E.getOffset()) << ")\n";
48+
});
49+
E.setKind(systemz::Delta64FromGOT);
50+
E.setTarget(getEntryForTarget(G, E.getTarget()));
51+
return true;
52+
}
53+
return false;
54+
}
55+
56+
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
57+
// the TLS Info entry's key value will be written by the fixTLVSectionByName
58+
// pass, so create mutable content.
59+
auto &TLSInfoEntry = G.createMutableContentBlock(
60+
getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
61+
orc::ExecutorAddr(), 8, 0);
62+
TLSInfoEntry.addEdge(systemz::Pointer64, 8, Target, 0);
63+
return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
64+
}
65+
66+
private:
67+
Section &getTLSInfoSection(LinkGraph &G) {
68+
if (!TLSInfoTable)
69+
TLSInfoTable = &G.createSection(getSectionName(), orc::MemProt::Read);
70+
return *TLSInfoTable;
71+
}
72+
73+
ArrayRef<char> getTLSInfoEntryContent() const {
74+
return {reinterpret_cast<const char *>(TLSInfoEntryContent),
75+
sizeof(TLSInfoEntryContent)};
76+
}
77+
78+
Section *TLSInfoTable = nullptr;
79+
};
80+
81+
const uint8_t TLSInfoTableManager_ELF_systemz::TLSInfoEntryContent[16] = {
82+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3084

3185
Error buildTables_ELF_systemz(LinkGraph &G) {
3286
LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
3387
systemz::GOTTableManager GOT;
3488
systemz::PLTTableManager PLT(GOT);
35-
visitExistingEdges(G, GOT, PLT);
89+
TLSInfoTableManager_ELF_systemz TLSInfo;
90+
visitExistingEdges(G, GOT, PLT, TLSInfo);
3691
return Error::success();
3792
}
3893

@@ -329,6 +384,15 @@ class ELFLinkGraphBuilder_systemz
329384
Kind = systemz::Delta32dblGOTBase;
330385
break;
331386
}
387+
// Tag for function call in general dynamic TLS code.
388+
case ELF::R_390_TLS_GDCALL: {
389+
break;
390+
}
391+
// Direct 64 bit for general dynamic thread local data.
392+
case ELF::R_390_TLS_GD64: {
393+
Kind = systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT;
394+
break;
395+
}
332396
default:
333397
return make_error<JITLinkError>(
334398
"In " + G->getName() + ": Unsupported systemz relocation type " +

llvm/lib/ExecutionEngine/JITLink/systemz.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ const char *getEdgeKindName(Edge::Kind R) {
104104
return "RequestGOTAndTransformToDelta12FromGOT";
105105
case RequestGOTAndTransformToDelta32dbl:
106106
return "RequestGOTAndTransformToDelta32dbl";
107+
case RequestTLSDescInGOTAndTransformToDelta64FromGOT:
108+
return "RequestTLSDescInGOTAndTransformToDelta64FromGOT";
107109
default:
108110
return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
109111
}

llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
988988
jitlink::LinkGraph &G, JITDylib &JD) {
989989
auto TLSGetAddrSymbolName = G.intern("__tls_get_addr");
990990
auto TLSDescResolveSymbolName = G.intern("__tlsdesc_resolver");
991+
auto TLSGetOffsetSymbolName = G.intern("__tls_get_offset");
991992
for (auto *Sym : G.external_symbols()) {
992993
if (Sym->getName() == TLSGetAddrSymbolName) {
993994
auto TLSGetAddr =
@@ -997,6 +998,10 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
997998
auto TLSGetAddr =
998999
MP.getExecutionSession().intern("___orc_rt_elfnix_tlsdesc_resolver");
9991000
Sym->setName(std::move(TLSGetAddr));
1001+
} else if (Sym->getName() == TLSGetOffsetSymbolName) {
1002+
auto TLSGetAddr =
1003+
MP.getExecutionSession().intern("___orc_rt_elfnix_tls_get_offset");
1004+
Sym->setName(std::move(TLSGetAddr));
10001005
}
10011006
}
10021007

0 commit comments

Comments
 (0)