[llvm] [JITLink] [GOFF] Initial support for GOFF (PR #224683)
Shimin Cui via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 06:47:36 PDT 2026
https://github.com/scui-ibm updated https://github.com/llvm/llvm-project/pull/224683
>From d4aac71d4a97dde2054f6989f6eeae684633bce5 Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Fri, 18 Sep 2026 16:32:03 +0000
Subject: [PATCH 1/3] [JITLink] [GOFF] Initial support for GOFF
---
.../llvm/ExecutionEngine/JITLink/GOFF.h | 37 +++
.../ExecutionEngine/JITLink/GOFF_systemz.h | 37 +++
.../llvm/ExecutionEngine/JITLink/systemz.h | 65 +++++
llvm/include/llvm/Object/GOFFObjectFile.h | 3 +
.../ExecutionEngine/JITLink/CMakeLists.txt | 5 +
llvm/lib/ExecutionEngine/JITLink/GOFF.cpp | 36 +++
.../JITLink/GOFFLinkGraphBuilder.cpp | 274 ++++++++++++++++++
.../JITLink/GOFFLinkGraphBuilder.h | 67 +++++
.../ExecutionEngine/JITLink/GOFF_systemz.cpp | 100 +++++++
llvm/lib/ExecutionEngine/JITLink/JITLink.cpp | 5 +
llvm/lib/ExecutionEngine/JITLink/systemz.cpp | 8 +
.../ExecutionEngine/Orc/LoadLinkableFile.cpp | 16 +
.../Orc/ObjectFileInterface.cpp | 44 +++
llvm/lib/Object/GOFFObjectFile.cpp | 48 +++
.../JITLink/systemz/GOFF_systemz_reloc_ptr.ll | 15 +
15 files changed, 760 insertions(+)
create mode 100644 llvm/include/llvm/ExecutionEngine/JITLink/GOFF.h
create mode 100644 llvm/include/llvm/ExecutionEngine/JITLink/GOFF_systemz.h
create mode 100644 llvm/lib/ExecutionEngine/JITLink/GOFF.cpp
create mode 100644 llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp
create mode 100644 llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h
create mode 100644 llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
create mode 100644 llvm/test/ExecutionEngine/JITLink/systemz/GOFF_systemz_reloc_ptr.ll
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/GOFF.h b/llvm/include/llvm/ExecutionEngine/JITLink/GOFF.h
new file mode 100644
index 0000000000000..3d554357b5c97
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/GOFF.h
@@ -0,0 +1,37 @@
+//===------- GOFF.h - Generic JIT link function for GOFF ------*- 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 GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_GOFF_H
+#define LLVM_EXECUTIONENGINE_JITLINK_GOFF_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+
+namespace llvm {
+namespace jitlink {
+
+/// Create a LinkGraph from an GOFF 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.
+LLVM_ABI Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromGOFFObject(MemoryBufferRef ObjectBuffer,
+ std::shared_ptr<orc::SymbolStringPool> SSP);
+
+/// Link the given graph.
+LLVM_ABI void link_GOFF(std::unique_ptr<LinkGraph> G,
+ std::unique_ptr<JITLinkContext> Ctx);
+
+} // namespace jitlink
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_GOFF_H
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/GOFF_systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/GOFF_systemz.h
new file mode 100644
index 0000000000000..eda4b049eb5c0
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/GOFF_systemz.h
@@ -0,0 +1,37 @@
+//===--- GOFF_systemz.h - JIT link functions for GOFF/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 GOFF/systemz.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_GOFF_SYSTEMZ_H
+#define LLVM_EXECUTIONENGINE_JITLINK_GOFF_SYSTEMZ_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+
+namespace llvm::jitlink {
+
+/// Create a LinkGraph from an GOFF/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.
+///
+LLVM_ABI Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromGOFFObject_systemz(
+ MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP);
+
+/// jit-link the given object buffer, which must be a GOFF systemz object file.
+///
+LLVM_ABI void link_GOFF_systemz(std::unique_ptr<LinkGraph> G,
+ std::unique_ptr<JITLinkContext> Ctx);
+
+} // namespace llvm::jitlink
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_GOFF_SYSTEMZ_H
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index efc1bda8edda6..82361c1d83962 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -87,6 +87,14 @@ enum EdgeKind_systemz : Edge::Kind {
///
Pointer8,
+ /// GOFF: Absolute add (field += value) for length 64 and 32.
+ Pointer64Add,
+ Pointer32Add,
+
+ /// GOFF: Absolute subtract (field -= value) for length 64 and 32.
+ Pointer64Sub,
+ Pointer32Sub,
+
/// A 64-bit delta.
///
/// Delta from the fixup to the target.
@@ -935,6 +943,63 @@ class PLTTableManager : public TableManager<PLTTableManager> {
/// replace a indirect jump by plt stub with a direct jump to the target.
LLVM_ABI Error optimizeGOTAndStubAccesses(LinkGraph &G);
+/// Apply fixup expression for edge to block content for GOFF.
+inline Error applyGOFFFixup(LinkGraph &G, Block &B, const Edge &E) {
+ using namespace support;
+
+ char *BlockWorkingMem = B.getAlreadyMutableContent().data();
+ char *FixupPtr = BlockWorkingMem + E.getOffset();
+ int64_t S = E.getTarget().getAddress().getValue();
+ int64_t A = E.getAddend();
+ assert(A == 0 && "Edge addend should be 0");
+
+ int64_t Value = S;
+ orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
+ int64_t P = FixupAddress.getValue();
+ Edge::Kind K = E.getKind();
+
+ DEBUG_WITH_TYPE("jitlink", {
+ dbgs() << " Applying fixup on " << G.getEdgeKindName(K)
+ << " edge, (S, P) = (" << formatv("{0:x}", S) << ", "
+ << formatv("{0:x}", P) << ")\n";
+ });
+
+ auto apply = [&](auto write, auto read, auto op) {
+ auto Current = read(FixupPtr);
+ DEBUG_WITH_TYPE("jitlink", {
+ dbgs() << " Addend = " << formatv("{0:x}", Current) << "\n";
+ });
+ write(FixupPtr, static_cast<decltype(Current)>(op(Current, Value)));
+ };
+
+ switch (K) {
+ case Pointer64:
+ write64be(FixupPtr, Value);
+ break;
+ case Pointer32:
+ write32be(FixupPtr, Value);
+ break;
+ case Pointer64Add:
+ apply(write64be, read64be, std::plus<uint64_t>{});
+ break;
+ case Pointer32Add:
+ apply(write32be, read32be, std::plus<uint32_t>{});
+ break;
+ case Pointer64Sub:
+ apply(write64be, read64be, std::minus<uint64_t>{});
+ break;
+ case Pointer32Sub:
+ apply(write32be, read32be, std::minus<uint32_t>{});
+ break;
+ default:
+ return make_error<JITLinkError>(
+ "In graph " + G.getName() + ", section " + B.getSection().getName() +
+ " unsupported edge kind " + getEdgeKindName(E.getKind()));
+ }
+
+ return Error::success();
+}
+
} // namespace systemz
} // namespace jitlink
} // namespace llvm
diff --git a/llvm/include/llvm/Object/GOFFObjectFile.h b/llvm/include/llvm/Object/GOFFObjectFile.h
index 080d18fc23bef..3d6a0da34c86b 100644
--- a/llvm/include/llvm/Object/GOFFObjectFile.h
+++ b/llvm/include/llvm/Object/GOFFObjectFile.h
@@ -139,6 +139,8 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
bool isSectionNoLoad(DataRefImpl Sec) const;
bool isSectionReadOnlyData(DataRefImpl Sec) const;
bool isSectionZeroInit(DataRefImpl Sec) const;
+ Error getSectionUniqueName(DataRefImpl Sec,
+ SmallVectorImpl<char> &Result) const;
private:
// SymbolRef.
@@ -154,6 +156,7 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
const uint8_t *getSymbolEsdRecord(DataRefImpl Symb) const;
bool isSymbolUnresolved(DataRefImpl Symb) const;
bool isSymbolIndirect(DataRefImpl Symb) const;
+ Expected<StringRef> getSymbolName(uint32_t SymIndex) const;
// SectionRef.
void moveSectionNext(DataRefImpl &Sec) const override;
diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
index c1456321327ef..329d19a341353 100644
--- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
@@ -43,6 +43,11 @@ add_llvm_component_library(LLVMJITLink
XCOFF_ppc64.cpp
XCOFFLinkGraphBuilder.cpp
+ # GOFF
+ GOFF.cpp
+ GOFF_systemz.cpp
+ GOFFLinkGraphBuilder.cpp
+
# Architectures:
aarch32.cpp
aarch64.cpp
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFF.cpp b/llvm/lib/ExecutionEngine/JITLink/GOFF.cpp
new file mode 100644
index 0000000000000..36f60b6de3f24
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFF.cpp
@@ -0,0 +1,36 @@
+//===--------------- GOFF.cpp - JIT linker function for GOFF --------------===//
+//
+// 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 GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/GOFF.h"
+#include "llvm/ExecutionEngine/JITLink/GOFF_systemz.h"
+#include "llvm/Object/GOFFObjectFile.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "jitlink"
+
+namespace llvm {
+namespace jitlink {
+
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromGOFFObject(MemoryBufferRef ObjectBuffer,
+ std::shared_ptr<orc::SymbolStringPool> SSP) {
+ return createLinkGraphFromGOFFObject_systemz(ObjectBuffer, std::move(SSP));
+}
+
+void link_GOFF(std::unique_ptr<LinkGraph> G,
+ std::unique_ptr<JITLinkContext> Ctx) {
+ link_GOFF_systemz(std::move(G), std::move(Ctx));
+}
+
+} // namespace jitlink
+} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp
new file mode 100644
index 0000000000000..79146891825c5
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp
@@ -0,0 +1,274 @@
+//===--- GOFFLinkGraphBuilder.cpp - GOFF LinkGraph Builder ----------------===//
+//
+// 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 GOFF LinkGraph building code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GOFFLinkGraphBuilder.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/ExecutionEngine/JITLink/GOFF_systemz.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITLink/systemz.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
+#include "llvm/Object/GOFFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::jitlink;
+using namespace llvm::object;
+
+#define DEBUG_TYPE "jitlink"
+
+namespace llvm {
+namespace jitlink {
+
+GOFFLinkGraphBuilder::GOFFLinkGraphBuilder(
+ const object::GOFFObjectFile &Obj,
+ std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
+ SubtargetFeatures Features,
+ LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
+ : Obj(Obj),
+ G(std::make_unique<LinkGraph>(
+ std::string(Obj.getFileName()), std::move(SSP), std::move(TT),
+ std::move(Features), std::move(GetEdgeKindName))) {}
+
+Expected<std::unique_ptr<LinkGraph>> GOFFLinkGraphBuilder::buildGraph() {
+ LLVM_DEBUG(dbgs() << "Building GOFFLinkGraph...\n");
+
+ // Check to make sure the object is relocatable.
+ if (!Obj.isRelocatableObject())
+ return make_error<JITLinkError>("Object is not a relocatable COFF file");
+
+ if (auto Err = processSections())
+ return std::move(Err);
+ if (auto Err = processSymbols())
+ return std::move(Err);
+ if (auto Err = processRelocations())
+ return std::move(Err);
+
+ return std::move(G);
+}
+
+Error GOFFLinkGraphBuilder::processSections() {
+ LLVM_DEBUG(dbgs() << "Processing GOFF sections ...\n");
+
+ for (const object::SectionRef Sec : Obj.sections()) {
+ Expected<StringRef> NameOrErr = Sec.getName();
+ if (!NameOrErr) {
+ return NameOrErr.takeError();
+ }
+
+ // Skip empty sections.
+ if (Sec.getSize() == 0)
+ return Error::success();
+
+ StringRef SectionName = *NameOrErr;
+ DataRefImpl SecRawDataRef = Sec.getRawDataRefImpl();
+ SmallString<16> UniqSectionName;
+ if (Error Err = Obj.getSectionUniqueName(SecRawDataRef, UniqSectionName)) {
+ return Err;
+ }
+
+ LLVM_DEBUG({
+ dbgs() << " section = " << SectionName
+ << ", uniq = " << UniqSectionName << ", idx = " << Sec.getIndex()
+ << ", size = " << format_hex_no_prefix(Sec.getSize(), 8)
+ << ", vma = " << format_hex(Sec.getAddress(), 16) << "\n";
+ });
+
+ // Skip debug sections.
+ if (Sec.isDebugSection())
+ continue;
+
+ // Get memory protection flags.
+ orc::MemProt Prot = orc::MemProt::Read;
+ if (Sec.isText())
+ Prot |= orc::MemProt::Exec;
+ else if (Sec.isData())
+ Prot |= orc::MemProt::Write;
+
+ // Get or create the section in the graph.
+ auto *GraphSec = G->findSectionByName(UniqSectionName);
+ assert(!GraphSec && "Should be named unique");
+ GraphSec = &G->createSection(UniqSectionName, Prot);
+
+ if (GraphSec->getMemProt() != Prot)
+ return make_error<JITLinkError>("MemProt should match");
+
+ uint32_t SecIndex = Sec.getIndex();
+ if (SectionMap.contains(SecIndex))
+ return make_error<JITLinkError>("Index already exists");
+
+ Expected<StringRef> ContentsOrErr = Sec.getContents();
+ if (!ContentsOrErr) {
+ return ContentsOrErr.takeError();
+ }
+
+ // Create the content block in the graph.
+ StringRef Contents = *ContentsOrErr;
+ uint64_t SecAddress = Sec.getAddress();
+ Block *B = &G->createContentBlock(*GraphSec, Contents,
+ orc::ExecutorAddr(SecAddress),
+ Sec.getAlignment().value(), 0);
+ SectionMap[SecIndex] = {GraphSec, B, Sec};
+ }
+
+ return Error::success();
+}
+
+Error GOFFLinkGraphBuilder::processSymbols() {
+ LLVM_DEBUG(dbgs() << "Processing GOFF symbols...\n");
+
+ for (object::GOFFSymbolRef Sym : Obj.symbols()) {
+ Expected<StringRef> NameOrErr = Sym.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ StringRef Name = *NameOrErr;
+ uint32_t SymEsdId = Sym.getRawDataRefImpl().d.a;
+ LLVM_DEBUG(dbgs() << " Processing symbol [" << SymEsdId << "] " << Name
+ << "\n");
+
+ Expected<uint32_t> SymFlagsOrErr = Sym.getSymbolGOFFFlags();
+ if (!SymFlagsOrErr)
+ return SymFlagsOrErr.takeError();
+
+ uint32_t Flags = *SymFlagsOrErr;
+ if (Flags & object::SymbolRef::SF_Undefined) {
+ LLVM_DEBUG(dbgs() << " created external symbol\n");
+ SymbolMap[SymEsdId] = &G->addExternalSymbol(
+ Name, Sym.getSize(), Flags & object::SymbolRef::SF_Weak);
+ continue;
+ }
+
+ auto SymbolTypeOrErr = Sym.getSymbolGOFFType();
+ if (!SymbolTypeOrErr)
+ return SymbolTypeOrErr.takeError();
+
+ Expected<section_iterator> SectionOrErr = Sym.getSection();
+ if (!SectionOrErr)
+ return SectionOrErr.takeError();
+
+ section_iterator SI = *SectionOrErr;
+ if (SI == Obj.section_end())
+ return make_error<JITLinkError>("Symbol section not found");
+
+ Expected<uint64_t> OffsetOrErr = Sym.getAddress();
+ if (!OffsetOrErr)
+ return OffsetOrErr.takeError();
+
+ uint32_t SecIndex = SI->getIndex();
+ Block *B = SectionMap[SecIndex].Block;
+ uint64_t Offset = *OffsetOrErr;
+ Linkage L =
+ (Flags & object::SymbolRef::SF_Weak) ? Linkage::Weak : Linkage::Strong;
+ Scope S{Scope::Local};
+ if (Flags & object::SymbolRef::SF_Hidden)
+ S = Scope::Hidden;
+ else if (Flags & object::SymbolRef::SF_Global)
+ S = Scope::Default;
+ SymbolRef::Type SymbolType = *SymbolTypeOrErr;
+ bool IsCallable = (SymbolType == object::SymbolRef::ST_Function);
+
+ LLVM_DEBUG(dbgs() << " creating with linkage = " << getLinkageName(L)
+ << ", scope = " << getScopeName(S)
+ << ", B = " << format_hex(B->getAddress().getValue(), 16)
+ << (IsCallable ? " function" : " non-callable") << "\n");
+
+ SymbolMap[SymEsdId] = &G->addDefinedSymbol(*B, Offset, Name, Sym.getSize(),
+ L, S, IsCallable, true);
+ }
+
+ return Error::success();
+}
+
+static systemz::EdgeKind_systemz getRelEdgeKind(uint64_t RelType) {
+ GOFF::RLDReferenceType RldRefType = getRLDReferenceType(RelType);
+ GOFF::RLDAction RldAct = getRLDAction(RelType);
+ GOFF::RLDFetchStore RldFetch = getRLDFetchStore(RelType);
+ uint8_t RldLength = getRLDTargetLength(RelType);
+ uint8_t RldBitLength = getRLDBitLength(RelType);
+ uint8_t RldBitWidth = 8 * RldLength + RldBitLength;
+
+ switch (RldRefType) {
+ case GOFF::RLD_RT_RAddress:
+ switch (RldBitWidth) {
+ case 64:
+ if (RldFetch == GOFF::RLD_FS_Fetch)
+ return (RldAct == GOFF::RLD_ACT_Add ? systemz::Pointer64Add
+ : systemz::Pointer64Sub);
+ else
+ return systemz::Pointer64;
+ break;
+ case 32:
+ if (RldFetch == GOFF::RLD_FS_Fetch)
+ return (RldAct == GOFF::RLD_ACT_Add ? systemz::Pointer32Add
+ : systemz::Pointer32Sub);
+ else
+ return systemz::Pointer32;
+ break;
+ default:
+ llvm_unreachable("Unsuppoted rld reference type");
+ }
+ break;
+ default:
+ llvm_unreachable("Unsuppoted rld reference type");
+ }
+}
+
+Error GOFFLinkGraphBuilder::processRelocations() {
+ LLVM_DEBUG(dbgs() << "Processing GOFF relocations...\n");
+
+ for (const object::SectionRef Sec : Obj.sections()) {
+ uint32_t SecIndex = Sec.getIndex();
+ auto SectionName = Sec.getName();
+ if (!SectionName)
+ return SectionName.takeError();
+
+ LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName << "\n");
+
+ for (object::RelocationRef Relocation : Sec.relocations()) {
+ object::SymbolRef Sym = *Relocation.getSymbol();
+ auto TargetNameOrErr = Sym.getName();
+ if (!TargetNameOrErr) {
+ return TargetNameOrErr.takeError();
+ }
+
+ SmallString<16> RelTypeName;
+ Relocation.getTypeName(RelTypeName);
+ uint64_t RelType = Relocation.getType();
+ systemz::EdgeKind_systemz EK = getRelEdgeKind(RelType);
+ jitlink::Block *B = SectionMap[SecIndex].Block;
+ uint32_t TargetBlockOffset = Sec.getAddress() + Relocation.getOffset() -
+ B->getAddress().getValue();
+ uint32_t REsdId = Sym.getRawDataRefImpl().d.a;
+ jitlink::Symbol *S = SymbolMap[REsdId];
+
+ LLVM_DEBUG({
+ dbgs() << " reloffset = " << format_hex(Relocation.getOffset(), 16)
+ << " typename = " << RelTypeName << " idx = " << REsdId
+ << " block = (" << B << ", "
+ << format_hex(B->getAddress().getValue(), 16) << ")"
+ << " targetname: " << *TargetNameOrErr << "\n";
+ });
+
+ B->addEdge(EK, TargetBlockOffset, *S, 0);
+ }
+ }
+ return Error::success();
+}
+
+} // namespace jitlink
+} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h
new file mode 100644
index 0000000000000..edc54ba99c1a9
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h
@@ -0,0 +1,67 @@
+//===------ GOFFLinkGraphBuilder.h - GOFF LinkGraph builder -----*- 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 GOFF LinkGraph building code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LIB_EXECUTIONENGINE_JITLINK_GOFFLINKGRAPHBUILDER_H
+#define LIB_EXECUTIONENGINE_JITLINK_GOFFLINKGRAPHBUILDER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
+#include "llvm/Object/GOFFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
+
+namespace llvm {
+namespace jitlink {
+
+// Builder for GOFF LinkGraphs.
+class GOFFLinkGraphBuilder {
+public:
+ virtual ~GOFFLinkGraphBuilder() = default;
+ Expected<std::unique_ptr<LinkGraph>> buildGraph();
+
+public:
+ GOFFLinkGraphBuilder(const object::GOFFObjectFile &Obj,
+ std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
+ SubtargetFeatures Features,
+ LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
+ LinkGraph &getGraph() const { return *G; }
+ const object::GOFFObjectFile &getObject() const { return Obj; }
+
+private:
+ // Process all sections in the GOFF file.
+ Error processSections();
+
+ // Process ESD symbols.
+ Error processSymbols();
+
+ // Process all relocations for all sections.
+ Error processRelocations();
+
+private:
+ const object::GOFFObjectFile &Obj;
+ std::unique_ptr<LinkGraph> G;
+
+ struct SectionEntry {
+ jitlink::Section *Section;
+ jitlink::Block *Block;
+ object::SectionRef SectionData;
+ };
+
+ DenseMap<uint32_t, jitlink::Symbol *> SymbolMap;
+ DenseMap<uint32_t, SectionEntry> SectionMap;
+};
+
+} // namespace jitlink
+} // namespace llvm
+
+#endif // LIB_EXECUTIONENGINE_JITLINK_GOFFLINKGRAPHBUILDER_H
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
new file mode 100644
index 0000000000000..b1086ee361ed0
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
@@ -0,0 +1,100 @@
+//===----------- GOFF_systemz.cpp - JIT linker function for GOFF ----------===//
+//
+// 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 GOFF/systemz.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITLink/GOFF_systemz.h"
+#include "GOFFLinkGraphBuilder.h"
+#include "JITLinkGeneric.h"
+#include "llvm/ExecutionEngine/JITLink/GOFF.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITLink/systemz.h"
+#include "llvm/Object/GOFFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <system_error>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "jitlink"
+
+namespace llvm {
+namespace jitlink {
+
+class GOFFJITLinker_systemz : public JITLinker<GOFFJITLinker_systemz> {
+ using JITLinkerBase = JITLinker<GOFFJITLinker_systemz>;
+ friend JITLinkerBase;
+
+public:
+ GOFFJITLinker_systemz(std::unique_ptr<JITLinkContext> Ctx,
+ std::unique_ptr<LinkGraph> G,
+ PassConfiguration PassConfig)
+ : JITLinkerBase(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
+
+private:
+ Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
+ if (auto Err = systemz::applyGOFFFixup(G, B, E)) {
+ return make_error<StringError>("Unsupported goff relocation type",
+ std::error_code());
+ }
+ return Error::success();
+ }
+};
+
+Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromGOFFObject_systemz(
+ MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
+ LLVM_DEBUG({
+ dbgs() << "Building jitlink graph for new input "
+ << ObjectBuffer.getBufferIdentifier() << "...\n";
+ });
+
+ file_magic Magic = identify_magic(ObjectBuffer.getBuffer());
+ if (Magic != file_magic::goff_object)
+ return make_error<JITLinkError>("Invalid GOFF Header");
+
+ auto GOFFObj = object::ObjectFile::createObjectFile(ObjectBuffer);
+ if (!GOFFObj)
+ return GOFFObj.takeError();
+ assert((*GOFFObj)->isGOFF() && "Expects an GOFF Object");
+ assert((*GOFFObj)->getArch() == Triple::systemz && "Only support systemz");
+
+ auto Features = (*GOFFObj)->getFeatures();
+ if (!Features)
+ return Features.takeError();
+ LLVM_DEBUG({
+ dbgs() << " Features: ";
+ (*Features).print(dbgs());
+ });
+
+ return GOFFLinkGraphBuilder(cast<object::GOFFObjectFile>(**GOFFObj),
+ std::move(SSP), (*GOFFObj)->makeTriple(),
+ std::move(*Features), systemz::getEdgeKindName)
+ .buildGraph();
+}
+
+void link_GOFF_systemz(std::unique_ptr<LinkGraph> G,
+ std::unique_ptr<JITLinkContext> Ctx) {
+
+ PassConfiguration PassCfg;
+ if (auto Err = Ctx->modifyPassConfig(*G, PassCfg))
+ return Ctx->notifyFailed(std::move(Err));
+
+ if (G->getTargetTriple().getArch() != Triple::systemz)
+ return Ctx->notifyFailed(make_error<JITLinkError>(
+ "Unsupported target machine architecture in GOFF link graph " +
+ G->getName()));
+
+ GOFFJITLinker_systemz::link(std::move(Ctx), std::move(G), std::move(PassCfg));
+ return;
+}
+
+} // namespace jitlink
+} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index 329414a5e1275..4b407470b4e98 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -12,6 +12,7 @@
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/ExecutionEngine/JITLink/COFF.h"
#include "llvm/ExecutionEngine/JITLink/ELF.h"
+#include "llvm/ExecutionEngine/JITLink/GOFF.h"
#include "llvm/ExecutionEngine/JITLink/MachO.h"
#include "llvm/ExecutionEngine/JITLink/XCOFF.h"
#include "llvm/ExecutionEngine/JITLink/aarch64.h"
@@ -527,6 +528,8 @@ createLinkGraphFromObject(MemoryBufferRef ObjectBuffer,
return createLinkGraphFromCOFFObject(ObjectBuffer, std::move(SSP));
case file_magic::xcoff_object_64:
return createLinkGraphFromXCOFFObject(ObjectBuffer, std::move(SSP));
+ case file_magic::goff_object:
+ return createLinkGraphFromGOFFObject(ObjectBuffer, std::move(SSP));
default:
return make_error<JITLinkError>("Unsupported file format");
};
@@ -560,6 +563,8 @@ void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) {
return link_COFF(std::move(G), std::move(Ctx));
case Triple::XCOFF:
return link_XCOFF(std::move(G), std::move(Ctx));
+ case Triple::GOFF:
+ return link_GOFF(std::move(G), std::move(Ctx));
default:
Ctx->notifyFailed(make_error<JITLinkError>("Unsupported object format"));
};
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index f5d335a17cf8b..0fa4b507016c1 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -46,6 +46,14 @@ const char *getEdgeKindName(Edge::Kind R) {
return "Pointer12";
case Pointer8:
return "Pointer8";
+ case Pointer64Add:
+ return "Pointer64Add";
+ case Pointer32Add:
+ return "Pointer32Add";
+ case Pointer64Sub:
+ return "Pointer64Sub";
+ case Pointer32Sub:
+ return "Pointer32Sub";
case Delta64:
return "Delta64";
case Delta32:
diff --git a/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp b/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp
index aab7b40372205..2dc7134a83491 100644
--- a/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp
@@ -38,6 +38,13 @@ checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT) {
return std::move(Obj);
}
+static Expected<std::unique_ptr<MemoryBuffer>>
+checkGOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
+ const Triple &TT) {
+ // TODO: Actually check the architecture of the file.
+ return std::move(Obj);
+}
+
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
loadLinkableFile(StringRef Path, const Triple &TT, LoadArchives LA,
std::optional<StringRef> IdentifierOverride) {
@@ -121,6 +128,15 @@ loadLinkableFile(StringRef Path, const Triple &TT, LoadArchives LA,
LinkableFileKind::RelocatableObject);
}
break;
+ case file_magic::goff_object:
+ if (!RequireFormat || *RequireFormat == Triple::GOFF) {
+ auto CheckedBuf = checkGOFFRelocatableObject(std::move(*Buf), TT);
+ if (!CheckedBuf)
+ return CheckedBuf.takeError();
+ return std::make_pair(std::move(*CheckedBuf),
+ LinkableFileKind::RelocatableObject);
+ }
+ break;
default:
break;
}
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
index b9cee98d45d77..664f10cf4ec63 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp
@@ -11,6 +11,7 @@
#include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/GOFFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/XCOFFObjectFile.h"
@@ -229,6 +230,47 @@ getCOFFObjectFileSymbolInfo(ExecutionSession &ES,
return I;
}
+static Expected<MaterializationUnit::Interface>
+getGOFFObjectFileSymbolInfo(ExecutionSession &ES,
+ const object::GOFFObjectFile &Obj) {
+ MaterializationUnit::Interface I;
+ for (auto &Sym : Obj.symbols()) {
+ Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
+ if (!SymFlagsOrErr)
+ return SymFlagsOrErr.takeError();
+
+ uint32_t Flags = *SymFlagsOrErr;
+ // Skip symbols not defined in this object file.
+ if (Flags & object::SymbolRef::SF_Undefined)
+ continue;
+ // Skip symbols that are not global.
+ if (!(Flags & object::SymbolRef::SF_Global))
+ continue;
+
+ auto SymbolType = Sym.getType();
+ if (!SymbolType)
+ return SymbolType.takeError();
+
+ // Skip file symbols.
+ if (*SymbolType == object::SymbolRef::ST_File)
+ continue;
+
+ auto Name = Sym.getName();
+ if (!Name)
+ return Name.takeError();
+
+ auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
+ if (!SymFlags)
+ return SymFlags.takeError();
+
+ // TODO: weak symbol.
+
+ I.SymbolFlags[ES.intern(std::move(*Name))] = std::move(*SymFlags);
+ }
+
+ return I;
+}
+
Expected<MaterializationUnit::Interface>
getXCOFFObjectFileSymbolInfo(ExecutionSession &ES,
const object::ObjectFile &Obj) {
@@ -330,6 +372,8 @@ getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) {
return getCOFFObjectFileSymbolInfo(ES, *COFFObj);
else if (auto *XCOFFObj = dyn_cast<object::XCOFFObjectFile>(Obj->get()))
return getXCOFFObjectFileSymbolInfo(ES, *XCOFFObj);
+ else if (auto *GOFFObj = dyn_cast<object::GOFFObjectFile>(Obj->get()))
+ return getGOFFObjectFileSymbolInfo(ES, *GOFFObj);
return getGenericObjectFileSymbolInfo(ES, **Obj);
}
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
index c7e89c86e4cfb..e5fc9f2f48fc3 100644
--- a/llvm/lib/Object/GOFFObjectFile.cpp
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -384,6 +384,12 @@ Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const {
return getSymbolName(Symbol.getRawDataRefImpl());
}
+Expected<StringRef> GOFFObjectFile::getSymbolName(uint32_t SymIndex) const {
+ DataRefImpl Symb;
+ Symb.d.a = SymIndex;
+ return getSymbolName(Symb);
+}
+
Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
uint32_t Offset;
const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
@@ -653,6 +659,48 @@ Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const {
return Name;
}
+Error GOFFObjectFile::getSectionUniqueName(
+ DataRefImpl Sec, SmallVectorImpl<char> &Result) const {
+
+ SectionEntryImpl EsdIds = SectionList[Sec.d.a];
+
+ const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
+ uint32_t ParentEsdId = 0;
+ ESDRecord::getParentEsdId(EsdRecord, ParentEsdId);
+ assert(ParentEsdId && "Should have parent");
+
+ DataRefImpl ParentEdSym;
+ ParentEdSym.d.a = ParentEsdId;
+ const uint8_t *ParentRecord = getSymbolEsdRecord(ParentEdSym);
+ GOFF::ESDSymbolType ParentSymbolType;
+ ESDRecord::getSymbolType(ParentRecord, ParentSymbolType);
+ assert(ParentSymbolType == GOFF::ESD_ST_SectionDefinition && "Not SD");
+
+ Expected<StringRef> ParentNameOrErr = getSymbolName(ParentEdSym);
+ if (!ParentNameOrErr)
+ return ParentNameOrErr.takeError();
+
+ Result.append(ParentNameOrErr->begin(), ParentNameOrErr->end());
+
+ Expected<StringRef> NameOrErr = getSymbolName(EsdIds.d.a);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ Result.append(1, '.');
+ Result.append(NameOrErr->begin(), NameOrErr->end());
+
+ if (EsdIds.d.b) {
+ Expected<StringRef> PrNameOrErr = getSymbolName(EsdIds.d.b);
+ if (!PrNameOrErr)
+ return PrNameOrErr.takeError();
+
+ Result.append(1, '.');
+ Result.append(PrNameOrErr->begin(), PrNameOrErr->end());
+ }
+
+ return Error::success();
+}
+
uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
uint32_t Offset;
const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/GOFF_systemz_reloc_ptr.ll b/llvm/test/ExecutionEngine/JITLink/systemz/GOFF_systemz_reloc_ptr.ll
new file mode 100644
index 0000000000000..4ab8f50c47bf0
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/GOFF_systemz_reloc_ptr.ll
@@ -0,0 +1,15 @@
+; llvm-jitlink -check is not available as it requries implementation of registerXCOFFGraphInfo.
+; Will revisit this testcase once support is more complete.
+
+; RUN: llc --filetype=obj -mtriple=s390x-ibm-zos -o GOFF_systemz_reloc_ptr.o < %s
+; RUN: llvm-jitlink -noexec -num-threads=0 --triple=s390x-ibm-zos GOFF_systemz_reloc_ptr.o \
+; RUN: -abs CELQSTRT=0x00400000
+
+;target datalayout = "E-m:z-p:64:64-i1:8:16-i8:8:16-i16:16-i32:32-i64:64-f32:32-f64:64-f128:64-a:8:16-n32:64"
+;target triple = "s390x-ibm-zos"
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
+
>From 53435bc44b23b46fdcb29ccc2a063313d5b47ffd Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Mon, 28 Sep 2026 19:41:08 +0000
Subject: [PATCH 2/3] Move processRelocations to GOFF_systemz.cpp
---
.../JITLink/GOFFLinkGraphBuilder.cpp | 97 ++-----------------
.../JITLink/GOFFLinkGraphBuilder.h | 36 ++++++-
.../ExecutionEngine/JITLink/GOFF_systemz.cpp | 97 ++++++++++++++++++-
3 files changed, 137 insertions(+), 93 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp
index 79146891825c5..ea16eba65b2dd 100644
--- a/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.cpp
@@ -12,9 +12,6 @@
#include "GOFFLinkGraphBuilder.h"
#include "llvm/BinaryFormat/GOFF.h"
-#include "llvm/ExecutionEngine/JITLink/GOFF_systemz.h"
-#include "llvm/ExecutionEngine/JITLink/JITLink.h"
-#include "llvm/ExecutionEngine/JITLink/systemz.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
#include "llvm/Object/GOFFObjectFile.h"
@@ -64,7 +61,7 @@ Expected<std::unique_ptr<LinkGraph>> GOFFLinkGraphBuilder::buildGraph() {
Error GOFFLinkGraphBuilder::processSections() {
LLVM_DEBUG(dbgs() << "Processing GOFF sections ...\n");
- for (const object::SectionRef Sec : Obj.sections()) {
+ for (const object::SectionRef Sec : sections()) {
Expected<StringRef> NameOrErr = Sec.getName();
if (!NameOrErr) {
return NameOrErr.takeError();
@@ -108,7 +105,7 @@ Error GOFFLinkGraphBuilder::processSections() {
return make_error<JITLinkError>("MemProt should match");
uint32_t SecIndex = Sec.getIndex();
- if (SectionMap.contains(SecIndex))
+ if (getGraphBlock(SecIndex))
return make_error<JITLinkError>("Index already exists");
Expected<StringRef> ContentsOrErr = Sec.getContents();
@@ -122,7 +119,7 @@ Error GOFFLinkGraphBuilder::processSections() {
Block *B = &G->createContentBlock(*GraphSec, Contents,
orc::ExecutorAddr(SecAddress),
Sec.getAlignment().value(), 0);
- SectionMap[SecIndex] = {GraphSec, B, Sec};
+ setGraphBlock(SecIndex, GraphSec, B, Sec);
}
return Error::success();
@@ -148,8 +145,9 @@ Error GOFFLinkGraphBuilder::processSymbols() {
uint32_t Flags = *SymFlagsOrErr;
if (Flags & object::SymbolRef::SF_Undefined) {
LLVM_DEBUG(dbgs() << " created external symbol\n");
- SymbolMap[SymEsdId] = &G->addExternalSymbol(
- Name, Sym.getSize(), Flags & object::SymbolRef::SF_Weak);
+ Symbol &GSym = G->addExternalSymbol(Name, Sym.getSize(),
+ Flags & object::SymbolRef::SF_Weak);
+ setGraphSymbol(SymEsdId, GSym);
continue;
}
@@ -170,7 +168,7 @@ Error GOFFLinkGraphBuilder::processSymbols() {
return OffsetOrErr.takeError();
uint32_t SecIndex = SI->getIndex();
- Block *B = SectionMap[SecIndex].Block;
+ Block *B = getGraphBlock(SecIndex);
uint64_t Offset = *OffsetOrErr;
Linkage L =
(Flags & object::SymbolRef::SF_Weak) ? Linkage::Weak : Linkage::Strong;
@@ -187,88 +185,13 @@ Error GOFFLinkGraphBuilder::processSymbols() {
<< ", B = " << format_hex(B->getAddress().getValue(), 16)
<< (IsCallable ? " function" : " non-callable") << "\n");
- SymbolMap[SymEsdId] = &G->addDefinedSymbol(*B, Offset, Name, Sym.getSize(),
- L, S, IsCallable, true);
+ Symbol &GSym = G->addDefinedSymbol(*B, Offset, Name, Sym.getSize(), L, S,
+ IsCallable, true);
+ setGraphSymbol(SymEsdId, GSym);
}
return Error::success();
}
-static systemz::EdgeKind_systemz getRelEdgeKind(uint64_t RelType) {
- GOFF::RLDReferenceType RldRefType = getRLDReferenceType(RelType);
- GOFF::RLDAction RldAct = getRLDAction(RelType);
- GOFF::RLDFetchStore RldFetch = getRLDFetchStore(RelType);
- uint8_t RldLength = getRLDTargetLength(RelType);
- uint8_t RldBitLength = getRLDBitLength(RelType);
- uint8_t RldBitWidth = 8 * RldLength + RldBitLength;
-
- switch (RldRefType) {
- case GOFF::RLD_RT_RAddress:
- switch (RldBitWidth) {
- case 64:
- if (RldFetch == GOFF::RLD_FS_Fetch)
- return (RldAct == GOFF::RLD_ACT_Add ? systemz::Pointer64Add
- : systemz::Pointer64Sub);
- else
- return systemz::Pointer64;
- break;
- case 32:
- if (RldFetch == GOFF::RLD_FS_Fetch)
- return (RldAct == GOFF::RLD_ACT_Add ? systemz::Pointer32Add
- : systemz::Pointer32Sub);
- else
- return systemz::Pointer32;
- break;
- default:
- llvm_unreachable("Unsuppoted rld reference type");
- }
- break;
- default:
- llvm_unreachable("Unsuppoted rld reference type");
- }
-}
-
-Error GOFFLinkGraphBuilder::processRelocations() {
- LLVM_DEBUG(dbgs() << "Processing GOFF relocations...\n");
-
- for (const object::SectionRef Sec : Obj.sections()) {
- uint32_t SecIndex = Sec.getIndex();
- auto SectionName = Sec.getName();
- if (!SectionName)
- return SectionName.takeError();
-
- LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName << "\n");
-
- for (object::RelocationRef Relocation : Sec.relocations()) {
- object::SymbolRef Sym = *Relocation.getSymbol();
- auto TargetNameOrErr = Sym.getName();
- if (!TargetNameOrErr) {
- return TargetNameOrErr.takeError();
- }
-
- SmallString<16> RelTypeName;
- Relocation.getTypeName(RelTypeName);
- uint64_t RelType = Relocation.getType();
- systemz::EdgeKind_systemz EK = getRelEdgeKind(RelType);
- jitlink::Block *B = SectionMap[SecIndex].Block;
- uint32_t TargetBlockOffset = Sec.getAddress() + Relocation.getOffset() -
- B->getAddress().getValue();
- uint32_t REsdId = Sym.getRawDataRefImpl().d.a;
- jitlink::Symbol *S = SymbolMap[REsdId];
-
- LLVM_DEBUG({
- dbgs() << " reloffset = " << format_hex(Relocation.getOffset(), 16)
- << " typename = " << RelTypeName << " idx = " << REsdId
- << " block = (" << B << ", "
- << format_hex(B->getAddress().getValue(), 16) << ")"
- << " targetname: " << *TargetNameOrErr << "\n";
- });
-
- B->addEdge(EK, TargetBlockOffset, *S, 0);
- }
- }
- return Error::success();
-}
-
} // namespace jitlink
} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h
index edc54ba99c1a9..07fb4866a8ab2 100644
--- a/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFFLinkGraphBuilder.h
@@ -29,15 +29,15 @@ class GOFFLinkGraphBuilder {
virtual ~GOFFLinkGraphBuilder() = default;
Expected<std::unique_ptr<LinkGraph>> buildGraph();
-public:
+protected:
GOFFLinkGraphBuilder(const object::GOFFObjectFile &Obj,
std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
SubtargetFeatures Features,
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
LinkGraph &getGraph() const { return *G; }
+
const object::GOFFObjectFile &getObject() const { return Obj; }
-private:
// Process all sections in the GOFF file.
Error processSections();
@@ -45,7 +45,37 @@ class GOFFLinkGraphBuilder {
Error processSymbols();
// Process all relocations for all sections.
- Error processRelocations();
+ virtual Error processRelocations() = 0;
+
+ void setGraphSymbol(uint32_t SymIndex, Symbol &Sym) {
+ assert(!SymbolMap.contains(SymIndex) && "Duplicate symbol at index");
+ SymbolMap[SymIndex] = &Sym;
+ }
+
+ Symbol *getGraphSymbol(uint32_t SymIndex) const {
+ if (SymbolMap.contains(SymIndex))
+ return SymbolMap.at(SymIndex);
+
+ return nullptr;
+ }
+
+ void setGraphBlock(uint32_t SecIndex, Section *Section, Block *B,
+ object::SectionRef SectionData) {
+ assert(!SectionMap.contains(SecIndex) &&
+ "Duplicate section block at index");
+ SectionMap[SecIndex] = {Section, B, SectionData};
+ }
+
+ Block *getGraphBlock(uint32_t SecIndex) const {
+ if (SectionMap.contains(SecIndex))
+ return SectionMap.at(SecIndex).Block;
+
+ return nullptr;
+ }
+
+ object::GOFFObjectFile::section_iterator_range sections() const {
+ return Obj.sections();
+ }
private:
const object::GOFFObjectFile &Obj;
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
index b1086ee361ed0..554b806e6667b 100644
--- a/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
@@ -49,6 +49,18 @@ class GOFFJITLinker_systemz : public JITLinker<GOFFJITLinker_systemz> {
}
};
+class GOFFLinkGraphBuilder_systemz : public GOFFLinkGraphBuilder {
+private:
+ Error processRelocations() override;
+
+public:
+ GOFFLinkGraphBuilder_systemz(const object::GOFFObjectFile &Obj,
+ std::shared_ptr<orc::SymbolStringPool> SSP,
+ const Triple T, const SubtargetFeatures Features)
+ : GOFFLinkGraphBuilder(Obj, std::move(SSP), std::move(T),
+ std::move(Features), systemz::getEdgeKindName) {}
+};
+
Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromGOFFObject_systemz(
MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
LLVM_DEBUG({
@@ -74,9 +86,9 @@ Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromGOFFObject_systemz(
(*Features).print(dbgs());
});
- return GOFFLinkGraphBuilder(cast<object::GOFFObjectFile>(**GOFFObj),
- std::move(SSP), (*GOFFObj)->makeTriple(),
- std::move(*Features), systemz::getEdgeKindName)
+ return GOFFLinkGraphBuilder_systemz(cast<object::GOFFObjectFile>(**GOFFObj),
+ std::move(SSP), (*GOFFObj)->makeTriple(),
+ std::move(*Features))
.buildGraph();
}
@@ -96,5 +108,84 @@ void link_GOFF_systemz(std::unique_ptr<LinkGraph> G,
return;
}
+static systemz::EdgeKind_systemz getRelEdgeKind(uint64_t RelType) {
+ GOFF::RLDReferenceType RldRefType = object::getRLDReferenceType(RelType);
+ GOFF::RLDAction RldAct = object::getRLDAction(RelType);
+ GOFF::RLDFetchStore RldFetch = object::getRLDFetchStore(RelType);
+ uint8_t RldLength = object::getRLDTargetLength(RelType);
+ uint8_t RldBitLength = object::getRLDBitLength(RelType);
+ uint8_t RldBitWidth = 8 * RldLength + RldBitLength;
+
+ switch (RldRefType) {
+ case GOFF::RLD_RT_RAddress:
+ switch (RldBitWidth) {
+ case 64:
+ if (RldFetch == GOFF::RLD_FS_Fetch)
+ return (RldAct == GOFF::RLD_ACT_Add ? systemz::Pointer64Add
+ : systemz::Pointer64Sub);
+ else
+ return systemz::Pointer64;
+ break;
+ case 32:
+ if (RldFetch == GOFF::RLD_FS_Fetch)
+ return (RldAct == GOFF::RLD_ACT_Add ? systemz::Pointer32Add
+ : systemz::Pointer32Sub);
+ else
+ return systemz::Pointer32;
+ break;
+ default:
+ llvm_unreachable("Unsuppoted rld reference type");
+ }
+ break;
+ default:
+ llvm_unreachable("Unsuppoted rld reference type");
+ }
+}
+
+Error GOFFLinkGraphBuilder_systemz::processRelocations() {
+ LLVM_DEBUG(dbgs() << "Processing GOFF relocations...\n");
+
+ for (const object::SectionRef Sec : sections()) {
+ uint32_t SecIndex = Sec.getIndex();
+ auto SectionName = Sec.getName();
+ if (!SectionName)
+ return SectionName.takeError();
+
+ LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName << "\n");
+
+ for (object::RelocationRef Relocation : Sec.relocations()) {
+ object::SymbolRef Sym = *Relocation.getSymbol();
+ auto TargetNameOrErr = Sym.getName();
+ if (!TargetNameOrErr) {
+ return TargetNameOrErr.takeError();
+ }
+
+ SmallString<16> RelTypeName;
+ Relocation.getTypeName(RelTypeName);
+ uint64_t RelType = Relocation.getType();
+ systemz::EdgeKind_systemz EK = getRelEdgeKind(RelType);
+ jitlink::Block *B = getGraphBlock(SecIndex);
+ assert(B && "Block not found");
+
+ uint32_t TargetBlockOffset = Sec.getAddress() + Relocation.getOffset() -
+ B->getAddress().getValue();
+ uint32_t REsdId = Sym.getRawDataRefImpl().d.a;
+ jitlink::Symbol *S = getGraphSymbol(REsdId);
+ assert(S && "Symbol not found");
+
+ LLVM_DEBUG({
+ dbgs() << " reloffset = " << format_hex(Relocation.getOffset(), 16)
+ << " typename = " << RelTypeName << " idx = " << REsdId
+ << " block = (" << B << ", "
+ << format_hex(B->getAddress().getValue(), 16) << ")"
+ << " targetname: " << *TargetNameOrErr << "\n";
+ });
+
+ B->addEdge(EK, TargetBlockOffset, *S, 0);
+ }
+ }
+ return Error::success();
+}
+
} // namespace jitlink
} // namespace llvm
>From 79e875aa2678c2eb7cef8f86562094b3f4232e8a Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Thu, 1 Oct 2026 13:45:34 +0000
Subject: [PATCH 3/3] Fix the assert - need jitlink symbols for GOFF ED
R-pointer
---
llvm/include/llvm/Object/GOFFObjectFile.h | 5 ++++
.../ExecutionEngine/JITLink/GOFF_systemz.cpp | 3 ++
llvm/lib/Object/GOFFObjectFile.cpp | 30 +++++++++++++++----
3 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Object/GOFFObjectFile.h b/llvm/include/llvm/Object/GOFFObjectFile.h
index 3d6a0da34c86b..2a0da45dae3a4 100644
--- a/llvm/include/llvm/Object/GOFFObjectFile.h
+++ b/llvm/include/llvm/Object/GOFFObjectFile.h
@@ -82,6 +82,9 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
SmallVector<SectionEntryImpl, 256> SectionList;
mutable DenseMap<uint32_t, SmallVector<uint8_t>> SectionDataCache;
+ // The flag to skip GOFF ED symbols or not during symbol traversal.
+ bool SkipEDSymbols = true;
+
// Flattened data for all logical records (record type + continuous data
// without headers).
SmallVector<std::pair<GOFF::RecordType, SmallVector<uint8_t>>> FlattenedData;
@@ -141,6 +144,7 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
bool isSectionZeroInit(DataRefImpl Sec) const;
Error getSectionUniqueName(DataRefImpl Sec,
SmallVectorImpl<char> &Result) const;
+ void setSkipEDSymbols(bool Skip) { SkipEDSymbols = Skip; }
private:
// SymbolRef.
@@ -156,6 +160,7 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
const uint8_t *getSymbolEsdRecord(DataRefImpl Symb) const;
bool isSymbolUnresolved(DataRefImpl Symb) const;
bool isSymbolIndirect(DataRefImpl Symb) const;
+ bool isEDSymbol(DataRefImpl Symb) const;
Expected<StringRef> getSymbolName(uint32_t SymIndex) const;
// SectionRef.
diff --git a/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
index 554b806e6667b..9616008287b9b 100644
--- a/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/GOFF_systemz.cpp
@@ -86,6 +86,9 @@ Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromGOFFObject_systemz(
(*Features).print(dbgs());
});
+ // Set the flag to preserve GOFF ED symbols for creating JITLink symbols.
+ cast<object::GOFFObjectFile>(**GOFFObj).setSkipEDSymbols(false);
+
return GOFFLinkGraphBuilder_systemz(cast<object::GOFFObjectFile>(**GOFFObj),
std::move(SSP), (*GOFFObj)->makeTriple(),
std::move(*Features))
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
index e5fc9f2f48fc3..5e0bc16f64a48 100644
--- a/llvm/lib/Object/GOFFObjectFile.cpp
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -424,6 +424,13 @@ bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
return false;
}
+bool GOFFObjectFile::isEDSymbol(DataRefImpl Symb) const {
+ const uint8_t *Record = getSymbolEsdRecord(Symb);
+ GOFF::ESDSymbolType SymbolType;
+ ESDRecord::getSymbolType(Record, SymbolType);
+ return (SymbolType == GOFF::ESD_ST_ElementDefinition);
+}
+
bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
const uint8_t *Record = getSymbolEsdRecord(Symb);
bool Indirect;
@@ -523,6 +530,20 @@ GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
return section_iterator(SectionRef(Sec, this));
const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
+ // check if this is a ED symbol.
+ if (!SkipEDSymbols && isEDSymbol(Symb)) {
+ for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
+ const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I);
+ if (SymEsdRecord == SectionEdRecord) {
+ Sec.d.a = I;
+ return section_iterator(SectionRef(Sec, this));
+ }
+ }
+ return createStringError(llvm::errc::invalid_argument,
+ "No section found for ED symbol with id " +
+ std::to_string(Symb.d.a));
+ }
+
uint32_t SymEdId;
ESDRecord::getParentEsdId(SymEsdRecord, SymEdId);
const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
@@ -828,11 +849,10 @@ void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
if (const uint8_t *EsdRecord = EsdPtrs[I]) {
GOFF::ESDSymbolType SymbolType;
ESDRecord::getSymbolType(EsdRecord, SymbolType);
- // Skip EDs - i.e. section symbols.
- bool IgnoreSpecialGOFFSymbols = true;
- bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
- (SymbolType == GOFF::ESD_ST_SectionDefinition)) &&
- IgnoreSpecialGOFFSymbols;
+ // Skip section symbols, including SDs and, if flagged, EDs.
+ bool SkipSymbol =
+ ((SymbolType == GOFF::ESD_ST_SectionDefinition) ||
+ (SymbolType == GOFF::ESD_ST_ElementDefinition && SkipEDSymbols));
if (!SkipSymbol) {
Symb.d.a = I;
return;
More information about the llvm-commits
mailing list