diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt --- a/compiler-rt/lib/orc/CMakeLists.txt +++ b/compiler-rt/lib/orc/CMakeLists.txt @@ -24,6 +24,7 @@ macho_tlv.arm64.S elfnix_tls.x86-64.S elfnix_tls.aarch64.S + elfnix_tls.ppc64.S ) # Common implementation headers will go here. @@ -149,6 +150,7 @@ set(ORC_ASM_SOURCES elfnix_tls.x86-64.S elfnix_tls.aarch64.S + elfnix_tls.ppc64.S ) endif() diff --git a/compiler-rt/lib/orc/elfnix_tls.ppc64.S b/compiler-rt/lib/orc/elfnix_tls.ppc64.S new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/orc/elfnix_tls.ppc64.S @@ -0,0 +1,33 @@ +//===-- orc_rt_elfnix_tls.ppc64.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 content of this file is PowerPC64 only. +#if defined(__powerpc64__) + + .text + // TODO: add fast-path for repeat access. + // See https://github.com/llvm/llvm-project/issues/51162. + .global ___orc_rt_elfnix_tls_get_addr +___orc_rt_elfnix_tls_get_addr: + addis 2, 12, .TOC.-___orc_rt_elfnix_tls_get_addr@ha + addi 2, 2, .TOC.-___orc_rt_elfnix_tls_get_addr@l + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + bl __orc_rt_elfnix_tls_get_addr_impl + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + +#endif diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S --- a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S @@ -1,4 +1,3 @@ -// XFAIL: target={{powerpc64.*}} // RUN: %clang -c -o %t %s // RUN: %llvm_jitlink %t // diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h --- a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h @@ -41,6 +41,8 @@ RequestCall, // Request calling function without TOC. RequestCallNoTOC, + RequestTLSDescInGOTAndTransformToTOCDelta16HA, + RequestTLSDescInGOTAndTransformToTOCDelta16LO, }; enum PLTCallStubKind { diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp @@ -31,6 +31,70 @@ constexpr StringRef ELFTOCSymbolName = ".TOC."; constexpr StringRef TOCSymbolAliasIdent = "__TOC__"; constexpr uint64_t ELFTOCBaseOffset = 0x8000; +constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO"; + +template +class TLSInfoTableManager_ELF_ppc64 + : public TableManager> { +public: + static const uint8_t TLSInfoEntryContent[16]; + + static StringRef getSectionName() { return ELFTLSInfoSectionName; } + + bool visitEdge(LinkGraph &G, Block *B, Edge &E) { + Edge::Kind K = E.getKind(); + if (K == ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA) { + E.setKind(ppc64::TOCDelta16HA); + E.setTarget(this->getEntryForTarget(G, E.getTarget())); + return true; + } + if (K == ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO) { + E.setKind(ppc64::TOCDelta16LO); + E.setTarget(this->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 + // `fixTLVSectionsAndEdges`, so create mutable content. + auto &TLSInfoEntry = G.createMutableContentBlock( + getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()), + orc::ExecutorAddr(), 8, 0); + TLSInfoEntry.addEdge(ppc64::Pointer64, 8, Target, 0); + return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false); + } + +private: + Section &getTLSInfoSection(LinkGraph &G) { + if (!TLSInfoTable) + TLSInfoTable = + &G.createSection(ELFTLSInfoSectionName, orc::MemProt::Read); + return *TLSInfoTable; + } + + ArrayRef getTLSInfoEntryContent() const { + return {reinterpret_cast(TLSInfoEntryContent), + sizeof(TLSInfoEntryContent)}; + } + + Section *TLSInfoTable = nullptr; +}; + +template <> +const uint8_t TLSInfoTableManager_ELF_ppc64< + support::endianness::little>::TLSInfoEntryContent[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ +}; + +template <> +const uint8_t TLSInfoTableManager_ELF_ppc64< + support::endianness::big>::TLSInfoEntryContent[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ +}; template Symbol &createELFGOTHeader(LinkGraph &G, @@ -91,8 +155,8 @@ registerExistingGOTEntries(G, TOC); ppc64::PLTTableManager PLT(TOC); - visitExistingEdges(G, TOC, PLT); - // TODO: Add TLS support. + TLSInfoTableManager_ELF_ppc64 TLSInfo; + visitExistingEdges(G, TOC, PLT, TLSInfo); // After visiting edges in LinkGraph, we have GOT entries built in the // synthesized section. @@ -164,6 +228,13 @@ if (LLVM_UNLIKELY(ELFReloc == ELF::R_PPC64_NONE)) return Error::success(); + // TLS model markers. We only support global-dynamic model now. + if (ELFReloc == ELF::R_PPC64_TLSGD) + return Error::success(); + if (ELFReloc == ELF::R_PPC64_TLSLD) + return make_error("Local-dynamic TLS model is not supported", + inconvertibleErrorCode()); + auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); if (!ObjSymbol) return ObjSymbol.takeError(); @@ -234,6 +305,12 @@ case ELF::R_PPC64_PCREL34: Kind = ppc64::Delta34; break; + case ELF::R_PPC64_GOT_TLSGD16_HA: + Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA; + break; + case ELF::R_PPC64_GOT_TLSGD16_LO: + Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO; + break; } Edge GE(Kind, Offset, *GraphSymbol, Addend); diff --git a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp @@ -94,6 +94,10 @@ return "RequestCall"; case RequestCallNoTOC: return "RequestCallNoTOC"; + case RequestTLSDescInGOTAndTransformToTOCDelta16HA: + return "RequestTLSDescInGOTAndTransformToTOCDelta16HA"; + case RequestTLSDescInGOTAndTransformToTOCDelta16LO: + return "RequestTLSDescInGOTAndTransformToTOCDelta16LO"; default: return getGenericEdgeKindName(static_cast(K)); }