LLVM 22.0.0git
ELF_systemz.cpp
Go to the documentation of this file.
1//===----- ELF_systemz.cpp - JIT linker implementation for ELF/systemz ----===//
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/systemz jit-link implementation.
10//
11//===----------------------------------------------------------------------===//
12
16
18#include "EHFrameSupportImpl.h"
19#include "ELFLinkGraphBuilder.h"
20#include "JITLinkGeneric.h"
21
22#define DEBUG_TYPE "jitlink"
23
24using namespace llvm;
25using namespace llvm::jitlink;
26
27namespace {
28
29constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
30
31Error buildTables_ELF_systemz(LinkGraph &G) {
32 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
35 visitExistingEdges(G, GOT, PLT);
36 return Error::success();
37}
38
39} // namespace
40
41namespace llvm {
42namespace jitlink {
43class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {
44 friend class JITLinker<ELFJITLinker_systemz>;
45
46public:
47 ELFJITLinker_systemz(std::unique_ptr<JITLinkContext> Ctx,
48 std::unique_ptr<LinkGraph> G,
49 PassConfiguration PassConfig)
50 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
51 if (shouldAddDefaultTargetPasses(getGraph().getTargetTriple()))
52 getPassConfig().PostAllocationPasses.push_back(
53 [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
54 }
55
56private:
57 Symbol *GOTSymbol = nullptr;
58
59 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
60 return systemz::applyFixup(G, B, E, GOTSymbol);
61 }
62
63 Error getOrCreateGOTSymbol(LinkGraph &G) {
64 auto DefineExternalGOTSymbolIfPresent =
66 [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
67 if (Sym.getName() != nullptr &&
68 *Sym.getName() == ELFGOTSymbolName)
69 if (auto *GOTSection = G.findSectionByName(
71 GOTSymbol = &Sym;
72 return {*GOTSection, true};
73 }
74 return {};
75 });
76
77 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
78 // external.
79 if (auto Err = DefineExternalGOTSymbolIfPresent(G))
80 return Err;
81
82 // If we succeeded then we're done.
83 if (GOTSymbol)
84 return Error::success();
85
86 // Otherwise look for a GOT section: If it already has a start symbol we'll
87 // record it, otherwise we'll create our own.
88 // If there's a GOT section but we didn't find an external GOT symbol...
89 if (auto *GOTSection =
90 G.findSectionByName(systemz::GOTTableManager::getSectionName())) {
91
92 // Check for an existing defined symbol.
93 for (auto *Sym : GOTSection->symbols())
94 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
95 GOTSymbol = Sym;
96 return Error::success();
97 }
98
99 // If there's no defined symbol then create one.
100 SectionRange SR(*GOTSection);
101 if (SR.empty())
102 GOTSymbol =
103 &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
105 else
106 GOTSymbol =
107 &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
108 Linkage::Strong, Scope::Local, false, true);
109 }
110
111 // If we still haven't found a GOT symbol then double check the externals.
112 // We may have a GOT-relative reference but no GOT section, in which case
113 // we just need to point the GOT symbol at some address in this graph.
114 if (!GOTSymbol) {
115 for (auto *Sym : G.external_symbols()) {
116 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
117 auto Blocks = G.blocks();
118 if (!Blocks.empty()) {
119 G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());
120 GOTSymbol = Sym;
121 break;
122 }
123 }
124 }
125 }
126
127 return Error::success();
128 }
129};
130
132 : public ELFLinkGraphBuilder<object::ELF64BE> {
133private:
134 using ELFT = object::ELF64BE;
135 using Base = ELFLinkGraphBuilder<ELFT>;
136 using Base::G; // Use LinkGraph pointer from base class.
137
138 Error addRelocations() override {
139 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
140
141 using Base = ELFLinkGraphBuilder<ELFT>;
142 using Self = ELFLinkGraphBuilder_systemz;
143 for (const auto &RelSect : Base::Sections) {
144 if (RelSect.sh_type == ELF::SHT_REL)
145 // Validate the section to read relocation entries from.
146 return make_error<StringError>("No SHT_REL in valid " +
147 G->getTargetTriple().getArchName() +
148 " ELF object files",
150
151 if (Error Err = Base::forEachRelaRelocation(RelSect, this,
152 &Self::addSingleRelocation))
153 return Err;
154 }
155
156 return Error::success();
157 }
158
159 Error addSingleRelocation(const typename ELFT::Rela &Rel,
160 const typename ELFT::Shdr &FixupSect,
161 Block &BlockToFix) {
162 using support::big32_t;
163 using Base = ELFLinkGraphBuilder<ELFT>;
164 auto ELFReloc = Rel.getType(false);
165
166 // No reloc.
167 if (LLVM_UNLIKELY(ELFReloc == ELF::R_390_NONE))
168 return Error::success();
169
170 uint32_t SymbolIndex = Rel.getSymbol(false);
171 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
172 if (!ObjSymbol)
173 return ObjSymbol.takeError();
174
175 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
176 if (!GraphSymbol)
178 formatv("Could not find symbol at given index, did you add it to "
179 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
180 SymbolIndex, (*ObjSymbol)->st_shndx,
181 Base::GraphSymbols.size()),
183
184 // Validate the relocation kind.
185 int64_t Addend = Rel.r_addend;
186 Edge::Kind Kind = Edge::Invalid;
187
188 switch (ELFReloc) {
189 case ELF::R_390_PC64: {
190 Kind = systemz::Delta64;
191 break;
192 }
193 case ELF::R_390_PC32: {
194 Kind = systemz::Delta32;
195 break;
196 }
197 case ELF::R_390_PC16: {
198 Kind = systemz::Delta16;
199 break;
200 }
201 case ELF::R_390_PC32DBL: {
202 Kind = systemz::Delta32dbl;
203 break;
204 }
205 case ELF::R_390_PC24DBL: {
206 Kind = systemz::Delta24dbl;
207 break;
208 }
209 case ELF::R_390_PC16DBL: {
210 Kind = systemz::Delta16dbl;
211 break;
212 }
213 case ELF::R_390_PC12DBL: {
214 Kind = systemz::Delta12dbl;
215 break;
216 }
217 case ELF::R_390_64: {
218 Kind = systemz::Pointer64;
219 break;
220 }
221 case ELF::R_390_32: {
222 Kind = systemz::Pointer32;
223 break;
224 }
225 case ELF::R_390_20: {
226 Kind = systemz::Pointer20;
227 break;
228 }
229 case ELF::R_390_16: {
230 Kind = systemz::Pointer16;
231 break;
232 }
233 case ELF::R_390_12: {
234 Kind = systemz::Pointer12;
235 break;
236 }
237 case ELF::R_390_8: {
238 Kind = systemz::Pointer8;
239 break;
240 }
241 // Relocations targeting the PLT associated with the symbol.
242 case ELF::R_390_PLT64: {
243 Kind = systemz::DeltaPLT64;
244 break;
245 }
246 case ELF::R_390_PLT32: {
247 Kind = systemz::DeltaPLT32;
248 break;
249 }
250 case ELF::R_390_PLT32DBL: {
252 break;
253 }
254 case ELF::R_390_PLT24DBL: {
256 break;
257 }
258 case ELF::R_390_PLT16DBL: {
260 break;
261 }
262 case ELF::R_390_PLT12DBL: {
264 break;
265 }
266 case ELF::R_390_PLTOFF64: {
268 break;
269 }
270 case ELF::R_390_PLTOFF32: {
272 break;
273 }
274 case ELF::R_390_PLTOFF16: {
276 break;
277 }
278 // Relocations targeting the actual symbol (just relative to the GOT).
279 case ELF::R_390_GOTOFF64: {
281 break;
282 }
283 case ELF::R_390_GOTOFF: {
285 break;
286 }
287 case ELF::R_390_GOTOFF16: {
289 break;
290 }
291 // Relocations targeting the GOT entry associated with the symbol.
292 case ELF::R_390_GOT64:
293 case ELF::R_390_GOTPLT64: {
295 break;
296 }
297 case ELF::R_390_GOT32:
298 case ELF::R_390_GOTPLT32: {
300 break;
301 }
302 case ELF::R_390_GOT20:
303 case ELF::R_390_GOTPLT20: {
305 break;
306 }
307 case ELF::R_390_GOT16:
308 case ELF::R_390_GOTPLT16: {
310 break;
311 }
312 case ELF::R_390_GOT12:
313 case ELF::R_390_GOTPLT12: {
315 break;
316 }
317 case ELF::R_390_GOTENT:
318 case ELF::R_390_GOTPLTENT: {
320 break;
321 }
322 // R_390_GOTPC and R_390_GOTPCDBL don't create GOT entry, they don't even
323 // have symbol.
324 case ELF::R_390_GOTPC: {
326 break;
327 }
328 case ELF::R_390_GOTPCDBL: {
330 break;
331 }
332 default:
334 "In " + G->getName() + ": Unsupported systemz relocation type " +
336 }
337 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
338 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
339 Edge GE(Kind, Offset, *GraphSymbol, Addend);
340 LLVM_DEBUG({
341 dbgs() << " ";
342 printEdge(dbgs(), BlockToFix, GE, systemz::getEdgeKindName(Kind));
343 dbgs() << "\n";
344 });
345
346 BlockToFix.addEdge(std::move(GE));
347
348 return Error::success();
349 }
350
351public:
354 std::shared_ptr<orc::SymbolStringPool> SSP,
355 Triple TT, SubtargetFeatures Features)
356 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
357 std::move(Features), FileName,
358 systemz::getEdgeKindName) {}
359};
360
362 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
363 LLVM_DEBUG({
364 dbgs() << "Building jitlink graph for new input "
365 << ObjectBuffer.getBufferIdentifier() << "...\n";
366 });
367
368 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
369 if (!ELFObj)
370 return ELFObj.takeError();
371
372 auto Features = (*ELFObj)->getFeatures();
373 if (!Features)
374 return Features.takeError();
375
376 assert((*ELFObj)->getArch() == Triple::systemz &&
377 "Only SystemZ is supported");
378
379 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj);
381 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
382 (*ELFObj)->makeTriple(), std::move(*Features))
383 .buildGraph();
384}
385
386void link_ELF_systemz(std::unique_ptr<LinkGraph> G,
387 std::unique_ptr<JITLinkContext> Ctx) {
388 PassConfiguration Config;
389 const Triple &TT = G->getTargetTriple();
390 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
391 // Add eh-frame passes.
392 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
393 Config.PrePrunePasses.push_back(
394 EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), systemz::Pointer32,
397 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
398
399 // Add a mark-live pass.
400 if (auto MarkLive = Ctx->getMarkLivePass(TT))
401 Config.PrePrunePasses.push_back(std::move(MarkLive));
402 else
403 Config.PrePrunePasses.push_back(markAllSymbolsLive);
404
405 // Add an in-place GOT/Stubs build pass.
406 Config.PostPrunePasses.push_back(buildTables_ELF_systemz);
407
408 // Resolve any external section start / end symbols.
409 Config.PostAllocationPasses.push_back(
412
413 // TODO: Add GOT/Stubs optimizer pass.
414 // Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);
415 }
416
417 if (auto Err = Ctx->modifyPassConfig(*G, Config))
418 return Ctx->notifyFailed(std::move(Err));
419
420 ELFJITLinker_systemz::link(std::move(Ctx), std::move(G), std::move(Config));
421}
422
423} // namespace jitlink
424} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:336
#define G(x, y, z)
Definition MD5.cpp:55
#define LLVM_DEBUG(...)
Definition Debug.h:114
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
StringRef getBufferIdentifier() const
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Represents an address in the executor process.
@ EM_S390
Definition ELF.h:155
@ SHT_REL
Definition ELF.h:1155
LLVM_ABI StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type)
Definition ELF.cpp:25
ELFType< llvm::endianness::big, true > ELF64BE
Definition ELFTypes.h:101
detail::packed_endian_specific_integral< int32_t, llvm::endianness::big, unaligned > big32_t
Definition Endian.h:340
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1867
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867
Elf_Rel_Impl< ELFType< E, Is64 >, true > Rela
Definition ELFTypes.h:66
Elf_Shdr_Impl< ELFType< E, Is64 > > Shdr
Definition ELFTypes.h:61