Skip to content

Commit 8313507

Browse files
committed
[JITLink][ELF][ppc64] Add skeleton ppc64 support and ELF/ppc64 JITLink backend.
This patch introduces a skeleton JITLink ppc64 support header and ELF/ppc64 backend. No relocations are supported in this initial version, but given a program requiring no relocations (e.g. one that just returns a constant value from main) the new backend is able to construct a LinkGraph from a ppc64 ELF relocatable object, and the llvm-jitlink tool is able to execute it. This commit should also serve as a good example of how to introduce a JITLink backend for a new architecture. Reviewed By: sgraenitz, v.g.vassilev, vchuravy, nemanjai, jain98, MaskRay Differential Revision: https://reviews.llvm.org/D148192
1 parent ca26665 commit 8313507

File tree

8 files changed

+317
-0
lines changed

8 files changed

+317
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===------ ELF_ppc64.h - JIT link functions for ELF/ppc64 ------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// jit-link functions for ELF/ppc64{le}.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_JITLINK_ELF_PPC64_H
14+
#define LLVM_EXECUTIONENGINE_JITLINK_ELF_PPC64_H
15+
16+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
17+
18+
namespace llvm::jitlink {
19+
20+
/// Create a LinkGraph from an ELF/ppc64 relocatable object.
21+
///
22+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
23+
/// its contents. The caller is responsible for ensuring that the object buffer
24+
/// outlives the graph.
25+
///
26+
/// WARNING: The big-endian backend has not been tested yet.
27+
Expected<std::unique_ptr<LinkGraph>>
28+
createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer);
29+
30+
/// Create a LinkGraph from an ELF/ppc64le relocatable object.
31+
///
32+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
33+
/// its contents. The caller is responsible for ensuring that the object buffer
34+
/// outlives the graph.
35+
Expected<std::unique_ptr<LinkGraph>>
36+
createLinkGraphFromELFObject_ppc64le(MemoryBufferRef ObjectBuffer);
37+
38+
/// jit-link the given object buffer, which must be a ELF ppc64le object file.
39+
///
40+
/// WARNING: The big-endian backend has not been tested yet.
41+
void link_ELF_ppc64(std::unique_ptr<LinkGraph> G,
42+
std::unique_ptr<JITLinkContext> Ctx);
43+
44+
/// jit-link the given object buffer, which must be a ELF ppc64le object file.
45+
void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G,
46+
std::unique_ptr<JITLinkContext> Ctx);
47+
48+
} // end namespace llvm::jitlink
49+
50+
#endif // LLVM_EXECUTIONENGINE_JITLINK_ELF_PPC64_H
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===--- ppc64.h - Generic JITLink ppc64 edge kinds, utilities --*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Generic utilities for graphs representing 64-bit PowerPC objects.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_JITLINK_PPC64_H
14+
#define LLVM_EXECUTIONENGINE_JITLINK_PPC64_H
15+
16+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
17+
18+
namespace llvm::jitlink::ppc64 {
19+
20+
/// Represents ppc64 fixups and other ppc64-specific edge kinds.
21+
/// TODO: Add edge kinds.
22+
enum EdgeKind_ppc64 : Edge::Kind {};
23+
24+
/// Returns a string name for the given ppc64 edge. For debugging purposes
25+
/// only.
26+
const char *getEdgeKindName(Edge::Kind K);
27+
28+
/// Apply fixup expression for edge to block content.
29+
/// TOOD: Add fixups as we add edges.
30+
inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
31+
const Symbol *GOTSymbol) {
32+
switch (E.getKind()) {
33+
default:
34+
return make_error<JITLinkError>(
35+
"In graph " + G.getName() + ", section " + B.getSection().getName() +
36+
" unsupported edge kind " + getEdgeKindName(E.getKind()));
37+
}
38+
39+
return Error::success();
40+
}
41+
42+
} // end namespace llvm::jitlink::ppc64
43+
44+
#endif // LLVM_EXECUTIONENGINE_JITLINK_PPC64_H

llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_llvm_component_library(LLVMJITLink
2424
ELF_aarch64.cpp
2525
ELF_i386.cpp
2626
ELF_loongarch.cpp
27+
ELF_ppc64.cpp
2728
ELF_riscv.cpp
2829
ELF_x86_64.cpp
2930

@@ -38,6 +39,7 @@ add_llvm_component_library(LLVMJITLink
3839
aarch64.cpp
3940
i386.cpp
4041
loongarch.cpp
42+
ppc64.cpp
4143
riscv.cpp
4244
x86_64.cpp
4345

llvm/lib/ExecutionEngine/JITLink/ELF.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
1818
#include "llvm/ExecutionEngine/JITLink/ELF_i386.h"
1919
#include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
20+
#include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"
2021
#include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
2122
#include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
2223
#include "llvm/Object/ELF.h"
@@ -63,6 +64,7 @@ createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) {
6364
if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
6465
return make_error<JITLinkError>("ELF magic not valid");
6566

67+
uint8_t DataEncoding = Buffer.data()[ELF::EI_DATA];
6668
Expected<uint16_t> TargetMachineArch = readTargetMachineArch(Buffer);
6769
if (!TargetMachineArch)
6870
return TargetMachineArch.takeError();
@@ -74,6 +76,12 @@ createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) {
7476
return createLinkGraphFromELFObject_aarch32(ObjectBuffer);
7577
case ELF::EM_LOONGARCH:
7678
return createLinkGraphFromELFObject_loongarch(ObjectBuffer);
79+
case ELF::EM_PPC64: {
80+
if (DataEncoding == ELF::ELFDATA2LSB)
81+
return createLinkGraphFromELFObject_ppc64le(ObjectBuffer);
82+
else
83+
return createLinkGraphFromELFObject_ppc64(ObjectBuffer);
84+
}
7785
case ELF::EM_RISCV:
7886
return createLinkGraphFromELFObject_riscv(ObjectBuffer);
7987
case ELF::EM_X86_64:
@@ -103,6 +111,12 @@ void link_ELF(std::unique_ptr<LinkGraph> G,
103111
case Triple::loongarch64:
104112
link_ELF_loongarch(std::move(G), std::move(Ctx));
105113
return;
114+
case Triple::ppc64:
115+
link_ELF_ppc64(std::move(G), std::move(Ctx));
116+
return;
117+
case Triple::ppc64le:
118+
link_ELF_ppc64le(std::move(G), std::move(Ctx));
119+
return;
106120
case Triple::riscv32:
107121
case Triple::riscv64:
108122
link_ELF_riscv(std::move(G), std::move(Ctx));
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===------- ELF_ppc64.cpp -JIT linker implementation for ELF/ppc64 -------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// ELF/ppc64 jit-link implementation.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"
14+
#include "llvm/ExecutionEngine/JITLink/ppc64.h"
15+
#include "llvm/Object/ELFObjectFile.h"
16+
#include "llvm/Support/Endian.h"
17+
18+
#include "ELFLinkGraphBuilder.h"
19+
#include "JITLinkGeneric.h"
20+
21+
#define DEBUG_TYPE "jitlink"
22+
23+
namespace llvm::jitlink {
24+
25+
template <support::endianness Endianness>
26+
class ELFLinkGraphBuilder_ppc64
27+
: public ELFLinkGraphBuilder<object::ELFType<Endianness, true>> {
28+
private:
29+
using ELFT = object::ELFType<Endianness, true>;
30+
using Base = ELFLinkGraphBuilder<ELFT>;
31+
32+
using Base::G; // Use LinkGraph pointer from base class.
33+
34+
Error addRelocations() override {
35+
LLVM_DEBUG(dbgs() << "Processing relocations:\n");
36+
37+
using Self = ELFLinkGraphBuilder_ppc64<Endianness>;
38+
for (const auto &RelSect : Base::Sections) {
39+
// Validate the section to read relocation entries from.
40+
if (RelSect.sh_type == ELF::SHT_REL)
41+
return make_error<StringError>("No SHT_REL in valid " +
42+
G->getTargetTriple().getArchName() +
43+
" ELF object files",
44+
inconvertibleErrorCode());
45+
46+
if (Error Err = Base::forEachRelaRelocation(RelSect, this,
47+
&Self::addSingleRelocation))
48+
return Err;
49+
}
50+
51+
return Error::success();
52+
}
53+
54+
Error addSingleRelocation(const typename ELFT::Rela &Rel,
55+
const typename ELFT::Shdr &FixupSection,
56+
Block &BlockToFix) {
57+
auto ELFReloc = Rel.getType(false);
58+
return make_error<JITLinkError>(
59+
"In " + G->getName() + ": Unsupported ppc64 relocation type " +
60+
object::getELFRelocationTypeName(ELF::EM_PPC64, ELFReloc));
61+
}
62+
63+
public:
64+
ELFLinkGraphBuilder_ppc64(StringRef FileName,
65+
const object::ELFFile<ELFT> &Obj, Triple TT,
66+
LinkGraph::FeatureVector Features)
67+
: ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),
68+
FileName, ppc64::getEdgeKindName) {}
69+
};
70+
71+
template <support::endianness Endianness>
72+
class ELFJITLinker_ppc64 : public JITLinker<ELFJITLinker_ppc64<Endianness>> {
73+
using JITLinkerBase = JITLinker<ELFJITLinker_ppc64<Endianness>>;
74+
friend JITLinkerBase;
75+
76+
public:
77+
ELFJITLinker_ppc64(std::unique_ptr<JITLinkContext> Ctx,
78+
std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
79+
: JITLinkerBase(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
80+
81+
private:
82+
Symbol *GOTSymbol = nullptr;
83+
84+
Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
85+
return ppc64::applyFixup(G, B, E, GOTSymbol);
86+
}
87+
};
88+
89+
template <support::endianness Endianness>
90+
Expected<std::unique_ptr<LinkGraph>>
91+
createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) {
92+
LLVM_DEBUG({
93+
dbgs() << "Building jitlink graph for new input "
94+
<< ObjectBuffer.getBufferIdentifier() << "...\n";
95+
});
96+
97+
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
98+
if (!ELFObj)
99+
return ELFObj.takeError();
100+
101+
auto Features = (*ELFObj)->getFeatures();
102+
if (!Features)
103+
return Features.takeError();
104+
105+
using ELFT = object::ELFType<Endianness, true>;
106+
auto &ELFObjFile = cast<object::ELFObjectFile<ELFT>>(**ELFObj);
107+
return ELFLinkGraphBuilder_ppc64<Endianness>(
108+
(*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
109+
(*ELFObj)->makeTriple(), Features->getFeatures())
110+
.buildGraph();
111+
}
112+
113+
template <support::endianness Endianness>
114+
void link_ELF_ppc64(std::unique_ptr<LinkGraph> G,
115+
std::unique_ptr<JITLinkContext> Ctx) {
116+
PassConfiguration Config;
117+
118+
if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
119+
// Construct a JITLinker and run the link function.
120+
// Add a mark-live pass.
121+
if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
122+
Config.PrePrunePasses.push_back(std::move(MarkLive));
123+
else
124+
Config.PrePrunePasses.push_back(markAllSymbolsLive);
125+
}
126+
127+
if (auto Err = Ctx->modifyPassConfig(*G, Config))
128+
return Ctx->notifyFailed(std::move(Err));
129+
130+
ELFJITLinker_ppc64<Endianness>::link(std::move(Ctx), std::move(G),
131+
std::move(Config));
132+
}
133+
134+
Expected<std::unique_ptr<LinkGraph>>
135+
createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) {
136+
return createLinkGraphFromELFObject_ppc64<support::big>(
137+
std::move(ObjectBuffer));
138+
}
139+
140+
Expected<std::unique_ptr<LinkGraph>>
141+
createLinkGraphFromELFObject_ppc64le(MemoryBufferRef ObjectBuffer) {
142+
return createLinkGraphFromELFObject_ppc64<support::little>(
143+
std::move(ObjectBuffer));
144+
}
145+
146+
/// jit-link the given object buffer, which must be a ELF ppc64 object file.
147+
void link_ELF_ppc64(std::unique_ptr<LinkGraph> G,
148+
std::unique_ptr<JITLinkContext> Ctx) {
149+
return link_ELF_ppc64<support::big>(std::move(G), std::move(Ctx));
150+
}
151+
152+
/// jit-link the given object buffer, which must be a ELF ppc64le object file.
153+
void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G,
154+
std::unique_ptr<JITLinkContext> Ctx) {
155+
return link_ELF_ppc64<support::little>(std::move(G), std::move(Ctx));
156+
}
157+
158+
} // end namespace llvm::jitlink
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----- ppc64.cpp - Generic JITLink ppc64 edge kinds, utilities ------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Generic utilities for graphs representing 64-bit PowerPC objects.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/ExecutionEngine/JITLink/ppc64.h"
14+
15+
#define DEBUG_TYPE "jitlink"
16+
17+
namespace llvm::jitlink::ppc64 {
18+
19+
const char *getEdgeKindName(Edge::Kind K) {
20+
// TODO: Add edge names.
21+
switch (K) {
22+
default:
23+
return getGenericEdgeKindName(static_cast<Edge::Kind>(K));
24+
}
25+
}
26+
27+
} // end namespace llvm::jitlink::ppc64
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
if not 'PowerPC' in config.root.targets:
2+
config.unsupported = True
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# RUN: llvm-mc -triple=powerpc64le-unknown-linux-gnu -filetype=obj -o %t %s
2+
# RUN: llvm-jitlink -noexec %t
3+
#
4+
# Check that a program that just returns immediately from main (requiring no
5+
# relocations at all) loads under llvm-jitlink.
6+
7+
.text
8+
.abiversion 2
9+
.file "ppc64le-no-relocs.c"
10+
.globl main
11+
.p2align 4
12+
.type main,@function
13+
main:
14+
.Lfunc_begin0:
15+
li 3, 0
16+
blr
17+
.long 0
18+
.quad 0
19+
.Lfunc_end0:
20+
.size main, .Lfunc_end0-.Lfunc_begin0

0 commit comments

Comments
 (0)