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
13#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
14#include "llvm/ExecutionEngine/JITLink/systemz.h"
15#include "llvm/Object/ELFObjectFile.h"
16
17#include "DefineExternalSectionStartAndEndSymbols.h"
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() ==
42 systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT) {
43 LLVM_DEBUG({
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 });
49 E.setKind(systemz::Delta64FromGOT);
50 E.setTarget(getEntryForTarget(G, Target&: 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 Parent&: getTLSInfoSection(G), MutableContent: G.allocateContent(Source: getTLSInfoEntryContent()),
61 Address: orc::ExecutorAddr(), Alignment: 8, AlignmentOffset: 0);
62 TLSInfoEntry.addEdge(K: systemz::Pointer64, Offset: 8, Target, Addend: 0);
63 return G.addAnonymousSymbol(Content&: TLSInfoEntry, Offset: 0, Size: 16, IsCallable: false, IsLive: false);
64 }
65
66private:
67 Section &getTLSInfoSection(LinkGraph &G) {
68 if (!TLSInfoTable)
69 TLSInfoTable = &G.createSection(Name: getSectionName(), Prot: 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");
87 systemz::GOTTableManager GOT;
88 systemz::PLTTableManager PLT(GOT);
89 TLSInfoTableManager_ELF_systemz TLSInfo;
90 visitExistingEdges(G, Vs&: GOT, Vs&: PLT, Vs&: 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(TT: getGraph().getTargetTriple()))
107 getPassConfig().PostAllocationPasses.push_back(
108 x: [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 =
120 createDefineExternalSectionStartAndEndSymbolsPass(
121 F: [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
122 if (Sym.getName() != nullptr &&
123 *Sym.getName() == ELFGOTSymbolName)
124 if (auto *GOTSection = G.findSectionByName(
125 Name: systemz::GOTTableManager::getSectionName())) {
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(Name: 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(Name: ELFGOTSymbolName, Address: orc::ExecutorAddr(), Size: 0,
159 L: Linkage::Strong, S: Scope::Local, IsLive: true);
160 else
161 GOTSymbol =
162 &G.addDefinedSymbol(Content&: *SR.getFirstBlock(), Offset: 0, Name: ELFGOTSymbolName, Size: 0,
163 L: Linkage::Strong, S: Scope::Local, IsCallable: false, IsLive: 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&: *Sym, Address: (*Blocks.begin())->getAddress());
175 GOTSymbol = Sym;
176 break;
177 }
178 }
179 }
180 }
181
182 return Error::success();
183 }
184};
185
186class ELFLinkGraphBuilder_systemz
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>(Args: "No SHT_REL in valid " +
202 G->getTargetTriple().getArchName() +
203 " ELF object files",
204 Args: inconvertibleErrorCode());
205
206 if (Error Err = Base::forEachRelaRelocation(RelSect, Instance: this,
207 Method: &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(isMips64EL: 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(isMips64EL: false);
226 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, SymTab: Base::SymTabSec);
227 if (!ObjSymbol)
228 return ObjSymbol.takeError();
229
230 Symbol *GraphSymbol = Base::getGraphSymbol(SymIndex: SymbolIndex);
231 if (!GraphSymbol)
232 return make_error<StringError>(
233 Args: formatv(Fmt: "Could not find symbol at given index, did you add it to "
234 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
235 Vals&: SymbolIndex, Vals: (*ObjSymbol)->st_shndx,
236 Vals: Base::GraphSymbols.size()),
237 Args: inconvertibleErrorCode());
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: {
306 Kind = systemz::DeltaPLT32dbl;
307 break;
308 }
309 case ELF::R_390_PLT24DBL: {
310 Kind = systemz::DeltaPLT24dbl;
311 break;
312 }
313 case ELF::R_390_PLT16DBL: {
314 Kind = systemz::DeltaPLT16dbl;
315 break;
316 }
317 case ELF::R_390_PLT12DBL: {
318 Kind = systemz::DeltaPLT12dbl;
319 break;
320 }
321 case ELF::R_390_PLTOFF64: {
322 Kind = systemz::Delta64PLTFromGOT;
323 break;
324 }
325 case ELF::R_390_PLTOFF32: {
326 Kind = systemz::Delta32PLTFromGOT;
327 break;
328 }
329 case ELF::R_390_PLTOFF16: {
330 Kind = systemz::Delta16PLTFromGOT;
331 break;
332 }
333 // Relocations targeting the actual symbol (just relative to the GOT).
334 case ELF::R_390_GOTOFF64: {
335 Kind = systemz::Delta64FromGOT;
336 break;
337 }
338 case ELF::R_390_GOTOFF: {
339 Kind = systemz::Delta32FromGOT;
340 break;
341 }
342 case ELF::R_390_GOTOFF16: {
343 Kind = systemz::Delta16FromGOT;
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: {
349 Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;
350 break;
351 }
352 case ELF::R_390_GOT32:
353 case ELF::R_390_GOTPLT32: {
354 Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;
355 break;
356 }
357 case ELF::R_390_GOT20:
358 case ELF::R_390_GOTPLT20: {
359 Kind = systemz::RequestGOTAndTransformToDelta20FromGOT;
360 break;
361 }
362 case ELF::R_390_GOT16:
363 case ELF::R_390_GOTPLT16: {
364 Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;
365 break;
366 }
367 case ELF::R_390_GOT12:
368 case ELF::R_390_GOTPLT12: {
369 Kind = systemz::RequestGOTAndTransformToDelta12FromGOT;
370 break;
371 }
372 case ELF::R_390_GOTENT:
373 case ELF::R_390_GOTPLTENT: {
374 Kind = systemz::RequestGOTAndTransformToDelta32dbl;
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: {
380 Kind = systemz::Delta32GOTBase;
381 break;
382 }
383 case ELF::R_390_GOTPCDBL: {
384 Kind = systemz::Delta32dblGOTBase;
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: {
393 Kind = systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT;
394 break;
395 }
396 default:
397 return make_error<JITLinkError>(
398 Args: "In " + G->getName() + ": Unsupported systemz relocation type " +
399 object::getELFRelocationTypeName(Machine: ELF::EM_S390, Type: ELFReloc));
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(E: std::move(GE));
411
412 return Error::success();
413 }
414
415public:
416 ELFLinkGraphBuilder_systemz(StringRef FileName,
417 const object::ELFFile<ELFT> &Obj,
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
425Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_systemz(
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(Object: 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>>(Val&: **ELFObj);
444 return ELFLinkGraphBuilder_systemz(
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(x: DWARFRecordSectionSplitter(".eh_frame"));
457 Config.PrePrunePasses.push_back(
458 x: EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), systemz::Pointer32,
459 systemz::Pointer64, systemz::Delta32, systemz::Delta64,
460 systemz::NegDelta32));
461 Config.PrePrunePasses.push_back(x: EHFrameNullTerminator(".eh_frame"));
462
463 // Add a mark-live pass.
464 if (auto MarkLive = Ctx->getMarkLivePass(TT))
465 Config.PrePrunePasses.push_back(x: std::move(MarkLive));
466 else
467 Config.PrePrunePasses.push_back(x: markAllSymbolsLive);
468
469 // Add an in-place GOT/Stubs build pass.
470 Config.PostPrunePasses.push_back(x: buildTables_ELF_systemz);
471
472 // Resolve any external section start / end symbols.
473 Config.PostAllocationPasses.push_back(
474 x: createDefineExternalSectionStartAndEndSymbolsPass(
475 F&: identifyELFSectionStartAndEndSymbols));
476
477 // Add GOT/Stubs optimizer pass.
478 Config.PreFixupPasses.push_back(x: systemz::optimizeGOTAndStubAccesses);
479 }
480
481 if (auto Err = Ctx->modifyPassConfig(G&: *G, Config))
482 return Ctx->notifyFailed(Err: std::move(Err));
483
484 ELFJITLinker_systemz::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(Config));
485}
486
487} // namespace jitlink
488} // namespace llvm
489