Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler-rt/lib/orc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
42 changes: 42 additions & 0 deletions compiler-rt/lib/orc/elfnix_tls.systemz.S
Original file line number Diff line number Diff line change
@@ -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 differs 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__)
67 changes: 67 additions & 0 deletions compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S
Original file line number Diff line number Diff line change
@@ -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",@progbits
.p2align 3, 0x0
.LCPI0_0:
.quad x@TLSGD
.LCPI0_1:
.quad y@TLSGD
.LCPI0_2:
.quad z@TLSGD

.text
.globl main
.p2align 4
.type main,@function
main:
stmg %r10, %r15, 80(%r15)
aghi %r15, -160
lgrl %r2, .LCPI0_0
larl %r12, _GLOBAL_OFFSET_TABLE_
brasl %r14, __tls_get_offset@PLT:tls_gdcall:x
lgr %r13, %r2
lgrl %r2, .LCPI0_1
brasl %r14, __tls_get_offset@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@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,@object # @x
.section .tbss,"awT",@nobits
.globl x
.p2align 2, 0x0
x:
.long 0 # 0x0
.size x, 4

.type y,@object # @y
.section .tdata,"awT",@progbits
.globl y
.p2align 2, 0x0
y:
.long 1 # 0x1
.size y, 4

.type z,@object # @z
.globl z
.p2align 2, 0x0
z:
.long 4294967295 # 0xffffffff
.size z, 4
15 changes: 15 additions & 0 deletions llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
66 changes: 65 additions & 1 deletion llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down Expand Up @@ -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 " +
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/ExecutionEngine/JITLink/systemz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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));
}
}

Expand Down