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

Ulrich Weigand via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 4 00:46:20 PST 2025


================
@@ -0,0 +1,938 @@
+//=== 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.
+  RequestGOTAndTransformToDelta64FromGOT,
+
+  /// 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.
+  RequestGOTAndTransformToDelta32FromGOT,
+
+  /// 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.
+  RequestGOTAndTransformToDelta16FromGOT,
+
+  /// A 32-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 : 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.
+  ///
+  DeltaPLT32dbl,
+
+  /// 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
+  ///
+  /// 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.
+  ///
+  DeltaPLT24dbl,
+
+  /// 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
+  ///
+  /// 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.
+  ///
+  DeltaPLT16dbl,
+
+  /// 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
+  ///
+  /// 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.
+  ///
+  DeltaPLT12dbl,
+
+  /// 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 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
+  ///
+  /// Errors:
+  ///   - The result of the fixup expression must fit into an int32, otherwise
+  ///     an out-of-range error will be returned.
+  ///
+  DeltaPLT32,
+
+  /// 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
+  ///
+  /// 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 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:
+  ///   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 12-bit offset from GOT to PLT.
+  ///
+  /// 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 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 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.
+  ///
+  RequestGOTAndTransformToDelta32,
+
+  /// 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:
+  ///   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.
+  ///
+  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,
+
+  /// 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:
+  ///   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.
+  ///
+  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:
+  ///   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.
+  ///
+  Delta32GOTBase,
+
+  /// 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.
+  ///
+  Delta32dblGOTBase,
+
+};
+
+/// 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);
+    write32be(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);
+    write16be(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:
+  case DeltaPLT64: {
+    int64_t Value = S + A - P;
+    write64be(FixupPtr, Value);
+    break;
+  }
+  case Delta32:
+  case DeltaPLT32: {
+    int64_t Value = S + A - P;
+    if (!LLVM_UNLIKELY(isInt<32>(Value)))
+      return makeTargetOutOfRangeError(G, B, E);
+    write32be(FixupPtr, Value);
+    break;
+  }
+  case Delta16: {
+    int64_t Value = S + A - P;
+    if (!LLVM_UNLIKELY(isInt<16>(Value)))
+      return makeTargetOutOfRangeError(G, B, E);
+    write16be(FixupPtr, Value);
+    break;
+  }
+  case NegDelta32: {
+    int64_t Value = P + A - S;
+    if (!LLVM_UNLIKELY(isInt<32>(Value)))
+      return makeTargetOutOfRangeError(G, B, E);
+    write32be(FixupPtr, Value);
+    break;
+  }
+  case Delta32dbl:
+  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 Delta24dbl:
+  case DeltaPLT24dbl: {
+    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:
+  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 Delta12dbl:
+  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 Delta32GOTBase: {
+    assert(GOTSymbol && "No GOT section symbol");
+    int64_t Value = GOTBase + A - P;
+    if (!LLVM_UNLIKELY(isInt<32>(Value)))
+      return makeTargetOutOfRangeError(G, B, E);
+    write32be(FixupPtr, Value);
+    break;
+  }
+  case Delta32dblGOTBase: {
+    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 DeltaPLT64FromGOT: {
+    assert(GOTSymbol && "No GOT section symbol");
+    int64_t Value = (S + A - GOTBase);
+    write64be(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);
+    write32be(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);
+    write16be(FixupPtr, Value);
+    break;
+  }
+  case DeltaPLT20FromGOT: {
+    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 DeltaPLT12FromGOT: {
+    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;
+  }
+  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:
+///   lgrl %r1, ptr
+///   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(Delta32dbl, 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::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::RequestGOTAndTransformToDelta32FromGOT:
+      KindToSet = systemz::DeltaPLT32FromGOT;
+      break;
+    case systemz::RequestGOTAndTransformToDelta64:
+    case systemz::RequestGOTAndTransformToDelta64FromGOT:
+      KindToSet = systemz::DeltaPLT64FromGOT;
+      break;
+    case systemz::RequestGOTAndTransformToDelta32dbl:
+      KindToSet = systemz::DeltaPLT32dbl;
+      break;
+    case systemz::Delta32GOTBase:
+    case systemz::Delta32dblGOTBase:
----------------
uweigand wrote:

These two don't need to transformed.  They really shouldn't be here at all ...

https://github.com/llvm/llvm-project/pull/144528


More information about the llvm-commits mailing list