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/DWARFRecordSectionSplitter.h" |
15 | #include "llvm/ExecutionEngine/JITLink/TableManager.h" |
16 | #include "llvm/ExecutionEngine/JITLink/ppc64.h" |
17 | #include "llvm/Object/ELFObjectFile.h" |
18 | |
19 | #include "EHFrameSupportImpl.h" |
20 | #include "ELFLinkGraphBuilder.h" |
21 | #include "JITLinkGeneric.h" |
22 | |
23 | #define DEBUG_TYPE "jitlink" |
24 | |
25 | namespace { |
26 | |
27 | using namespace llvm; |
28 | using namespace llvm::jitlink; |
29 | |
30 | constexpr StringRef ELFTOCSymbolName = ".TOC." ; |
31 | constexpr StringRef TOCSymbolAliasIdent = "__TOC__" ; |
32 | constexpr uint64_t ELFTOCBaseOffset = 0x8000; |
33 | constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO" ; |
34 | |
35 | template <llvm::endianness Endianness> |
36 | class TLSInfoTableManager_ELF_ppc64 |
37 | : public TableManager<TLSInfoTableManager_ELF_ppc64<Endianness>> { |
38 | public: |
39 | static const uint8_t TLSInfoEntryContent[16]; |
40 | |
41 | static StringRef getSectionName() { return ELFTLSInfoSectionName; } |
42 | |
43 | bool visitEdge(LinkGraph &G, Block *B, Edge &E) { |
44 | Edge::Kind K = E.getKind(); |
45 | switch (K) { |
46 | case ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA: |
47 | E.setKind(ppc64::TOCDelta16HA); |
48 | E.setTarget(this->getEntryForTarget(G, E.getTarget())); |
49 | return true; |
50 | case ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO: |
51 | E.setKind(ppc64::TOCDelta16LO); |
52 | E.setTarget(this->getEntryForTarget(G, E.getTarget())); |
53 | return true; |
54 | case ppc64::RequestTLSDescInGOTAndTransformToDelta34: |
55 | E.setKind(ppc64::Delta34); |
56 | E.setTarget(this->getEntryForTarget(G, E.getTarget())); |
57 | return true; |
58 | default: |
59 | return false; |
60 | } |
61 | } |
62 | |
63 | Symbol &createEntry(LinkGraph &G, Symbol &Target) { |
64 | // The TLS Info entry's key value will be written by |
65 | // `fixTLVSectionsAndEdges`, so create mutable content. |
66 | auto &TLSInfoEntry = G.createMutableContentBlock( |
67 | getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()), |
68 | orc::ExecutorAddr(), 8, 0); |
69 | TLSInfoEntry.addEdge(ppc64::Pointer64, 8, Target, 0); |
70 | return G.addAnonymousSymbol(Content&: TLSInfoEntry, Offset: 0, Size: 16, IsCallable: false, IsLive: false); |
71 | } |
72 | |
73 | private: |
74 | Section &getTLSInfoSection(LinkGraph &G) { |
75 | if (!TLSInfoTable) |
76 | TLSInfoTable = |
77 | &G.createSection(Name: ELFTLSInfoSectionName, Prot: orc::MemProt::Read); |
78 | return *TLSInfoTable; |
79 | } |
80 | |
81 | ArrayRef<char> getTLSInfoEntryContent() const { |
82 | return {reinterpret_cast<const char *>(TLSInfoEntryContent), |
83 | sizeof(TLSInfoEntryContent)}; |
84 | } |
85 | |
86 | Section *TLSInfoTable = nullptr; |
87 | }; |
88 | |
89 | template <> |
90 | const uint8_t TLSInfoTableManager_ELF_ppc64< |
91 | llvm::endianness::little>::TLSInfoEntryContent[16] = { |
92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ |
93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ |
94 | }; |
95 | |
96 | template <> |
97 | const uint8_t TLSInfoTableManager_ELF_ppc64< |
98 | llvm::endianness::big>::TLSInfoEntryContent[16] = { |
99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ |
100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ |
101 | }; |
102 | |
103 | template <llvm::endianness Endianness> |
104 | Symbol &(LinkGraph &G, |
105 | ppc64::TOCTableManager<Endianness> &TOC) { |
106 | Symbol *TOCSymbol = nullptr; |
107 | |
108 | for (Symbol *Sym : G.defined_symbols()) |
109 | if (LLVM_UNLIKELY(Sym->getName() == ELFTOCSymbolName)) { |
110 | TOCSymbol = Sym; |
111 | break; |
112 | } |
113 | |
114 | if (LLVM_LIKELY(TOCSymbol == nullptr)) { |
115 | for (Symbol *Sym : G.external_symbols()) |
116 | if (Sym->getName() == ELFTOCSymbolName) { |
117 | TOCSymbol = Sym; |
118 | break; |
119 | } |
120 | } |
121 | |
122 | if (!TOCSymbol) |
123 | TOCSymbol = &G.addExternalSymbol(Name: ELFTOCSymbolName, Size: 0, IsWeaklyReferenced: false); |
124 | |
125 | return TOC.getEntryForTarget(G, *TOCSymbol); |
126 | } |
127 | |
128 | // Register preexisting GOT entries with TOC table manager. |
129 | template <llvm::endianness Endianness> |
130 | inline void |
131 | registerExistingGOTEntries(LinkGraph &G, |
132 | ppc64::TOCTableManager<Endianness> &TOC) { |
133 | auto isGOTEntry = [](const Edge &E) { |
134 | return E.getKind() == ppc64::Pointer64 && E.getTarget().isExternal(); |
135 | }; |
136 | if (Section *dotTOCSection = G.findSectionByName(Name: ".toc" )) { |
137 | for (Block *B : dotTOCSection->blocks()) |
138 | for (Edge &E : B->edges()) |
139 | if (isGOTEntry(E)) |
140 | TOC.registerPreExistingEntry(E.getTarget(), |
141 | G.addAnonymousSymbol(Content&: *B, Offset: E.getOffset(), |
142 | Size: G.getPointerSize(), |
143 | IsCallable: false, IsLive: false)); |
144 | } |
145 | } |
146 | |
147 | template <llvm::endianness Endianness> |
148 | Error buildTables_ELF_ppc64(LinkGraph &G) { |
149 | LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n" ); |
150 | ppc64::TOCTableManager<Endianness> TOC; |
151 | // Before visiting edges, we create a header containing the address of TOC |
152 | // base as ELFABIv2 suggests: |
153 | // > The GOT consists of an 8-byte header that contains the TOC base (the |
154 | // first TOC base when multiple TOCs are present), followed by an array of |
155 | // 8-byte addresses. |
156 | createELFGOTHeader(G, TOC); |
157 | |
158 | // There might be compiler-generated GOT entries in ELF relocatable file. |
159 | registerExistingGOTEntries(G, TOC); |
160 | |
161 | ppc64::PLTTableManager<Endianness> PLT(TOC); |
162 | TLSInfoTableManager_ELF_ppc64<Endianness> TLSInfo; |
163 | visitExistingEdges(G, TOC, PLT, TLSInfo); |
164 | |
165 | // After visiting edges in LinkGraph, we have GOT entries built in the |
166 | // synthesized section. |
167 | // Merge sections included in TOC into synthesized TOC section, |
168 | // thus TOC is compact and reducing chances of relocation |
169 | // overflow. |
170 | if (Section *TOCSection = G.findSectionByName(Name: TOC.getSectionName())) { |
171 | // .got and .plt are not normally present in a relocatable object file |
172 | // because they are linker generated. |
173 | if (Section *gotSection = G.findSectionByName(Name: ".got" )) |
174 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *gotSection); |
175 | if (Section *tocSection = G.findSectionByName(Name: ".toc" )) |
176 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *tocSection); |
177 | if (Section *sdataSection = G.findSectionByName(Name: ".sdata" )) |
178 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *sdataSection); |
179 | if (Section *sbssSection = G.findSectionByName(Name: ".sbss" )) |
180 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *sbssSection); |
181 | // .tocbss no longer appears in ELFABIv2. Leave it here to be compatible |
182 | // with rtdyld. |
183 | if (Section *tocbssSection = G.findSectionByName(Name: ".tocbss" )) |
184 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *tocbssSection); |
185 | if (Section *pltSection = G.findSectionByName(Name: ".plt" )) |
186 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *pltSection); |
187 | } |
188 | |
189 | return Error::success(); |
190 | } |
191 | |
192 | } // namespace |
193 | |
194 | namespace llvm::jitlink { |
195 | |
196 | template <llvm::endianness Endianness> |
197 | class ELFLinkGraphBuilder_ppc64 |
198 | : public ELFLinkGraphBuilder<object::ELFType<Endianness, true>> { |
199 | private: |
200 | using ELFT = object::ELFType<Endianness, true>; |
201 | using Base = ELFLinkGraphBuilder<ELFT>; |
202 | |
203 | using Base::G; // Use LinkGraph pointer from base class. |
204 | |
205 | Error addRelocations() override { |
206 | LLVM_DEBUG(dbgs() << "Processing relocations:\n" ); |
207 | |
208 | using Self = ELFLinkGraphBuilder_ppc64<Endianness>; |
209 | for (const auto &RelSect : Base::Sections) { |
210 | // Validate the section to read relocation entries from. |
211 | if (RelSect.sh_type == ELF::SHT_REL) |
212 | return make_error<StringError>("No SHT_REL in valid " + |
213 | G->getTargetTriple().getArchName() + |
214 | " ELF object files" , |
215 | inconvertibleErrorCode()); |
216 | |
217 | if (Error Err = Base::forEachRelaRelocation(RelSect, this, |
218 | &Self::addSingleRelocation)) |
219 | return Err; |
220 | } |
221 | |
222 | return Error::success(); |
223 | } |
224 | |
225 | Error addSingleRelocation(const typename ELFT::Rela &Rel, |
226 | const typename ELFT::Shdr &FixupSection, |
227 | Block &BlockToFix) { |
228 | using Base = ELFLinkGraphBuilder<ELFT>; |
229 | auto ELFReloc = Rel.getType(false); |
230 | |
231 | // R_PPC64_NONE is a no-op. |
232 | if (LLVM_UNLIKELY(ELFReloc == ELF::R_PPC64_NONE)) |
233 | return Error::success(); |
234 | |
235 | // TLS model markers. We only support global-dynamic model now. |
236 | if (ELFReloc == ELF::R_PPC64_TLSGD) |
237 | return Error::success(); |
238 | if (ELFReloc == ELF::R_PPC64_TLSLD) |
239 | return make_error<StringError>(Args: "Local-dynamic TLS model is not supported" , |
240 | Args: inconvertibleErrorCode()); |
241 | |
242 | if (ELFReloc == ELF::R_PPC64_PCREL_OPT) |
243 | // TODO: Support PCREL optimization, now ignore it. |
244 | return Error::success(); |
245 | |
246 | if (ELFReloc == ELF::R_PPC64_TPREL34) |
247 | return make_error<StringError>(Args: "Local-exec TLS model is not supported" , |
248 | Args: inconvertibleErrorCode()); |
249 | |
250 | auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); |
251 | if (!ObjSymbol) |
252 | return ObjSymbol.takeError(); |
253 | |
254 | uint32_t SymbolIndex = Rel.getSymbol(false); |
255 | Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); |
256 | if (!GraphSymbol) |
257 | return make_error<StringError>( |
258 | formatv("Could not find symbol at given index, did you add it to " |
259 | "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}" , |
260 | SymbolIndex, (*ObjSymbol)->st_shndx, |
261 | Base::GraphSymbols.size()), |
262 | inconvertibleErrorCode()); |
263 | |
264 | int64_t Addend = Rel.r_addend; |
265 | orc::ExecutorAddr FixupAddress = |
266 | orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset; |
267 | Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); |
268 | Edge::Kind Kind = Edge::Invalid; |
269 | |
270 | switch (ELFReloc) { |
271 | default: |
272 | return make_error<JITLinkError>( |
273 | "In " + G->getName() + ": Unsupported ppc64 relocation type " + |
274 | object::getELFRelocationTypeName(Machine: ELF::EM_PPC64, Type: ELFReloc)); |
275 | case ELF::R_PPC64_ADDR64: |
276 | Kind = ppc64::Pointer64; |
277 | break; |
278 | case ELF::R_PPC64_ADDR32: |
279 | Kind = ppc64::Pointer32; |
280 | break; |
281 | case ELF::R_PPC64_ADDR16: |
282 | Kind = ppc64::Pointer16; |
283 | break; |
284 | case ELF::R_PPC64_ADDR16_DS: |
285 | Kind = ppc64::Pointer16DS; |
286 | break; |
287 | case ELF::R_PPC64_ADDR16_HA: |
288 | Kind = ppc64::Pointer16HA; |
289 | break; |
290 | case ELF::R_PPC64_ADDR16_HI: |
291 | Kind = ppc64::Pointer16HI; |
292 | break; |
293 | case ELF::R_PPC64_ADDR16_HIGH: |
294 | Kind = ppc64::Pointer16HIGH; |
295 | break; |
296 | case ELF::R_PPC64_ADDR16_HIGHA: |
297 | Kind = ppc64::Pointer16HIGHA; |
298 | break; |
299 | case ELF::R_PPC64_ADDR16_HIGHER: |
300 | Kind = ppc64::Pointer16HIGHER; |
301 | break; |
302 | case ELF::R_PPC64_ADDR16_HIGHERA: |
303 | Kind = ppc64::Pointer16HIGHERA; |
304 | break; |
305 | case ELF::R_PPC64_ADDR16_HIGHEST: |
306 | Kind = ppc64::Pointer16HIGHEST; |
307 | break; |
308 | case ELF::R_PPC64_ADDR16_HIGHESTA: |
309 | Kind = ppc64::Pointer16HIGHESTA; |
310 | break; |
311 | case ELF::R_PPC64_ADDR16_LO: |
312 | Kind = ppc64::Pointer16LO; |
313 | break; |
314 | case ELF::R_PPC64_ADDR16_LO_DS: |
315 | Kind = ppc64::Pointer16LODS; |
316 | break; |
317 | case ELF::R_PPC64_ADDR14: |
318 | Kind = ppc64::Pointer14; |
319 | break; |
320 | case ELF::R_PPC64_TOC: |
321 | Kind = ppc64::TOC; |
322 | break; |
323 | case ELF::R_PPC64_TOC16: |
324 | Kind = ppc64::TOCDelta16; |
325 | break; |
326 | case ELF::R_PPC64_TOC16_HA: |
327 | Kind = ppc64::TOCDelta16HA; |
328 | break; |
329 | case ELF::R_PPC64_TOC16_HI: |
330 | Kind = ppc64::TOCDelta16HI; |
331 | break; |
332 | case ELF::R_PPC64_TOC16_DS: |
333 | Kind = ppc64::TOCDelta16DS; |
334 | break; |
335 | case ELF::R_PPC64_TOC16_LO: |
336 | Kind = ppc64::TOCDelta16LO; |
337 | break; |
338 | case ELF::R_PPC64_TOC16_LO_DS: |
339 | Kind = ppc64::TOCDelta16LODS; |
340 | break; |
341 | case ELF::R_PPC64_REL16: |
342 | Kind = ppc64::Delta16; |
343 | break; |
344 | case ELF::R_PPC64_REL16_HA: |
345 | Kind = ppc64::Delta16HA; |
346 | break; |
347 | case ELF::R_PPC64_REL16_HI: |
348 | Kind = ppc64::Delta16HI; |
349 | break; |
350 | case ELF::R_PPC64_REL16_LO: |
351 | Kind = ppc64::Delta16LO; |
352 | break; |
353 | case ELF::R_PPC64_REL32: |
354 | Kind = ppc64::Delta32; |
355 | break; |
356 | case ELF::R_PPC64_REL24_NOTOC: |
357 | Kind = ppc64::RequestCallNoTOC; |
358 | break; |
359 | case ELF::R_PPC64_REL24: |
360 | Kind = ppc64::RequestCall; |
361 | // Determining a target is external or not is deferred in PostPrunePass. |
362 | // We assume branching to local entry by default, since in PostPrunePass, |
363 | // we don't have any context to determine LocalEntryOffset. If it finally |
364 | // turns out to be an external call, we'll have a stub for the external |
365 | // target, the target of this edge will be the stub and its addend will be |
366 | // set 0. |
367 | Addend += ELF::decodePPC64LocalEntryOffset(Other: (*ObjSymbol)->st_other); |
368 | break; |
369 | case ELF::R_PPC64_REL64: |
370 | Kind = ppc64::Delta64; |
371 | break; |
372 | case ELF::R_PPC64_PCREL34: |
373 | Kind = ppc64::Delta34; |
374 | break; |
375 | case ELF::R_PPC64_GOT_PCREL34: |
376 | Kind = ppc64::RequestGOTAndTransformToDelta34; |
377 | break; |
378 | case ELF::R_PPC64_GOT_TLSGD16_HA: |
379 | Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA; |
380 | break; |
381 | case ELF::R_PPC64_GOT_TLSGD16_LO: |
382 | Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO; |
383 | break; |
384 | case ELF::R_PPC64_GOT_TLSGD_PCREL34: |
385 | Kind = ppc64::RequestTLSDescInGOTAndTransformToDelta34; |
386 | break; |
387 | } |
388 | |
389 | Edge GE(Kind, Offset, *GraphSymbol, Addend); |
390 | BlockToFix.addEdge(E: std::move(GE)); |
391 | return Error::success(); |
392 | } |
393 | |
394 | public: |
395 | ELFLinkGraphBuilder_ppc64(StringRef FileName, |
396 | const object::ELFFile<ELFT> &Obj, Triple TT, |
397 | SubtargetFeatures Features) |
398 | : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features), |
399 | FileName, ppc64::getEdgeKindName) {} |
400 | }; |
401 | |
402 | template <llvm::endianness Endianness> |
403 | class ELFJITLinker_ppc64 : public JITLinker<ELFJITLinker_ppc64<Endianness>> { |
404 | using JITLinkerBase = JITLinker<ELFJITLinker_ppc64<Endianness>>; |
405 | friend JITLinkerBase; |
406 | |
407 | public: |
408 | ELFJITLinker_ppc64(std::unique_ptr<JITLinkContext> Ctx, |
409 | std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) |
410 | : JITLinkerBase(std::move(Ctx), std::move(G), std::move(PassConfig)) { |
411 | JITLinkerBase::getPassConfig().PostAllocationPasses.push_back( |
412 | [this](LinkGraph &G) { return defineTOCBase(G); }); |
413 | } |
414 | |
415 | private: |
416 | Symbol *TOCSymbol = nullptr; |
417 | |
418 | Error defineTOCBase(LinkGraph &G) { |
419 | for (Symbol *Sym : G.defined_symbols()) { |
420 | if (LLVM_UNLIKELY(Sym->getName() == ELFTOCSymbolName)) { |
421 | TOCSymbol = Sym; |
422 | return Error::success(); |
423 | } |
424 | } |
425 | |
426 | assert(TOCSymbol == nullptr && |
427 | "TOCSymbol should not be defined at this point" ); |
428 | |
429 | for (Symbol *Sym : G.external_symbols()) { |
430 | if (Sym->getName() == ELFTOCSymbolName) { |
431 | TOCSymbol = Sym; |
432 | break; |
433 | } |
434 | } |
435 | |
436 | if (Section *TOCSection = G.findSectionByName( |
437 | Name: ppc64::TOCTableManager<Endianness>::getSectionName())) { |
438 | assert(!TOCSection->empty() && "TOC section should have reserved an " |
439 | "entry for containing the TOC base" ); |
440 | |
441 | SectionRange SR(*TOCSection); |
442 | orc::ExecutorAddr TOCBaseAddr(SR.getFirstBlock()->getAddress() + |
443 | ELFTOCBaseOffset); |
444 | assert(TOCSymbol && TOCSymbol->isExternal() && |
445 | ".TOC. should be a external symbol at this point" ); |
446 | G.makeAbsolute(Sym&: *TOCSymbol, Address: TOCBaseAddr); |
447 | // Create an alias of .TOC. so that rtdyld checker can recognize. |
448 | G.addAbsoluteSymbol(Name: TOCSymbolAliasIdent, Address: TOCSymbol->getAddress(), |
449 | Size: TOCSymbol->getSize(), L: TOCSymbol->getLinkage(), |
450 | S: TOCSymbol->getScope(), IsLive: TOCSymbol->isLive()); |
451 | return Error::success(); |
452 | } |
453 | |
454 | // If TOC section doesn't exist, which means no TOC relocation is found, we |
455 | // don't need a TOCSymbol. |
456 | return Error::success(); |
457 | } |
458 | |
459 | Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { |
460 | return ppc64::applyFixup<Endianness>(G, B, E, TOCSymbol); |
461 | } |
462 | }; |
463 | |
464 | template <llvm::endianness Endianness> |
465 | Expected<std::unique_ptr<LinkGraph>> |
466 | createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) { |
467 | LLVM_DEBUG({ |
468 | dbgs() << "Building jitlink graph for new input " |
469 | << ObjectBuffer.getBufferIdentifier() << "...\n" ; |
470 | }); |
471 | |
472 | auto ELFObj = object::ObjectFile::createELFObjectFile(Object: ObjectBuffer); |
473 | if (!ELFObj) |
474 | return ELFObj.takeError(); |
475 | |
476 | auto Features = (*ELFObj)->getFeatures(); |
477 | if (!Features) |
478 | return Features.takeError(); |
479 | |
480 | using ELFT = object::ELFType<Endianness, true>; |
481 | auto &ELFObjFile = cast<object::ELFObjectFile<ELFT>>(**ELFObj); |
482 | return ELFLinkGraphBuilder_ppc64<Endianness>( |
483 | (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), |
484 | (*ELFObj)->makeTriple(), std::move(*Features)) |
485 | .buildGraph(); |
486 | } |
487 | |
488 | template <llvm::endianness Endianness> |
489 | void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, |
490 | std::unique_ptr<JITLinkContext> Ctx) { |
491 | PassConfiguration Config; |
492 | |
493 | if (Ctx->shouldAddDefaultTargetPasses(TT: G->getTargetTriple())) { |
494 | // Construct a JITLinker and run the link function. |
495 | |
496 | // Add eh-frame passes. |
497 | Config.PrePrunePasses.push_back(x: DWARFRecordSectionSplitter(".eh_frame" )); |
498 | Config.PrePrunePasses.push_back(x: EHFrameEdgeFixer( |
499 | ".eh_frame" , G->getPointerSize(), ppc64::Pointer32, ppc64::Pointer64, |
500 | ppc64::Delta32, ppc64::Delta64, ppc64::NegDelta32)); |
501 | Config.PrePrunePasses.push_back(x: EHFrameNullTerminator(".eh_frame" )); |
502 | |
503 | // Add a mark-live pass. |
504 | if (auto MarkLive = Ctx->getMarkLivePass(TT: G->getTargetTriple())) |
505 | Config.PrePrunePasses.push_back(x: std::move(MarkLive)); |
506 | else |
507 | Config.PrePrunePasses.push_back(x: markAllSymbolsLive); |
508 | } |
509 | |
510 | Config.PostPrunePasses.push_back(buildTables_ELF_ppc64<Endianness>); |
511 | |
512 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config)) |
513 | return Ctx->notifyFailed(Err: std::move(Err)); |
514 | |
515 | ELFJITLinker_ppc64<Endianness>::link(std::move(Ctx), std::move(G), |
516 | std::move(Config)); |
517 | } |
518 | |
519 | Expected<std::unique_ptr<LinkGraph>> |
520 | createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) { |
521 | return createLinkGraphFromELFObject_ppc64<llvm::endianness::big>( |
522 | ObjectBuffer: std::move(ObjectBuffer)); |
523 | } |
524 | |
525 | Expected<std::unique_ptr<LinkGraph>> |
526 | createLinkGraphFromELFObject_ppc64le(MemoryBufferRef ObjectBuffer) { |
527 | return createLinkGraphFromELFObject_ppc64<llvm::endianness::little>( |
528 | ObjectBuffer: std::move(ObjectBuffer)); |
529 | } |
530 | |
531 | /// jit-link the given object buffer, which must be a ELF ppc64 object file. |
532 | void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, |
533 | std::unique_ptr<JITLinkContext> Ctx) { |
534 | return link_ELF_ppc64<llvm::endianness::big>(G: std::move(G), Ctx: std::move(Ctx)); |
535 | } |
536 | |
537 | /// jit-link the given object buffer, which must be a ELF ppc64le object file. |
538 | void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G, |
539 | std::unique_ptr<JITLinkContext> Ctx) { |
540 | return link_ELF_ppc64<llvm::endianness::little>(G: std::move(G), Ctx: std::move(Ctx)); |
541 | } |
542 | |
543 | } // end namespace llvm::jitlink |
544 | |