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