[llvm] JITLink: Add initial SystemZ Support. (PR #144528)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 17 08:13:20 PDT 2025
https://github.com/anoopkg6 updated https://github.com/llvm/llvm-project/pull/144528
>From e4a4547a394266c1b0c8e464b12ccc0b1cbaf091 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Tue, 17 Jun 2025 15:00:13 +0200
Subject: [PATCH] Add initial llvm-jitlink support for SystemZ.
---
.../ExecutionEngine/JITLink/ELF_systemz.h | 39 +
.../llvm/ExecutionEngine/JITLink/systemz.h | 1089 +++++++++++++++++
.../ExecutionEngine/JITLink/CMakeLists.txt | 2 +
llvm/lib/ExecutionEngine/JITLink/ELF.cpp | 6 +
.../ExecutionEngine/JITLink/ELF_systemz.cpp | 437 +++++++
llvm/lib/ExecutionEngine/JITLink/JITLink.cpp | 6 +
llvm/lib/ExecutionEngine/JITLink/systemz.cpp | 121 ++
.../JITLink/systemz/ELF_systemz_ehframe.s | 58 +
.../JITLink/systemz/ELF_systemz_got.s | 78 ++
.../JITLink/systemz/ELF_systemz_reloc_abs16.s | 35 +
.../JITLink/systemz/ELF_systemz_reloc_abs32.s | 32 +
.../JITLink/systemz/ELF_systemz_reloc_abs64.s | 28 +
.../JITLink/systemz/ELF_systemz_reloc_abs8.s | 38 +
.../systemz/ELF_systemz_reloc_call_pic.s | 82 ++
.../systemz/ELF_systemz_reloc_disp12.s | 28 +
.../systemz/ELF_systemz_reloc_disp20.s | 31 +
.../JITLink/systemz/ELF_systemz_reloc_got.s | 244 ++++
.../systemz/ELF_systemz_reloc_gotrel.s | 68 +
.../JITLink/systemz/ELF_systemz_reloc_pc.s | 20 +
.../JITLink/systemz/ELF_systemz_reloc_pc16.s | 40 +
.../JITLink/systemz/ELF_systemz_reloc_pc32.s | 40 +
.../JITLink/systemz/ELF_systemz_reloc_pc64.s | 34 +
.../JITLink/systemz/ELF_systemz_reloc_pcdbl.s | 84 ++
.../JITLink/systemz/ELF_systemz_reloc_plt.s | 71 ++
.../systemz/ELF_systemz_reloc_pltdbl.s | 51 +
.../JITLink/systemz/lit.local.cfg | 2 +
llvm/test/ExecutionEngine/lit.local.cfg | 2 +-
27 files changed, 2765 insertions(+), 1 deletion(-)
create mode 100644 llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h
create mode 100644 llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
create mode 100644 llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
create mode 100644 llvm/lib/ExecutionEngine/JITLink/systemz.cpp
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_ehframe.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs64.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_got.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc64.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pcdbl.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pltdbl.s
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/lit.local.cfg
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h
new file mode 100644
index 0000000000000..c78bc7cc1f499
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h
@@ -0,0 +1,39 @@
+//===--- ELF_systemz.h - JIT link functions for ELF/systemz --*- C++ -*----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+//
+// jit-link functions for ELF/systemz.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_ELF_SYSTEMZ_H
+#define LLVM_EXECUTIONENGINE_JITLINK_ELF_SYSTEMZ_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+
+namespace llvm {
+namespace jitlink {
+
+/// Create a LinkGraph from an ELF/systemz relocatable object
+///
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject_systemz(MemoryBufferRef ObjectBuffer);
+
+/// jit-link the given object buffer, which must be a ELF systemz relocatable
+/// object file.
+void link_ELF_systemz(std::unique_ptr<LinkGraph> G,
+ std::unique_ptr<JITLinkContext> Ctx);
+
+} // end namespace jitlink
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_ELF_SYSTEMZ_H
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
new file mode 100644
index 0000000000000..e1498ff820fe6
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -0,0 +1,1089 @@
+//=== systemz.h - Generic JITLink systemz edge kinds, utilities -*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic utilities for graphs representing systemz objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_SYSTEMZ_H
+#define LLVM_EXECUTIONENGINE_JITLINK_SYSTEMZ_H
+
+#include "TableManager.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+
+using namespace llvm::support::endian;
+
+namespace llvm {
+namespace jitlink {
+namespace systemz {
+
+/// Represents systemz fixups and other systemz-specific edge kinds.
+enum EdgeKind_systemz : Edge::Kind {
+
+ /// A plain 64-bit pointer value relocation.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target + Addend : uint64
+ ///
+ Pointer64 = Edge::FirstRelocation,
+
+ /// A plain 32-bit pointer value relocation.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target + Addend : uint32
+ ///
+ /// Errors:
+ /// - The target must reside in the low 32-bits of the address space,
+ /// otherwise an out-of-range error will be returned.
+ ///
+ Pointer32,
+
+ /// A plain 20-bit pointer value relocation.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target + Addend : uint20
+ ///
+ /// Errors:
+ /// - The target must reside in the mid 20-bits of the address space,
+ /// otherwise an out-of-range error will be returned.
+ ///
+ Pointer20,
+
+ /// A plain 16-bit pointer value relocation.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target + Addend : uint16
+ ///
+ /// Errors:
+ /// - The target must reside in the low 16-bits of the address space,
+ /// otherwise an out-of-range error will be returned.
+ ///
+ Pointer16,
+
+ /// A plain 12-bit pointer value relocation.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target + Addend : uint12
+ ///
+ /// Errors:
+ /// - The target must reside in the low 12-bits of the address space,
+ /// otherwise an out-of-range error will be returned.
+ ///
+ Pointer12,
+
+ /// A plain 8-bit pointer value relocation.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target + Addend : uint8
+ ///
+ /// Errors:
+ /// - The target must reside in the low 8-bits of the address space,
+ /// otherwise an out-of-range error will be returned.
+ ///
+ Pointer8,
+
+ /// A 64-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - Fixup + Addend : int64
+ ///
+ Delta64,
+
+ /// A 32-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - Fixup + Addend : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta32,
+
+ /// A 16-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - Fixup + Addend : int16
+ ///
+ /// Errors:
+ /// - The result of the fixup expression must fit into an int16, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta16,
+
+ /// A 32-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend : int32) >> 1
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int33, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ Delta32dbl,
+
+ /// A 24-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend : int24) >> 1
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int25, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ Delta24dbl,
+
+ /// A 16-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend : int16) >> 1
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int17, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ Delta16dbl,
+
+ /// A 12-bit delta.
+ ///
+ /// Delta from the fixup to the target.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend : int12) >> 1
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int13, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ Delta12dbl,
+
+ /// A 64-bit negative delta.
+ ///
+ /// Delta from target back to the fixup.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Fixup - Target + Addend : int64
+ ///
+ NegDelta64,
+
+ /// A 32-bit negative delta.
+ ///
+ /// Delta from the target back to the fixup.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Fixup - Target + Addend : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ NegDelta32,
+
+ /// A 64-bit GOT delta.
+ ///
+ /// Delta from the global offset table to the target
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTSymbol + Addend : int64
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ Delta64FromGOT,
+
+ /// A 32-bit GOT delta.
+ ///
+ /// Delta from the global offset table to the target
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTSymbol + Addend : int32
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ Delta32FromGOT,
+
+ /// A 16-bit GOT delta.
+ ///
+ /// Delta from the global offset table to the target
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTSymbol + Addend : int16
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int16, otherwise
+ /// an out-of-range error will be returned.
+ Delta16FromGOT,
+
+ /// A 32-bit PC-relative branch.
+ ///
+ /// Represents a PC-relative call or branch to a target. This can be used to
+ /// identify, record, and/or patch call sites.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int33, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ BranchPCRelPLT32dbl,
+
+ /// A 24-bit PC-relative branch.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int24
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int25, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ BranchPCRelPLT24dbl,
+
+ /// A 16-bit PC-relative branch.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int16
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int17, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ BranchPCRelPLT16dbl,
+
+ /// A 12-bit PC-relative branch.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int12
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int13, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ BranchPCRelPLT12dbl,
+
+ /// A 64-bit PC-relative PLT address.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - Fixup + Addend : int64
+ ///
+ BranchPCRelPLT64,
+
+ /// A 32-bit PC-relative PLT address.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - Fixup + Addend : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ BranchPCRelPLT32,
+
+ /// A 32-bit PC-relative branch to a pointer jump stub.
+ /// Create a jump stub block that jumps via the pointer at the given symbol.
+ ///
+ /// Stub Content:
+ /// larl %r1, ptr
+ /// lg %r1, 0(%r1)
+ /// j %r1
+ ///
+ /// Fixup expression at offset 2 of branch Instruction:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int33, otherwise an out-of-range error will be returned.
+ /// an out-of-range error will be returned.
+ ///
+ Branch32dblToStub,
+
+ /// A 64-bit offset from GOT to PLT.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int64
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ ///
+ DeltaPLT64FromGOT,
+
+ /// A 32-bit offset from GOT to PLT.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int32
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ DeltaPLT32FromGOT,
+
+ /// A 16-bit offset from GOT to PLT.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int16
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int16, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ DeltaPLT16FromGOT,
+
+ /// A 64-bit GOT offset.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int64
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ ///
+ Delta64GOT,
+
+ /// A 32-bit GOT offset.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int32
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta32GOT,
+
+ /// A 20-bit GOT offset.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int20
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int20, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta20GOT,
+
+ /// A 16-bit GOT offset.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int16
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int16, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta16GOT,
+
+ /// A 12-bit GOT offset.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int12
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int12, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta12GOT,
+
+ /// A 32-bit PC rel. offset to GOT.
+ ///
+ /// Fixup expression:
+ /// Fixup <- GOTBase - Fixup + Addend : int32
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ DeltaPCRelGOT,
+
+ /// A 32-bit PC rel. offset to GOT shifted by 1.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (GOTBase - Fixup + Addend) >> 1 : int32
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int33, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ DeltaPCRelGOTdbl,
+
+ /// A 64-bit offset to Jump Slot.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int64
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ ///
+ Delta64JumpSlot,
+
+ /// A 32-bit offset to Jump Slot.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int32
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int32, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta32JumpSlot,
+
+ /// A 20-bit offset to Jump Slot.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int20
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int20, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta20JumpSlot,
+
+ /// A 16-bit offset to Jump Slot.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int16
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int16, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta16JumpSlot,
+
+ /// A 12-bit offset to Jump Slot.
+ ///
+ /// Fixup expression:
+ /// Fixup <- Target - GOTBase + Addend : int12
+ ///
+ /// Errors:
+ /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+ /// symbol was not been defined.
+ /// - The result of the fixup expression must fit into an int12, otherwise
+ /// an out-of-range error will be returned.
+ ///
+ Delta12JumpSlot,
+
+ /// A 32-bit PC rel. offset to Jump Slot.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int33, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ PCRel32JumpSlot,
+
+ /// A 32-bit PC rel. to GOT entry >> 1.
+ ///
+ /// Fixup expression:
+ /// Fixup <- (Target - Fixup + Addend) >> 1 : int32
+ ///
+ /// Errors:
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// fit into an int33, otherwise an out-of-range error will be returned.
+ /// - The result of the fixup expression before shifting right by 1 must
+ /// be multiple of 2, otherwise an alignment error will be returned.
+ ///
+ PCRel32GOTEntry,
+
+};
+
+/// Returns a string name for the given systemz edge. For debugging purposes
+/// only
+const char *getEdgeKindName(Edge::Kind K);
+
+/// Apply fixup expression for edge to block content.
+inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
+ const Symbol *GOTSymbol) {
+ using namespace support;
+
+ char *BlockWorkingMem = B.getAlreadyMutableContent().data();
+ char *FixupPtr = BlockWorkingMem + E.getOffset();
+ orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
+ int64_t S = E.getTarget().getAddress().getValue();
+ int64_t A = E.getAddend();
+ int64_t P = FixupAddress.getValue();
+ int64_t GOTBase = GOTSymbol ? GOTSymbol->getAddress().getValue() : 0;
+ Edge::Kind K = E.getKind();
+
+ DEBUG_WITH_TYPE("jitlink", {
+ dbgs() << " Applying fixup on " << G.getEdgeKindName(K)
+ << " edge, (S, A, P, .GOT.) = (" << formatv("{0:x}", S) << ", "
+ << formatv("{0:x}", A) << ", " << formatv("{0:x}", P) << ", "
+ << formatv("{0:x}", GOTBase) << ")\n";
+ });
+
+ const auto isAlignmentCorrect = [](uint64_t Value, int N) {
+ return (Value & (N - 1)) ? false : true;
+ };
+
+ switch (K) {
+ case Pointer64: {
+ uint64_t Value = S + A;
+ write64be(FixupPtr, Value);
+ break;
+ }
+ case Pointer32: {
+ uint64_t Value = S + A;
+ if (!LLVM_UNLIKELY(isUInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(ubig32_t *)FixupPtr = Value;
+ break;
+ }
+ case Pointer20: {
+ uint64_t Value = S + A;
+ if (!LLVM_UNLIKELY(isInt<20>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ write32be(FixupPtr, (read32be(FixupPtr) & 0xF00000FF) |
+ ((Value & 0xFFF) << 16) | ((Value & 0xFF000) >> 4));
+ break;
+ }
+ case Pointer16: {
+ uint64_t Value = S + A;
+ if (!LLVM_UNLIKELY(isUInt<16>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(ubig16_t *)FixupPtr = Value;
+ break;
+ }
+ case Pointer12: {
+ uint64_t Value = S + A;
+ if (!LLVM_UNLIKELY(isUInt<12>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ write16be(FixupPtr, (read16be(FixupPtr) & 0xF000) | Value);
+ break;
+ }
+ case Pointer8: {
+ uint64_t Value = S + A;
+ if (!LLVM_UNLIKELY(isUInt<8>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(uint8_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta64: {
+ int64_t Value = S + A - P;
+ *(big64_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta32: {
+ int64_t Value = S + A - P;
+ if (!LLVM_UNLIKELY(isInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta16: {
+ int64_t Value = S + A - P;
+ if (!LLVM_UNLIKELY(isInt<16>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big16_t *)FixupPtr = Value;
+ break;
+ }
+ case NegDelta32: {
+ int64_t Value = P + A - S;
+ if (!LLVM_UNLIKELY(isInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta32dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<33>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write32be(FixupPtr, Value >> 1);
+ break;
+ }
+ case Delta24dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<25>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ FixupPtr[0] = Value >> 17;
+ FixupPtr[1] = Value >> 9;
+ FixupPtr[2] = Value >> 1;
+ break;
+ }
+ case Delta16dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<17>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write16be(FixupPtr, Value >> 1);
+ break;
+ }
+ case Delta12dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<13>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write16be(FixupPtr,
+ (read16be(FixupPtr) & 0xF000) | ((Value >> 1) & 0x0FFF));
+ break;
+ }
+ case Delta64FromGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = S - GOTBase + A;
+ *(big64_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta32FromGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta16FromGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isInt<16>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big16_t *)FixupPtr = Value;
+ break;
+ }
+ case DeltaPCRelGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = GOTBase + A - P;
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case DeltaPCRelGOTdbl: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = (GOTBase + A - P);
+ if (!LLVM_UNLIKELY(isInt<33>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write32be(FixupPtr, Value >> 1);
+ break;
+ }
+ case BranchPCRelPLT32dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<33>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write32be(FixupPtr, Value >> 1);
+ break;
+ }
+ case BranchPCRelPLT24dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<25>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ FixupPtr[0] = Value >> 17;
+ FixupPtr[1] = Value >> 9;
+ FixupPtr[2] = Value >> 1;
+ break;
+ }
+ case BranchPCRelPLT16dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<17>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write16be(FixupPtr, Value >> 1);
+ break;
+ }
+ case BranchPCRelPLT12dbl: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<13>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write16be(FixupPtr,
+ (read16be(FixupPtr) & 0xF000) | ((Value >> 1) & 0x0FFF));
+ break;
+ }
+ case BranchPCRelPLT64: {
+ int64_t Value = (S + A - P);
+ *(big64_t *)FixupPtr = Value;
+ break;
+ }
+ case BranchPCRelPLT32: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case DeltaPLT64FromGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = (S + A - GOTBase);
+ *(big64_t *)FixupPtr = Value;
+ break;
+ }
+ case DeltaPLT32FromGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = (S + A - GOTBase);
+ if (!LLVM_UNLIKELY(isInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case DeltaPLT16FromGOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = (S + A - GOTBase);
+ if (!LLVM_UNLIKELY(isInt<16>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big16_t *)FixupPtr = Value;
+ break;
+ }
+ case Branch32dblToStub: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<33>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ char *AddrToPatch = FixupPtr + 2;
+ *(big32_t *)AddrToPatch = (Value >> 1);
+ break;
+ }
+ case PCRel32GOTEntry: {
+ int64_t Value = (S + A - P);
+ if (!LLVM_UNLIKELY(isInt<33>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write32be(FixupPtr, Value >> 1);
+ break;
+ }
+ case Delta64GOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = S - GOTBase + A;
+ *(big64_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta32GOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isUInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta20GOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isInt<20>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ write32be(FixupPtr, (read32be(FixupPtr) & 0xF00000FF) |
+ ((Value & 0xFFF) << 16) | ((Value & 0xFF000) >> 4));
+ break;
+ }
+ case Delta16GOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isUInt<16>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big16_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta12GOT: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isUInt<12>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ write16be(FixupPtr, (read16be(FixupPtr) & 0xF000) | Value);
+ break;
+ }
+ case Delta64JumpSlot: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ *(big64_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta32JumpSlot: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isUInt<32>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big32_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta20JumpSlot: {
+ assert(GOTSymbol && "No GOT section symbol");
+ int64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isInt<20>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ write32be(FixupPtr, (read32be(FixupPtr) & 0xF00000FF) |
+ ((Value & 0xFFF) << 16) | ((Value & 0xFF000) >> 4));
+ break;
+ }
+ case Delta16JumpSlot: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isUInt<16>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ *(big16_t *)FixupPtr = Value;
+ break;
+ }
+ case Delta12JumpSlot: {
+ assert(GOTSymbol && "No GOT section symbol");
+ uint64_t Value = S - GOTBase + A;
+ if (!LLVM_UNLIKELY(isUInt<13>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ write16be(FixupPtr, (read16be(FixupPtr) & 0xF000) | Value);
+ break;
+ }
+ case PCRel32JumpSlot: {
+ int64_t Value = S + A - P;
+ if (!LLVM_UNLIKELY(isInt<33>(Value)))
+ return makeTargetOutOfRangeError(G, B, E);
+ if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
+ return makeAlignmentError(FixupAddress, Value, 2, E);
+ write32be(FixupPtr, Value >> 1);
+ break;
+ }
+ default:
+ return make_error<JITLinkError>(
+ "In graph " + G.getName() + ", section " + B.getSection().getName() +
+ " unsupported edge kind " + getEdgeKindName(E.getKind()));
+ }
+
+ return Error::success();
+}
+
+/// SystemZ null pointer content.
+extern const char NullPointerContent[8];
+inline ArrayRef<char> getGOTEntryBlockContent(LinkGraph &G) {
+ return {reinterpret_cast<const char *>(NullPointerContent),
+ G.getPointerSize()};
+}
+
+/// SystemZ pointer jump stub content.
+///
+/// Contains the instruction sequence for an indirect jump via an in-memory
+/// pointer:
+/// larl %r1, ptr
+/// lg %r1, 0(%r1)
+/// j %r1
+constexpr size_t StubEntrySize = 14;
+extern const char Pointer64JumpStubContent[StubEntrySize];
+inline ArrayRef<char> getStubBlockContent(LinkGraph &G) {
+ auto StubContent = Pointer64JumpStubContent;
+ return {reinterpret_cast<const char *>(StubContent), StubEntrySize};
+}
+
+/// Creates a new pointer block in the given section and returns an
+/// Anonymous symbol pointing to it.
+///
+/// If InitialTarget is given then an Pointer64 relocation will be added to the
+/// block pointing at InitialTarget.
+inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
+ Symbol *InitialTarget = nullptr,
+ uint64_t InitialAddend = 0) {
+ auto &B = G.createContentBlock(PointerSection, getGOTEntryBlockContent(G),
+ orc::ExecutorAddr(), G.getPointerSize(), 0);
+ if (InitialTarget)
+ B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
+ return G.addAnonymousSymbol(B, 0, G.getPointerSize(), false, false);
+}
+
+/// Create a jump stub block that jumps via the pointer at the given symbol.
+///
+/// The stub block will have the following default values:
+/// alignment: 8-bit
+/// alignment-offset: 0
+inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
+ Symbol &PointerSymbol) {
+ auto &B = G.createContentBlock(StubSection, getStubBlockContent(G),
+ orc::ExecutorAddr(), 8, 0);
+ B.addEdge(Branch32dblToStub, 0, PointerSymbol, 0);
+ return B;
+}
+
+/// Create a jump stub that jumps via the pointer at the given symbol and
+/// an anonymous symbol pointing to it. Return the anonymous symbol.
+///
+/// The stub block will be created by createPointerJumpStubBlock.
+inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
+ Section &StubSection,
+ Symbol &PointerSymbol) {
+ return G.addAnonymousSymbol(
+ createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0,
+ StubEntrySize, true, false);
+}
+
+/// Global Offset Table Builder.
+class GOTTableManager : public TableManager<GOTTableManager> {
+public:
+ static StringRef getSectionName() { return "$__GOT"; }
+
+ bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+ if (E.getTarget().isDefined())
+ return false;
+ Edge::Kind KindToSet = Edge::Invalid;
+ switch (E.getKind()) {
+ case systemz::Delta12GOT:
+ case systemz::Delta16GOT:
+ case systemz::Delta20GOT:
+ case systemz::Delta32GOT:
+ case systemz::Delta64GOT:
+ case systemz::Delta16FromGOT:
+ case systemz::Delta32FromGOT:
+ case systemz::Delta64FromGOT:
+ case systemz::Delta12JumpSlot:
+ case systemz::Delta16JumpSlot:
+ case systemz::Delta32JumpSlot:
+ case systemz::Delta64JumpSlot:
+ case systemz::Delta20JumpSlot: {
+ case systemz::DeltaPCRelGOT:
+ case systemz::DeltaPCRelGOTdbl:
+ case systemz::PCRel32GOTEntry:
+ case systemz::PCRel32JumpSlot:
+ KindToSet = E.getKind();
+ break;
+ }
+ default:
+ return false;
+ }
+ assert(KindToSet != Edge::Invalid &&
+ "Fell through switch, but no new kind to set");
+ DEBUG_WITH_TYPE("jitlink", {
+ dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
+ << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
+ << formatv("{0:x}", E.getOffset()) << ")\n";
+ });
+ E.setTarget(getEntryForTarget(G, E.getTarget()));
+ return true;
+ }
+
+ Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+ return createAnonymousPointer(G, getGOTSection(G), &Target);
+ }
+
+private:
+ Section &getGOTSection(LinkGraph &G) {
+ if (!GOTSection)
+ GOTSection = &G.createSection(getSectionName(),
+ orc::MemProt::Read | orc::MemProt::Exec);
+ return *GOTSection;
+ }
+
+ Section *GOTSection = nullptr;
+};
+
+/// Procedure Linkage Table Builder.
+class PLTTableManager : public TableManager<PLTTableManager> {
+public:
+ PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
+
+ static StringRef getSectionName() { return "$__STUBS"; }
+
+ bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+ if (E.getTarget().isDefined())
+ return false;
+
+ switch (E.getKind()) {
+ case systemz::BranchPCRelPLT32:
+ case systemz::BranchPCRelPLT64:
+ case systemz::BranchPCRelPLT12dbl:
+ case systemz::BranchPCRelPLT16dbl:
+ case systemz::BranchPCRelPLT24dbl:
+ case systemz::BranchPCRelPLT32dbl:
+ case systemz::DeltaPLT16FromGOT:
+ case systemz::DeltaPLT32FromGOT:
+ case systemz::DeltaPLT64FromGOT:
+ break;
+ default:
+ return false;
+ }
+ DEBUG_WITH_TYPE("jitlink", {
+ dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
+ << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
+ << formatv("{0:x}", E.getOffset()) << ")\n";
+ });
+ E.setTarget(getEntryForTarget(G, E.getTarget()));
+ return true;
+ }
+
+ Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+ return createAnonymousPointerJumpStub(G, getStubsSection(G),
+ GOT.getEntryForTarget(G, Target));
+ }
+
+public:
+ Section &getStubsSection(LinkGraph &G) {
+ if (!StubsSection)
+ StubsSection = &G.createSection(getSectionName(),
+ orc::MemProt::Read | orc::MemProt::Exec);
+ return *StubsSection;
+ }
+
+ GOTTableManager &GOT;
+ Section *StubsSection = nullptr;
+};
+
+} // namespace systemz
+} // namespace jitlink
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_SYSTEMZ_H
diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
index e5f5a99c39bc0..bd78150407830 100644
--- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
@@ -26,6 +26,7 @@ add_llvm_component_library(LLVMJITLink
ELF_loongarch.cpp
ELF_ppc64.cpp
ELF_riscv.cpp
+ ELF_systemz.cpp
ELF_x86_64.cpp
# COFF
@@ -41,6 +42,7 @@ add_llvm_component_library(LLVMJITLink
loongarch.cpp
ppc64.cpp
riscv.cpp
+ systemz.cpp
x86_64.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
index fdcce20cd2d10..374982d9e2b1d 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
@@ -19,6 +19,7 @@
#include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
#include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"
#include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
+#include "llvm/ExecutionEngine/JITLink/ELF_systemz.h"
#include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Format.h"
@@ -99,6 +100,8 @@ createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) {
}
case ELF::EM_RISCV:
return createLinkGraphFromELFObject_riscv(ObjectBuffer);
+ case ELF::EM_S390:
+ return createLinkGraphFromELFObject_systemz(ObjectBuffer);
case ELF::EM_X86_64:
return createLinkGraphFromELFObject_x86_64(ObjectBuffer);
case ELF::EM_386:
@@ -136,6 +139,9 @@ void link_ELF(std::unique_ptr<LinkGraph> G,
case Triple::riscv64:
link_ELF_riscv(std::move(G), std::move(Ctx));
return;
+ case Triple::systemz:
+ link_ELF_systemz(std::move(G), std::move(Ctx));
+ return;
case Triple::x86_64:
link_ELF_x86_64(std::move(G), std::move(Ctx));
return;
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
new file mode 100644
index 0000000000000..6d598d62b1fc2
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -0,0 +1,437 @@
+//===----- ELF_systemz.cpp - JIT linker implementation for ELF/systemz ----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// ELF/systemz jit-link implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
+#include "llvm/ExecutionEngine/JITLink/systemz.h"
+#include "llvm/Object/ELFObjectFile.h"
+
+#include "DefineExternalSectionStartAndEndSymbols.h"
+#include "EHFrameSupportImpl.h"
+#include "ELFLinkGraphBuilder.h"
+#include "JITLinkGeneric.h"
+
+#define DEBUG_TYPE "jitlink"
+
+using namespace llvm;
+using namespace llvm::jitlink;
+
+namespace {
+
+constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
+
+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);
+ return Error::success();
+}
+
+} // namespace
+
+namespace llvm {
+namespace jitlink {
+class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {
+ friend class JITLinker<ELFJITLinker_systemz>;
+
+public:
+ ELFJITLinker_systemz(std::unique_ptr<JITLinkContext> Ctx,
+ std::unique_ptr<LinkGraph> G,
+ PassConfiguration PassConfig)
+ : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
+ if (shouldAddDefaultTargetPasses(getGraph().getTargetTriple()))
+ getPassConfig().PostAllocationPasses.push_back(
+ [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
+ }
+
+private:
+ Symbol *GOTSymbol = nullptr;
+
+ Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
+ return systemz::applyFixup(G, B, E, GOTSymbol);
+ }
+
+ Error getOrCreateGOTSymbol(LinkGraph &G) {
+ auto DefineExternalGOTSymbolIfPresent =
+ createDefineExternalSectionStartAndEndSymbolsPass(
+ [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
+ if (Sym.getName() == ELFGOTSymbolName)
+ if (auto *GOTSection = G.findSectionByName(
+ systemz::GOTTableManager::getSectionName())) {
+ GOTSymbol = &Sym;
+ return {*GOTSection, true};
+ }
+ return {};
+ });
+
+ // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
+ // external.
+ if (auto Err = DefineExternalGOTSymbolIfPresent(G))
+ return Err;
+
+ // If we succeeded then we're done.
+ if (GOTSymbol)
+ return Error::success();
+
+ // Otherwise look for a GOT section: If it already has a start symbol we'll
+ // record it, otherwise we'll create our own.
+ // If there's a GOT section but we didn't find an external GOT symbol...
+ if (auto *GOTSection =
+ G.findSectionByName(systemz::GOTTableManager::getSectionName())) {
+
+ // Check for an existing defined symbol.
+ for (auto *Sym : GOTSection->symbols())
+ if (Sym->getName() == ELFGOTSymbolName) {
+ GOTSymbol = Sym;
+ return Error::success();
+ }
+
+ // If there's no defined symbol then create one.
+ SectionRange SR(*GOTSection);
+ if (SR.empty())
+ GOTSymbol =
+ &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
+ Linkage::Strong, Scope::Local, true);
+ else
+ GOTSymbol =
+ &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
+ Linkage::Strong, Scope::Local, false, true);
+ }
+
+ // If we still haven't found a GOT symbol then double check the externals.
+ // We may have a GOT-relative reference but no GOT section, in which case
+ // we just need to point the GOT symbol at some address in this graph.
+ if (!GOTSymbol) {
+ for (auto *Sym : G.external_symbols()) {
+ if (Sym->getName() == ELFGOTSymbolName) {
+ auto Blocks = G.blocks();
+ if (!Blocks.empty()) {
+ G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());
+ GOTSymbol = Sym;
+ break;
+ }
+ }
+ }
+ }
+
+ return Error::success();
+ }
+};
+
+class ELFLinkGraphBuilder_systemz
+ : public ELFLinkGraphBuilder<object::ELF64BE> {
+private:
+ using ELFT = object::ELF64BE;
+ using Base = ELFLinkGraphBuilder<ELFT>;
+ using Base::G; // Use LinkGraph pointer from base class.
+
+ Error addRelocations() override {
+ LLVM_DEBUG(dbgs() << "Processing relocations:\n");
+
+ using Base = ELFLinkGraphBuilder<ELFT>;
+ using Self = ELFLinkGraphBuilder_systemz;
+ for (const auto &RelSect : Base::Sections) {
+ if (RelSect.sh_type == ELF::SHT_REL)
+ // Validate the section to read relocation entries from.
+ return make_error<StringError>("No SHT_REL in valid " +
+ G->getTargetTriple().getArchName() +
+ " ELF object files",
+ inconvertibleErrorCode());
+
+ if (Error Err = Base::forEachRelaRelocation(RelSect, this,
+ &Self::addSingleRelocation))
+ return Err;
+ }
+
+ return Error::success();
+ }
+
+ Error addSingleRelocation(const typename ELFT::Rela &Rel,
+ const typename ELFT::Shdr &FixupSect,
+ Block &BlockToFix) {
+ using support::big32_t;
+ using Base = ELFLinkGraphBuilder<ELFT>;
+ auto ELFReloc = Rel.getType(false);
+
+ // No reloc.
+ if (LLVM_UNLIKELY(ELFReloc == ELF::R_390_NONE))
+ return Error::success();
+
+ uint32_t SymbolIndex = Rel.getSymbol(false);
+ auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
+ if (!ObjSymbol)
+ return ObjSymbol.takeError();
+
+ Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
+ if (!GraphSymbol)
+ return make_error<StringError>(
+ formatv("Could not find symbol at given index, did you add it to "
+ "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
+ SymbolIndex, (*ObjSymbol)->st_shndx,
+ Base::GraphSymbols.size()),
+ inconvertibleErrorCode());
+
+ // Validate the relocation kind.
+ int64_t Addend = Rel.r_addend;
+ Edge::Kind Kind = Edge::Invalid;
+
+ switch (ELFReloc) {
+ case ELF::R_390_PC64: {
+ Kind = systemz::Delta64;
+ break;
+ }
+ case ELF::R_390_PC32: {
+ Kind = systemz::Delta32;
+ break;
+ }
+ case ELF::R_390_PC16: {
+ Kind = systemz::Delta16;
+ break;
+ }
+ case ELF::R_390_PC32DBL: {
+ Kind = systemz::Delta32dbl;
+ break;
+ }
+ case ELF::R_390_PC24DBL: {
+ Kind = systemz::Delta24dbl;
+ break;
+ }
+ case ELF::R_390_PC16DBL: {
+ Kind = systemz::Delta16dbl;
+ break;
+ }
+ case ELF::R_390_PC12DBL: {
+ Kind = systemz::Delta12dbl;
+ break;
+ }
+ case ELF::R_390_64: {
+ Kind = systemz::Pointer64;
+ break;
+ }
+ case ELF::R_390_32: {
+ Kind = systemz::Pointer32;
+ break;
+ }
+ case ELF::R_390_20: {
+ Kind = systemz::Pointer20;
+ break;
+ }
+ case ELF::R_390_16: {
+ Kind = systemz::Pointer16;
+ break;
+ }
+ case ELF::R_390_12: {
+ Kind = systemz::Pointer12;
+ break;
+ }
+ case ELF::R_390_8: {
+ Kind = systemz::Pointer8;
+ break;
+ }
+ // Relocations targeting the PLT associated with the symbol.
+ case ELF::R_390_PLT64: {
+ Kind = systemz::BranchPCRelPLT64;
+ break;
+ }
+ case ELF::R_390_PLT32: {
+ Kind = systemz::BranchPCRelPLT32;
+ break;
+ }
+ case ELF::R_390_PLT32DBL: {
+ Kind = systemz::BranchPCRelPLT32dbl;
+ break;
+ }
+ case ELF::R_390_PLT24DBL: {
+ Kind = systemz::BranchPCRelPLT24dbl;
+ break;
+ }
+ case ELF::R_390_PLT16DBL: {
+ Kind = systemz::BranchPCRelPLT16dbl;
+ break;
+ }
+ case ELF::R_390_PLT12DBL: {
+ Kind = systemz::BranchPCRelPLT12dbl;
+ break;
+ }
+ case ELF::R_390_PLTOFF64: {
+ Kind = systemz::DeltaPLT64FromGOT;
+ break;
+ }
+ case ELF::R_390_PLTOFF32: {
+ Kind = systemz::DeltaPLT32FromGOT;
+ break;
+ }
+ case ELF::R_390_PLTOFF16: {
+ Kind = systemz::DeltaPLT16FromGOT;
+ break;
+ }
+ // Relocations targeting the GOT entry associated with the symbol.
+ case ELF::R_390_GOTOFF64: {
+ Kind = systemz::Delta64FromGOT;
+ break;
+ }
+ // Seems loke ‘R_390_GOTOFF32’.
+ case ELF::R_390_GOTOFF: {
+ Kind = systemz::Delta32FromGOT;
+ break;
+ }
+ case ELF::R_390_GOTOFF16: {
+ Kind = systemz::Delta16FromGOT;
+ break;
+ }
+ case ELF::R_390_GOT64: {
+ Kind = systemz::Delta64GOT;
+ break;
+ }
+ case ELF::R_390_GOT32: {
+ Kind = systemz::Delta32GOT;
+ break;
+ }
+ case ELF::R_390_GOT20: {
+ Kind = systemz::Delta20GOT;
+ break;
+ }
+ case ELF::R_390_GOT16: {
+ Kind = systemz::Delta16GOT;
+ break;
+ }
+ case ELF::R_390_GOT12: {
+ Kind = systemz::Delta12GOT;
+ break;
+ }
+ case ELF::R_390_GOTPC: {
+ Kind = systemz::DeltaPCRelGOT;
+ break;
+ }
+ case ELF::R_390_GOTPCDBL: {
+ Kind = systemz::DeltaPCRelGOTdbl;
+ break;
+ }
+ case ELF::R_390_GOTPLT64: {
+ Kind = systemz::Delta64JumpSlot;
+ break;
+ }
+ case ELF::R_390_GOTPLT32: {
+ Kind = systemz::Delta32JumpSlot;
+ break;
+ }
+ case ELF::R_390_GOTPLT20: {
+ Kind = systemz::Delta20JumpSlot;
+ break;
+ }
+ case ELF::R_390_GOTPLT16: {
+ Kind = systemz::Delta16JumpSlot;
+ break;
+ }
+ case ELF::R_390_GOTPLT12: {
+ Kind = systemz::Delta12JumpSlot;
+ break;
+ }
+ case ELF::R_390_GOTPLTENT: {
+ Kind = systemz::PCRel32JumpSlot;
+ break;
+ }
+ case ELF::R_390_GOTENT: {
+ Kind = systemz::PCRel32GOTEntry;
+ break;
+ }
+ default:
+ return make_error<JITLinkError>(
+ "In " + G->getName() + ": Unsupported systemz relocation type " +
+ object::getELFRelocationTypeName(ELF::EM_S390, ELFReloc));
+ }
+ auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
+ Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
+ Edge GE(Kind, Offset, *GraphSymbol, Addend);
+ LLVM_DEBUG({
+ dbgs() << " ";
+ printEdge(dbgs(), BlockToFix, GE, systemz::getEdgeKindName(Kind));
+ dbgs() << "\n";
+ });
+
+ BlockToFix.addEdge(std::move(GE));
+
+ return Error::success();
+ }
+
+public:
+ ELFLinkGraphBuilder_systemz(StringRef FileName,
+ const object::ELFFile<ELFT> &Obj, Triple TT,
+ SubtargetFeatures Features)
+ : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),
+ FileName, systemz::getEdgeKindName) {}
+};
+
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject_systemz(MemoryBufferRef ObjectBuffer) {
+ LLVM_DEBUG({
+ dbgs() << "Building jitlink graph for new input "
+ << ObjectBuffer.getBufferIdentifier() << "...\n";
+ });
+
+ auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
+ if (!ELFObj)
+ return ELFObj.takeError();
+
+ auto Features = (*ELFObj)->getFeatures();
+ if (!Features)
+ return Features.takeError();
+
+ assert((*ELFObj)->getArch() == Triple::systemz &&
+ "Only SystemZ (big endian) is supported for now");
+
+ auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj);
+ return ELFLinkGraphBuilder_systemz(
+ (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
+ (*ELFObj)->makeTriple(), std::move(*Features))
+ .buildGraph();
+}
+
+void link_ELF_systemz(std::unique_ptr<LinkGraph> G,
+ std::unique_ptr<JITLinkContext> Ctx) {
+ PassConfiguration Config;
+ const Triple &TT = G->getTargetTriple();
+ if (Ctx->shouldAddDefaultTargetPasses(TT)) {
+ // Add eh-frame passes.
+ Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
+ Config.PrePrunePasses.push_back(
+ EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), systemz::Pointer32,
+ systemz::Pointer64, systemz::Delta32, systemz::Delta64,
+ systemz::NegDelta32));
+ Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
+
+ // Add a mark-live pass.
+ if (auto MarkLive = Ctx->getMarkLivePass(TT))
+ Config.PrePrunePasses.push_back(std::move(MarkLive));
+ else
+ Config.PrePrunePasses.push_back(markAllSymbolsLive);
+
+ // Add an in-place GOT/Stubs build pass.
+ Config.PostPrunePasses.push_back(buildTables_ELF_systemz);
+
+ // Resolve any external section start / end symbols.
+ Config.PostAllocationPasses.push_back(
+ createDefineExternalSectionStartAndEndSymbolsPass(
+ identifyELFSectionStartAndEndSymbols));
+
+ // TODO: Add GOT/Stubs optimizer pass.
+ // Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);
+ }
+
+ if (auto Err = Ctx->modifyPassConfig(*G, Config))
+ return Ctx->notifyFailed(std::move(Err));
+
+ ELFJITLinker_systemz::link(std::move(Ctx), std::move(G), std::move(Config));
+}
+
+} // namespace jitlink
+} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index ef382c3ce695a..453c26cca8eae 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -16,6 +16,7 @@
#include "llvm/ExecutionEngine/JITLink/aarch64.h"
#include "llvm/ExecutionEngine/JITLink/i386.h"
#include "llvm/ExecutionEngine/JITLink/loongarch.h"
+#include "llvm/ExecutionEngine/JITLink/systemz.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -459,6 +460,8 @@ AnonymousPointerCreator getAnonymousPointerCreator(const Triple &TT) {
case Triple::loongarch32:
case Triple::loongarch64:
return loongarch::createAnonymousPointer;
+ case Triple::systemz:
+ return systemz::createAnonymousPointer;
default:
return nullptr;
}
@@ -475,6 +478,8 @@ PointerJumpStubCreator getPointerJumpStubCreator(const Triple &TT) {
case Triple::loongarch32:
case Triple::loongarch64:
return loongarch::createAnonymousPointerJumpStub;
+ case Triple::systemz:
+ return systemz::createAnonymousPointerJumpStub;
default:
return nullptr;
}
@@ -503,6 +508,7 @@ std::unique_ptr<LinkGraph> absoluteSymbolsLinkGraph(const Triple &TT,
switch (TT.getArch()) {
case Triple::aarch64:
case llvm::Triple::riscv64:
+ case Triple::systemz:
case Triple::x86_64:
PointerSize = 8;
break;
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
new file mode 100644
index 0000000000000..36ba857d8f5c4
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -0,0 +1,121 @@
+//===---- systemz.cpp - Generic JITLink systemz edge kinds, utilities -----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic utilities for graphs representing systemz objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/systemz.h"
+
+#define DEBUG_TYPE "jitlink"
+
+namespace llvm {
+namespace jitlink {
+namespace systemz {
+
+const char NullPointerContent[8] = {0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+const char Pointer64JumpStubContent[14] = {
+ static_cast<char>(0xC0), 0x10, 0x00, 0x00, 0x00, 0x00, // larl r1
+ static_cast<char>(0xE3), 0x10, 0x10, 0x00, 0x00, 0x04, // LG 1, 0(1)
+ static_cast<char>(0x07), 0xF1, // BCR 15, 1
+};
+
+const char *getEdgeKindName(Edge::Kind R) {
+ switch (R) {
+ case Pointer64:
+ return "Pointer64";
+ case Pointer32:
+ return "Pointer32";
+ case Pointer20:
+ return "Pointer20";
+ case Pointer16:
+ return "Pointer16";
+ case Pointer12:
+ return "Pointer12";
+ case Pointer8:
+ return "Pointer8";
+ case Delta64:
+ return "Delta64";
+ case Delta32:
+ return "Delta32";
+ case Delta16:
+ return "Delta16";
+ case Delta32dbl:
+ return "Delta32dbl";
+ case Delta24dbl:
+ return "Delta24dbl";
+ case Delta16dbl:
+ return "Delta16dbl";
+ case Delta12dbl:
+ return "Delta12dbl";
+ case NegDelta64:
+ return "NegDelta64";
+ case NegDelta32:
+ return "NegDelta32";
+ case Delta64FromGOT:
+ return "Delta64FromGOT";
+ case Delta32FromGOT:
+ return "Delta32FromGOT";
+ case Delta16FromGOT:
+ return "Delta16FromGOT";
+ case BranchPCRelPLT32dbl:
+ return "BranchPCRelPLT32dbl";
+ case BranchPCRelPLT24dbl:
+ return "BranchPCRelPLT24dbl";
+ case BranchPCRelPLT16dbl:
+ return "BranchPCRelPLT16dbl";
+ case BranchPCRelPLT12dbl:
+ return "BranchPCRelPLT12dbl";
+ case PCRel32GOTEntry:
+ return "PCRel32GOTENTRY";
+ case BranchPCRelPLT64:
+ return "BranchPCRelPLT64";
+ case BranchPCRelPLT32:
+ return "BranchPCRelPLT32";
+ case DeltaPLT64FromGOT:
+ return "DeltaPLT64FromGOT";
+ case DeltaPLT32FromGOT:
+ return "DeltaPLT32FromGOT";
+ case DeltaPLT16FromGOT:
+ return "DeltaPLT16FromGOT";
+ case Delta64GOT:
+ return "Delta64GOT";
+ case Delta32GOT:
+ return "Delta32GOT";
+ case Delta20GOT:
+ return "Delta20GOT";
+ case Delta16GOT:
+ return "Delta16GOT";
+ case Delta12GOT:
+ return "Delta12GOT";
+ case DeltaPCRelGOT:
+ return "DeltaPCRelGOT";
+ case DeltaPCRelGOTdbl:
+ return "DeltaPCRelGOTdbl";
+ case Delta64JumpSlot:
+ return "Delta64JumpSlot";
+ case Delta32JumpSlot:
+ return "Delta32JumpSlot";
+ case Delta20JumpSlot:
+ return "Delta20JumpSlot";
+ case Delta16JumpSlot:
+ return "Delta16JumpSlot";
+ case Delta12JumpSlot:
+ return "Delta12JumpSlot";
+ case PCRel32JumpSlot:
+ return "PCRel32JumpSlot";
+ default:
+ return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
+ }
+}
+
+} // namespace systemz
+} // namespace jitlink
+} // namespace llvm
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_ehframe.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_ehframe.s
new file mode 100644
index 0000000000000..fca8345ff207c
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_ehframe.s
@@ -0,0 +1,58 @@
+# REQUIRES: asserts
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux-gnu -filetype=obj -o %t %s
+# RUN: llvm-jitlink -noexec -phony-externals -debug-only=jitlink %t 2>&1 | \
+# RUN: FileCheck %s
+#
+# Check that splitting of eh-frame sections works.
+#
+# CHECK: DWARFRecordSectionSplitter: Processing .eh_frame...
+# CHECK: Processing block at
+# CHECK: Processing CFI record at
+# CHECK: Processing CFI record at
+# CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
+# CHECK: Processing block at
+# CHECK: Record is CIE
+# CHECK: Processing block at
+# CHECK: Record is FDE
+# CHECK: Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK: Processing PC-begin at
+# CHECK: Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK: Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+
+ .text
+ .file "exceptions.cpp"
+ # Start of file scope inline assembly
+ .globl _ZSt21ios_base_library_initv
+
+ # End of file scope inline assembly
+ .globl main # -- Begin function main
+ .p2align 4
+ .type main, at function
+main: # @main
+ .cfi_startproc
+# %bb.0: # %entry
+ stmg %r11, %r15, 88(%r15)
+ .cfi_offset %r11, -72
+ .cfi_offset %r14, -48
+ .cfi_offset %r15, -40
+ aghi %r15, -168
+ .cfi_def_cfa_offset 328
+ lgr %r11, %r15
+ .cfi_def_cfa_register %r11
+ mvhi 164(%r11), 0
+ lghi %r2, 4
+ brasl %r14, __cxa_allocate_exception at PLT
+ mvhi 0(%r2), 1
+ lgrl %r3, _ZTIi at GOT
+ lghi %r4, 0
+ brasl %r14, __cxa_throw at PLT
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+ .cfi_endproc
+ # -- End function
+ .section ".note.GNU-stack","", at progbits
+ .addrsig
+ .addrsig_sym __cxa_allocate_exception
+ .addrsig_sym __cxa_throw
+ .addrsig_sym _ZTIi
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s
new file mode 100644
index 0000000000000..00b111d5d59f1
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s
@@ -0,0 +1,78 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t/elf_reloc.o %s
+#
+# RUN: llvm-jitlink -noexec \
+# RUN: -slab-allocate 100Kb -slab-address 0x6ff00000 -slab-page-size 4096 \
+# RUN: -abs foo=0x6ff04040 \
+# RUN: -abs bar=0x6ff04048 \
+# RUN: %t/elf_reloc.o
+#
+# Check R_390_GOT* handling.
+
+ .text
+ .globl main
+ .type main, at function
+main:
+ larl %r12, _GLOBAL_OFFSET_TABLE_
+ .reloc .+2, R_390_GOTENT, foo+2
+ larl %r1, 0
+ .reloc .+2, R_390_GOTENT, bar+2
+ larl %r1, 0
+ .reloc .+2, R_390_GOTPLTENT, foo+2
+ larl %r1, 0
+ .reloc .+2, R_390_GOTPLTENT, bar+2
+ larl %r1, 0
+ .reloc .+2, R_390_GOT12, foo
+ l %r1, 0(%r12)
+ .reloc .+2, R_390_GOT12, bar
+ l %r1, 0(%r12)
+ .reloc .+2, R_390_GOTPLT12, foo
+ l %r1, 0(%r12)
+ .reloc .+2, R_390_GOTPLT12, bar
+ l %r1, 0(%r12)
+ .reloc .+2, R_390_GOT20, foo
+ lg %r1, 0(%r12)
+ .reloc .+2, R_390_GOT20, bar
+ lg %r1, 0(%r12)
+ .reloc .+2, R_390_GOTPLT20, foo
+ lg %r1, 0(%r12)
+ .reloc .+2, R_390_GOTPLT20, bar
+ lg %r1, 0(%r12)
+ br %r14
+ .size main, .-main
+
+ .data
+ .reloc ., R_390_GOT16, foo
+ .space 2
+ .reloc ., R_390_GOT16, bar
+ .space 2
+ .reloc ., R_390_GOTPLT16, foo
+ .space 2
+ .reloc ., R_390_GOTPLT16, bar
+ .space 2
+ .reloc ., R_390_GOT32, foo
+ .space 4
+ .reloc ., R_390_GOT32, bar
+ .space 4
+ .reloc ., R_390_GOTPLT32, foo
+ .space 4
+ .reloc ., R_390_GOTPLT32, bar
+ .space 4
+ .reloc ., R_390_GOT64, foo
+ .space 8
+ .reloc ., R_390_GOT64, bar
+ .space 8
+ .reloc ., R_390_GOTPLT64, foo
+ .space 8
+ .reloc ., R_390_GOTPLT64, bar
+ .space 8
+ .reloc ., R_390_GOTPC, foo
+ .space 4
+ .reloc ., R_390_GOTPC, bar
+ .space 4
+ .reloc ., R_390_GOTPCDBL, foo
+ .space 4
+ .reloc ., R_390_GOTPCDBL, bar
+ .space 4
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s
new file mode 100644
index 0000000000000..3d1484acaf9ae
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s
@@ -0,0 +1,35 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+# RUN: llvm-jitlink -noexec -abs X=0xFFFF -check=%s %t.o
+
+# RUN: not llvm-jitlink -noexec -abs X=0x10000 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# Check success and failure cases of R_390_16 handling.
+
+# jitlink-check: *{8}P = X
+
+# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer16 fixup
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+ .type P, at object
+ .data
+ .globl P
+ .p2align 1
+P:
+ .short 0
+ .short 0
+ .short 0
+ .short X # Using byte here generates R_390_16.
+ .size P, 8
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s
new file mode 100644
index 0000000000000..2b3122b91ff5e
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s
@@ -0,0 +1,32 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+# RUN: llvm-jitlink -noexec -abs X=0x12345678 -check=%s %t.o
+#
+# RUN: not llvm-jitlink -noexec -abs X=0x123456789 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# Check success and failure cases of R_390_32 handling.
+
+# jitlink-check: *{8}P = X
+
+# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer32 fixup
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+ .type P, at object
+ .data
+ .globl P
+ .p2align 2
+P:
+ .long 0
+ .long X # Using long here generates R_390_32.
+ .size P, 8
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs64.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs64.s
new file mode 100644
index 0000000000000..63d2a1a539aeb
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs64.s
@@ -0,0 +1,28 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+# RUN: llvm-jitlink -noexec -abs X=0xffffffffffffffff -check=%s %t.o
+#
+# Check success and failure cases of R_390_64 handling.
+
+# jitlink-check: *{8}P = X
+
+# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer64 fixup
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+ .type P, at object
+ .data
+ .globl P
+ .p2align 4
+P:
+ .quad X # Using quad here generates R_390_64.
+ .size P, 8
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s
new file mode 100644
index 0000000000000..6b9d9503035f5
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s
@@ -0,0 +1,38 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+# RUN: llvm-jitlink -noexec -abs X=0xFF -check=%s %t.o
+
+# RUN: not llvm-jitlink -noexec -abs X=0x100 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# Check success and failure cases of R_390_8 handling.
+
+# jitlink-check: *{8}P = X
+
+# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer8 fixup
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+ .type P, at object
+ .data
+ .globl P
+P:
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte X # Using byte here generates R_390_8.
+ .size P, 8
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
new file mode 100644
index 0000000000000..2b4c3d2102231
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
@@ -0,0 +1,82 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t/elf_pic_reloc.o %s
+#
+# RUN: llvm-jitlink -noexec \
+# RUN: -slab-allocate 100Kb -slab-address 0xfff00000 -slab-page-size 4096 \
+# RUN: -abs external_data=0x1 \
+# RUN: -abs extern_out_of_range32=0x7fff00000000 \
+# RUN: -abs extern_in_range32=0xffe00000 \
+# RUN: -check %s %t/elf_pic_reloc.o
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .globl named_func
+ .p2align 4
+ .type named_func, at function
+named_func:
+ br %r14
+ .size named_func, .-named_func
+
+# Check R_390_PLT32DBL handling with a call to a local function in the text
+# section. This produces a Branch32 edge that is resolved like a regular
+# BranchPCRelPLT32dbl(no PLT entry created).
+#
+# jitlink-check: decode_operand(test_call_local, 1) = \
+# jitlink-check: named_func - test_call_local
+ .globl test_call_local
+ .p2align 4
+ .type test_call_local, at function
+test_call_local:
+ brasl %r14, named_func at PLT
+
+ .size test_call_local, .-test_call_local
+
+# Check R_390_PLT32dbl(BranchPCRelPLT32dbl) handling with a call to an
+# external via PLT. This produces a Branch32ToStub edge, because externals are
+# not defined locally. As the target is out-of-range from the callsite,
+# the edge keeps using its PLT entry.
+#
+# jitlink-check: decode_operand(test_call_extern_plt, 1) = \
+# jitlink-check: stub_addr(elf_pic_reloc.o, extern_out_of_range32) - \
+# jitlink-check: test_call_extern_plt
+# jitlink-check: *{8}(got_addr(elf_pic_reloc.o, extern_out_of_range32)) = \
+# jitlink-check: extern_out_of_range32
+ .globl test_call_extern_plt
+ .p2align 4
+ .type test_call_extern_plt, at function
+test_call_extern_plt:
+ brasl %r14, extern_out_of_range32 at plt
+
+ .size test_call_extern_plt, .-test_call_extern_plt
+
+# Check R_390_PLT32(BranchPCRelPLT32dbl) handling with a call to an external.
+# This produces a Branch32ToStub edge, because externals are not defined
+# locally. During resolution, the target turns out to be in-range from the
+# callsite.
+### TODO: edge can be relaxed in post-allocation optimization, it will then
+### require:
+### jitlink-check: decode_operand(test_call_extern, 1) = \
+### jitlink-check: extern_in_range32 - test_call_extern
+#
+# Same as test_call_extern_plt(no-optimization)
+# jitlink-check: decode_operand(test_call_extern, 1) = \
+# jitlink-check: stub_addr(elf_pic_reloc.o, extern_in_range32) - \
+# jitlink-check: test_call_extern
+# jitlink-check: *{8}(got_addr(elf_pic_reloc.o, extern_in_range32)) = \
+# jitlink-check: extern_in_range32
+ .globl test_call_extern
+ .p2align 4
+ .type test_call_extern, at function
+test_call_extern:
+ brasl %r14, extern_in_range32 at plt
+ .size test_call_extern, .-test_call_extern
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s
new file mode 100644
index 0000000000000..3a5ebf9f3ba70
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s
@@ -0,0 +1,28 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec -abs DISP=0xFFF -check=%s %t.o
+
+# RUN: not llvm-jitlink -noexec -abs DISP=0x1000 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# Check success and failure cases of R_390_12 handling.
+
+# CHECK-ERROR: relocation target "DISP" {{.*}} is out of range of
+# CHECK-ERROR: Pointer12 fixup
+
+# jitlink-check: decode_operand(main, 2) = DISP
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ .reloc .+2, R_390_12, DISP
+ l %r6, 0(%r7,%r8)
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s
new file mode 100644
index 0000000000000..e6d22aff78f50
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s
@@ -0,0 +1,31 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec -abs DISP=0x7FFFF -check=%s %t.o
+
+# RUN: not llvm-jitlink -noexec -abs DISP=0x80000 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+
+# RUN: not llvm-jitlink -noexec -abs DISP=0xFFFFF %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# Check success and failure cases of R_390_20 handling.
+
+# CHECK-ERROR: relocation target "DISP" {{.*}} is out of range of
+# CHECK-ERROR: Pointer20 fixup
+
+# jitlink-check: decode_operand(main, 2) = DISP
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ .reloc .+2, R_390_20, DISP
+ lg %r6, 0(%r7,%r8)
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_got.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_got.s
new file mode 100644
index 0000000000000..7da48cfa704e2
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_got.s
@@ -0,0 +1,244 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t/elf_reloc.o %s
+#
+# RUN: llvm-jitlink -noexec \
+# RUN: -slab-allocate 100Kb -slab-address 0x6ff00000 -slab-page-size 4096 \
+# RUN: -abs foo=0x6ff04040 \
+# RUN: -abs bar=0x6ff04048 \
+# RUN: %t/elf_reloc.o -check %s
+
+# Verifying GOT related relocations.
+
+ .text
+ .globl main
+ .type main, at function
+main:
+# jitlink-check: decode_operand(main, 1) = _GLOBAL_OFFSET_TABLE_ - main
+ larl %r12, _GLOBAL_OFFSET_TABLE_
+ .globl test_gotent_foo
+test_gotent_foo:
+# jitlink-check: decode_operand(test_gotent_foo, 1) = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - test_gotent_foo)
+ .reloc .+2, R_390_GOTENT, foo+2
+ larl %r1, 0
+ .size test_gotent_foo, .-test_gotent_foo
+
+ .globl test_gotent_bar
+test_gotent_bar:
+# jitlink-check: decode_operand(test_gotent_bar, 1) = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - test_gotent_bar)
+ .reloc .+2, R_390_GOTENT, bar+2
+ larl %r1, 0
+ .size test_gotent_bar, .-test_gotent_bar
+
+ .globl test_gotpltent_foo
+test_gotpltent_foo:
+# jitlink-check: decode_operand(test_gotpltent_foo, 1) = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - test_gotpltent_foo)
+ .reloc .+2, R_390_GOTPLTENT, foo+2
+ larl %r1, 0
+ .size test_gotpltent_foo, .-test_gotpltent_foo
+
+ .globl test_gotpltent_bar
+test_gotpltent_bar:
+# jitlink-check: decode_operand(test_gotpltent_bar, 1) = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - test_gotpltent_bar)
+ .reloc .+2, R_390_GOTPLTENT, bar+2
+ larl %r1, 0
+ .size test_gotpltent_bar, .-test_gotpltent_bar
+
+ .globl test_got12_foo
+test_got12_foo:
+# jitlink-check: decode_operand(test_got12_foo, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOT12, foo
+ l %r1, 0(%r12)
+ .size test_got12_foo, .-test_got12_foo
+
+ .globl test_got12_bar
+test_got12_bar:
+# jitlink-check: decode_operand(test_got12_bar, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOT12, bar
+ l %r1, 0(%r12)
+ .size test_got12_bar, .-test_got12_bar
+
+ .globl test_gotplt12_foo
+test_gotplt12_foo:
+# jitlink-check: decode_operand(test_gotplt12_foo, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOTPLT12, foo
+ l %r1, 0(%r12)
+ .size test_gotplt12_foo, .-test_gotplt12_foo
+
+ .globl test_gotplt12_bar
+test_gotplt12_bar:
+# jitlink-check: decode_operand(test_gotplt12_bar, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOTPLT12, bar
+ l %r1, 0(%r12)
+ .size test_gotplt12_bar, .-test_gotplt12_bar
+
+ .globl test_got20_foo
+test_got20_foo:
+# jitlink-check: decode_operand(test_got20_foo, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOT20, foo
+ lg %r1, 0(%r12)
+ .size test_got20_foo, .-test_got20_foo
+
+ .globl test_got20_bar
+test_got20_bar:
+# jitlink-check: decode_operand(test_got20_bar, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOT20, bar
+ lg %r1, 0(%r12)
+ .size test_got20_bar, .-test_got20_bar
+
+ .globl test_gotplt20_foo
+test_gotplt20_foo:
+# jitlink-check: decode_operand(test_gotplt20_foo, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOTPLT20, foo
+ lg %r1, 0(%r12)
+ .size test_gotplt20_foo, .-test_gotplt20_foo
+
+ .globl test_gotplt20_bar
+test_gotplt20_bar:
+# jitlink-check: decode_operand(test_gotplt20_bar, 2) = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+ .reloc .+2, R_390_GOTPLT20, bar
+ lg %r1, 0(%r12)
+ .size test_gotplt20_bar, .-test_gotplt20_bar
+ br %r14
+ .size main, .-main
+
+ .data
+ .globl test_got16_foo
+# jitlink-check: *{2}test_got16_foo = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_got16_foo:
+ .reloc ., R_390_GOT16, foo
+ .space 2
+ .size test_got16_foo, .-test_got16_foo
+
+ .globl test_got16_bar
+# jitlink-check: *{2}test_got16_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_got16_bar:
+ .reloc ., R_390_GOT16, bar
+ .space 2
+ .size test_got16_bar, .-test_got16_bar
+
+ .globl test_gotplt16_foo
+# jitlink-check: *{2}test_gotplt16_foo = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_gotplt16_foo:
+ .reloc ., R_390_GOTPLT16, foo
+ .space 2
+ .size test_gotplt16_foo, .-test_gotplt16_foo
+
+ .globl test_gotplt16_bar
+# jitlink-check: *{2}test_gotplt16_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_gotplt16_bar:
+ .reloc ., R_390_GOTPLT16, bar
+ .space 2
+ .size test_gotplt16_bar, .-test_gotplt16_bar
+
+ .globl test_got32_foo
+# jitlink-check: *{4}test_got32_foo = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_got32_foo:
+ .reloc ., R_390_GOT32, foo
+ .space 4
+ .size test_got32_foo, .-test_got32_foo
+
+ .globl test_got32_bar
+# jitlink-check: *{4}test_got32_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_got32_bar:
+ .reloc ., R_390_GOT32, bar
+ .space 4
+ .size test_got32_bar, .-test_got32_bar
+
+ .globl test_gotplt32_foo
+# jitlink-check: *{4}test_gotplt32_foo = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_gotplt32_foo:
+ .reloc ., R_390_GOTPLT32, foo
+ .space 4
+ .size test_gotplt32_foo, .-test_gotplt32_foo
+
+ .globl test_gotplt32_bar
+# jitlink-check: *{4}test_gotplt32_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_gotplt32_bar:
+ .reloc ., R_390_GOTPLT32, bar
+ .space 4
+ .size test_gotplt32_bar, .-test_gotplt32_bar
+
+ .globl test_got64_foo
+# jitlink-check: *{8}test_got64_foo = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_got64_foo:
+ .reloc ., R_390_GOT64, foo
+ .space 8
+ .size test_got64_foo, .-test_got64_foo
+
+ .globl test_got64_bar
+# jitlink-check: *{8}test_got64_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_got64_bar:
+ .reloc ., R_390_GOT64, bar
+ .space 8
+ .size test_got64_bar, .-test_got64_bar
+
+ .globl test_gotplt64_foo
+# jitlink-check: *{8}test_gotplt64_foo = \
+# jitlink-check: (got_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_gotplt64_foo:
+ .reloc ., R_390_GOTPLT64, foo
+ .space 8
+ .size test_gotplt64_foo, .-test_gotplt64_foo
+
+ .globl test_gotplt64_bar
+# jitlink-check: *{8}test_gotplt64_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_gotplt64_bar:
+ .reloc ., R_390_GOTPLT64, bar
+ .space 8
+ .size test_gotplt64_bar, .-test_gotplt64_bar
+
+ .globl test_gotpc_foo
+# jitlink-check: *{4}test_gotpc_foo = _GLOBAL_OFFSET_TABLE_ - test_gotpc_foo
+test_gotpc_foo:
+ .reloc ., R_390_GOTPC, foo
+ .space 4
+ .size test_gotpc_foo, .-test_gotpc_foo
+
+ .globl test_gotpc_bar
+# jitlink-check: *{4}test_gotpc_bar = _GLOBAL_OFFSET_TABLE_ - test_gotpc_bar
+test_gotpc_bar:
+ .reloc ., R_390_GOTPC, bar
+ .space 4
+ .size test_gotpc_bar, .-test_gotpc_bar
+
+ .globl test_gotpcdbl_foo
+# jitlink-check: *{4}test_gotpcdbl_foo = \
+# jitlink-check: (_GLOBAL_OFFSET_TABLE_ - test_gotpcdbl_foo) >> 1
+test_gotpcdbl_foo:
+ .reloc ., R_390_GOTPCDBL, foo
+ .space 4
+ .size test_gotpcdbl_foo, .-test_gotpcdbl_foo
+
+ .globl test_gotpcdbl_bar
+# jitlink-check: *{4}test_gotpcdbl_bar = \
+# jitlink-check: (_GLOBAL_OFFSET_TABLE_ - test_gotpcdbl_bar) >> 1
+test_gotpcdbl_bar:
+ .reloc ., R_390_GOTPCDBL, bar
+ .space 4
+ .size test_gotpcdbl_bar, .-test_gotpcdbl_bar
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s
new file mode 100644
index 0000000000000..bb1220d3780bb
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s
@@ -0,0 +1,68 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t/elf_reloc.o %s
+#
+# RUN: llvm-jitlink -noexec \
+# RUN: -slab-allocate 100Kb -slab-address 0x6ff00000 -slab-page-size 4096 \
+# RUN: -abs foo=0x6ff04080 \
+# RUN: -abs bar=0x6ff04040 \
+# RUN: %t/elf_reloc.o -check %s
+
+ .text
+ .globl main
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .data
+ .globl test_gotoff16_bar
+# jitlink-check: *{2}test_gotoff16_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_gotoff16_bar:
+ .reloc ., R_390_GOTOFF16, bar
+ .space 2
+ .size test_gotoff16_bar, .-test_gotoff16_bar
+
+ .globl test_pltoff16_foo
+# jitlink-check: *{2}test_pltoff16_foo = \
+# jitlink-check: (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_pltoff16_foo:
+ .reloc ., R_390_PLTOFF16, foo
+ .space 2
+ .size test_pltoff16_foo, .-test_pltoff16_foo
+
+
+ .globl test_gotoff32_bar
+# jitlink-check: *{4}test_gotoff32_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_gotoff32_bar:
+ .reloc ., R_390_GOTOFF, bar
+ .space 4
+ .size test_gotoff32_bar, .-test_gotoff32_bar
+
+ .globl test_pltoff32_foo
+# jitlink-check: *{4}test_pltoff32_foo = \
+# jitlink-check: (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_pltoff32_foo:
+ .reloc ., R_390_PLTOFF32, foo
+ .space 4
+ .size test_pltoff32_foo, .-test_pltoff32_foo
+
+ .globl test_gotoff64_bar
+# jitlink-check: *{8}test_gotoff64_bar = \
+# jitlink-check: (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+test_gotoff64_bar:
+ .reloc ., R_390_GOTOFF64, bar
+ .space 8
+ .size test_gotoff64_bar, .-test_gotoff64_bar
+
+ .globl test_pltoff64_foo
+# jitlink-check: *{8}test_pltoff64_foo = \
+# jitlink-check: (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+test_pltoff64_foo:
+ .reloc ., R_390_PLTOFF64, foo
+ .space 8
+ .size test_pltoff64_foo, .-test_pltoff64_foo
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc.s
new file mode 100644
index 0000000000000..4b3a65e53ab93
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc.s
@@ -0,0 +1,20 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec %t.o
+#
+# Check R_390_PC* handling.
+
+ .text
+ .globl main
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .rodata
+ .short main-. # Generate R_390_PC16 relocation.
+ .long main-. # Generate R_390_PC32 relocation.
+ .quad main-. # Generate R_390_PC64 relocation.
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s
new file mode 100644
index 0000000000000..47a7262902fd9
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s
@@ -0,0 +1,40 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -defsym OFFSET=0x8000 -filetype=obj -o %t.o %s
+# RUN: llvm-jitlink -noexec -abs OFFSET=0x8000 -check=%s %t.o
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -defsym OFFSET=0xFFFF -filetype=obj -o %t.o %s
+# RUN: not llvm-jitlink -noexec -abs OFFSET=0xFFFF %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -defsym OFFSET=0x8001 -filetype=obj -o %t.o %s
+# RUN: not llvm-jitlink -noexec -abs OFFSET=0x8001 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# jitlink-check: *{2}test_pc16 = OFFSET
+
+# CHECK-ERROR: {{.*}} is out of range of Delta16 fixup
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .globl test_pc16
+test_pc16:
+ .reloc test_pc16, R_390_PC16, .-OFFSET
+ .space 2
+ .size test_pc16, .-test_pc16
+
+ .globl test_pc16dbl
+test_pc16dbl:
+ .reloc test_pc16dbl, R_390_PC16DBL, .-(OFFSET + OFFSET)
+ .space 2
+ .size test_pc16dbl, .-test_pc16dbl
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s
new file mode 100644
index 0000000000000..cda90dbe5a316
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s
@@ -0,0 +1,40 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -defsym OFFSET=0x80000000 -filetype=obj -o %t.o %s
+# RUN: llvm-jitlink -noexec -abs OFFSET=0x80000000 -check=%s %t.o
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -defsym OFFSET=0xFFFFFFFF -filetype=obj -o %t.o %s
+# RUN: not llvm-jitlink -noexec -abs OFFSET=0xFFFFFFFF %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -defsym OFFSET=0x80000001 -filetype=obj -o %t.o %s
+# RUN: not llvm-jitlink -noexec -abs OFFSET=0x80000001 %t.o 2>&1 | \
+# RUN: FileCheck -check-prefix=CHECK-ERROR %s
+#
+# jitlink-check: *{4}test_pc32 = OFFSET
+
+# CHECK-ERROR: {{.*}} is out of range of Delta32 fixup
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .globl test_pc32
+test_pc32:
+ .reloc test_pc32, R_390_PC32, .-OFFSET
+ .space 4
+ .size test_pc32, .-test_pc32
+
+ .globl test_pc32dbl
+test_pc32dbl:
+ .reloc test_pc32dbl, R_390_PC32DBL, .-(OFFSET + OFFSET)
+ .space 4
+ .size test_pc32dbl, .-test_pc32dbl
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc64.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc64.s
new file mode 100644
index 0000000000000..0d33ae2976de5
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc64.s
@@ -0,0 +1,34 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t/elf_reloc.o %s
+#
+# RUN: llvm-jitlink -noexec \
+# RUN: -slab-allocate 100Kb -slab-address 0xffff0000 -slab-page-size 4096 \
+# RUN: -abs external_data=0x1 \
+# RUN: -abs foo=0x6ff04040 \
+# RUN: -abs bar=0x6ff04048 \
+# RUN: -check %s %t/elf_reloc.o
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .globl test_pc64_foo
+# jitlink-check: *{8}test_pc64_foo = foo - test_pc64_foo
+test_pc64_foo:
+ .reloc ., R_390_PC64, foo
+ .space 8
+ .size test_pc64_foo, .-test_pc64_foo
+
+ .globl test_pc64_bar
+# jitlink-check: *{8}test_pc64_bar = bar - test_pc64_bar
+test_pc64_bar:
+ .reloc ., R_390_PC64, bar
+ .space 8
+ .size test_pc64_bar, .-test_pc64_bar
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pcdbl.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pcdbl.s
new file mode 100644
index 0000000000000..efe8357e76bef
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pcdbl.s
@@ -0,0 +1,84 @@
+# REQUIRES: system-linux
+# RUN: llvm-mc -triple=systemz-unknown-linux -mcpu=z16 -position-independent \
+# RUN: -defsym OFF12=0xffe -defsym OFF16=4 -defsym OFF24=6 \
+# RUN: -defsym OFF32=6 -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec -abs OFF12=0xffe -abs OFF16=4 -abs OFF24=6 \
+# RUN: -abs OFF32=6 -check=%s %t.o
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -mcpu=z16 -position-independent \
+# RUN: -defsym OFF12=6 -defsym OFF16=0xfffe -defsym OFF24=6 \
+# RUN: -defsym OFF32=6 -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec -abs OFF12=6 -abs OFF16=0xfffe -abs OFF24=6 \
+# RUN: -abs OFF32=6 -check=%s %t.o
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -mcpu=z16 -position-independent \
+# RUN: -defsym OFF12=6 -defsym OFF16=4 -defsym OFF24=0xfffffe \
+# RUN: -defsym OFF32=6 -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec -abs OFF12=6 -abs OFF16=4 -abs OFF24=0xfffffe \
+# RUN: -abs OFF32=6 -check=%s %t.o
+#
+# RUN: llvm-mc -triple=systemz-unknown-linux -mcpu=z16 -position-independent \
+# RUN: -defsym OFF12=6 -defsym OFF16=4 -defsym OFF24=6 \
+# RUN: -defsym OFF32=0xffffffc8 -filetype=obj -o %t.o %s
+#
+# RUN: llvm-jitlink -noexec -abs OFF12=6 -abs OFF16=4 -abs OFF24=6 \
+# RUN: -abs OFF32=0xffffffc8 -check=%s %t.o
+
+# Check R_390_PC*dbl relocations.
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+# R_390_PC16DBL
+# jitlink-check: *{2}(test_pc16dbl + 2) = (OFF16 >> 1)
+ .globl test_pc16dbl
+ .p2align 3
+test_pc16dbl:
+ je .Lpc16dbl
+ .space OFF16 - 4
+.Lpc16dbl:
+ jne test_pc16dbl
+ .size test_pc16dbl,.-test_pc16dbl
+
+# R_390_PC32DBL
+# jitlink-check: *{4}(test_pc32dbl + 2) = (OFF32 >> 1)
+ .globl test_pc32dbl
+ .p2align 3
+test_pc32dbl:
+ jge .Lpc32dbl
+ .space OFF32 - 6
+.Lpc32dbl:
+ jgne test_pc32dbl
+ .size test_pc32dbl,.-test_pc32dbl
+
+# R_390_PC12DBL
+# jitlink-check: ((*{2} (test_pc12dbl + 1)) & 0x0fff) = (OFF12 >> 1)
+ .globl test_pc12dbl
+ .p2align 4
+test_pc12dbl:
+ bprp 0, .Lpc12dbl, 0
+ .space OFF12 - 6
+.Lpc12dbl:
+ bprp 0, test_pc12dbl, 0
+ .size test_pc12dbl,.-test_pc12dbl
+
+# R_390_PC24DBL
+# jitlink-check: ((*{4} (test_pc24dbl + 2)) & 0x0ffffff) = (OFF24 >> 1)
+ .globl test_pc24dbl
+ .p2align 4
+test_pc24dbl:
+ bprp 0, 0, .Lpc24dbl
+ .space OFF24 - 6
+.Lpc24dbl:
+ bprp 0, 0, test_pc24dbl
+ .size test_pc24dbl,.-test_pc24dbl
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s
new file mode 100644
index 0000000000000..47f064b45816a
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s
@@ -0,0 +1,71 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -filetype=obj -o %t/elf_reloc.o %s
+#
+# RUN: llvm-jitlink -noexec \
+# RUN: -slab-allocate 100Kb -slab-address 0xffff0000 -slab-page-size 4096 \
+# RUN: -abs external_data=0x1 \
+# RUN: -abs foo=0x6ff04040 \
+# RUN: -abs bar=0x6ff04048 \
+# RUN: -check %s %t/elf_reloc.o
+
+# Check R_390_PLT32/64 relocations.
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+ .globl test_plt32_foo
+# jitlink-check: *{4}test_plt32_foo = \
+# jitlink-check: stub_addr(elf_reloc.o, foo) - test_plt32_foo
+test_plt32_foo:
+ .reloc ., R_390_PLT32, foo
+ .space 4
+ .size test_plt32_foo, .-test_plt32_foo
+
+ .globl test_plt32_bar
+# jitlink-check: *{4}test_plt32_bar = \
+# jitlink-check: stub_addr(elf_reloc.o, bar) - test_plt32_bar
+test_plt32_bar:
+ .reloc ., R_390_PLT32, bar
+ .space 4
+ .size test_plt32_bar, .-test_plt32_bar
+
+ .globl test_plt64_foo
+# jitlink-check: *{8}test_plt64_foo = \
+# jitlink-check: stub_addr(elf_reloc.o, foo) - test_plt64_foo
+test_plt64_foo:
+ .reloc ., R_390_PLT64, foo
+ .space 8
+ .size test_plt64_foo, .-test_plt64_foo
+
+ .globl test_plt64_bar
+# jitlink-check: *{8}test_plt64_bar = \
+# jitlink-check: stub_addr(elf_reloc.o, bar) - test_plt64_bar
+test_plt64_bar:
+ .reloc ., R_390_PLT64, bar
+ .space 8
+ .size test_plt64_bar, .-test_plt64_bar
+
+ .globl test_plt32dbl_foo
+# jitlink-check: *{4}test_plt32dbl_foo = \
+# jitlink-check: (stub_addr(elf_reloc.o, foo) - test_plt32dbl_foo) >> 1
+test_plt32dbl_foo:
+ .reloc ., R_390_PLT32DBL, foo
+ .space 4
+ .size test_plt32dbl_foo, .-test_plt32dbl_foo
+
+ .globl test_plt32dbl_bar
+# jitlink-check: *{4}test_plt32dbl_bar = \
+# jitlink-check: (stub_addr(elf_reloc.o, bar) - test_plt32dbl_bar) >> 1
+test_plt32dbl_bar:
+ .reloc ., R_390_PLT32DBL, bar
+ .space 4
+ .size test_plt32dbl_bar, .-test_plt32dbl_bar
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pltdbl.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pltdbl.s
new file mode 100644
index 0000000000000..c36a77684008a
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pltdbl.s
@@ -0,0 +1,51 @@
+# REQUIRES: system-linux
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=systemz-unknown-linux -position-independent \
+# RUN: -mcpu=z16 -filetype=obj -o %t/elf_reloc.o %s
+
+# RUN: llvm-jitlink -noexec \
+# RUN: -abs external_addr12=0xffe \
+# RUN: -abs external_addr16=0xfffe \
+# RUN: -abs external_addr24=0xffffe \
+# RUN: %t/elf_reloc.o -check %s
+
+
+ .text
+ .section .text.main
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ br %r14
+ .size main, .-main
+
+# R_390_PLT16DBL
+# jitlink-check: *{2}(test_plt16dbl + 4) = \
+# jitlink-check: (stub_addr(elf_reloc.o, external_addr16) - \
+# jitlink-check: test_plt16dbl) >> 1
+ .globl test_plt16dbl
+ .p2align 4
+test_plt16dbl:
+ bpp 0, external_addr16 at plt, 0
+ .size test_plt16dbl,.-test_plt16dbl
+
+# R_390_PLT12DBL
+# jitlink-check: ((*{2}(test_plt12dbl + 1)) & 0x0fff) = \
+# jitlink-check: (stub_addr(elf_reloc.o, external_addr12) - \
+# jitlink-check: test_plt12dbl) >> 1
+ .globl test_plt12dbl
+ .p2align 4
+test_plt12dbl:
+ bprp 0, external_addr12 at plt, 0
+ .size test_plt12dbl,.-test_plt12dbl
+
+# R_390_PLT24DBL
+# jitlink-check: ((*{4}(test_plt24dbl + 2)) & 0x0ffffff) = \
+# jitlink-check: (stub_addr(elf_reloc.o, external_addr24) - \
+# jitlink-check: test_plt24dbl) >> 1
+ .globl test_plt24dbl
+ .p2align 4
+test_plt24dbl:
+ bprp 0, 0, external_addr24 at plt
+ .size test_plt24dbl,.-test_plt24dbl
+
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/lit.local.cfg b/llvm/test/ExecutionEngine/JITLink/systemz/lit.local.cfg
new file mode 100644
index 0000000000000..caf81b69c06fd
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "SystemZ" in config.root.targets:
+ config.unsupported = True
diff --git a/llvm/test/ExecutionEngine/lit.local.cfg b/llvm/test/ExecutionEngine/lit.local.cfg
index c748de14c8409..840ee60d2cf1d 100644
--- a/llvm/test/ExecutionEngine/lit.local.cfg
+++ b/llvm/test/ExecutionEngine/lit.local.cfg
@@ -1,4 +1,4 @@
-if config.root.native_target in ['Sparc', 'SystemZ', 'Hexagon', 'RISCV']:
+if config.root.native_target in ['Sparc', 'Hexagon', 'RISCV']:
config.unsupported = True
# ExecutionEngine tests are not expected to pass in a cross-compilation setup.
More information about the llvm-commits
mailing list