[llvm] JITLink: Add initial SystemZ Support. (PR #144528)

via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 7 08:27:04 PST 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 01/10] 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.

>From 04235320662f8292fc81e0d8577701c3585686e8 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Tue, 17 Jun 2025 20:16:37 +0200
Subject: [PATCH 02/10] Resolve issues with conflicts

---
 .../ExecutionEngine/JITLink/ELF_systemz.h     |  4 ++--
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   | 23 +++++++++++--------
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h
index c78bc7cc1f499..a996dfd9543df 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_systemz.h
@@ -25,8 +25,8 @@ namespace jitlink {
 /// 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);
+Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_systemz(
+    MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP);
 
 /// jit-link the given object buffer, which must be a ELF systemz relocatable
 /// object file.
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 6d598d62b1fc2..47d2d4651f881 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -64,7 +64,8 @@ class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {
     auto DefineExternalGOTSymbolIfPresent =
         createDefineExternalSectionStartAndEndSymbolsPass(
             [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
-              if (Sym.getName() == ELFGOTSymbolName)
+              if (Sym.getName() != nullptr &&
+                  *Sym.getName() == ELFGOTSymbolName)
                 if (auto *GOTSection = G.findSectionByName(
                         systemz::GOTTableManager::getSectionName())) {
                   GOTSymbol = &Sym;
@@ -90,7 +91,7 @@ class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {
 
       // Check for an existing defined symbol.
       for (auto *Sym : GOTSection->symbols())
-        if (Sym->getName() == ELFGOTSymbolName) {
+        if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
           GOTSymbol = Sym;
           return Error::success();
         }
@@ -112,7 +113,7 @@ class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {
     // 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) {
+        if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
           auto Blocks = G.blocks();
           if (!Blocks.empty()) {
             G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());
@@ -365,14 +366,16 @@ class ELFLinkGraphBuilder_systemz
 
 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) {}
+                              const object::ELFFile<ELFT> &Obj,
+                              std::shared_ptr<orc::SymbolStringPool> SSP,
+                              Triple TT, SubtargetFeatures Features)
+      : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
+                                  std::move(Features), FileName,
+                                  systemz::getEdgeKindName) {}
 };
 
-Expected<std::unique_ptr<LinkGraph>>
-createLinkGraphFromELFObject_systemz(MemoryBufferRef ObjectBuffer) {
+Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_systemz(
+    MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
   LLVM_DEBUG({
     dbgs() << "Building jitlink graph for new input "
            << ObjectBuffer.getBufferIdentifier() << "...\n";
@@ -391,7 +394,7 @@ createLinkGraphFromELFObject_systemz(MemoryBufferRef ObjectBuffer) {
 
   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj);
   return ELFLinkGraphBuilder_systemz(
-             (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
+             (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
              (*ELFObj)->makeTriple(), std::move(*Features))
       .buildGraph();
 }

>From 72ff4e38533f1a9101365408590d6d5ccefb31fc Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Tue, 17 Jun 2025 21:26:26 +0200
Subject: [PATCH 03/10] Fix build error

---
 .../llvm/ExecutionEngine/JITLink/systemz.h      |  3 +--
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp    | 17 ++++++++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index e1498ff820fe6..d63446f35fffd 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -992,16 +992,15 @@ class GOTTableManager : public TableManager<GOTTableManager> {
     case systemz::Delta64FromGOT:
     case systemz::Delta12JumpSlot:
     case systemz::Delta16JumpSlot:
+    case systemz::Delta20JumpSlot:
     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;
     }
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index 36ba857d8f5c4..c9276bedafe99 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -22,9 +22,20 @@ 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
+    static_cast<char>(0xC0u),
+    0x10,
+    0x00,
+    0x00,
+    0x00,
+    0x00, // larl r1
+    static_cast<char>(0xE3u),
+    0x10,
+    0x10,
+    0x00,
+    0x00,
+    0x04, // LG 1, 0(1)
+    static_cast<char>(0x07u),
+    static_cast<char>(0xF1u), // BCR 15, 1
 };
 
 const char *getEdgeKindName(Edge::Kind R) {

>From 7ec023ed49010ec23682fde7927fadc53b644f98 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Thu, 17 Jul 2025 00:53:54 +0200
Subject: [PATCH 04/10] Fixed jitlink-check: CHECK-ERROR - error message format
 changed.

---
 .../ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s   | 2 +-
 .../ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s   | 2 +-
 .../ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s    | 2 +-
 .../ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s  | 2 +-
 .../ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s  | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s
index 3d1484acaf9ae..04e828685c040 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs16.s
@@ -10,7 +10,7 @@
 
 # jitlink-check: *{8}P = X
 
-# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer16 fixup
+# CHECK-ERROR: relocation target {{.*}} (X) is out of range of Pointer16 fixup
 
         .text
         .section        .text.main
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s
index 2b3122b91ff5e..1a63acdb63d57 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs32.s
@@ -10,7 +10,7 @@
 
 # jitlink-check: *{8}P = X
 
-# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer32 fixup
+# CHECK-ERROR: relocation target {{.*}} (X) is out of range of Pointer32 fixup
 
         .text
         .section        .text.main
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s
index 6b9d9503035f5..5f23f289140a6 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_abs8.s
@@ -10,7 +10,7 @@
 
 # jitlink-check: *{8}P = X
 
-# CHECK-ERROR: relocation target "X" {{.*}} is out of range of Pointer8 fixup
+# CHECK-ERROR: relocation target {{.*}} (X) is out of range of Pointer8 fixup
 
         .text
         .section        .text.main
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s
index 3a5ebf9f3ba70..cf12cdc987ce3 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp12.s
@@ -10,7 +10,7 @@
 #
 # Check success and failure cases of R_390_12 handling.
 
-# CHECK-ERROR: relocation target "DISP" {{.*}} is out of range of
+# CHECK-ERROR: relocation target {{.*}} (DISP) is out of range of
 # CHECK-ERROR: Pointer12 fixup
 
 # jitlink-check: decode_operand(main, 2) = DISP
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s
index e6d22aff78f50..5c7de535cf8b4 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_disp20.s
@@ -13,7 +13,7 @@
 #
 # Check success and failure cases of R_390_20 handling.
 
-# CHECK-ERROR: relocation target "DISP" {{.*}} is out of range of
+# CHECK-ERROR: relocation target {{.*}} (DISP) is out of range of
 # CHECK-ERROR: Pointer20 fixup
 
 # jitlink-check: decode_operand(main, 2) = DISP

>From a52657a9153ddb483452916cbf75b01fc47f9781 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Sat, 1 Nov 2025 21:22:52 +0100
Subject: [PATCH 05/10] Incorporate code review feedback

---
 .../llvm/ExecutionEngine/JITLink/systemz.h    | 278 +++++-------------
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   |  77 ++---
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp  |  92 +++---
 3 files changed, 140 insertions(+), 307 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index d63446f35fffd..3f692e0ecc383 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -213,7 +213,7 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
   ///     symbol was not been defined.
-  Delta64FromGOT,
+  RequestGOTAndTransformToDelta64FromGOT,
 
   /// A 32-bit GOT delta.
   ///
@@ -227,7 +227,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///     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,
+  RequestGOTAndTransformToDelta32FromGOT,
 
   /// A 16-bit GOT delta.
   ///
@@ -241,7 +241,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///     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,
+  RequestGOTAndTransformToDelta16FromGOT,
 
   /// A 32-bit PC-relative branch.
   ///
@@ -257,7 +257,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression  before shifting right by 1 must
   ///     be multiple of 2, otherwise an alignment error will be returned.
   ///
-  BranchPCRelPLT32dbl,
+  DeltaPLT32dbl,
 
   /// A 24-bit PC-relative branch.
   ///
@@ -270,7 +270,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression  before shifting right by 1 must
   ///     be multiple of 2, otherwise an alignment error will be returned.
   ///
-  BranchPCRelPLT24dbl,
+  DeltaPLT24dbl,
 
   /// A 16-bit PC-relative branch.
   ///
@@ -283,7 +283,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression  before shifting right by 1 must
   ///     be multiple of 2, otherwise an alignment error will be returned.
   ///
-  BranchPCRelPLT16dbl,
+  DeltaPLT16dbl,
 
   /// A 12-bit PC-relative branch.
   ///
@@ -296,14 +296,14 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression  before shifting right by 1 must
   ///     be multiple of 2, otherwise an alignment error will be returned.
   ///
-  BranchPCRelPLT12dbl,
+  DeltaPLT12dbl,
 
   /// A 64-bit PC-relative PLT address.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - Fixup + Addend : int64
   ///
-  BranchPCRelPLT64,
+  DeltaPLT64,
 
   /// A 32-bit PC-relative PLT address.
   ///
@@ -314,14 +314,13 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int32, otherwise
   ///     an out-of-range error will be returned.
   ///
-  BranchPCRelPLT32,
+  DeltaPLT32,
 
   /// 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)
+  ///   lgrl %r1, ptr
   ///   j     %r1
   ///
   ///  Fixup expression at offset 2 of branch Instruction:
@@ -380,7 +379,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
   ///     symbol was not been defined.
   ///
-  Delta64GOT,
+  RequestGOTAndTransformToDelta64,
 
   /// A 32-bit GOT offset.
   ///
@@ -393,7 +392,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int32, otherwise
   ///     an out-of-range error will be returned.
   ///
-  Delta32GOT,
+  RequestGOTAndTransformToDelta32,
 
   /// A 20-bit GOT offset.
   ///
@@ -406,7 +405,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int20, otherwise
   ///     an out-of-range error will be returned.
   ///
-  Delta20GOT,
+  RequestGOTAndTransformToDelta20,
 
   /// A 16-bit GOT offset.
   ///
@@ -419,7 +418,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int16, otherwise
   ///     an out-of-range error will be returned.
   ///
-  Delta16GOT,
+  RequestGOTAndTransformToDelta16,
 
   /// A 12-bit GOT offset.
   ///
@@ -432,7 +431,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int12, otherwise
   ///     an out-of-range error will be returned.
   ///
-  Delta12GOT,
+  RequestGOTAndTransformToDelta12,
 
   /// A 32-bit PC rel. offset to GOT.
   ///
@@ -445,7 +444,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int32, otherwise
   ///     an out-of-range error will be returned.
   ///
-  DeltaPCRelGOT,
+  RequestGOTAndTransformToDelta32GOTBase,
 
   /// A 32-bit PC rel. offset to GOT shifted by 1.
   ///
@@ -460,83 +459,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - 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,
+  RequestGOTAndTransformToDelta32GOTBasedbl,
 
   /// A 32-bit PC rel. to GOT entry >> 1.
   ///
@@ -549,7 +472,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression  before shifting right by 1 must
   ///     be multiple of 2, otherwise an alignment error will be returned.
   ///
-  PCRel32GOTEntry,
+  RequestGOTAndTransformToDelta32dbl,
 
 };
 
@@ -592,7 +515,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     uint64_t Value = S + A;
     if (!LLVM_UNLIKELY(isUInt<32>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
-    *(ubig32_t *)FixupPtr = Value;
+    write32be(FixupPtr, Value);
     break;
   }
   case Pointer20: {
@@ -607,7 +530,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     uint64_t Value = S + A;
     if (!LLVM_UNLIKELY(isUInt<16>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
-    *(ubig16_t *)FixupPtr = Value;
+    write16be(FixupPtr, Value);
     break;
   }
   case Pointer12: {
@@ -626,28 +549,28 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   }
   case Delta64: {
     int64_t Value = S + A - P;
-    *(big64_t *)FixupPtr = Value;
+    write64be(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;
+    write32be(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;
+    write16be(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;
+    write32be(FixupPtr, Value);
     break;
   }
   case Delta32dbl: {
@@ -689,35 +612,37 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
               (read16be(FixupPtr) & 0xF000) | ((Value >> 1) & 0x0FFF));
     break;
   }
-  case Delta64FromGOT: {
+  case RequestGOTAndTransformToDelta64FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = S - GOTBase + A;
-    *(big64_t *)FixupPtr = Value;
+    write64be(FixupPtr, Value);
     break;
   }
-  case Delta32FromGOT: {
+  case RequestGOTAndTransformToDelta32FromGOT: {
     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;
+    write32be(FixupPtr, Value);
     break;
   }
-  case Delta16FromGOT: {
+  case RequestGOTAndTransformToDelta16FromGOT: {
     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;
+    write16be(FixupPtr, Value);
     break;
   }
-  case DeltaPCRelGOT: {
+  case RequestGOTAndTransformToDelta32GOTBase: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = GOTBase + A - P;
-    *(big32_t *)FixupPtr = Value;
+    if (!LLVM_UNLIKELY(isInt<32>(Value)))
+      return makeTargetOutOfRangeError(G, B, E);
+    write32be(FixupPtr, Value);
     break;
   }
-  case DeltaPCRelGOTdbl: {
+  case RequestGOTAndTransformToDelta32GOTBasedbl: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (GOTBase + A - P);
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
@@ -727,7 +652,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value >> 1);
     break;
   }
-  case BranchPCRelPLT32dbl: {
+  case DeltaPLT32dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -736,7 +661,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value >> 1);
     break;
   }
-  case BranchPCRelPLT24dbl: {
+  case DeltaPLT24dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<25>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -745,7 +670,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     FixupPtr[2] = Value >> 1;
     break;
   }
-  case BranchPCRelPLT16dbl: {
+  case DeltaPLT16dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<17>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -754,7 +679,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write16be(FixupPtr, Value >> 1);
     break;
   }
-  case BranchPCRelPLT12dbl: {
+  case DeltaPLT12dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<13>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -764,22 +689,22 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
               (read16be(FixupPtr) & 0xF000) | ((Value >> 1) & 0x0FFF));
     break;
   }
-  case BranchPCRelPLT64: {
+  case DeltaPLT64: {
     int64_t Value = (S + A - P);
-    *(big64_t *)FixupPtr = Value;
+    write64be(FixupPtr, Value);
     break;
   }
-  case BranchPCRelPLT32: {
+  case DeltaPLT32: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<32>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
-    *(big32_t *)FixupPtr = Value;
+    write32be(FixupPtr, Value);
     break;
   }
   case DeltaPLT64FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (S + A - GOTBase);
-    *(big64_t *)FixupPtr = Value;
+    write64be(FixupPtr, Value);
     break;
   }
   case DeltaPLT32FromGOT: {
@@ -787,7 +712,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     int64_t Value = (S + A - GOTBase);
     if (!LLVM_UNLIKELY(isInt<32>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
-    *(big32_t *)FixupPtr = Value;
+    write32be(FixupPtr, Value);
     break;
   }
   case DeltaPLT16FromGOT: {
@@ -795,7 +720,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     int64_t Value = (S + A - GOTBase);
     if (!LLVM_UNLIKELY(isInt<16>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
-    *(big16_t *)FixupPtr = Value;
+    write16be(FixupPtr, Value);
     break;
   }
   case Branch32dblToStub: {
@@ -803,10 +728,10 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     char *AddrToPatch = FixupPtr + 2;
-    *(big32_t *)AddrToPatch = (Value >> 1);
+    write32be(AddrToPatch, Value >> 1);
     break;
   }
-  case PCRel32GOTEntry: {
+  case RequestGOTAndTransformToDelta32dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -815,21 +740,21 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value >> 1);
     break;
   }
-  case Delta64GOT: {
+  case RequestGOTAndTransformToDelta64: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = S - GOTBase + A;
-    *(big64_t *)FixupPtr = Value;
+    write64be(FixupPtr, Value);
     break;
   }
-  case Delta32GOT: {
+  case RequestGOTAndTransformToDelta32: {
     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;
+    write32be(FixupPtr, Value);
     break;
   }
-  case Delta20GOT: {
+  case RequestGOTAndTransformToDelta20: {
     assert(GOTSymbol && "No GOT section symbol");
     uint64_t Value = S - GOTBase + A;
     if (!LLVM_UNLIKELY(isInt<20>(Value)))
@@ -838,15 +763,15 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
                             ((Value & 0xFFF) << 16) | ((Value & 0xFF000) >> 4));
     break;
   }
-  case Delta16GOT: {
+  case RequestGOTAndTransformToDelta16: {
     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;
+    write16be(FixupPtr, Value);
     break;
   }
-  case Delta12GOT: {
+  case RequestGOTAndTransformToDelta12: {
     assert(GOTSymbol && "No GOT section symbol");
     uint64_t Value = S - GOTBase + A;
     if (!LLVM_UNLIKELY(isUInt<12>(Value)))
@@ -854,54 +779,6 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &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() +
@@ -922,8 +799,7 @@ inline ArrayRef<char> getGOTEntryBlockContent(LinkGraph &G) {
 ///
 /// Contains the instruction sequence for an indirect jump via an in-memory
 /// pointer:
-///   larl %r1, ptr
-///   lg   %r1, 0(%r1)
+///   lgrl %r1, ptr
 ///   j    %r1
 constexpr size_t StubEntrySize = 14;
 extern const char Pointer64JumpStubContent[StubEntrySize];
@@ -982,23 +858,17 @@ class GOTTableManager : public TableManager<GOTTableManager> {
       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::Delta20JumpSlot:
-    case systemz::Delta32JumpSlot:
-    case systemz::Delta64JumpSlot:
-    case systemz::DeltaPCRelGOT:
-    case systemz::DeltaPCRelGOTdbl:
-    case systemz::PCRel32GOTEntry:
-    case systemz::PCRel32JumpSlot:
+    case systemz::RequestGOTAndTransformToDelta12:
+    case systemz::RequestGOTAndTransformToDelta16:
+    case systemz::RequestGOTAndTransformToDelta20:
+    case systemz::RequestGOTAndTransformToDelta32:
+    case systemz::RequestGOTAndTransformToDelta64:
+    case systemz::RequestGOTAndTransformToDelta16FromGOT:
+    case systemz::RequestGOTAndTransformToDelta32FromGOT:
+    case systemz::RequestGOTAndTransformToDelta64FromGOT:
+    case systemz::RequestGOTAndTransformToDelta32GOTBase:
+    case systemz::RequestGOTAndTransformToDelta32GOTBasedbl:
+    case systemz::RequestGOTAndTransformToDelta32dbl:
       KindToSet = E.getKind();
       break;
     default:
@@ -1042,12 +912,12 @@ class PLTTableManager : public TableManager<PLTTableManager> {
       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::DeltaPLT32:
+    case systemz::DeltaPLT64:
+    case systemz::DeltaPLT12dbl:
+    case systemz::DeltaPLT16dbl:
+    case systemz::DeltaPLT24dbl:
+    case systemz::DeltaPLT32dbl:
     case systemz::DeltaPLT16FromGOT:
     case systemz::DeltaPLT32FromGOT:
     case systemz::DeltaPLT64FromGOT:
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 47d2d4651f881..630736d3d1ad4 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -240,27 +240,27 @@ class ELFLinkGraphBuilder_systemz
     }
     // Relocations targeting the PLT associated with the symbol.
     case ELF::R_390_PLT64: {
-      Kind = systemz::BranchPCRelPLT64;
+      Kind = systemz::DeltaPLT64;
       break;
     }
     case ELF::R_390_PLT32: {
-      Kind = systemz::BranchPCRelPLT32;
+      Kind = systemz::DeltaPLT32;
       break;
     }
     case ELF::R_390_PLT32DBL: {
-      Kind = systemz::BranchPCRelPLT32dbl;
+      Kind = systemz::DeltaPLT32dbl;
       break;
     }
     case ELF::R_390_PLT24DBL: {
-      Kind = systemz::BranchPCRelPLT24dbl;
+      Kind = systemz::DeltaPLT24dbl;
       break;
     }
     case ELF::R_390_PLT16DBL: {
-      Kind = systemz::BranchPCRelPLT16dbl;
+      Kind = systemz::DeltaPLT16dbl;
       break;
     }
     case ELF::R_390_PLT12DBL: {
-      Kind = systemz::BranchPCRelPLT12dbl;
+      Kind = systemz::DeltaPLT12dbl;
       break;
     }
     case ELF::R_390_PLTOFF64: {
@@ -277,72 +277,53 @@ class ELFLinkGraphBuilder_systemz
     }
     // Relocations targeting the GOT entry associated with the symbol.
     case ELF::R_390_GOTOFF64: {
-      Kind = systemz::Delta64FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;
       break;
     }
-    // Seems loke ‘R_390_GOTOFF32’.
     case ELF::R_390_GOTOFF: {
-      Kind = systemz::Delta32FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;
       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;
+      Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;
       break;
     }
+    case ELF::R_390_GOT64:
     case ELF::R_390_GOTPLT64: {
-      Kind = systemz::Delta64JumpSlot;
+      Kind = systemz::RequestGOTAndTransformToDelta64;
       break;
     }
+    case ELF::R_390_GOT32:
     case ELF::R_390_GOTPLT32: {
-      Kind = systemz::Delta32JumpSlot;
+      Kind = systemz::RequestGOTAndTransformToDelta32;
       break;
     }
+    case ELF::R_390_GOT20:
     case ELF::R_390_GOTPLT20: {
-      Kind = systemz::Delta20JumpSlot;
+      Kind = systemz::RequestGOTAndTransformToDelta20;
       break;
     }
+    case ELF::R_390_GOT16:
     case ELF::R_390_GOTPLT16: {
-      Kind = systemz::Delta16JumpSlot;
+      Kind = systemz::RequestGOTAndTransformToDelta16;
       break;
     }
+    case ELF::R_390_GOT12:
     case ELF::R_390_GOTPLT12: {
-      Kind = systemz::Delta12JumpSlot;
+      Kind = systemz::RequestGOTAndTransformToDelta12;
       break;
     }
-    case ELF::R_390_GOTPLTENT: {
-      Kind = systemz::PCRel32JumpSlot;
+    case ELF::R_390_GOTPC: {
+      Kind = systemz::RequestGOTAndTransformToDelta32GOTBase;
       break;
     }
-    case ELF::R_390_GOTENT: {
-      Kind = systemz::PCRel32GOTEntry;
+    case ELF::R_390_GOTPCDBL: {
+      Kind = systemz::RequestGOTAndTransformToDelta32GOTBasedbl;
+      break;
+    }
+    case ELF::R_390_GOTENT:
+    case ELF::R_390_GOTPLTENT: {
+      Kind = systemz::RequestGOTAndTransformToDelta32dbl;
       break;
     }
     default:
@@ -390,7 +371,7 @@ Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_systemz(
     return Features.takeError();
 
   assert((*ELFObj)->getArch() == Triple::systemz &&
-         "Only SystemZ (big endian) is supported for now");
+         "Only SystemZ is supported");
 
   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj);
   return ELFLinkGraphBuilder_systemz(
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index c9276bedafe99..273f3345f10d6 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -22,18 +22,12 @@ const char NullPointerContent[8] = {0x00, 0x00, 0x00, 0x00,
                                     0x00, 0x00, 0x00, 0x00};
 
 const char Pointer64JumpStubContent[14] = {
-    static_cast<char>(0xC0u),
-    0x10,
+    static_cast<char>(0xC4u),
+    0x18,
     0x00,
     0x00,
     0x00,
-    0x00, // larl r1
-    static_cast<char>(0xE3u),
-    0x10,
-    0x10,
-    0x00,
-    0x00,
-    0x04, // LG 1, 0(1)
+    0x00, // lgrl r1
     static_cast<char>(0x07u),
     static_cast<char>(0xF1u), // BCR 15, 1
 };
@@ -70,58 +64,46 @@ const char *getEdgeKindName(Edge::Kind R) {
     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 RequestGOTAndTransformToDelta64FromGOT:
+    return "RequestGOTAndTransformToDelta64FromGOT";
+  case RequestGOTAndTransformToDelta32FromGOT:
+    return "RequestGOTAndTransformToDelta32FromGOT";
+  case RequestGOTAndTransformToDelta16FromGOT:
+    return "RequestGOTAndTransformToDelta16FromGOT";
+  case DeltaPLT32dbl:
+    return "DeltaPLT32dbl";
+  case DeltaPLT24dbl:
+    return "DeltaPLT24dbl";
+  case DeltaPLT16dbl:
+    return "DeltaPLT16dbl";
+  case DeltaPLT12dbl:
+    return "DeltaPLT12dbl";
+  case RequestGOTAndTransformToDelta32dbl:
+    return "RequestGOTAndTransformToDelta32dbl";
+  case DeltaPLT64:
+    return "DeltaPLT64";
+  case DeltaPLT32:
+    return "DeltaPLT32";
   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";
+  case RequestGOTAndTransformToDelta64:
+    return "RequestGOTAndTransformToDelta64";
+  case RequestGOTAndTransformToDelta32:
+    return "RequestGOTAndTransformToDelta32";
+  case RequestGOTAndTransformToDelta20:
+    return "RequestGOTAndTransformToDelta20";
+  case RequestGOTAndTransformToDelta16:
+    return "RequestGOTAndTransformToDelta16";
+  case RequestGOTAndTransformToDelta12:
+    return "RequestGOTAndTransformToDelta12";
+  case RequestGOTAndTransformToDelta32GOTBase:
+    return "RequestGOTAndTransformToDelta32GOTBase";
+  case RequestGOTAndTransformToDelta32GOTBasedbl:
+    return "RequestGOTAndTransformToDelta32GOTBasedbl";
   default:
     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
   }

>From c0cc3db1c4546c03495aea6468087a68f724bfa2 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Tue, 4 Nov 2025 05:54:11 +0100
Subject: [PATCH 06/10] Incorporate code review feedback

---
 .../llvm/ExecutionEngine/JITLink/systemz.h    | 362 +++++++++---------
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   |   4 +-
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp  |   8 +-
 3 files changed, 177 insertions(+), 197 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index 3f692e0ecc383..ebb0d7042d430 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -243,10 +243,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///     an out-of-range error will be returned.
   RequestGOTAndTransformToDelta16FromGOT,
 
-  /// A 32-bit PC-relative branch.
+  /// A 32-bit PC rel. PLT shifted by 1.
   ///
-  /// Represents a PC-relative call or branch to a target. This can be used to
-  /// identify, record, and/or patch call sites.
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int32
@@ -259,7 +259,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT32dbl,
 
-  /// A 24-bit PC-relative branch.
+  /// A 24-bit PC rel. PLT shifted by 1.
+  ///
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int24
@@ -272,7 +275,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT24dbl,
 
-  /// A 16-bit PC-relative branch.
+  /// A 16-bit  PC rel. PLT shifted by 1.
+  ///
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int16
@@ -285,7 +291,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT16dbl,
 
-  /// A 12-bit PC-relative branch.
+  /// A 12-bit PC rel. PLT shifted by 1.
+  ///
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int12
@@ -298,14 +307,20 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT12dbl,
 
-  /// A 64-bit PC-relative PLT address.
+  /// A 64-bit PC rel. PLT address.
+  ///
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - Fixup + Addend : int64
   ///
   DeltaPLT64,
 
-  /// A 32-bit PC-relative PLT address.
+  /// A 32-bit PC rel. PLT address.
+  ///
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - Fixup + Addend : int32
@@ -316,25 +331,11 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT32,
 
-  /// 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:
-  ///   lgrl %r1, ptr
-  ///   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.
   ///
+  /// Delta from the fixup to the target. This will lead to creation of a
+  /// PLT stub.
+  ///
   /// Fixup expression:
   ///   Fixup <- Target - GOTBase + Addend : int64
   ///
@@ -357,6 +358,19 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT32FromGOT,
 
+  /// A 20-bit offset from GOT to PLT.
+  ///
+  /// 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 int16, otherwise
+  ///     an out-of-range error will be returned.
+  ///
+  DeltaPLT20FromGOT,
+
   /// A 16-bit offset from GOT to PLT.
   ///
   /// Fixup expression:
@@ -370,69 +384,139 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT16FromGOT,
 
-  /// A 64-bit GOT offset.
+  /// A 12-bit offset from GOT to PLT.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTBase + Addend : int64
+  ///   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 int16, otherwise
+  ///     an out-of-range error will be returned.
+  ///
+  DeltaPLT12FromGOT,
+
+  /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
   ///
   RequestGOTAndTransformToDelta64,
 
-  /// A 32-bit GOT offset.
+  /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTBase + Addend : int32
+  ///   NONE
   ///
   /// 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.
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
   ///
   RequestGOTAndTransformToDelta32,
 
-  /// A 20-bit GOT offset.
+  /// A GOT entry getter/constructor, transformed to Delta20 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTBase + Addend : int20
+  ///   NONE
   ///
   /// 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.
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
   ///
   RequestGOTAndTransformToDelta20,
 
-  /// A 16-bit GOT offset.
+  /// A GOT entry getter/constructor, transformed to Delta16 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTBase + Addend : int16
+  ///   NONE
   ///
   /// 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.
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
   ///
   RequestGOTAndTransformToDelta16,
 
-  /// A 12-bit GOT offset.
+  /// A GOT entry getter/constructor, transformed to Delta12 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTBase + Addend : int12
+  ///   NONE
   ///
   /// 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.
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
   ///
   RequestGOTAndTransformToDelta12,
 
+  /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
+  /// entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// the GOT entry for the edge's current target, maintaining the same addend.
+  /// A GOT entry for the target should be created if one does not already
+  /// exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///     phase will result in an assert/unreachable during the fixup phase.
+  ///
+  RequestGOTAndTransformToDelta32dbl,
+
   /// A 32-bit PC rel. offset to GOT.
   ///
   /// Fixup expression:
@@ -444,7 +528,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int32, otherwise
   ///     an out-of-range error will be returned.
   ///
-  RequestGOTAndTransformToDelta32GOTBase,
+  Delta32GOTBase,
 
   /// A 32-bit PC rel. offset to GOT shifted by 1.
   ///
@@ -459,20 +543,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression  before shifting right by 1 must
   ///     be multiple of 2, otherwise an alignment error will be returned.
   ///
-  RequestGOTAndTransformToDelta32GOTBasedbl,
-
-  /// 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.
-  ///
-  RequestGOTAndTransformToDelta32dbl,
+  Delta32dblGOTBase,
 
 };
 
@@ -547,12 +618,14 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     *(uint8_t *)FixupPtr = Value;
     break;
   }
-  case Delta64: {
+  case Delta64:
+  case DeltaPLT64: {
     int64_t Value = S + A - P;
     write64be(FixupPtr, Value);
     break;
   }
-  case Delta32: {
+  case Delta32:
+  case DeltaPLT32: {
     int64_t Value = S + A - P;
     if (!LLVM_UNLIKELY(isInt<32>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -573,7 +646,8 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value);
     break;
   }
-  case Delta32dbl: {
+  case Delta32dbl:
+  case DeltaPLT32dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -582,7 +656,8 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value >> 1);
     break;
   }
-  case Delta24dbl: {
+  case Delta24dbl:
+  case DeltaPLT24dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<25>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -593,7 +668,8 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     FixupPtr[2] = Value >> 1;
     break;
   }
-  case Delta16dbl: {
+  case Delta16dbl:
+  case DeltaPLT16dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<17>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -602,7 +678,8 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write16be(FixupPtr, Value >> 1);
     break;
   }
-  case Delta12dbl: {
+  case Delta12dbl:
+  case DeltaPLT12dbl: {
     int64_t Value = (S + A - P);
     if (!LLVM_UNLIKELY(isInt<13>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
@@ -612,29 +689,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
               (read16be(FixupPtr) & 0xF000) | ((Value >> 1) & 0x0FFF));
     break;
   }
-  case RequestGOTAndTransformToDelta64FromGOT: {
-    assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = S - GOTBase + A;
-    write64be(FixupPtr, Value);
-    break;
-  }
-  case RequestGOTAndTransformToDelta32FromGOT: {
-    assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = S - GOTBase + A;
-    if (!LLVM_UNLIKELY(isInt<32>(Value)))
-      return makeTargetOutOfRangeError(G, B, E);
-    write32be(FixupPtr, Value);
-    break;
-  }
-  case RequestGOTAndTransformToDelta16FromGOT: {
-    assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = S - GOTBase + A;
-    if (!LLVM_UNLIKELY(isInt<16>(Value)))
-      return makeTargetOutOfRangeError(G, B, E);
-    write16be(FixupPtr, Value);
-    break;
-  }
-  case RequestGOTAndTransformToDelta32GOTBase: {
+  case Delta32GOTBase: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = GOTBase + A - P;
     if (!LLVM_UNLIKELY(isInt<32>(Value)))
@@ -642,7 +697,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value);
     break;
   }
-  case RequestGOTAndTransformToDelta32GOTBasedbl: {
+  case Delta32dblGOTBase: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (GOTBase + A - P);
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
@@ -652,55 +707,6 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value >> 1);
     break;
   }
-  case DeltaPLT32dbl: {
-    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 DeltaPLT24dbl: {
-    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 DeltaPLT16dbl: {
-    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 DeltaPLT12dbl: {
-    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 DeltaPLT64: {
-    int64_t Value = (S + A - P);
-    write64be(FixupPtr, Value);
-    break;
-  }
-  case DeltaPLT32: {
-    int64_t Value = (S + A - P);
-    if (!LLVM_UNLIKELY(isInt<32>(Value)))
-      return makeTargetOutOfRangeError(G, B, E);
-    write32be(FixupPtr, Value);
-    break;
-  }
   case DeltaPLT64FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (S + A - GOTBase);
@@ -723,38 +729,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write16be(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;
-    write32be(AddrToPatch, Value >> 1);
-    break;
-  }
-  case RequestGOTAndTransformToDelta32dbl: {
-    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 RequestGOTAndTransformToDelta64: {
-    assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = S - GOTBase + A;
-    write64be(FixupPtr, Value);
-    break;
-  }
-  case RequestGOTAndTransformToDelta32: {
-    assert(GOTSymbol && "No GOT section symbol");
-    uint64_t Value = S - GOTBase + A;
-    if (!LLVM_UNLIKELY(isUInt<32>(Value)))
-      return makeTargetOutOfRangeError(G, B, E);
-    write32be(FixupPtr, Value);
-    break;
-  }
-  case RequestGOTAndTransformToDelta20: {
+  case DeltaPLT20FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     uint64_t Value = S - GOTBase + A;
     if (!LLVM_UNLIKELY(isInt<20>(Value)))
@@ -763,15 +738,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
                             ((Value & 0xFFF) << 16) | ((Value & 0xFF000) >> 4));
     break;
   }
-  case RequestGOTAndTransformToDelta16: {
-    assert(GOTSymbol && "No GOT section symbol");
-    uint64_t Value = S - GOTBase + A;
-    if (!LLVM_UNLIKELY(isUInt<16>(Value)))
-      return makeTargetOutOfRangeError(G, B, E);
-    write16be(FixupPtr, Value);
-    break;
-  }
-  case RequestGOTAndTransformToDelta12: {
+  case DeltaPLT12FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     uint64_t Value = S - GOTBase + A;
     if (!LLVM_UNLIKELY(isUInt<12>(Value)))
@@ -832,7 +799,7 @@ 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);
+  B.addEdge(Delta32dbl, 0, PointerSymbol, 0);
   return B;
 }
 
@@ -859,16 +826,28 @@ class GOTTableManager : public TableManager<GOTTableManager> {
     Edge::Kind KindToSet = Edge::Invalid;
     switch (E.getKind()) {
     case systemz::RequestGOTAndTransformToDelta12:
+      KindToSet = systemz::DeltaPLT12FromGOT;
+      break;
     case systemz::RequestGOTAndTransformToDelta16:
+    case systemz::RequestGOTAndTransformToDelta16FromGOT:
+      KindToSet = systemz::DeltaPLT16FromGOT;
+      break;
     case systemz::RequestGOTAndTransformToDelta20:
+      KindToSet = systemz::DeltaPLT20FromGOT;
+      break;
     case systemz::RequestGOTAndTransformToDelta32:
-    case systemz::RequestGOTAndTransformToDelta64:
-    case systemz::RequestGOTAndTransformToDelta16FromGOT:
     case systemz::RequestGOTAndTransformToDelta32FromGOT:
+      KindToSet = systemz::DeltaPLT32FromGOT;
+      break;
+    case systemz::RequestGOTAndTransformToDelta64:
     case systemz::RequestGOTAndTransformToDelta64FromGOT:
-    case systemz::RequestGOTAndTransformToDelta32GOTBase:
-    case systemz::RequestGOTAndTransformToDelta32GOTBasedbl:
+      KindToSet = systemz::DeltaPLT64FromGOT;
+      break;
     case systemz::RequestGOTAndTransformToDelta32dbl:
+      KindToSet = systemz::DeltaPLT32dbl;
+      break;
+    case systemz::Delta32GOTBase:
+    case systemz::Delta32dblGOTBase:
       KindToSet = E.getKind();
       break;
     default:
@@ -881,6 +860,7 @@ class GOTTableManager : public TableManager<GOTTableManager> {
              << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
              << formatv("{0:x}", E.getOffset()) << ")\n";
     });
+    E.setKind(KindToSet);
     E.setTarget(getEntryForTarget(G, E.getTarget()));
     return true;
   }
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 630736d3d1ad4..74d9531d3631f 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -314,11 +314,11 @@ class ELFLinkGraphBuilder_systemz
       break;
     }
     case ELF::R_390_GOTPC: {
-      Kind = systemz::RequestGOTAndTransformToDelta32GOTBase;
+      Kind = systemz::Delta32GOTBase;
       break;
     }
     case ELF::R_390_GOTPCDBL: {
-      Kind = systemz::RequestGOTAndTransformToDelta32GOTBasedbl;
+      Kind = systemz::Delta32dblGOTBase;
       break;
     }
     case ELF::R_390_GOTENT:
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index 273f3345f10d6..4e64036ea1eac 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -100,10 +100,10 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "RequestGOTAndTransformToDelta16";
   case RequestGOTAndTransformToDelta12:
     return "RequestGOTAndTransformToDelta12";
-  case RequestGOTAndTransformToDelta32GOTBase:
-    return "RequestGOTAndTransformToDelta32GOTBase";
-  case RequestGOTAndTransformToDelta32GOTBasedbl:
-    return "RequestGOTAndTransformToDelta32GOTBasedbl";
+  case Delta32GOTBase:
+    return "Delta32GOTBase";
+  case Delta32dblGOTBase:
+    return "Delta32dblGOTBase";
   default:
     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
   }

>From 47482b25280f7b78009def2013dd1c5afc2802a9 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Wed, 5 Nov 2025 03:55:05 +0100
Subject: [PATCH 07/10] 1. Created GOTPC section for R_390_GOTPC and
 R_390_GOTPCDBL relocation. 2. Incorporate code review feedback.

---
 .../llvm/ExecutionEngine/JITLink/systemz.h    | 264 ++++++++++--------
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   |  23 +-
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp  |  30 +-
 3 files changed, 175 insertions(+), 142 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index ebb0d7042d430..460ed429418b1 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -49,7 +49,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   Fixup <- Target + Addend : uint20
   ///
   /// Errors:
-  ///   - The target must reside in the mid 20-bits of the address space,
+  ///   - The target must reside in the low 20-bits of the address space,
   ///     otherwise an out-of-range error will be returned.
   ///
   Pointer20,
@@ -203,50 +203,67 @@ enum EdgeKind_systemz : Edge::Kind {
   ///     an out-of-range error will be returned.
   NegDelta32,
 
-  /// A 64-bit GOT delta.
+  /// A GOT entry getter/constructor, transformed to DeltaPLT64FromGOT pointing
+  /// at the GOT entry for the original target.
   ///
-  /// Delta from the global offset table to the target
+  /// Indicates that this edge should be transformed into a DeltaPLT64FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTSymbol + Addend : int64
+  ///   NONE
   ///
   /// Errors:
-  ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
-  ///     symbol was not been defined.
-  RequestGOTAndTransformToDelta64FromGOT,
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///
+  RequestGOTAndTransformToDeltaPLT64FromGOT,
 
-  /// A 32-bit GOT delta.
+  /// A GOT entry getter/constructor, transformed to DeltaPLT32FromGOT pointing
+  /// at the GOT entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a DeltaPLT32FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
   ///
-  /// Delta from the global offset table to the target
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTSymbol + Addend : int32
+  ///   NONE
   ///
   /// 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.
-  RequestGOTAndTransformToDelta32FromGOT,
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///
+  RequestGOTAndTransformToDeltaPLT32FromGOT,
 
-  /// A 16-bit GOT delta.
+  /// A GOT entry getter/constructor, transformed to DeltaPLT16FromGOT pointing
+  /// at the GOT entry for the original target.
   ///
-  /// Delta from the global offset table to the target
+  /// Indicates that this edge should be transformed into a DeltaPLT16FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTSymbol + Addend : int16
+  ///   NONE
   ///
   /// 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.
-  RequestGOTAndTransformToDelta16FromGOT,
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///
+  RequestGOTAndTransformToDeltaPLT16FromGOT,
 
-  /// A 32-bit PC rel. PLT shifted by 1.
+  /// A 32-bit Delta shifted by 1.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
+  /// Delta from the fixup to the PLT slot for the target. This will lead to
+  /// creation of a PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int32
@@ -259,10 +276,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT32dbl,
 
-  /// A 24-bit PC rel. PLT shifted by 1.
+  /// A 24-bit Delta shifted by 1.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
+  /// Delta from the fixup to the PLT slot for the target. This will lead to
+  /// creation of a PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int24
@@ -275,10 +292,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT24dbl,
 
-  /// A 16-bit  PC rel. PLT shifted by 1.
+  /// A 16-bit Delta shifted by 1.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
+  /// Delta from the fixup to the PLT slot for the target. This will lead to
+  /// creation of a PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int16
@@ -291,10 +308,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT16dbl,
 
-  /// A 12-bit PC rel. PLT shifted by 1.
+  /// A 12-bit Delta shifted by 1.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
+  /// Delta from the fixup to the PLT slot for the target. This will lead to
+  /// creation of a PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend) >> 1 : int12
@@ -307,20 +324,20 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT12dbl,
 
-  /// A 64-bit PC rel. PLT address.
+  /// A 64-bit Delta.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
+  /// Delta from the fixup to the PLT slot for the target. This will lead to
+  /// creation of a PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - Fixup + Addend : int64
   ///
   DeltaPLT64,
 
-  /// A 32-bit PC rel. PLT address.
+  /// A 32-bit Delta.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
+  /// Delta from the fixup to the PLT slot for the target. This will lead to
+  /// creation of a PLT stub.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - Fixup + Addend : int32
@@ -397,13 +414,13 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT12FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
-  /// entry for the original target.
+  /// A GOT entry getter/constructor, transformed to DeltaPLT20FromGOT pointing
+  /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a Delta32 targeting
-  /// the GOT entry for the edge's current target, maintaining the same addend.
-  /// A GOT entry for the target should be created if one does not already
-  /// exist.
+  /// Indicates that this edge should be transformed into a DeltaPLT20FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
   ///
   /// Edges of this kind are usually handled by a GOT builder pass inserted by
   /// default.
@@ -413,17 +430,16 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///     phase will result in an assert/unreachable during the fixup phase.
   ///
-  RequestGOTAndTransformToDelta64,
+  RequestGOTAndTransformToDeltaPLT20FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
-  /// entry for the original target.
+  /// A GOT entry getter/constructor, transformed to DeltaPLT12FromGOT pointing
+  /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a Delta32 targeting
-  /// the GOT entry for the edge's current target, maintaining the same addend.
-  /// A GOT entry for the target should be created if one does not already
-  /// exist.
+  /// Indicates that this edge should be transformed into a DeltaPLT12FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
   ///
   /// Edges of this kind are usually handled by a GOT builder pass inserted by
   /// default.
@@ -435,12 +451,12 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///     phase will result in an assert/unreachable during the fixup phase.
   ///
-  RequestGOTAndTransformToDelta32,
+  RequestGOTAndTransformToDeltaPLT12FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to Delta20 pointing at the GOT
-  /// entry for the original target.
+  /// A GOT entry getter/constructor, transformed to Delta32dbl pointing at
+  /// the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a Delta32 targeting
+  /// Indicates that this edge should be transformed into a Delta32dbl targeting
   /// the GOT entry for the edge's current target, maintaining the same addend.
   /// A GOT entry for the target should be created if one does not already
   /// exist.
@@ -455,38 +471,18 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///     phase will result in an assert/unreachable during the fixup phase.
   ///
-  RequestGOTAndTransformToDelta20,
-
-  /// A GOT entry getter/constructor, transformed to Delta16 pointing at the GOT
-  /// entry for the original target.
-  ///
-  /// Indicates that this edge should be transformed into a Delta32 targeting
-  /// the GOT entry for the edge's current target, maintaining the same addend.
-  /// A GOT entry for the target should be created if one does not already
-  /// exist.
-  ///
-  /// Edges of this kind are usually handled by a GOT builder pass inserted by
-  /// default.
-  ///
-  /// Fixup expression:
-  ///   NONE
-  ///
-  /// Errors:
-  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///     phase will result in an assert/unreachable during the fixup phase.
-  ///
-  RequestGOTAndTransformToDelta16,
+  RequestGOTAndTransformToDelta32dbl,
 
-  /// A GOT entry getter/constructor, transformed to Delta12 pointing at the GOT
-  /// entry for the original target.
+  /// A GOTPC entry getter/constructor, transformed to Delta32GOTBase
+  /// delta to GOT base.
   ///
-  /// Indicates that this edge should be transformed into a Delta32 targeting
-  /// the GOT entry for the edge's current target, maintaining the same addend.
-  /// A GOT entry for the target should be created if one does not already
-  /// exist.
+  /// Indicates that this edge should be transformed into a Delta32GOTBase
+  /// targeting the GOTPC entry for the edge's current target, maintaining
+  /// the same addend. A GOTPC entry for the target should be created if
+  /// one does not already exist.
   ///
-  /// Edges of this kind are usually handled by a GOT builder pass inserted by
-  /// default.
+  /// Edges of this kind are usually handled by a GOTPC builder pass inserted
+  /// by default.
   ///
   /// Fixup expression:
   ///   NONE
@@ -494,19 +490,18 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///     phase will result in an assert/unreachable during the fixup phase.
-  ///
-  RequestGOTAndTransformToDelta12,
+  RequestGOTPCAndTransformToDelta32GOTBase,
 
-  /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
-  /// entry for the original target.
+  /// A GOTPC entry getter/constructor, transformed to Delta32dblGOTBase
+  /// delta to GOT base.
   ///
-  /// Indicates that this edge should be transformed into a Delta32 targeting
-  /// the GOT entry for the edge's current target, maintaining the same addend.
-  /// A GOT entry for the target should be created if one does not already
-  /// exist.
+  /// Indicates that this edge should be transformed into a Delta32dblGOTBase
+  /// targeting the GOTPC entry for the edge's current target, maintaining
+  /// the same addend. A GOTPC entry for the target should be created if
+  /// one does not already exist.
   ///
-  /// Edges of this kind are usually handled by a GOT builder pass inserted by
-  /// default.
+  /// Edges of this kind are usually handled by a GOTPC builder pass inserted
+  /// by default.
   ///
   /// Fixup expression:
   ///   NONE
@@ -514,10 +509,9 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///     phase will result in an assert/unreachable during the fixup phase.
-  ///
-  RequestGOTAndTransformToDelta32dbl,
+  RequestGOTPCAndTransformToDelta32dblGOTBase,
 
-  /// A 32-bit PC rel. offset to GOT.
+  /// A 32-bit Delta to GOT base.
   ///
   /// Fixup expression:
   ///   Fixup <- GOTBase - Fixup + Addend : int32
@@ -530,7 +524,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   Delta32GOTBase,
 
-  /// A 32-bit PC rel. offset to GOT shifted by 1.
+  /// A 32-bit Delta to GOT base shifted by 1.
   ///
   /// Fixup expression:
   ///   Fixup <- (GOTBase - Fixup + Addend) >> 1 : int32
@@ -799,7 +793,7 @@ inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
                                          Symbol &PointerSymbol) {
   auto &B = G.createContentBlock(StubSection, getStubBlockContent(G),
                                  orc::ExecutorAddr(), 8, 0);
-  B.addEdge(Delta32dbl, 0, PointerSymbol, 0);
+  B.addEdge(Delta32dbl, 2, PointerSymbol, 0);
   return B;
 }
 
@@ -825,31 +819,24 @@ class GOTTableManager : public TableManager<GOTTableManager> {
       return false;
     Edge::Kind KindToSet = Edge::Invalid;
     switch (E.getKind()) {
-    case systemz::RequestGOTAndTransformToDelta12:
+    case systemz::RequestGOTAndTransformToDeltaPLT12FromGOT:
       KindToSet = systemz::DeltaPLT12FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDelta16:
-    case systemz::RequestGOTAndTransformToDelta16FromGOT:
+    case systemz::RequestGOTAndTransformToDeltaPLT16FromGOT:
       KindToSet = systemz::DeltaPLT16FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDelta20:
+    case systemz::RequestGOTAndTransformToDeltaPLT20FromGOT:
       KindToSet = systemz::DeltaPLT20FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDelta32:
-    case systemz::RequestGOTAndTransformToDelta32FromGOT:
+    case systemz::RequestGOTAndTransformToDeltaPLT32FromGOT:
       KindToSet = systemz::DeltaPLT32FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDelta64:
-    case systemz::RequestGOTAndTransformToDelta64FromGOT:
+    case systemz::RequestGOTAndTransformToDeltaPLT64FromGOT:
       KindToSet = systemz::DeltaPLT64FromGOT;
       break;
     case systemz::RequestGOTAndTransformToDelta32dbl:
       KindToSet = systemz::DeltaPLT32dbl;
       break;
-    case systemz::Delta32GOTBase:
-    case systemz::Delta32dblGOTBase:
-      KindToSet = E.getKind();
-      break;
     default:
       return false;
     }
@@ -931,6 +918,53 @@ class PLTTableManager : public TableManager<PLTTableManager> {
   Section *StubsSection = nullptr;
 };
 
+/// GOTPC Table Builder.
+class GOTPCTableManager : public TableManager<GOTPCTableManager> {
+public:
+  GOTPCTableManager(GOTTableManager &GOT) : GOT(GOT) {}
+
+  static StringRef getSectionName() { return "$__GOTPC"; }
+
+  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+    Edge::Kind KindToSet = Edge::Invalid;
+    switch (E.getKind()) {
+    case systemz::RequestGOTPCAndTransformToDelta32GOTBase:
+      KindToSet = systemz::Delta32GOTBase;
+      break;
+    case systemz::RequestGOTPCAndTransformToDelta32dblGOTBase:
+      KindToSet = systemz::Delta32dblGOTBase;
+      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.setKind(KindToSet);
+    E.setTarget(getEntryForTarget(G, E.getTarget()));
+    return true;
+  }
+
+  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+    return createAnonymousPointer(G, getGOTPCSection(G), &Target);
+  }
+
+private:
+  Section &getGOTPCSection(LinkGraph &G) {
+    if (!GOTPCSection)
+      GOTPCSection = &G.createSection(getSectionName(),
+                                      orc::MemProt::Read | orc::MemProt::Exec);
+    return *GOTPCSection;
+  }
+
+  GOTTableManager &GOT;
+  Section *GOTPCSection = nullptr;
+};
+
 } // namespace systemz
 } // namespace jitlink
 } // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 74d9531d3631f..9ddba46e3b211 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -32,7 +32,8 @@ 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);
+  systemz::GOTPCTableManager GOTPC(GOT);
+  visitExistingEdges(G, GOT, PLT, GOTPC);
   return Error::success();
 }
 
@@ -277,48 +278,48 @@ class ELFLinkGraphBuilder_systemz
     }
     // Relocations targeting the GOT entry associated with the symbol.
     case ELF::R_390_GOTOFF64: {
-      Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT64FromGOT;
       break;
     }
     case ELF::R_390_GOTOFF: {
-      Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT32FromGOT;
       break;
     }
     case ELF::R_390_GOTOFF16: {
-      Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT16FromGOT;
       break;
     }
     case ELF::R_390_GOT64:
     case ELF::R_390_GOTPLT64: {
-      Kind = systemz::RequestGOTAndTransformToDelta64;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT64FromGOT;
       break;
     }
     case ELF::R_390_GOT32:
     case ELF::R_390_GOTPLT32: {
-      Kind = systemz::RequestGOTAndTransformToDelta32;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT32FromGOT;
       break;
     }
     case ELF::R_390_GOT20:
     case ELF::R_390_GOTPLT20: {
-      Kind = systemz::RequestGOTAndTransformToDelta20;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT20FromGOT;
       break;
     }
     case ELF::R_390_GOT16:
     case ELF::R_390_GOTPLT16: {
-      Kind = systemz::RequestGOTAndTransformToDelta16;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT16FromGOT;
       break;
     }
     case ELF::R_390_GOT12:
     case ELF::R_390_GOTPLT12: {
-      Kind = systemz::RequestGOTAndTransformToDelta12;
+      Kind = systemz::RequestGOTAndTransformToDeltaPLT12FromGOT;
       break;
     }
     case ELF::R_390_GOTPC: {
-      Kind = systemz::Delta32GOTBase;
+      Kind = systemz::RequestGOTPCAndTransformToDelta32GOTBase;
       break;
     }
     case ELF::R_390_GOTPCDBL: {
-      Kind = systemz::Delta32dblGOTBase;
+      Kind = systemz::RequestGOTPCAndTransformToDelta32dblGOTBase;
       break;
     }
     case ELF::R_390_GOTENT:
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index 4e64036ea1eac..7f6d18c04ca59 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -64,12 +64,12 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "NegDelta64";
   case NegDelta32:
     return "NegDelta32";
-  case RequestGOTAndTransformToDelta64FromGOT:
-    return "RequestGOTAndTransformToDelta64FromGOT";
-  case RequestGOTAndTransformToDelta32FromGOT:
-    return "RequestGOTAndTransformToDelta32FromGOT";
-  case RequestGOTAndTransformToDelta16FromGOT:
-    return "RequestGOTAndTransformToDelta16FromGOT";
+  case RequestGOTAndTransformToDeltaPLT64FromGOT:
+    return "RequestGOTAndTransformToDeltaPLT64FromGOT";
+  case RequestGOTAndTransformToDeltaPLT32FromGOT:
+    return "RequestGOTAndTransformToDeltaPLT32FromGOT";
+  case RequestGOTAndTransformToDeltaPLT16FromGOT:
+    return "RequestGOTAndTransformToDeltaPLT16FromGOT";
   case DeltaPLT32dbl:
     return "DeltaPLT32dbl";
   case DeltaPLT24dbl:
@@ -90,16 +90,14 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "DeltaPLT32FromGOT";
   case DeltaPLT16FromGOT:
     return "DeltaPLT16FromGOT";
-  case RequestGOTAndTransformToDelta64:
-    return "RequestGOTAndTransformToDelta64";
-  case RequestGOTAndTransformToDelta32:
-    return "RequestGOTAndTransformToDelta32";
-  case RequestGOTAndTransformToDelta20:
-    return "RequestGOTAndTransformToDelta20";
-  case RequestGOTAndTransformToDelta16:
-    return "RequestGOTAndTransformToDelta16";
-  case RequestGOTAndTransformToDelta12:
-    return "RequestGOTAndTransformToDelta12";
+  case RequestGOTAndTransformToDeltaPLT20FromGOT:
+    return "RequestGOTAndTransformToDeltaPLT20FromGOT";
+  case RequestGOTAndTransformToDeltaPLT12FromGOT:
+    return "RequestGOTAndTransformToDeltaPLT12FromGOT";
+  case RequestGOTPCAndTransformToDelta32GOTBase:
+    return "RequestGOTPCAndTransformToDelta32GOTBase";
+  case RequestGOTPCAndTransformToDelta32dblGOTBase:
+    return "RequestGOTPCAndTransformToDelta32dblGOTBase";
   case Delta32GOTBase:
     return "Delta32GOTBase";
   case Delta32dblGOTBase:

>From f6b25567ba07596c2afdd3db8ca728ae4a953d95 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Thu, 6 Nov 2025 02:54:25 +0100
Subject: [PATCH 08/10] Incorporate code review feedback

---
 .../llvm/ExecutionEngine/JITLink/systemz.h    | 212 +++++++-----------
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   |  44 ++--
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp  |  42 ++--
 3 files changed, 127 insertions(+), 171 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index 460ed429418b1..1ef5f693d87d8 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -203,10 +203,10 @@ enum EdgeKind_systemz : Edge::Kind {
   ///     an out-of-range error will be returned.
   NegDelta32,
 
-  /// A GOT entry getter/constructor, transformed to DeltaPLT64FromGOT pointing
+  /// A GOT entry getter/constructor, transformed to Delta64FromGOT pointing
   /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a DeltaPLT64FromGOT
+  /// Indicates that this edge should be transformed into a Delta64FromGOT
   /// targeting the GOT entry for the edge's current target, maintaining the
   /// same addend. A GOT entry for the target should be created if one does
   /// not already exist.
@@ -220,12 +220,12 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///
-  RequestGOTAndTransformToDeltaPLT64FromGOT,
+  RequestGOTAndTransformToDelta64FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to DeltaPLT32FromGOT pointing
+  /// A GOT entry getter/constructor, transformed to Delta32FromGOT pointing
   /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a DeltaPLT32FromGOT
+  /// Indicates that this edge should be transformed into a Delta32FromGOT
   /// targeting the GOT entry for the edge's current target, maintaining the
   /// same addend. A GOT entry for the target should be created if one does
   /// not already exist.
@@ -239,12 +239,12 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///
-  RequestGOTAndTransformToDeltaPLT32FromGOT,
+  RequestGOTAndTransformToDelta32FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to DeltaPLT16FromGOT pointing
+  /// A GOT entry getter/constructor, transformed to Delta16FromGOT pointing
   /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a DeltaPLT16FromGOT
+  /// Indicates that this edge should be transformed into a Delta16FromGOT
   /// targeting the GOT entry for the edge's current target, maintaining the
   /// same addend. A GOT entry for the target should be created if one does
   /// not already exist.
@@ -258,7 +258,7 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///
-  RequestGOTAndTransformToDeltaPLT16FromGOT,
+  RequestGOTAndTransformToDelta16FromGOT,
 
   /// A 32-bit Delta shifted by 1.
   ///
@@ -350,9 +350,6 @@ enum EdgeKind_systemz : Edge::Kind {
 
   /// A 64-bit offset from GOT to PLT.
   ///
-  /// Delta from the fixup to the target. This will lead to creation of a
-  /// PLT stub.
-  ///
   /// Fixup expression:
   ///   Fixup <- Target - GOTBase + Addend : int64
   ///
@@ -360,7 +357,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
   ///     symbol was not been defined.
   ///
-  DeltaPLT64FromGOT,
+  Delta64PLTFromGOT,
 
   /// A 32-bit offset from GOT to PLT.
   ///
@@ -373,12 +370,12 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int32, otherwise
   ///     an out-of-range error will be returned.
   ///
-  DeltaPLT32FromGOT,
+  Delta32PLTFromGOT,
 
-  /// A 20-bit offset from GOT to PLT.
+  /// A 16-bit offset from GOT to PLT.
   ///
   /// Fixup expression:
-  ///   Fixup <- Target - GOTBase + Addend : int20
+  ///   Fixup <- Target - GOTBase + Addend : int16
   ///
   /// Errors:
   ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
@@ -386,9 +383,33 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int16, otherwise
   ///     an out-of-range error will be returned.
   ///
-  DeltaPLT20FromGOT,
+  Delta16PLTFromGOT,
 
-  /// A 16-bit offset from GOT to PLT.
+  /// A 64-bit offset from GOT.
+  ///
+  /// Fixup expression:
+  ///   Fixup <- Target - GOTBase + Addend : int64
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
+  ///     symbol was not been defined.
+  ///
+  Delta64FromGOT,
+
+  /// A 32-bit offset from GOT.
+  ///
+  /// 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.
+  ///
+  Delta32FromGOT,
+
+  /// A 16-bit offset from GOT.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - GOTBase + Addend : int16
@@ -399,9 +420,22 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int16, otherwise
   ///     an out-of-range error will be returned.
   ///
-  DeltaPLT16FromGOT,
+  Delta16FromGOT,
+
+  /// A 20-bit offset from GOT.
+  ///
+  /// 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 int16, otherwise
+  ///     an out-of-range error will be returned.
+  ///
+  Delta20FromGOT,
 
-  /// A 12-bit offset from GOT to PLT.
+  /// A 12-bit offset from GOT.
   ///
   /// Fixup expression:
   ///   Fixup <- Target - GOTBase + Addend : int12
@@ -412,12 +446,12 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - The result of the fixup expression must fit into an int16, otherwise
   ///     an out-of-range error will be returned.
   ///
-  DeltaPLT12FromGOT,
+  Delta12FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to DeltaPLT20FromGOT pointing
+  /// A GOT entry getter/constructor, transformed to Delta20FromGOT pointing
   /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a DeltaPLT20FromGOT
+  /// Indicates that this edge should be transformed into a Delta20FromGOT
   /// targeting the GOT entry for the edge's current target, maintaining the
   /// same addend. A GOT entry for the target should be created if one does
   /// not already exist.
@@ -431,12 +465,12 @@ enum EdgeKind_systemz : Edge::Kind {
   /// Errors:
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///
-  RequestGOTAndTransformToDeltaPLT20FromGOT,
+  RequestGOTAndTransformToDelta20FromGOT,
 
-  /// A GOT entry getter/constructor, transformed to DeltaPLT12FromGOT pointing
+  /// A GOT entry getter/constructor, transformed to Delta12FromGOT pointing
   /// at the GOT entry for the original target.
   ///
-  /// Indicates that this edge should be transformed into a DeltaPLT12FromGOT
+  /// Indicates that this edge should be transformed into a Delta12FromGOT
   /// targeting the GOT entry for the edge's current target, maintaining the
   /// same addend. A GOT entry for the target should be created if one does
   /// not already exist.
@@ -451,7 +485,7 @@ enum EdgeKind_systemz : Edge::Kind {
   ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
   ///     phase will result in an assert/unreachable during the fixup phase.
   ///
-  RequestGOTAndTransformToDeltaPLT12FromGOT,
+  RequestGOTAndTransformToDelta12FromGOT,
 
   /// A GOT entry getter/constructor, transformed to Delta32dbl pointing at
   /// the GOT entry for the original target.
@@ -473,44 +507,6 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   RequestGOTAndTransformToDelta32dbl,
 
-  /// A GOTPC entry getter/constructor, transformed to Delta32GOTBase
-  /// delta to GOT base.
-  ///
-  /// Indicates that this edge should be transformed into a Delta32GOTBase
-  /// targeting the GOTPC entry for the edge's current target, maintaining
-  /// the same addend. A GOTPC entry for the target should be created if
-  /// one does not already exist.
-  ///
-  /// Edges of this kind are usually handled by a GOTPC builder pass inserted
-  /// by default.
-  ///
-  /// Fixup expression:
-  ///   NONE
-  ///
-  /// Errors:
-  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///     phase will result in an assert/unreachable during the fixup phase.
-  RequestGOTPCAndTransformToDelta32GOTBase,
-
-  /// A GOTPC entry getter/constructor, transformed to Delta32dblGOTBase
-  /// delta to GOT base.
-  ///
-  /// Indicates that this edge should be transformed into a Delta32dblGOTBase
-  /// targeting the GOTPC entry for the edge's current target, maintaining
-  /// the same addend. A GOTPC entry for the target should be created if
-  /// one does not already exist.
-  ///
-  /// Edges of this kind are usually handled by a GOTPC builder pass inserted
-  /// by default.
-  ///
-  /// Fixup expression:
-  ///   NONE
-  ///
-  /// Errors:
-  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///     phase will result in an assert/unreachable during the fixup phase.
-  RequestGOTPCAndTransformToDelta32dblGOTBase,
-
   /// A 32-bit Delta to GOT base.
   ///
   /// Fixup expression:
@@ -701,13 +697,15 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value >> 1);
     break;
   }
-  case DeltaPLT64FromGOT: {
+  case Delta64PLTFromGOT:
+  case Delta64FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (S + A - GOTBase);
     write64be(FixupPtr, Value);
     break;
   }
-  case DeltaPLT32FromGOT: {
+  case Delta32PLTFromGOT:
+  case Delta32FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (S + A - GOTBase);
     if (!LLVM_UNLIKELY(isInt<32>(Value)))
@@ -715,7 +713,8 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write32be(FixupPtr, Value);
     break;
   }
-  case DeltaPLT16FromGOT: {
+  case Delta16PLTFromGOT:
+  case Delta16FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     int64_t Value = (S + A - GOTBase);
     if (!LLVM_UNLIKELY(isInt<16>(Value)))
@@ -723,7 +722,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     write16be(FixupPtr, Value);
     break;
   }
-  case DeltaPLT20FromGOT: {
+  case Delta20FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     uint64_t Value = S - GOTBase + A;
     if (!LLVM_UNLIKELY(isInt<20>(Value)))
@@ -732,7 +731,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
                             ((Value & 0xFFF) << 16) | ((Value & 0xFF000) >> 4));
     break;
   }
-  case DeltaPLT12FromGOT: {
+  case Delta12FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
     uint64_t Value = S - GOTBase + A;
     if (!LLVM_UNLIKELY(isUInt<12>(Value)))
@@ -819,20 +818,20 @@ class GOTTableManager : public TableManager<GOTTableManager> {
       return false;
     Edge::Kind KindToSet = Edge::Invalid;
     switch (E.getKind()) {
-    case systemz::RequestGOTAndTransformToDeltaPLT12FromGOT:
-      KindToSet = systemz::DeltaPLT12FromGOT;
+    case systemz::RequestGOTAndTransformToDelta12FromGOT:
+      KindToSet = systemz::Delta12FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDeltaPLT16FromGOT:
-      KindToSet = systemz::DeltaPLT16FromGOT;
+    case systemz::RequestGOTAndTransformToDelta16FromGOT:
+      KindToSet = systemz::Delta16FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDeltaPLT20FromGOT:
-      KindToSet = systemz::DeltaPLT20FromGOT;
+    case systemz::RequestGOTAndTransformToDelta20FromGOT:
+      KindToSet = systemz::Delta20FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDeltaPLT32FromGOT:
-      KindToSet = systemz::DeltaPLT32FromGOT;
+    case systemz::RequestGOTAndTransformToDelta32FromGOT:
+      KindToSet = systemz::Delta32FromGOT;
       break;
-    case systemz::RequestGOTAndTransformToDeltaPLT64FromGOT:
-      KindToSet = systemz::DeltaPLT64FromGOT;
+    case systemz::RequestGOTAndTransformToDelta64FromGOT:
+      KindToSet = systemz::Delta64FromGOT;
       break;
     case systemz::RequestGOTAndTransformToDelta32dbl:
       KindToSet = systemz::DeltaPLT32dbl;
@@ -885,9 +884,9 @@ class PLTTableManager : public TableManager<PLTTableManager> {
     case systemz::DeltaPLT16dbl:
     case systemz::DeltaPLT24dbl:
     case systemz::DeltaPLT32dbl:
-    case systemz::DeltaPLT16FromGOT:
-    case systemz::DeltaPLT32FromGOT:
-    case systemz::DeltaPLT64FromGOT:
+    case systemz::Delta16PLTFromGOT:
+    case systemz::Delta32PLTFromGOT:
+    case systemz::Delta64PLTFromGOT:
       break;
     default:
       return false;
@@ -918,53 +917,6 @@ class PLTTableManager : public TableManager<PLTTableManager> {
   Section *StubsSection = nullptr;
 };
 
-/// GOTPC Table Builder.
-class GOTPCTableManager : public TableManager<GOTPCTableManager> {
-public:
-  GOTPCTableManager(GOTTableManager &GOT) : GOT(GOT) {}
-
-  static StringRef getSectionName() { return "$__GOTPC"; }
-
-  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
-    Edge::Kind KindToSet = Edge::Invalid;
-    switch (E.getKind()) {
-    case systemz::RequestGOTPCAndTransformToDelta32GOTBase:
-      KindToSet = systemz::Delta32GOTBase;
-      break;
-    case systemz::RequestGOTPCAndTransformToDelta32dblGOTBase:
-      KindToSet = systemz::Delta32dblGOTBase;
-      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.setKind(KindToSet);
-    E.setTarget(getEntryForTarget(G, E.getTarget()));
-    return true;
-  }
-
-  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
-    return createAnonymousPointer(G, getGOTPCSection(G), &Target);
-  }
-
-private:
-  Section &getGOTPCSection(LinkGraph &G) {
-    if (!GOTPCSection)
-      GOTPCSection = &G.createSection(getSectionName(),
-                                      orc::MemProt::Read | orc::MemProt::Exec);
-    return *GOTPCSection;
-  }
-
-  GOTTableManager &GOT;
-  Section *GOTPCSection = nullptr;
-};
-
 } // namespace systemz
 } // namespace jitlink
 } // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 9ddba46e3b211..2ad2b6226d58f 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -32,8 +32,7 @@ Error buildTables_ELF_systemz(LinkGraph &G) {
   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
   systemz::GOTTableManager GOT;
   systemz::PLTTableManager PLT(GOT);
-  systemz::GOTPCTableManager GOTPC(GOT);
-  visitExistingEdges(G, GOT, PLT, GOTPC);
+  visitExistingEdges(G, GOT, PLT);
   return Error::success();
 }
 
@@ -265,66 +264,69 @@ class ELFLinkGraphBuilder_systemz
       break;
     }
     case ELF::R_390_PLTOFF64: {
-      Kind = systemz::DeltaPLT64FromGOT;
+      Kind = systemz::Delta64PLTFromGOT;
       break;
     }
     case ELF::R_390_PLTOFF32: {
-      Kind = systemz::DeltaPLT32FromGOT;
+      Kind = systemz::Delta32PLTFromGOT;
       break;
     }
     case ELF::R_390_PLTOFF16: {
-      Kind = systemz::DeltaPLT16FromGOT;
+      Kind = systemz::Delta16PLTFromGOT;
       break;
     }
-    // Relocations targeting the GOT entry associated with the symbol.
+    // Relocations targeting the actual symbol (just relative to the GOT).
     case ELF::R_390_GOTOFF64: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT64FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;
       break;
     }
     case ELF::R_390_GOTOFF: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT32FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;
       break;
     }
     case ELF::R_390_GOTOFF16: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT16FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;
       break;
     }
+    // Relocations targeting the GOT entry associated with the symbol.
     case ELF::R_390_GOT64:
     case ELF::R_390_GOTPLT64: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT64FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;
       break;
     }
     case ELF::R_390_GOT32:
     case ELF::R_390_GOTPLT32: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT32FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;
       break;
     }
     case ELF::R_390_GOT20:
     case ELF::R_390_GOTPLT20: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT20FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta20FromGOT;
       break;
     }
     case ELF::R_390_GOT16:
     case ELF::R_390_GOTPLT16: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT16FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;
       break;
     }
     case ELF::R_390_GOT12:
     case ELF::R_390_GOTPLT12: {
-      Kind = systemz::RequestGOTAndTransformToDeltaPLT12FromGOT;
+      Kind = systemz::RequestGOTAndTransformToDelta12FromGOT;
       break;
     }
-    case ELF::R_390_GOTPC: {
-      Kind = systemz::RequestGOTPCAndTransformToDelta32GOTBase;
+    case ELF::R_390_GOTENT:
+    case ELF::R_390_GOTPLTENT: {
+      Kind = systemz::RequestGOTAndTransformToDelta32dbl;
       break;
     }
-    case ELF::R_390_GOTPCDBL: {
-      Kind = systemz::RequestGOTPCAndTransformToDelta32dblGOTBase;
+    // R_390_GOTPC and R_390_GOTPCDBL don't create GOT entry, they don't even
+    // have symbol.
+    case ELF::R_390_GOTPC: {
+      Kind = systemz::Delta32GOTBase;
       break;
     }
-    case ELF::R_390_GOTENT:
-    case ELF::R_390_GOTPLTENT: {
-      Kind = systemz::RequestGOTAndTransformToDelta32dbl;
+    case ELF::R_390_GOTPCDBL: {
+      Kind = systemz::Delta32dblGOTBase;
       break;
     }
     default:
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index 7f6d18c04ca59..6cc6c79065d1d 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -64,12 +64,12 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "NegDelta64";
   case NegDelta32:
     return "NegDelta32";
-  case RequestGOTAndTransformToDeltaPLT64FromGOT:
-    return "RequestGOTAndTransformToDeltaPLT64FromGOT";
-  case RequestGOTAndTransformToDeltaPLT32FromGOT:
-    return "RequestGOTAndTransformToDeltaPLT32FromGOT";
-  case RequestGOTAndTransformToDeltaPLT16FromGOT:
-    return "RequestGOTAndTransformToDeltaPLT16FromGOT";
+  case RequestGOTAndTransformToDelta64FromGOT:
+    return "RequestGOTAndTransformToDelta64FromGOT";
+  case RequestGOTAndTransformToDelta32FromGOT:
+    return "RequestGOTAndTransformToDelta32FromGOT";
+  case RequestGOTAndTransformToDelta16FromGOT:
+    return "RequestGOTAndTransformToDelta16FromGOT";
   case DeltaPLT32dbl:
     return "DeltaPLT32dbl";
   case DeltaPLT24dbl:
@@ -84,20 +84,22 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "DeltaPLT64";
   case DeltaPLT32:
     return "DeltaPLT32";
-  case DeltaPLT64FromGOT:
-    return "DeltaPLT64FromGOT";
-  case DeltaPLT32FromGOT:
-    return "DeltaPLT32FromGOT";
-  case DeltaPLT16FromGOT:
-    return "DeltaPLT16FromGOT";
-  case RequestGOTAndTransformToDeltaPLT20FromGOT:
-    return "RequestGOTAndTransformToDeltaPLT20FromGOT";
-  case RequestGOTAndTransformToDeltaPLT12FromGOT:
-    return "RequestGOTAndTransformToDeltaPLT12FromGOT";
-  case RequestGOTPCAndTransformToDelta32GOTBase:
-    return "RequestGOTPCAndTransformToDelta32GOTBase";
-  case RequestGOTPCAndTransformToDelta32dblGOTBase:
-    return "RequestGOTPCAndTransformToDelta32dblGOTBase";
+  case Delta64FromGOT:
+    return "Delta64FromGOT";
+  case Delta32FromGOT:
+    return "Delta32FromGOT";
+  case Delta16FromGOT:
+    return "Delta16FromGOT";
+  case Delta64PLTFromGOT:
+    return "Delta64PLTFromGOT";
+  case Delta32PLTFromGOT:
+    return "Delta32PLTFromGOT";
+  case Delta16PLTFromGOT:
+    return "Delta16PLTFromGOT";
+  case RequestGOTAndTransformToDelta20FromGOT:
+    return "RequestGOTAndTransformToDelta20FromGOT";
+  case RequestGOTAndTransformToDelta12FromGOT:
+    return "RequestGOTAndTransformToDelta12FromGOT";
   case Delta32GOTBase:
     return "Delta32GOTBase";
   case Delta32dblGOTBase:

>From 5c118d31e2de0ece9f983dfe73b97dcf34f96632 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Fri, 7 Nov 2025 01:45:20 +0100
Subject: [PATCH 09/10] Incorporate code review feedback

---
 .../llvm/ExecutionEngine/JITLink/systemz.h    | 128 +++++++++---------
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   |   6 +-
 .../JITLink/systemz/ELF_systemz_got.s         |  78 -----------
 .../systemz/ELF_systemz_reloc_call_pic.s      |  14 +-
 .../systemz/ELF_systemz_reloc_gotrel.s        |  16 +--
 .../JITLink/systemz/ELF_systemz_reloc_pc16.s  |   1 +
 .../JITLink/systemz/ELF_systemz_reloc_pc32.s  |   1 +
 7 files changed, 84 insertions(+), 160 deletions(-)
 delete mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index 1ef5f693d87d8..a55a821a5226f 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -203,63 +203,6 @@ enum EdgeKind_systemz : Edge::Kind {
   ///     an out-of-range error will be returned.
   NegDelta32,
 
-  /// A GOT entry getter/constructor, transformed to Delta64FromGOT pointing
-  /// at the GOT entry for the original target.
-  ///
-  /// Indicates that this edge should be transformed into a Delta64FromGOT
-  /// targeting the GOT entry for the edge's current target, maintaining the
-  /// same addend. A GOT entry for the target should be created if one does
-  /// not already exist.
-  ///
-  /// Edges of this kind are usually handled by a GOT builder pass inserted by
-  /// default.
-  ///
-  /// Fixup expression:
-  ///   NONE
-  ///
-  /// Errors:
-  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///
-  RequestGOTAndTransformToDelta64FromGOT,
-
-  /// A GOT entry getter/constructor, transformed to Delta32FromGOT pointing
-  /// at the GOT entry for the original target.
-  ///
-  /// Indicates that this edge should be transformed into a Delta32FromGOT
-  /// targeting the GOT entry for the edge's current target, maintaining the
-  /// same addend. A GOT entry for the target should be created if one does
-  /// not already exist.
-  ///
-  /// Edges of this kind are usually handled by a GOT builder pass inserted by
-  /// default.
-  ///
-  /// Fixup expression:
-  ///   NONE
-  ///
-  /// Errors:
-  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///
-  RequestGOTAndTransformToDelta32FromGOT,
-
-  /// A GOT entry getter/constructor, transformed to Delta16FromGOT pointing
-  /// at the GOT entry for the original target.
-  ///
-  /// Indicates that this edge should be transformed into a Delta16FromGOT
-  /// targeting the GOT entry for the edge's current target, maintaining the
-  /// same addend. A GOT entry for the target should be created if one does
-  /// not already exist.
-  ///
-  /// Edges of this kind are usually handled by a GOT builder pass inserted by
-  /// default.
-  ///
-  /// Fixup expression:
-  ///   NONE
-  ///
-  /// Errors:
-  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
-  ///
-  RequestGOTAndTransformToDelta16FromGOT,
-
   /// A 32-bit Delta shifted by 1.
   ///
   /// Delta from the fixup to the PLT slot for the target. This will lead to
@@ -448,6 +391,44 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   Delta12FromGOT,
 
+  /// A GOT entry getter/constructor, transformed to Delta64FromGOT pointing
+  /// at the GOT entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta64FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///
+  RequestGOTAndTransformToDelta64FromGOT,
+
+  /// A GOT entry getter/constructor, transformed to Delta32FromGOT pointing
+  /// at the GOT entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta32FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///
+  RequestGOTAndTransformToDelta32FromGOT,
+
   /// A GOT entry getter/constructor, transformed to Delta20FromGOT pointing
   /// at the GOT entry for the original target.
   ///
@@ -467,6 +448,25 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   RequestGOTAndTransformToDelta20FromGOT,
 
+  /// A GOT entry getter/constructor, transformed to Delta16FromGOT pointing
+  /// at the GOT entry for the original target.
+  ///
+  /// Indicates that this edge should be transformed into a Delta16FromGOT
+  /// targeting the GOT entry for the edge's current target, maintaining the
+  /// same addend. A GOT entry for the target should be created if one does
+  /// not already exist.
+  ///
+  /// Edges of this kind are usually handled by a GOT builder pass inserted by
+  /// default.
+  ///
+  /// Fixup expression:
+  ///   NONE
+  ///
+  /// Errors:
+  ///   - *ASSERTION* Failure to handle edges of this kind prior to the fixup
+  ///
+  RequestGOTAndTransformToDelta16FromGOT,
+
   /// A GOT entry getter/constructor, transformed to Delta12FromGOT pointing
   /// at the GOT entry for the original target.
   ///
@@ -638,7 +638,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   }
   case Delta32dbl:
   case DeltaPLT32dbl: {
-    int64_t Value = (S + A - P);
+    int64_t Value = S + A - P;
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
@@ -648,7 +648,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   }
   case Delta24dbl:
   case DeltaPLT24dbl: {
-    int64_t Value = (S + A - P);
+    int64_t Value = S + A - P;
     if (!LLVM_UNLIKELY(isInt<25>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
@@ -660,7 +660,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   }
   case Delta16dbl:
   case DeltaPLT16dbl: {
-    int64_t Value = (S + A - P);
+    int64_t Value = S + A - P;
     if (!LLVM_UNLIKELY(isInt<17>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
@@ -670,7 +670,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   }
   case Delta12dbl:
   case DeltaPLT12dbl: {
-    int64_t Value = (S + A - P);
+    int64_t Value = S + A - P;
     if (!LLVM_UNLIKELY(isInt<13>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     if (!LLVM_UNLIKELY(isAlignmentCorrect(Value, 2)))
@@ -700,14 +700,14 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   case Delta64PLTFromGOT:
   case Delta64FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = (S + A - GOTBase);
+    int64_t Value = S + A - GOTBase;
     write64be(FixupPtr, Value);
     break;
   }
   case Delta32PLTFromGOT:
   case Delta32FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = (S + A - GOTBase);
+    int64_t Value = S + A - GOTBase;
     if (!LLVM_UNLIKELY(isInt<32>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     write32be(FixupPtr, Value);
@@ -716,7 +716,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
   case Delta16PLTFromGOT:
   case Delta16FromGOT: {
     assert(GOTSymbol && "No GOT section symbol");
-    int64_t Value = (S + A - GOTBase);
+    int64_t Value = S + A - GOTBase;
     if (!LLVM_UNLIKELY(isInt<16>(Value)))
       return makeTargetOutOfRangeError(G, B, E);
     write16be(FixupPtr, Value);
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 2ad2b6226d58f..29eeecceea766 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -277,15 +277,15 @@ class ELFLinkGraphBuilder_systemz
     }
     // Relocations targeting the actual symbol (just relative to the GOT).
     case ELF::R_390_GOTOFF64: {
-      Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;
+      Kind = systemz::Delta64FromGOT;
       break;
     }
     case ELF::R_390_GOTOFF: {
-      Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;
+      Kind = systemz::Delta32FromGOT;
       break;
     }
     case ELF::R_390_GOTOFF16: {
-      Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;
+      Kind = systemz::Delta16FromGOT;
       break;
     }
     // Relocations targeting the GOT entry associated with the symbol.
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s
deleted file mode 100644
index 00b111d5d59f1..0000000000000
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_got.s
+++ /dev/null
@@ -1,78 +0,0 @@
-# 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_call_pic.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
index 2b4c3d2102231..25a48e00e4413 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
@@ -26,9 +26,9 @@ 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).
+# Check R_390_PC32DBL handling with a call to a local function in the text
+# section. This produces a Delta32dbl edge that is resolved like a regular
+# direct relative branches(no PLT entry created).
 #
 # jitlink-check: decode_operand(test_call_local, 1) = \
 # jitlink-check:   named_func - test_call_local
@@ -40,8 +40,8 @@ test_call_local:
 
         .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 
+# Check R_390_PLT32dbl(DeltaPLT32dbl)  handling with a call to an 
+# external via PLT. This produces a Delta32dbl edge, because externals are 
 # not defined locally. As the target is out-of-range from the callsite, 
 # the edge keeps using its PLT entry.
 #
@@ -58,8 +58,8 @@ test_call_extern_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 
+# Check R_390_PLT32(DeltaPLT32dbl) handling with a call to an external. 
+# This produces a Delta32dbl 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
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s
index bb1220d3780bb..af37b3f75ca42 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_gotrel.s
@@ -18,8 +18,7 @@ main:
 
 	.data
 	.globl test_gotoff16_bar
-# jitlink-check: *{2}test_gotoff16_bar =  \
-# jitlink-check:      (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+# jitlink-check: *{2}test_gotoff16_bar = (bar - _GLOBAL_OFFSET_TABLE_) & 0xffff
 test_gotoff16_bar:
 	.reloc ., R_390_GOTOFF16, bar
 	.space 2
@@ -27,7 +26,8 @@ test_gotoff16_bar:
 
        .globl test_pltoff16_foo
 # jitlink-check: *{2}test_pltoff16_foo =  \
-# jitlink-check:      (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+# jitlink-check:      (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_) \
+# jitlink-check:       & 0xffff
 test_pltoff16_foo:
         .reloc ., R_390_PLTOFF16, foo 
         .space 2
@@ -35,8 +35,8 @@ test_pltoff16_foo:
 
 
        .globl test_gotoff32_bar
-# jitlink-check: *{4}test_gotoff32_bar =  \
-# jitlink-check:      (got_addr(elf_reloc.o, bar) - _GLOBAL_OFFSET_TABLE_)
+# jitlink-check: *{4}test_gotoff32_bar = (bar - _GLOBAL_OFFSET_TABLE_) \
+# jitlink-check:       & 0xffffffff
 test_gotoff32_bar:
         .reloc ., R_390_GOTOFF, bar
         .space 4 
@@ -44,15 +44,15 @@ test_gotoff32_bar:
 
         .globl test_pltoff32_foo
 # jitlink-check: *{4}test_pltoff32_foo = \
-# jitlink-check:      (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_)
+# jitlink-check:      (stub_addr(elf_reloc.o, foo) - _GLOBAL_OFFSET_TABLE_) \
+# jitlink-check:       & 0xffffffff
 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_)
+# jitlink-check: *{8}test_gotoff64_bar = bar - _GLOBAL_OFFSET_TABLE_
 test_gotoff64_bar:
         .reloc ., R_390_GOTOFF64, bar
         .space 8 
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s
index 47a7262902fd9..0da54b2a58972 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc16.s
@@ -14,6 +14,7 @@
 # RUN:   FileCheck -check-prefix=CHECK-ERROR %s
 #
 # jitlink-check: *{2}test_pc16 = OFFSET
+# jitlink-check: *{2}test_pc16dbl = OFFSET
 
 # CHECK-ERROR:  {{.*}} is out of range of Delta16 fixup
 
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s
index cda90dbe5a316..503fd2d0a5d49 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_pc32.s
@@ -14,6 +14,7 @@
 # RUN:   FileCheck -check-prefix=CHECK-ERROR %s
 #
 # jitlink-check: *{4}test_pc32 = OFFSET
+# jitlink-check: *{4}test_pc32dbl = OFFSET
 
 # CHECK-ERROR:  {{.*}} is out of range of Delta32 fixup
 

>From dde6b1f78954e7721396791f5dbeeda40e1b42c2 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Fri, 7 Nov 2025 17:26:32 +0100
Subject: [PATCH 10/10] Minor cleanup

---
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp | 24 ++++++++++----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index 6cc6c79065d1d..e217729b1c7aa 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -64,12 +64,6 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "NegDelta64";
   case NegDelta32:
     return "NegDelta32";
-  case RequestGOTAndTransformToDelta64FromGOT:
-    return "RequestGOTAndTransformToDelta64FromGOT";
-  case RequestGOTAndTransformToDelta32FromGOT:
-    return "RequestGOTAndTransformToDelta32FromGOT";
-  case RequestGOTAndTransformToDelta16FromGOT:
-    return "RequestGOTAndTransformToDelta16FromGOT";
   case DeltaPLT32dbl:
     return "DeltaPLT32dbl";
   case DeltaPLT24dbl:
@@ -78,8 +72,6 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "DeltaPLT16dbl";
   case DeltaPLT12dbl:
     return "DeltaPLT12dbl";
-  case RequestGOTAndTransformToDelta32dbl:
-    return "RequestGOTAndTransformToDelta32dbl";
   case DeltaPLT64:
     return "DeltaPLT64";
   case DeltaPLT32:
@@ -96,14 +88,22 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "Delta32PLTFromGOT";
   case Delta16PLTFromGOT:
     return "Delta16PLTFromGOT";
-  case RequestGOTAndTransformToDelta20FromGOT:
-    return "RequestGOTAndTransformToDelta20FromGOT";
-  case RequestGOTAndTransformToDelta12FromGOT:
-    return "RequestGOTAndTransformToDelta12FromGOT";
   case Delta32GOTBase:
     return "Delta32GOTBase";
   case Delta32dblGOTBase:
     return "Delta32dblGOTBase";
+  case RequestGOTAndTransformToDelta64FromGOT:
+    return "RequestGOTAndTransformToDelta64FromGOT";
+  case RequestGOTAndTransformToDelta32FromGOT:
+    return "RequestGOTAndTransformToDelta32FromGOT";
+  case RequestGOTAndTransformToDelta20FromGOT:
+    return "RequestGOTAndTransformToDelta20FromGOT";
+  case RequestGOTAndTransformToDelta16FromGOT:
+    return "RequestGOTAndTransformToDelta16FromGOT";
+  case RequestGOTAndTransformToDelta12FromGOT:
+    return "RequestGOTAndTransformToDelta12FromGOT";
+  case RequestGOTAndTransformToDelta32dbl:
+    return "RequestGOTAndTransformToDelta32dbl";
   default:
     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
   }



More information about the llvm-commits mailing list