xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp (revision a2464ee12761660f50d0b6f59f233949ebcacc87)
1 //===------ ELFNixPlatform.cpp - Utilities for executing MachO in Orc -----===//
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 #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
10 
11 #include "llvm/BinaryFormat/ELF.h"
12 #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
13 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
14 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
15 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
16 #include "llvm/Support/BinaryByteStream.h"
17 #include "llvm/Support/Debug.h"
18 
19 #define DEBUG_TYPE "orc"
20 
21 using namespace llvm;
22 using namespace llvm::orc;
23 using namespace llvm::orc::shared;
24 
25 namespace {
26 
27 class DSOHandleMaterializationUnit : public MaterializationUnit {
28 public:
29   DSOHandleMaterializationUnit(ELFNixPlatform &ENP,
30                                const SymbolStringPtr &DSOHandleSymbol)
31       : MaterializationUnit(
32             createDSOHandleSectionInterface(ENP, DSOHandleSymbol)),
33         ENP(ENP) {}
34 
35   StringRef getName() const override { return "DSOHandleMU"; }
36 
37   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
38     unsigned PointerSize;
39     support::endianness Endianness;
40     jitlink::Edge::Kind EdgeKind;
41     const auto &TT =
42         ENP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
43 
44     switch (TT.getArch()) {
45     case Triple::x86_64:
46       PointerSize = 8;
47       Endianness = support::endianness::little;
48       EdgeKind = jitlink::x86_64::Pointer64;
49       break;
50     default:
51       llvm_unreachable("Unrecognized architecture");
52     }
53 
54     // void *__dso_handle = &__dso_handle;
55     auto G = std::make_unique<jitlink::LinkGraph>(
56         "<DSOHandleMU>", TT, PointerSize, Endianness,
57         jitlink::getGenericEdgeKindName);
58     auto &DSOHandleSection =
59         G->createSection(".data.__dso_handle", jitlink::MemProt::Read);
60     auto &DSOHandleBlock = G->createContentBlock(
61         DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(),
62         8, 0);
63     auto &DSOHandleSymbol = G->addDefinedSymbol(
64         DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(),
65         jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
66     DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0);
67 
68     ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
69   }
70 
71   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
72 
73 private:
74   static MaterializationUnit::Interface
75   createDSOHandleSectionInterface(ELFNixPlatform &ENP,
76                                   const SymbolStringPtr &DSOHandleSymbol) {
77     SymbolFlagsMap SymbolFlags;
78     SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported;
79     return MaterializationUnit::Interface(std::move(SymbolFlags),
80                                           DSOHandleSymbol);
81   }
82 
83   ArrayRef<char> getDSOHandleContent(size_t PointerSize) {
84     static const char Content[8] = {0};
85     assert(PointerSize <= sizeof Content);
86     return {Content, PointerSize};
87   }
88 
89   ELFNixPlatform &ENP;
90 };
91 
92 StringRef EHFrameSectionName = ".eh_frame";
93 StringRef InitArrayFuncSectionName = ".init_array";
94 
95 StringRef ThreadBSSSectionName = ".tbss";
96 StringRef ThreadDataSectionName = ".tdata";
97 
98 StringRef InitSectionNames[] = {InitArrayFuncSectionName};
99 
100 } // end anonymous namespace
101 
102 namespace llvm {
103 namespace orc {
104 
105 Expected<std::unique_ptr<ELFNixPlatform>>
106 ELFNixPlatform::Create(ExecutionSession &ES,
107                        ObjectLinkingLayer &ObjLinkingLayer,
108                        JITDylib &PlatformJD, const char *OrcRuntimePath,
109                        Optional<SymbolAliasMap> RuntimeAliases) {
110 
111   auto &EPC = ES.getExecutorProcessControl();
112 
113   // If the target is not supported then bail out immediately.
114   if (!supportedTarget(EPC.getTargetTriple()))
115     return make_error<StringError>("Unsupported ELFNixPlatform triple: " +
116                                        EPC.getTargetTriple().str(),
117                                    inconvertibleErrorCode());
118 
119   // Create default aliases if the caller didn't supply any.
120   if (!RuntimeAliases)
121     RuntimeAliases = standardPlatformAliases(ES);
122 
123   // Define the aliases.
124   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
125     return std::move(Err);
126 
127   // Add JIT-dispatch function support symbols.
128   if (auto Err = PlatformJD.define(absoluteSymbols(
129           {{ES.intern("__orc_rt_jit_dispatch"),
130             {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
131              JITSymbolFlags::Exported}},
132            {ES.intern("__orc_rt_jit_dispatch_ctx"),
133             {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
134              JITSymbolFlags::Exported}}})))
135     return std::move(Err);
136 
137   // Create a generator for the ORC runtime archive.
138   auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
139       ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
140   if (!OrcRuntimeArchiveGenerator)
141     return OrcRuntimeArchiveGenerator.takeError();
142 
143   // Create the instance.
144   Error Err = Error::success();
145   auto P = std::unique_ptr<ELFNixPlatform>(
146       new ELFNixPlatform(ES, ObjLinkingLayer, PlatformJD,
147                          std::move(*OrcRuntimeArchiveGenerator), Err));
148   if (Err)
149     return std::move(Err);
150   return std::move(P);
151 }
152 
153 Error ELFNixPlatform::setupJITDylib(JITDylib &JD) {
154   return JD.define(
155       std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol));
156 }
157 
158 Error ELFNixPlatform::teardownJITDylib(JITDylib &JD) {
159   return Error::success();
160 }
161 
162 Error ELFNixPlatform::notifyAdding(ResourceTracker &RT,
163                                    const MaterializationUnit &MU) {
164   auto &JD = RT.getJITDylib();
165   const auto &InitSym = MU.getInitializerSymbol();
166   if (!InitSym)
167     return Error::success();
168 
169   RegisteredInitSymbols[&JD].add(InitSym,
170                                  SymbolLookupFlags::WeaklyReferencedSymbol);
171   LLVM_DEBUG({
172     dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym
173            << " for MU " << MU.getName() << "\n";
174   });
175   return Error::success();
176 }
177 
178 Error ELFNixPlatform::notifyRemoving(ResourceTracker &RT) {
179   llvm_unreachable("Not supported yet");
180 }
181 
182 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
183                        ArrayRef<std::pair<const char *, const char *>> AL) {
184   for (auto &KV : AL) {
185     auto AliasName = ES.intern(KV.first);
186     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
187     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
188                                      JITSymbolFlags::Exported};
189   }
190 }
191 
192 SymbolAliasMap ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES) {
193   SymbolAliasMap Aliases;
194   addAliases(ES, Aliases, requiredCXXAliases());
195   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
196   return Aliases;
197 }
198 
199 ArrayRef<std::pair<const char *, const char *>>
200 ELFNixPlatform::requiredCXXAliases() {
201   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
202       {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"},
203       {"atexit", "__orc_rt_elfnix_atexit"}};
204 
205   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
206 }
207 
208 ArrayRef<std::pair<const char *, const char *>>
209 ELFNixPlatform::standardRuntimeUtilityAliases() {
210   static const std::pair<const char *, const char *>
211       StandardRuntimeUtilityAliases[] = {
212           {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},
213           {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
214 
215   return ArrayRef<std::pair<const char *, const char *>>(
216       StandardRuntimeUtilityAliases);
217 }
218 
219 bool ELFNixPlatform::isInitializerSection(StringRef SecName) {
220   for (auto &Name : InitSectionNames) {
221     if (Name.equals(SecName))
222       return true;
223   }
224   return false;
225 }
226 
227 bool ELFNixPlatform::supportedTarget(const Triple &TT) {
228   switch (TT.getArch()) {
229   case Triple::x86_64:
230     return true;
231   default:
232     return false;
233   }
234 }
235 
236 ELFNixPlatform::ELFNixPlatform(
237     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
238     JITDylib &PlatformJD,
239     std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
240     : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
241       DSOHandleSymbol(ES.intern("__dso_handle")) {
242   ErrorAsOutParameter _(&Err);
243 
244   ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));
245 
246   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
247 
248   // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
249   // the platform now), so set it up.
250   if (auto E2 = setupJITDylib(PlatformJD)) {
251     Err = std::move(E2);
252     return;
253   }
254 
255   RegisteredInitSymbols[&PlatformJD].add(
256       DSOHandleSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);
257 
258   // Associate wrapper function tags with JIT-side function implementations.
259   if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
260     Err = std::move(E2);
261     return;
262   }
263 
264   // Lookup addresses of runtime functions callable by the platform,
265   // call the platform bootstrap function to initialize the platform-state
266   // object in the executor.
267   if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) {
268     Err = std::move(E2);
269     return;
270   }
271 }
272 
273 Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
274   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
275 
276   using GetInitializersSPSSig =
277       SPSExpected<SPSELFNixJITDylibInitializerSequence>(SPSString);
278   WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] =
279       ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
280           this, &ELFNixPlatform::rt_getInitializers);
281 
282   using GetDeinitializersSPSSig =
283       SPSExpected<SPSELFJITDylibDeinitializerSequence>(SPSExecutorAddr);
284   WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] =
285       ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
286           this, &ELFNixPlatform::rt_getDeinitializers);
287 
288   using LookupSymbolSPSSig =
289       SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
290   WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] =
291       ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
292                                               &ELFNixPlatform::rt_lookupSymbol);
293 
294   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
295 }
296 
297 void ELFNixPlatform::getInitializersBuildSequencePhase(
298     SendInitializerSequenceFn SendResult, JITDylib &JD,
299     std::vector<JITDylibSP> DFSLinkOrder) {
300   ELFNixJITDylibInitializerSequence FullInitSeq;
301   {
302     std::lock_guard<std::mutex> Lock(PlatformMutex);
303     for (auto &InitJD : reverse(DFSLinkOrder)) {
304       LLVM_DEBUG({
305         dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName()
306                << "\" to sequence\n";
307       });
308       auto ISItr = InitSeqs.find(InitJD.get());
309       if (ISItr != InitSeqs.end()) {
310         FullInitSeq.emplace_back(std::move(ISItr->second));
311         InitSeqs.erase(ISItr);
312       }
313     }
314   }
315 
316   SendResult(std::move(FullInitSeq));
317 }
318 
319 void ELFNixPlatform::getInitializersLookupPhase(
320     SendInitializerSequenceFn SendResult, JITDylib &JD) {
321 
322   auto DFSLinkOrder = JD.getDFSLinkOrder();
323   if (!DFSLinkOrder) {
324     SendResult(DFSLinkOrder.takeError());
325     return;
326   }
327 
328   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
329   ES.runSessionLocked([&]() {
330     for (auto &InitJD : *DFSLinkOrder) {
331       auto RISItr = RegisteredInitSymbols.find(InitJD.get());
332       if (RISItr != RegisteredInitSymbols.end()) {
333         NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
334         RegisteredInitSymbols.erase(RISItr);
335       }
336     }
337   });
338 
339   // If there are no further init symbols to look up then move on to the next
340   // phase.
341   if (NewInitSymbols.empty()) {
342     getInitializersBuildSequencePhase(std::move(SendResult), JD,
343                                       std::move(*DFSLinkOrder));
344     return;
345   }
346 
347   // Otherwise issue a lookup and re-run this phase when it completes.
348   lookupInitSymbolsAsync(
349       [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
350         if (Err)
351           SendResult(std::move(Err));
352         else
353           getInitializersLookupPhase(std::move(SendResult), JD);
354       },
355       ES, std::move(NewInitSymbols));
356 }
357 
358 void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
359                                         StringRef JDName) {
360   LLVM_DEBUG({
361     dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n";
362   });
363 
364   JITDylib *JD = ES.getJITDylibByName(JDName);
365   if (!JD) {
366     LLVM_DEBUG({
367       dbgs() << "  No such JITDylib \"" << JDName << "\". Sending error.\n";
368     });
369     SendResult(make_error<StringError>("No JITDylib named " + JDName,
370                                        inconvertibleErrorCode()));
371     return;
372   }
373 
374   getInitializersLookupPhase(std::move(SendResult), *JD);
375 }
376 
377 void ELFNixPlatform::rt_getDeinitializers(
378     SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) {
379   LLVM_DEBUG({
380     dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
381            << formatv("{0:x}", Handle.getValue()) << "\")\n";
382   });
383 
384   JITDylib *JD = nullptr;
385 
386   {
387     std::lock_guard<std::mutex> Lock(PlatformMutex);
388     auto I = HandleAddrToJITDylib.find(Handle);
389     if (I != HandleAddrToJITDylib.end())
390       JD = I->second;
391   }
392 
393   if (!JD) {
394     LLVM_DEBUG({
395       dbgs() << "  No JITDylib for handle "
396              << formatv("{0:x}", Handle.getValue()) << "\n";
397     });
398     SendResult(make_error<StringError>("No JITDylib associated with handle " +
399                                            formatv("{0:x}", Handle.getValue()),
400                                        inconvertibleErrorCode()));
401     return;
402   }
403 
404   SendResult(ELFNixJITDylibDeinitializerSequence());
405 }
406 
407 void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
408                                      ExecutorAddr Handle,
409                                      StringRef SymbolName) {
410   LLVM_DEBUG({
411     dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
412            << formatv("{0:x}", Handle.getValue()) << "\")\n";
413   });
414 
415   JITDylib *JD = nullptr;
416 
417   {
418     std::lock_guard<std::mutex> Lock(PlatformMutex);
419     auto I = HandleAddrToJITDylib.find(Handle);
420     if (I != HandleAddrToJITDylib.end())
421       JD = I->second;
422   }
423 
424   if (!JD) {
425     LLVM_DEBUG({
426       dbgs() << "  No JITDylib for handle "
427              << formatv("{0:x}", Handle.getValue()) << "\n";
428     });
429     SendResult(make_error<StringError>("No JITDylib associated with handle " +
430                                            formatv("{0:x}", Handle.getValue()),
431                                        inconvertibleErrorCode()));
432     return;
433   }
434 
435   // Use functor class to work around XL build compiler issue on AIX.
436   class RtLookupNotifyComplete {
437   public:
438     RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
439         : SendResult(std::move(SendResult)) {}
440     void operator()(Expected<SymbolMap> Result) {
441       if (Result) {
442         assert(Result->size() == 1 && "Unexpected result map count");
443         SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
444       } else {
445         SendResult(Result.takeError());
446       }
447     }
448 
449   private:
450     SendSymbolAddressFn SendResult;
451   };
452 
453   ES.lookup(
454       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
455       SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,
456       RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
457 }
458 
459 Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) {
460 
461   std::pair<const char *, ExecutorAddr *> Symbols[] = {
462       {"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap},
463       {"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown},
464       {"__orc_rt_elfnix_register_object_sections",
465        &orc_rt_elfnix_register_object_sections},
466       {"__orc_rt_elfnix_create_pthread_key",
467        &orc_rt_elfnix_create_pthread_key}};
468 
469   SymbolLookupSet RuntimeSymbols;
470   std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord;
471   for (const auto &KV : Symbols) {
472     auto Name = ES.intern(KV.first);
473     RuntimeSymbols.add(Name);
474     AddrsToRecord.push_back({std::move(Name), KV.second});
475   }
476 
477   auto RuntimeSymbolAddrs = ES.lookup(
478       {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols);
479   if (!RuntimeSymbolAddrs)
480     return RuntimeSymbolAddrs.takeError();
481 
482   for (const auto &KV : AddrsToRecord) {
483     auto &Name = KV.first;
484     assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?");
485     KV.second->setValue((*RuntimeSymbolAddrs)[Name].getAddress());
486   }
487 
488   auto PJDDSOHandle = ES.lookup(
489       {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol);
490   if (!PJDDSOHandle)
491     return PJDDSOHandle.takeError();
492 
493   if (auto Err = ES.callSPSWrapper<void(uint64_t)>(
494           orc_rt_elfnix_platform_bootstrap, PJDDSOHandle->getAddress()))
495     return Err;
496 
497   // FIXME: Ordering is fuzzy here. We're probably best off saying
498   // "behavior is undefined if code that uses the runtime is added before
499   // the platform constructor returns", then move all this to the constructor.
500   RuntimeBootstrapped = true;
501   std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs;
502   {
503     std::lock_guard<std::mutex> Lock(PlatformMutex);
504     DeferredPOSRs = std::move(BootstrapPOSRs);
505   }
506 
507   for (auto &D : DeferredPOSRs)
508     if (auto Err = registerPerObjectSections(D))
509       return Err;
510 
511   return Error::success();
512 }
513 
514 Error ELFNixPlatform::registerInitInfo(
515     JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {
516 
517   std::unique_lock<std::mutex> Lock(PlatformMutex);
518 
519   ELFNixJITDylibInitializers *InitSeq = nullptr;
520   {
521     auto I = InitSeqs.find(&JD);
522     if (I == InitSeqs.end()) {
523       // If there's no init sequence entry yet then we need to look up the
524       // header symbol to force creation of one.
525       Lock.unlock();
526 
527       auto SearchOrder =
528           JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
529       if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError())
530         return Err;
531 
532       Lock.lock();
533       I = InitSeqs.find(&JD);
534       assert(I != InitSeqs.end() &&
535              "Entry missing after header symbol lookup?");
536     }
537     InitSeq = &I->second;
538   }
539 
540   for (auto *Sec : InitSections) {
541     // FIXME: Avoid copy here.
542     jitlink::SectionRange R(*Sec);
543     InitSeq->InitSections[Sec->getName()].push_back(
544         {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())});
545   }
546 
547   return Error::success();
548 }
549 
550 Error ELFNixPlatform::registerPerObjectSections(
551     const ELFPerObjectSectionsToRegister &POSR) {
552 
553   if (!orc_rt_elfnix_register_object_sections)
554     return make_error<StringError>("Attempting to register per-object "
555                                    "sections, but runtime support has not "
556                                    "been loaded yet",
557                                    inconvertibleErrorCode());
558 
559   Error ErrResult = Error::success();
560   if (auto Err = ES.callSPSWrapper<shared::SPSError(
561                      SPSELFPerObjectSectionsToRegister)>(
562           orc_rt_elfnix_register_object_sections, ErrResult, POSR))
563     return Err;
564   return ErrResult;
565 }
566 
567 Expected<uint64_t> ELFNixPlatform::createPThreadKey() {
568   if (!orc_rt_elfnix_create_pthread_key)
569     return make_error<StringError>(
570         "Attempting to create pthread key in target, but runtime support has "
571         "not been loaded yet",
572         inconvertibleErrorCode());
573 
574   Expected<uint64_t> Result(0);
575   if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
576           orc_rt_elfnix_create_pthread_key, Result))
577     return std::move(Err);
578   return Result;
579 }
580 
581 void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig(
582     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
583     jitlink::PassConfiguration &Config) {
584 
585   // If the initializer symbol is the __dso_handle symbol then just add
586   // the DSO handle support passes.
587   if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) {
588     addDSOHandleSupportPasses(MR, Config);
589     // The DSOHandle materialization unit doesn't require any other
590     // support, so we can bail out early.
591     return;
592   }
593 
594   // If the object contains initializers then add passes to record them.
595   if (MR.getInitializerSymbol())
596     addInitializerSupportPasses(MR, Config);
597 
598   // Add passes for eh-frame and TLV support.
599   addEHAndTLVSupportPasses(MR, Config);
600 }
601 
602 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
603 ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies(
604     MaterializationResponsibility &MR) {
605   std::lock_guard<std::mutex> Lock(PluginMutex);
606   auto I = InitSymbolDeps.find(&MR);
607   if (I != InitSymbolDeps.end()) {
608     SyntheticSymbolDependenciesMap Result;
609     Result[MR.getInitializerSymbol()] = std::move(I->second);
610     InitSymbolDeps.erase(&MR);
611     return Result;
612   }
613   return SyntheticSymbolDependenciesMap();
614 }
615 
616 void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses(
617     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
618 
619   /// Preserve init sections.
620   Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {
621     if (auto Err = preserveInitSections(G, MR))
622       return Err;
623     return Error::success();
624   });
625 
626   Config.PostFixupPasses.push_back(
627       [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
628         return registerInitSections(G, JD);
629       });
630 }
631 
632 void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses(
633     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
634 
635   Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](
636                                             jitlink::LinkGraph &G) -> Error {
637     auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
638       return Sym->getName() == *MP.DSOHandleSymbol;
639     });
640     assert(I != G.defined_symbols().end() && "Missing DSO handle symbol");
641     {
642       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
643       auto HandleAddr = (*I)->getAddress();
644       MP.HandleAddrToJITDylib[HandleAddr] = &JD;
645       assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists");
646       MP.InitSeqs.insert(std::make_pair(
647           &JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr)));
648     }
649     return Error::success();
650   });
651 }
652 
653 void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses(
654     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
655 
656   // Insert TLV lowering at the start of the PostPrunePasses, since we want
657   // it to run before GOT/PLT lowering.
658 
659   // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build
660   // pass has done. Because the TLS descriptor need to be allocate in GOT.
661   Config.PostPrunePasses.push_back(
662       [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
663         return fixTLVSectionsAndEdges(G, JD);
664       });
665 
666   // Add a pass to register the final addresses of the eh-frame and TLV sections
667   // with the runtime.
668   Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
669     ELFPerObjectSectionsToRegister POSR;
670 
671     if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) {
672       jitlink::SectionRange R(*EHFrameSection);
673       if (!R.empty())
674         POSR.EHFrameSection = {ExecutorAddr(R.getStart()),
675                                ExecutorAddr(R.getEnd())};
676     }
677 
678     // Get a pointer to the thread data section if there is one. It will be used
679     // below.
680     jitlink::Section *ThreadDataSection =
681         G.findSectionByName(ThreadDataSectionName);
682 
683     // Handle thread BSS section if there is one.
684     if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) {
685       // If there's already a thread data section in this graph then merge the
686       // thread BSS section content into it, otherwise just treat the thread
687       // BSS section as the thread data section.
688       if (ThreadDataSection)
689         G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
690       else
691         ThreadDataSection = ThreadBSSSection;
692     }
693 
694     // Having merged thread BSS (if present) and thread data (if present),
695     // record the resulting section range.
696     if (ThreadDataSection) {
697       jitlink::SectionRange R(*ThreadDataSection);
698       if (!R.empty())
699         POSR.ThreadDataSection = {ExecutorAddr(R.getStart()),
700                                   ExecutorAddr(R.getEnd())};
701     }
702 
703     if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
704 
705       // If we're still bootstrapping the runtime then just record this
706       // frame for now.
707       if (!MP.RuntimeBootstrapped) {
708         std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
709         MP.BootstrapPOSRs.push_back(POSR);
710         return Error::success();
711       }
712 
713       // Otherwise register it immediately.
714       if (auto Err = MP.registerPerObjectSections(POSR))
715         return Err;
716     }
717 
718     return Error::success();
719   });
720 }
721 
722 Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
723     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
724 
725   JITLinkSymbolSet InitSectionSymbols;
726   for (auto &InitSectionName : InitSectionNames) {
727     // Skip non-init sections.
728     auto *InitSection = G.findSectionByName(InitSectionName);
729     if (!InitSection)
730       continue;
731 
732     // Make a pass over live symbols in the section: those blocks are already
733     // preserved.
734     DenseSet<jitlink::Block *> AlreadyLiveBlocks;
735     for (auto &Sym : InitSection->symbols()) {
736       auto &B = Sym->getBlock();
737       if (Sym->isLive() && Sym->getOffset() == 0 &&
738           Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
739         InitSectionSymbols.insert(Sym);
740         AlreadyLiveBlocks.insert(&B);
741       }
742     }
743 
744     // Add anonymous symbols to preserve any not-already-preserved blocks.
745     for (auto *B : InitSection->blocks())
746       if (!AlreadyLiveBlocks.count(B))
747         InitSectionSymbols.insert(
748             &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
749   }
750 
751   if (!InitSectionSymbols.empty()) {
752     std::lock_guard<std::mutex> Lock(PluginMutex);
753     InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
754   }
755 
756   return Error::success();
757 }
758 
759 Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections(
760     jitlink::LinkGraph &G, JITDylib &JD) {
761 
762   SmallVector<jitlink::Section *> InitSections;
763 
764   LLVM_DEBUG({ dbgs() << "ELFNixPlatform::registerInitSections\n"; });
765 
766   for (auto InitSectionName : InitSectionNames) {
767     if (auto *Sec = G.findSectionByName(InitSectionName)) {
768       InitSections.push_back(Sec);
769     }
770   }
771 
772   // Dump the scraped inits.
773   LLVM_DEBUG({
774     dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n";
775     for (auto *Sec : InitSections) {
776       jitlink::SectionRange R(*Sec);
777       dbgs() << "  " << Sec->getName() << ": "
778              << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n";
779     }
780   });
781 
782   return MP.registerInitInfo(JD, InitSections);
783 }
784 
785 Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
786     jitlink::LinkGraph &G, JITDylib &JD) {
787 
788   // TODO implement TLV support
789   for (auto *Sym : G.external_symbols())
790     if (Sym->getName() == "__tls_get_addr") {
791       Sym->setName("___orc_rt_elfnix_tls_get_addr");
792     }
793 
794   auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO");
795 
796   if (TLSInfoEntrySection) {
797     Optional<uint64_t> Key;
798     {
799       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
800       auto I = MP.JITDylibToPThreadKey.find(&JD);
801       if (I != MP.JITDylibToPThreadKey.end())
802         Key = I->second;
803     }
804     if (!Key) {
805       if (auto KeyOrErr = MP.createPThreadKey())
806         Key = *KeyOrErr;
807       else
808         return KeyOrErr.takeError();
809     }
810 
811     uint64_t PlatformKeyBits =
812         support::endian::byte_swap(*Key, G.getEndianness());
813 
814     for (auto *B : TLSInfoEntrySection->blocks()) {
815       // FIXME: The TLS descriptor byte length may different with different
816       // ISA
817       assert(B->getSize() == (G.getPointerSize() * 2) &&
818              "TLS descriptor must be 2 words length");
819       auto TLSInfoEntryContent = B->getMutableContent(G);
820       memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize());
821     }
822   }
823 
824   return Error::success();
825 }
826 
827 } // End namespace orc.
828 } // End namespace llvm.
829