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_";
30constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
31
32// TLS Info Builder.
33class TLSInfoTableManager_ELF_systemz
34 : public TableManager<TLSInfoTableManager_ELF_systemz> {
35public:
36 static StringRef getSectionName() { return ELFTLSInfoSectionName; }
37
38 static const uint8_t TLSInfoEntryContent[16];
39
40 bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
41 if (E.getKind() ==
44 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
45 << formatv("{0:x}", B->getFixupAddress(E)) << " ("
46 << formatv("{0:x}", B->getAddress()) << " + "
47 << formatv("{0:x}", E.getOffset()) << ")\n";
48 });
50 E.setTarget(getEntryForTarget(G, E.getTarget()));
51 return true;
52 }
53 return false;
54 }
55
56 Symbol &createEntry(LinkGraph &G, Symbol &Target) {
57 // the TLS Info entry's key value will be written by the fixTLVSectionByName
58 // pass, so create mutable content.
59 auto &TLSInfoEntry = G.createMutableContentBlock(
60 getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
61 orc::ExecutorAddr(), 8, 0);
62 TLSInfoEntry.addEdge(systemz::Pointer64, 8, Target, 0);
63 return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
64 }
65
66private:
67 Section &getTLSInfoSection(LinkGraph &G) {
68 if (!TLSInfoTable)
69 TLSInfoTable = &G.createSection(getSectionName(), orc::MemProt::Read);
70 return *TLSInfoTable;
71 }
72
73 ArrayRef<char> getTLSInfoEntryContent() const {
74 return {reinterpret_cast<const char *>(TLSInfoEntryContent),
75 sizeof(TLSInfoEntryContent)};
76 }
77
78 Section *TLSInfoTable = nullptr;
79};
80
81const uint8_t TLSInfoTableManager_ELF_systemz::TLSInfoEntryContent[16] = {
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
84
85Error buildTables_ELF_systemz(LinkGraph &G) {
86 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
89 TLSInfoTableManager_ELF_systemz TLSInfo;
90 visitExistingEdges(G, GOT, PLT, TLSInfo);
91 return Error::success();
92}
93
94} // namespace
95
96namespace llvm {
97namespace jitlink {
98class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {
99 friend class JITLinker<ELFJITLinker_systemz>;
100
101public:
102 ELFJITLinker_systemz(std::unique_ptr<JITLinkContext> Ctx,
103 std::unique_ptr<LinkGraph> G,
104 PassConfiguration PassConfig)
105 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
106 if (shouldAddDefaultTargetPasses(getGraph().getTargetTriple()))
107 getPassConfig().PostAllocationPasses.push_back(
108 [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
109 }
110
111private:
112 Symbol *GOTSymbol = nullptr;
113
114 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
115 return systemz::applyFixup(G, B, E, GOTSymbol);
116 }
117
118 Error getOrCreateGOTSymbol(LinkGraph &G) {
119 auto DefineExternalGOTSymbolIfPresent =
121 [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
122 if (Sym.getName() != nullptr &&
123 *Sym.getName() == ELFGOTSymbolName)
124 if (auto *GOTSection = G.findSectionByName(
126 GOTSymbol = &Sym;
127 return {*GOTSection, true};
128 }
129 return {};
130 });
131
132 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
133 // external.
134 if (auto Err = DefineExternalGOTSymbolIfPresent(G))
135 return Err;
136
137 // If we succeeded then we're done.
138 if (GOTSymbol)
139 return Error::success();
140
141 // Otherwise look for a GOT section: If it already has a start symbol we'll
142 // record it, otherwise we'll create our own.
143 // If there's a GOT section but we didn't find an external GOT symbol...
144 if (auto *GOTSection =
145 G.findSectionByName(systemz::GOTTableManager::getSectionName())) {
146
147 // Check for an existing defined symbol.
148 for (auto *Sym : GOTSection->symbols())
149 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
150 GOTSymbol = Sym;
151 return Error::success();
152 }
153
154 // If there's no defined symbol then create one.
155 SectionRange SR(*GOTSection);
156 if (SR.empty())
157 GOTSymbol =
158 &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
160 else
161 GOTSymbol =
162 &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
163 Linkage::Strong, Scope::Local, false, true);
164 }
165
166 // If we still haven't found a GOT symbol then double check the externals.
167 // We may have a GOT-relative reference but no GOT section, in which case
168 // we just need to point the GOT symbol at some address in this graph.
169 if (!GOTSymbol) {
170 for (auto *Sym : G.external_symbols()) {
171 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
172 auto Blocks = G.blocks();
173 if (!Blocks.empty()) {
174 G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());
175 GOTSymbol = Sym;
176 break;
177 }
178 }
179 }
180 }
181
182 return Error::success();
183 }
184};
185
187 : public ELFLinkGraphBuilder<object::ELF64BE> {
188private:
189 using ELFT = object::ELF64BE;
190 using Base = ELFLinkGraphBuilder<ELFT>;
191 using Base::G; // Use LinkGraph pointer from base class.
192
193 Error addRelocations() override {
194 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
195
196 using Base = ELFLinkGraphBuilder<ELFT>;
197 using Self = ELFLinkGraphBuilder_systemz;
198 for (const auto &RelSect : Base::Sections) {
199 if (RelSect.sh_type == ELF::SHT_REL)
200 // Validate the section to read relocation entries from.
201 return make_error<StringError>("No SHT_REL in valid " +
202 G->getTargetTriple().getArchName() +
203 " ELF object files",
205
206 if (Error Err = Base::forEachRelaRelocation(RelSect, this,
207 &Self::addSingleRelocation))
208 return Err;
209 }
210
211 return Error::success();
212 }
213
214 Error addSingleRelocation(const typename ELFT::Rela &Rel,
215 const typename ELFT::Shdr &FixupSect,
216 Block &BlockToFix) {
217 using support::big32_t;
218 using Base = ELFLinkGraphBuilder<ELFT>;
219 auto ELFReloc = Rel.getType(false);
220
221 // No reloc.
222 if (LLVM_UNLIKELY(ELFReloc == ELF::R_390_NONE))
223 return Error::success();
224
225 uint32_t SymbolIndex = Rel.getSymbol(false);
226 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
227 if (!ObjSymbol)
228 return ObjSymbol.takeError();
229
230 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
231 if (!GraphSymbol)
233 formatv("Could not find symbol at given index, did you add it to "
234 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
235 SymbolIndex, (*ObjSymbol)->st_shndx,
236 Base::GraphSymbols.size()),
238
239 // Validate the relocation kind.
240 int64_t Addend = Rel.r_addend;
241 Edge::Kind Kind = Edge::Invalid;
242
243 switch (ELFReloc) {
244 case ELF::R_390_PC64: {
245 Kind = systemz::Delta64;
246 break;
247 }
248 case ELF::R_390_PC32: {
249 Kind = systemz::Delta32;
250 break;
251 }
252 case ELF::R_390_PC16: {
253 Kind = systemz::Delta16;
254 break;
255 }
256 case ELF::R_390_PC32DBL: {
257 Kind = systemz::Delta32dbl;
258 break;
259 }
260 case ELF::R_390_PC24DBL: {
261 Kind = systemz::Delta24dbl;
262 break;
263 }
264 case ELF::R_390_PC16DBL: {
265 Kind = systemz::Delta16dbl;
266 break;
267 }
268 case ELF::R_390_PC12DBL: {
269 Kind = systemz::Delta12dbl;
270 break;
271 }
272 case ELF::R_390_64: {
273 Kind = systemz::Pointer64;
274 break;
275 }
276 case ELF::R_390_32: {
277 Kind = systemz::Pointer32;
278 break;
279 }
280 case ELF::R_390_20: {
281 Kind = systemz::Pointer20;
282 break;
283 }
284 case ELF::R_390_16: {
285 Kind = systemz::Pointer16;
286 break;
287 }
288 case ELF::R_390_12: {
289 Kind = systemz::Pointer12;
290 break;
291 }
292 case ELF::R_390_8: {
293 Kind = systemz::Pointer8;
294 break;
295 }
296 // Relocations targeting the PLT associated with the symbol.
297 case ELF::R_390_PLT64: {
298 Kind = systemz::DeltaPLT64;
299 break;
300 }
301 case ELF::R_390_PLT32: {
302 Kind = systemz::DeltaPLT32;
303 break;
304 }
305 case ELF::R_390_PLT32DBL: {
307 break;
308 }
309 case ELF::R_390_PLT24DBL: {
311 break;
312 }
313 case ELF::R_390_PLT16DBL: {
315 break;
316 }
317 case ELF::R_390_PLT12DBL: {
319 break;
320 }
321 case ELF::R_390_PLTOFF64: {
323 break;
324 }
325 case ELF::R_390_PLTOFF32: {
327 break;
328 }
329 case ELF::R_390_PLTOFF16: {
331 break;
332 }
333 // Relocations targeting the actual symbol (just relative to the GOT).
334 case ELF::R_390_GOTOFF64: {
336 break;
337 }
338 case ELF::R_390_GOTOFF: {
340 break;
341 }
342 case ELF::R_390_GOTOFF16: {
344 break;
345 }
346 // Relocations targeting the GOT entry associated with the symbol.
347 case ELF::R_390_GOT64:
348 case ELF::R_390_GOTPLT64: {
350 break;
351 }
352 case ELF::R_390_GOT32:
353 case ELF::R_390_GOTPLT32: {
355 break;
356 }
357 case ELF::R_390_GOT20:
358 case ELF::R_390_GOTPLT20: {
360 break;
361 }
362 case ELF::R_390_GOT16:
363 case ELF::R_390_GOTPLT16: {
365 break;
366 }
367 case ELF::R_390_GOT12:
368 case ELF::R_390_GOTPLT12: {
370 break;
371 }
372 case ELF::R_390_GOTENT:
373 case ELF::R_390_GOTPLTENT: {
375 break;
376 }
377 // R_390_GOTPC and R_390_GOTPCDBL don't create GOT entry, they don't even
378 // have symbol.
379 case ELF::R_390_GOTPC: {
381 break;
382 }
383 case ELF::R_390_GOTPCDBL: {
385 break;
386 }
387 // Tag for function call in general dynamic TLS code.
388 case ELF::R_390_TLS_GDCALL: {
389 break;
390 }
391 // Direct 64 bit for general dynamic thread local data.
392 case ELF::R_390_TLS_GD64: {
394 break;
395 }
396 default:
398 "In " + G->getName() + ": Unsupported systemz relocation type " +
400 }
401 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
402 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
403 Edge GE(Kind, Offset, *GraphSymbol, Addend);
404 LLVM_DEBUG({
405 dbgs() << " ";
406 printEdge(dbgs(), BlockToFix, GE, systemz::getEdgeKindName(Kind));
407 dbgs() << "\n";
408 });
409
410 BlockToFix.addEdge(std::move(GE));
411
412 return Error::success();
413 }
414
415public:
418 std::shared_ptr<orc::SymbolStringPool> SSP,
419 Triple TT, SubtargetFeatures Features)
420 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
421 std::move(Features), FileName,
422 systemz::getEdgeKindName) {}
423};
424
426 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
427 LLVM_DEBUG({
428 dbgs() << "Building jitlink graph for new input "
429 << ObjectBuffer.getBufferIdentifier() << "...\n";
430 });
431
432 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
433 if (!ELFObj)
434 return ELFObj.takeError();
435
436 auto Features = (*ELFObj)->getFeatures();
437 if (!Features)
438 return Features.takeError();
439
440 assert((*ELFObj)->getArch() == Triple::systemz &&
441 "Only SystemZ is supported");
442
443 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj);
445 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
446 (*ELFObj)->makeTriple(), std::move(*Features))
447 .buildGraph();
448}
449
450void link_ELF_systemz(std::unique_ptr<LinkGraph> G,
451 std::unique_ptr<JITLinkContext> Ctx) {
452 PassConfiguration Config;
453 const Triple &TT = G->getTargetTriple();
454 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
455 // Add eh-frame passes.
456 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
457 Config.PrePrunePasses.push_back(
458 EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), systemz::Pointer32,
461 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
462
463 // Add a mark-live pass.
464 if (auto MarkLive = Ctx->getMarkLivePass(TT))
465 Config.PrePrunePasses.push_back(std::move(MarkLive));
466 else
467 Config.PrePrunePasses.push_back(markAllSymbolsLive);
468
469 // Add an in-place GOT/Stubs build pass.
470 Config.PostPrunePasses.push_back(buildTables_ELF_systemz);
471
472 // Resolve any external section start / end symbols.
473 Config.PostAllocationPasses.push_back(
476
477 // TODO: Add GOT/Stubs optimizer pass.
478 // Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);
479 }
480
481 if (auto Err = Ctx->modifyPassConfig(*G, Config))
482 return Ctx->notifyFailed(std::move(Err));
483
484 ELFJITLinker_systemz::link(std::move(Ctx), std::move(G), std::move(Config));
485}
486
487} // namespace jitlink
488} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
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.
Target - Wrapper for Target specific information.
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
static constexpr const StringLiteral & getSectionName(DebugSectionKind SectionKind)
Return the name of the section.
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:532
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:1915
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:870
Elf_Rel_Impl< ELFType< E, Is64 >, true > Rela
Definition ELFTypes.h:66
Elf_Shdr_Impl< ELFType< E, Is64 > > Shdr
Definition ELFTypes.h:61