xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1349cc55cSDimitry Andric //===------ ELFNixPlatform.cpp - Utilities for executing MachO in Orc -----===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric 
9349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
10349cc55cSDimitry Andric 
11349cc55cSDimitry Andric #include "llvm/BinaryFormat/ELF.h"
12349cc55cSDimitry Andric #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
1381ad6265SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch64.h"
14349cc55cSDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86_64.h"
15349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
16349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
17349cc55cSDimitry Andric #include "llvm/Support/BinaryByteStream.h"
18349cc55cSDimitry Andric #include "llvm/Support/Debug.h"
19*bdd1243dSDimitry Andric #include <optional>
20349cc55cSDimitry Andric 
21349cc55cSDimitry Andric #define DEBUG_TYPE "orc"
22349cc55cSDimitry Andric 
23349cc55cSDimitry Andric using namespace llvm;
24349cc55cSDimitry Andric using namespace llvm::orc;
25349cc55cSDimitry Andric using namespace llvm::orc::shared;
26349cc55cSDimitry Andric 
27349cc55cSDimitry Andric namespace {
28349cc55cSDimitry Andric 
29349cc55cSDimitry Andric class DSOHandleMaterializationUnit : public MaterializationUnit {
30349cc55cSDimitry Andric public:
31349cc55cSDimitry Andric   DSOHandleMaterializationUnit(ELFNixPlatform &ENP,
32349cc55cSDimitry Andric                                const SymbolStringPtr &DSOHandleSymbol)
330eae32dcSDimitry Andric       : MaterializationUnit(
340eae32dcSDimitry Andric             createDSOHandleSectionInterface(ENP, DSOHandleSymbol)),
35349cc55cSDimitry Andric         ENP(ENP) {}
36349cc55cSDimitry Andric 
37349cc55cSDimitry Andric   StringRef getName() const override { return "DSOHandleMU"; }
38349cc55cSDimitry Andric 
39349cc55cSDimitry Andric   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
40349cc55cSDimitry Andric     unsigned PointerSize;
41349cc55cSDimitry Andric     support::endianness Endianness;
42349cc55cSDimitry Andric     jitlink::Edge::Kind EdgeKind;
43349cc55cSDimitry Andric     const auto &TT =
44349cc55cSDimitry Andric         ENP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
45349cc55cSDimitry Andric 
46349cc55cSDimitry Andric     switch (TT.getArch()) {
47349cc55cSDimitry Andric     case Triple::x86_64:
48349cc55cSDimitry Andric       PointerSize = 8;
49349cc55cSDimitry Andric       Endianness = support::endianness::little;
50349cc55cSDimitry Andric       EdgeKind = jitlink::x86_64::Pointer64;
51349cc55cSDimitry Andric       break;
5281ad6265SDimitry Andric     case Triple::aarch64:
5381ad6265SDimitry Andric       PointerSize = 8;
5481ad6265SDimitry Andric       Endianness = support::endianness::little;
5581ad6265SDimitry Andric       EdgeKind = jitlink::aarch64::Pointer64;
5681ad6265SDimitry Andric       break;
57349cc55cSDimitry Andric     default:
58349cc55cSDimitry Andric       llvm_unreachable("Unrecognized architecture");
59349cc55cSDimitry Andric     }
60349cc55cSDimitry Andric 
61349cc55cSDimitry Andric     // void *__dso_handle = &__dso_handle;
62349cc55cSDimitry Andric     auto G = std::make_unique<jitlink::LinkGraph>(
63349cc55cSDimitry Andric         "<DSOHandleMU>", TT, PointerSize, Endianness,
64349cc55cSDimitry Andric         jitlink::getGenericEdgeKindName);
65349cc55cSDimitry Andric     auto &DSOHandleSection =
66*bdd1243dSDimitry Andric         G->createSection(".data.__dso_handle", MemProt::Read);
67349cc55cSDimitry Andric     auto &DSOHandleBlock = G->createContentBlock(
6804eeddc0SDimitry Andric         DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(),
6904eeddc0SDimitry Andric         8, 0);
70349cc55cSDimitry Andric     auto &DSOHandleSymbol = G->addDefinedSymbol(
71349cc55cSDimitry Andric         DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(),
72349cc55cSDimitry Andric         jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
73349cc55cSDimitry Andric     DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0);
74349cc55cSDimitry Andric 
75349cc55cSDimitry Andric     ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
76349cc55cSDimitry Andric   }
77349cc55cSDimitry Andric 
78349cc55cSDimitry Andric   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
79349cc55cSDimitry Andric 
80349cc55cSDimitry Andric private:
810eae32dcSDimitry Andric   static MaterializationUnit::Interface
820eae32dcSDimitry Andric   createDSOHandleSectionInterface(ELFNixPlatform &ENP,
83349cc55cSDimitry Andric                                   const SymbolStringPtr &DSOHandleSymbol) {
84349cc55cSDimitry Andric     SymbolFlagsMap SymbolFlags;
85349cc55cSDimitry Andric     SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported;
860eae32dcSDimitry Andric     return MaterializationUnit::Interface(std::move(SymbolFlags),
870eae32dcSDimitry Andric                                           DSOHandleSymbol);
88349cc55cSDimitry Andric   }
89349cc55cSDimitry Andric 
90349cc55cSDimitry Andric   ArrayRef<char> getDSOHandleContent(size_t PointerSize) {
91349cc55cSDimitry Andric     static const char Content[8] = {0};
92349cc55cSDimitry Andric     assert(PointerSize <= sizeof Content);
93349cc55cSDimitry Andric     return {Content, PointerSize};
94349cc55cSDimitry Andric   }
95349cc55cSDimitry Andric 
96349cc55cSDimitry Andric   ELFNixPlatform &ENP;
97349cc55cSDimitry Andric };
98349cc55cSDimitry Andric 
99349cc55cSDimitry Andric StringRef EHFrameSectionName = ".eh_frame";
100349cc55cSDimitry Andric StringRef InitArrayFuncSectionName = ".init_array";
101349cc55cSDimitry Andric 
102349cc55cSDimitry Andric StringRef ThreadBSSSectionName = ".tbss";
103349cc55cSDimitry Andric StringRef ThreadDataSectionName = ".tdata";
104349cc55cSDimitry Andric 
105349cc55cSDimitry Andric } // end anonymous namespace
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric namespace llvm {
108349cc55cSDimitry Andric namespace orc {
109349cc55cSDimitry Andric 
110349cc55cSDimitry Andric Expected<std::unique_ptr<ELFNixPlatform>>
111349cc55cSDimitry Andric ELFNixPlatform::Create(ExecutionSession &ES,
112349cc55cSDimitry Andric                        ObjectLinkingLayer &ObjLinkingLayer,
113349cc55cSDimitry Andric                        JITDylib &PlatformJD, const char *OrcRuntimePath,
114*bdd1243dSDimitry Andric                        std::optional<SymbolAliasMap> RuntimeAliases) {
115349cc55cSDimitry Andric 
116349cc55cSDimitry Andric   auto &EPC = ES.getExecutorProcessControl();
117349cc55cSDimitry Andric 
118349cc55cSDimitry Andric   // If the target is not supported then bail out immediately.
119349cc55cSDimitry Andric   if (!supportedTarget(EPC.getTargetTriple()))
120349cc55cSDimitry Andric     return make_error<StringError>("Unsupported ELFNixPlatform triple: " +
121349cc55cSDimitry Andric                                        EPC.getTargetTriple().str(),
122349cc55cSDimitry Andric                                    inconvertibleErrorCode());
123349cc55cSDimitry Andric 
124349cc55cSDimitry Andric   // Create default aliases if the caller didn't supply any.
12581ad6265SDimitry Andric   if (!RuntimeAliases) {
12681ad6265SDimitry Andric     auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD);
12781ad6265SDimitry Andric     if (!StandardRuntimeAliases)
12881ad6265SDimitry Andric       return StandardRuntimeAliases.takeError();
12981ad6265SDimitry Andric     RuntimeAliases = std::move(*StandardRuntimeAliases);
13081ad6265SDimitry Andric   }
131349cc55cSDimitry Andric 
132349cc55cSDimitry Andric   // Define the aliases.
133349cc55cSDimitry Andric   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
134349cc55cSDimitry Andric     return std::move(Err);
135349cc55cSDimitry Andric 
136349cc55cSDimitry Andric   // Add JIT-dispatch function support symbols.
137349cc55cSDimitry Andric   if (auto Err = PlatformJD.define(absoluteSymbols(
138349cc55cSDimitry Andric           {{ES.intern("__orc_rt_jit_dispatch"),
139349cc55cSDimitry Andric             {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
140349cc55cSDimitry Andric              JITSymbolFlags::Exported}},
141349cc55cSDimitry Andric            {ES.intern("__orc_rt_jit_dispatch_ctx"),
142349cc55cSDimitry Andric             {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
143349cc55cSDimitry Andric              JITSymbolFlags::Exported}}})))
144349cc55cSDimitry Andric     return std::move(Err);
145349cc55cSDimitry Andric 
146349cc55cSDimitry Andric   // Create a generator for the ORC runtime archive.
147349cc55cSDimitry Andric   auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
148349cc55cSDimitry Andric       ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
149349cc55cSDimitry Andric   if (!OrcRuntimeArchiveGenerator)
150349cc55cSDimitry Andric     return OrcRuntimeArchiveGenerator.takeError();
151349cc55cSDimitry Andric 
152349cc55cSDimitry Andric   // Create the instance.
153349cc55cSDimitry Andric   Error Err = Error::success();
154349cc55cSDimitry Andric   auto P = std::unique_ptr<ELFNixPlatform>(
155349cc55cSDimitry Andric       new ELFNixPlatform(ES, ObjLinkingLayer, PlatformJD,
156349cc55cSDimitry Andric                          std::move(*OrcRuntimeArchiveGenerator), Err));
157349cc55cSDimitry Andric   if (Err)
158349cc55cSDimitry Andric     return std::move(Err);
159349cc55cSDimitry Andric   return std::move(P);
160349cc55cSDimitry Andric }
161349cc55cSDimitry Andric 
162349cc55cSDimitry Andric Error ELFNixPlatform::setupJITDylib(JITDylib &JD) {
163349cc55cSDimitry Andric   return JD.define(
164349cc55cSDimitry Andric       std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol));
165349cc55cSDimitry Andric }
166349cc55cSDimitry Andric 
16704eeddc0SDimitry Andric Error ELFNixPlatform::teardownJITDylib(JITDylib &JD) {
16804eeddc0SDimitry Andric   return Error::success();
16904eeddc0SDimitry Andric }
17004eeddc0SDimitry Andric 
171349cc55cSDimitry Andric Error ELFNixPlatform::notifyAdding(ResourceTracker &RT,
172349cc55cSDimitry Andric                                    const MaterializationUnit &MU) {
173349cc55cSDimitry Andric   auto &JD = RT.getJITDylib();
174349cc55cSDimitry Andric   const auto &InitSym = MU.getInitializerSymbol();
175349cc55cSDimitry Andric   if (!InitSym)
176349cc55cSDimitry Andric     return Error::success();
177349cc55cSDimitry Andric 
178349cc55cSDimitry Andric   RegisteredInitSymbols[&JD].add(InitSym,
179349cc55cSDimitry Andric                                  SymbolLookupFlags::WeaklyReferencedSymbol);
180349cc55cSDimitry Andric   LLVM_DEBUG({
181349cc55cSDimitry Andric     dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym
182349cc55cSDimitry Andric            << " for MU " << MU.getName() << "\n";
183349cc55cSDimitry Andric   });
184349cc55cSDimitry Andric   return Error::success();
185349cc55cSDimitry Andric }
186349cc55cSDimitry Andric 
187349cc55cSDimitry Andric Error ELFNixPlatform::notifyRemoving(ResourceTracker &RT) {
188349cc55cSDimitry Andric   llvm_unreachable("Not supported yet");
189349cc55cSDimitry Andric }
190349cc55cSDimitry Andric 
191349cc55cSDimitry Andric static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
192349cc55cSDimitry Andric                        ArrayRef<std::pair<const char *, const char *>> AL) {
193349cc55cSDimitry Andric   for (auto &KV : AL) {
194349cc55cSDimitry Andric     auto AliasName = ES.intern(KV.first);
195349cc55cSDimitry Andric     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
196349cc55cSDimitry Andric     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
197349cc55cSDimitry Andric                                      JITSymbolFlags::Exported};
198349cc55cSDimitry Andric   }
199349cc55cSDimitry Andric }
200349cc55cSDimitry Andric 
20181ad6265SDimitry Andric Expected<SymbolAliasMap>
20281ad6265SDimitry Andric ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES,
20381ad6265SDimitry Andric                                         JITDylib &PlatformJD) {
204349cc55cSDimitry Andric   SymbolAliasMap Aliases;
205349cc55cSDimitry Andric   addAliases(ES, Aliases, requiredCXXAliases());
206349cc55cSDimitry Andric   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
20781ad6265SDimitry Andric 
20881ad6265SDimitry Andric   // Determine whether or not the libunwind extended-API function for
20981ad6265SDimitry Andric   // dynamically registering an entire .eh_frame section is available.
21081ad6265SDimitry Andric   // If it is not, we assume that libgcc_s is being used, and alias to
21181ad6265SDimitry Andric   // its __register_frame with the same functionality.
21281ad6265SDimitry Andric   auto RTRegisterFrame = ES.intern("__orc_rt_register_eh_frame_section");
21381ad6265SDimitry Andric   auto LibUnwindRegisterFrame = ES.intern("__unw_add_dynamic_eh_frame_section");
21481ad6265SDimitry Andric   auto RTDeregisterFrame = ES.intern("__orc_rt_deregister_eh_frame_section");
21581ad6265SDimitry Andric   auto LibUnwindDeregisterFrame =
21681ad6265SDimitry Andric       ES.intern("__unw_remove_dynamic_eh_frame_section");
21781ad6265SDimitry Andric   auto SM = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
21881ad6265SDimitry Andric                       SymbolLookupSet()
21981ad6265SDimitry Andric                           .add(LibUnwindRegisterFrame,
22081ad6265SDimitry Andric                                SymbolLookupFlags::WeaklyReferencedSymbol)
22181ad6265SDimitry Andric                           .add(LibUnwindDeregisterFrame,
22281ad6265SDimitry Andric                                SymbolLookupFlags::WeaklyReferencedSymbol));
22381ad6265SDimitry Andric   if (!SM) { // Weak-ref means no "missing symbol" errors, so this must be
22481ad6265SDimitry Andric              // something more serious that we should report.
22581ad6265SDimitry Andric     return SM.takeError();
22681ad6265SDimitry Andric   } else if (SM->size() == 2) {
22781ad6265SDimitry Andric     LLVM_DEBUG({
22881ad6265SDimitry Andric       dbgs() << "Using libunwind " << LibUnwindRegisterFrame
22981ad6265SDimitry Andric              << " for unwind info registration\n";
23081ad6265SDimitry Andric     });
23181ad6265SDimitry Andric     Aliases[std::move(RTRegisterFrame)] = {LibUnwindRegisterFrame,
23281ad6265SDimitry Andric                                            JITSymbolFlags::Exported};
23381ad6265SDimitry Andric     Aliases[std::move(RTDeregisterFrame)] = {LibUnwindDeregisterFrame,
23481ad6265SDimitry Andric                                              JITSymbolFlags::Exported};
23581ad6265SDimitry Andric   } else {
23681ad6265SDimitry Andric     // Since LLVM libunwind is not present, we assume that unwinding
23781ad6265SDimitry Andric     // is provided by libgcc
23881ad6265SDimitry Andric     LLVM_DEBUG({
23981ad6265SDimitry Andric       dbgs() << "Using libgcc __register_frame"
24081ad6265SDimitry Andric              << " for unwind info registration\n";
24181ad6265SDimitry Andric     });
24281ad6265SDimitry Andric     Aliases[std::move(RTRegisterFrame)] = {ES.intern("__register_frame"),
24381ad6265SDimitry Andric                                            JITSymbolFlags::Exported};
24481ad6265SDimitry Andric     Aliases[std::move(RTDeregisterFrame)] = {ES.intern("__deregister_frame"),
24581ad6265SDimitry Andric                                              JITSymbolFlags::Exported};
24681ad6265SDimitry Andric   }
24781ad6265SDimitry Andric 
248349cc55cSDimitry Andric   return Aliases;
249349cc55cSDimitry Andric }
250349cc55cSDimitry Andric 
251349cc55cSDimitry Andric ArrayRef<std::pair<const char *, const char *>>
252349cc55cSDimitry Andric ELFNixPlatform::requiredCXXAliases() {
253349cc55cSDimitry Andric   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
254349cc55cSDimitry Andric       {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"},
255349cc55cSDimitry Andric       {"atexit", "__orc_rt_elfnix_atexit"}};
256349cc55cSDimitry Andric 
257349cc55cSDimitry Andric   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
258349cc55cSDimitry Andric }
259349cc55cSDimitry Andric 
260349cc55cSDimitry Andric ArrayRef<std::pair<const char *, const char *>>
261349cc55cSDimitry Andric ELFNixPlatform::standardRuntimeUtilityAliases() {
262349cc55cSDimitry Andric   static const std::pair<const char *, const char *>
263349cc55cSDimitry Andric       StandardRuntimeUtilityAliases[] = {
264349cc55cSDimitry Andric           {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},
26581ad6265SDimitry Andric           {"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"},
26681ad6265SDimitry Andric           {"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"},
26781ad6265SDimitry Andric           {"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"},
26881ad6265SDimitry Andric           {"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"},
269349cc55cSDimitry Andric           {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
270349cc55cSDimitry Andric 
271349cc55cSDimitry Andric   return ArrayRef<std::pair<const char *, const char *>>(
272349cc55cSDimitry Andric       StandardRuntimeUtilityAliases);
273349cc55cSDimitry Andric }
274349cc55cSDimitry Andric 
275349cc55cSDimitry Andric bool ELFNixPlatform::isInitializerSection(StringRef SecName) {
27681ad6265SDimitry Andric   if (SecName.consume_front(InitArrayFuncSectionName) &&
27781ad6265SDimitry Andric       (SecName.empty() || SecName[0] == '.'))
278349cc55cSDimitry Andric     return true;
279349cc55cSDimitry Andric   return false;
280349cc55cSDimitry Andric }
281349cc55cSDimitry Andric 
282349cc55cSDimitry Andric bool ELFNixPlatform::supportedTarget(const Triple &TT) {
283349cc55cSDimitry Andric   switch (TT.getArch()) {
284349cc55cSDimitry Andric   case Triple::x86_64:
28581ad6265SDimitry Andric   case Triple::aarch64:
286349cc55cSDimitry Andric     return true;
287349cc55cSDimitry Andric   default:
288349cc55cSDimitry Andric     return false;
289349cc55cSDimitry Andric   }
290349cc55cSDimitry Andric }
291349cc55cSDimitry Andric 
292349cc55cSDimitry Andric ELFNixPlatform::ELFNixPlatform(
293349cc55cSDimitry Andric     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
294349cc55cSDimitry Andric     JITDylib &PlatformJD,
295349cc55cSDimitry Andric     std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
296349cc55cSDimitry Andric     : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
297349cc55cSDimitry Andric       DSOHandleSymbol(ES.intern("__dso_handle")) {
298349cc55cSDimitry Andric   ErrorAsOutParameter _(&Err);
299349cc55cSDimitry Andric 
300349cc55cSDimitry Andric   ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));
301349cc55cSDimitry Andric 
302349cc55cSDimitry Andric   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
303349cc55cSDimitry Andric 
304349cc55cSDimitry Andric   // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
305349cc55cSDimitry Andric   // the platform now), so set it up.
306349cc55cSDimitry Andric   if (auto E2 = setupJITDylib(PlatformJD)) {
307349cc55cSDimitry Andric     Err = std::move(E2);
308349cc55cSDimitry Andric     return;
309349cc55cSDimitry Andric   }
310349cc55cSDimitry Andric 
311349cc55cSDimitry Andric   RegisteredInitSymbols[&PlatformJD].add(
312349cc55cSDimitry Andric       DSOHandleSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);
313349cc55cSDimitry Andric 
314349cc55cSDimitry Andric   // Associate wrapper function tags with JIT-side function implementations.
315349cc55cSDimitry Andric   if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
316349cc55cSDimitry Andric     Err = std::move(E2);
317349cc55cSDimitry Andric     return;
318349cc55cSDimitry Andric   }
319349cc55cSDimitry Andric 
320349cc55cSDimitry Andric   // Lookup addresses of runtime functions callable by the platform,
321349cc55cSDimitry Andric   // call the platform bootstrap function to initialize the platform-state
322349cc55cSDimitry Andric   // object in the executor.
323349cc55cSDimitry Andric   if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) {
324349cc55cSDimitry Andric     Err = std::move(E2);
325349cc55cSDimitry Andric     return;
326349cc55cSDimitry Andric   }
327349cc55cSDimitry Andric }
328349cc55cSDimitry Andric 
329349cc55cSDimitry Andric Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
330349cc55cSDimitry Andric   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
331349cc55cSDimitry Andric 
332349cc55cSDimitry Andric   using GetInitializersSPSSig =
333349cc55cSDimitry Andric       SPSExpected<SPSELFNixJITDylibInitializerSequence>(SPSString);
334349cc55cSDimitry Andric   WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] =
335349cc55cSDimitry Andric       ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
336349cc55cSDimitry Andric           this, &ELFNixPlatform::rt_getInitializers);
337349cc55cSDimitry Andric 
338349cc55cSDimitry Andric   using GetDeinitializersSPSSig =
339349cc55cSDimitry Andric       SPSExpected<SPSELFJITDylibDeinitializerSequence>(SPSExecutorAddr);
340349cc55cSDimitry Andric   WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] =
341349cc55cSDimitry Andric       ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
342349cc55cSDimitry Andric           this, &ELFNixPlatform::rt_getDeinitializers);
343349cc55cSDimitry Andric 
344349cc55cSDimitry Andric   using LookupSymbolSPSSig =
345349cc55cSDimitry Andric       SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
346349cc55cSDimitry Andric   WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] =
347349cc55cSDimitry Andric       ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
348349cc55cSDimitry Andric                                               &ELFNixPlatform::rt_lookupSymbol);
349349cc55cSDimitry Andric 
350349cc55cSDimitry Andric   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
351349cc55cSDimitry Andric }
352349cc55cSDimitry Andric 
353349cc55cSDimitry Andric void ELFNixPlatform::getInitializersBuildSequencePhase(
354349cc55cSDimitry Andric     SendInitializerSequenceFn SendResult, JITDylib &JD,
355349cc55cSDimitry Andric     std::vector<JITDylibSP> DFSLinkOrder) {
356349cc55cSDimitry Andric   ELFNixJITDylibInitializerSequence FullInitSeq;
357349cc55cSDimitry Andric   {
358349cc55cSDimitry Andric     std::lock_guard<std::mutex> Lock(PlatformMutex);
359349cc55cSDimitry Andric     for (auto &InitJD : reverse(DFSLinkOrder)) {
360349cc55cSDimitry Andric       LLVM_DEBUG({
361349cc55cSDimitry Andric         dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName()
362349cc55cSDimitry Andric                << "\" to sequence\n";
363349cc55cSDimitry Andric       });
364349cc55cSDimitry Andric       auto ISItr = InitSeqs.find(InitJD.get());
365349cc55cSDimitry Andric       if (ISItr != InitSeqs.end()) {
366349cc55cSDimitry Andric         FullInitSeq.emplace_back(std::move(ISItr->second));
367349cc55cSDimitry Andric         InitSeqs.erase(ISItr);
368349cc55cSDimitry Andric       }
369349cc55cSDimitry Andric     }
370349cc55cSDimitry Andric   }
371349cc55cSDimitry Andric 
372349cc55cSDimitry Andric   SendResult(std::move(FullInitSeq));
373349cc55cSDimitry Andric }
374349cc55cSDimitry Andric 
375349cc55cSDimitry Andric void ELFNixPlatform::getInitializersLookupPhase(
376349cc55cSDimitry Andric     SendInitializerSequenceFn SendResult, JITDylib &JD) {
377349cc55cSDimitry Andric 
378349cc55cSDimitry Andric   auto DFSLinkOrder = JD.getDFSLinkOrder();
37904eeddc0SDimitry Andric   if (!DFSLinkOrder) {
38004eeddc0SDimitry Andric     SendResult(DFSLinkOrder.takeError());
38104eeddc0SDimitry Andric     return;
38204eeddc0SDimitry Andric   }
38304eeddc0SDimitry Andric 
384349cc55cSDimitry Andric   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
385349cc55cSDimitry Andric   ES.runSessionLocked([&]() {
38604eeddc0SDimitry Andric     for (auto &InitJD : *DFSLinkOrder) {
387349cc55cSDimitry Andric       auto RISItr = RegisteredInitSymbols.find(InitJD.get());
388349cc55cSDimitry Andric       if (RISItr != RegisteredInitSymbols.end()) {
389349cc55cSDimitry Andric         NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
390349cc55cSDimitry Andric         RegisteredInitSymbols.erase(RISItr);
391349cc55cSDimitry Andric       }
392349cc55cSDimitry Andric     }
393349cc55cSDimitry Andric   });
394349cc55cSDimitry Andric 
395349cc55cSDimitry Andric   // If there are no further init symbols to look up then move on to the next
396349cc55cSDimitry Andric   // phase.
397349cc55cSDimitry Andric   if (NewInitSymbols.empty()) {
398349cc55cSDimitry Andric     getInitializersBuildSequencePhase(std::move(SendResult), JD,
39904eeddc0SDimitry Andric                                       std::move(*DFSLinkOrder));
400349cc55cSDimitry Andric     return;
401349cc55cSDimitry Andric   }
402349cc55cSDimitry Andric 
403349cc55cSDimitry Andric   // Otherwise issue a lookup and re-run this phase when it completes.
404349cc55cSDimitry Andric   lookupInitSymbolsAsync(
405349cc55cSDimitry Andric       [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
406349cc55cSDimitry Andric         if (Err)
407349cc55cSDimitry Andric           SendResult(std::move(Err));
408349cc55cSDimitry Andric         else
409349cc55cSDimitry Andric           getInitializersLookupPhase(std::move(SendResult), JD);
410349cc55cSDimitry Andric       },
411349cc55cSDimitry Andric       ES, std::move(NewInitSymbols));
412349cc55cSDimitry Andric }
413349cc55cSDimitry Andric 
414349cc55cSDimitry Andric void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
415349cc55cSDimitry Andric                                         StringRef JDName) {
416349cc55cSDimitry Andric   LLVM_DEBUG({
417349cc55cSDimitry Andric     dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n";
418349cc55cSDimitry Andric   });
419349cc55cSDimitry Andric 
420349cc55cSDimitry Andric   JITDylib *JD = ES.getJITDylibByName(JDName);
421349cc55cSDimitry Andric   if (!JD) {
422349cc55cSDimitry Andric     LLVM_DEBUG({
423349cc55cSDimitry Andric       dbgs() << "  No such JITDylib \"" << JDName << "\". Sending error.\n";
424349cc55cSDimitry Andric     });
425349cc55cSDimitry Andric     SendResult(make_error<StringError>("No JITDylib named " + JDName,
426349cc55cSDimitry Andric                                        inconvertibleErrorCode()));
427349cc55cSDimitry Andric     return;
428349cc55cSDimitry Andric   }
429349cc55cSDimitry Andric 
430349cc55cSDimitry Andric   getInitializersLookupPhase(std::move(SendResult), *JD);
431349cc55cSDimitry Andric }
432349cc55cSDimitry Andric 
433349cc55cSDimitry Andric void ELFNixPlatform::rt_getDeinitializers(
434349cc55cSDimitry Andric     SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) {
435349cc55cSDimitry Andric   LLVM_DEBUG({
436349cc55cSDimitry Andric     dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
437349cc55cSDimitry Andric            << formatv("{0:x}", Handle.getValue()) << "\")\n";
438349cc55cSDimitry Andric   });
439349cc55cSDimitry Andric 
440349cc55cSDimitry Andric   JITDylib *JD = nullptr;
441349cc55cSDimitry Andric 
442349cc55cSDimitry Andric   {
443349cc55cSDimitry Andric     std::lock_guard<std::mutex> Lock(PlatformMutex);
44404eeddc0SDimitry Andric     auto I = HandleAddrToJITDylib.find(Handle);
445349cc55cSDimitry Andric     if (I != HandleAddrToJITDylib.end())
446349cc55cSDimitry Andric       JD = I->second;
447349cc55cSDimitry Andric   }
448349cc55cSDimitry Andric 
449349cc55cSDimitry Andric   if (!JD) {
450349cc55cSDimitry Andric     LLVM_DEBUG({
451349cc55cSDimitry Andric       dbgs() << "  No JITDylib for handle "
452349cc55cSDimitry Andric              << formatv("{0:x}", Handle.getValue()) << "\n";
453349cc55cSDimitry Andric     });
454349cc55cSDimitry Andric     SendResult(make_error<StringError>("No JITDylib associated with handle " +
455349cc55cSDimitry Andric                                            formatv("{0:x}", Handle.getValue()),
456349cc55cSDimitry Andric                                        inconvertibleErrorCode()));
457349cc55cSDimitry Andric     return;
458349cc55cSDimitry Andric   }
459349cc55cSDimitry Andric 
460349cc55cSDimitry Andric   SendResult(ELFNixJITDylibDeinitializerSequence());
461349cc55cSDimitry Andric }
462349cc55cSDimitry Andric 
463349cc55cSDimitry Andric void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
464349cc55cSDimitry Andric                                      ExecutorAddr Handle,
465349cc55cSDimitry Andric                                      StringRef SymbolName) {
466349cc55cSDimitry Andric   LLVM_DEBUG({
467349cc55cSDimitry Andric     dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
468349cc55cSDimitry Andric            << formatv("{0:x}", Handle.getValue()) << "\")\n";
469349cc55cSDimitry Andric   });
470349cc55cSDimitry Andric 
471349cc55cSDimitry Andric   JITDylib *JD = nullptr;
472349cc55cSDimitry Andric 
473349cc55cSDimitry Andric   {
474349cc55cSDimitry Andric     std::lock_guard<std::mutex> Lock(PlatformMutex);
47504eeddc0SDimitry Andric     auto I = HandleAddrToJITDylib.find(Handle);
476349cc55cSDimitry Andric     if (I != HandleAddrToJITDylib.end())
477349cc55cSDimitry Andric       JD = I->second;
478349cc55cSDimitry Andric   }
479349cc55cSDimitry Andric 
480349cc55cSDimitry Andric   if (!JD) {
481349cc55cSDimitry Andric     LLVM_DEBUG({
482349cc55cSDimitry Andric       dbgs() << "  No JITDylib for handle "
483349cc55cSDimitry Andric              << formatv("{0:x}", Handle.getValue()) << "\n";
484349cc55cSDimitry Andric     });
485349cc55cSDimitry Andric     SendResult(make_error<StringError>("No JITDylib associated with handle " +
486349cc55cSDimitry Andric                                            formatv("{0:x}", Handle.getValue()),
487349cc55cSDimitry Andric                                        inconvertibleErrorCode()));
488349cc55cSDimitry Andric     return;
489349cc55cSDimitry Andric   }
490349cc55cSDimitry Andric 
491349cc55cSDimitry Andric   // Use functor class to work around XL build compiler issue on AIX.
492349cc55cSDimitry Andric   class RtLookupNotifyComplete {
493349cc55cSDimitry Andric   public:
494349cc55cSDimitry Andric     RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
495349cc55cSDimitry Andric         : SendResult(std::move(SendResult)) {}
496349cc55cSDimitry Andric     void operator()(Expected<SymbolMap> Result) {
497349cc55cSDimitry Andric       if (Result) {
498349cc55cSDimitry Andric         assert(Result->size() == 1 && "Unexpected result map count");
499349cc55cSDimitry Andric         SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
500349cc55cSDimitry Andric       } else {
501349cc55cSDimitry Andric         SendResult(Result.takeError());
502349cc55cSDimitry Andric       }
503349cc55cSDimitry Andric     }
504349cc55cSDimitry Andric 
505349cc55cSDimitry Andric   private:
506349cc55cSDimitry Andric     SendSymbolAddressFn SendResult;
507349cc55cSDimitry Andric   };
508349cc55cSDimitry Andric 
509349cc55cSDimitry Andric   ES.lookup(
510349cc55cSDimitry Andric       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
511349cc55cSDimitry Andric       SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,
512349cc55cSDimitry Andric       RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
513349cc55cSDimitry Andric }
514349cc55cSDimitry Andric 
515349cc55cSDimitry Andric Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) {
516349cc55cSDimitry Andric 
517349cc55cSDimitry Andric   std::pair<const char *, ExecutorAddr *> Symbols[] = {
518349cc55cSDimitry Andric       {"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap},
519349cc55cSDimitry Andric       {"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown},
520349cc55cSDimitry Andric       {"__orc_rt_elfnix_register_object_sections",
521349cc55cSDimitry Andric        &orc_rt_elfnix_register_object_sections},
522349cc55cSDimitry Andric       {"__orc_rt_elfnix_create_pthread_key",
523349cc55cSDimitry Andric        &orc_rt_elfnix_create_pthread_key}};
524349cc55cSDimitry Andric 
525349cc55cSDimitry Andric   SymbolLookupSet RuntimeSymbols;
526349cc55cSDimitry Andric   std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord;
527349cc55cSDimitry Andric   for (const auto &KV : Symbols) {
528349cc55cSDimitry Andric     auto Name = ES.intern(KV.first);
529349cc55cSDimitry Andric     RuntimeSymbols.add(Name);
530349cc55cSDimitry Andric     AddrsToRecord.push_back({std::move(Name), KV.second});
531349cc55cSDimitry Andric   }
532349cc55cSDimitry Andric 
533349cc55cSDimitry Andric   auto RuntimeSymbolAddrs = ES.lookup(
534349cc55cSDimitry Andric       {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols);
535349cc55cSDimitry Andric   if (!RuntimeSymbolAddrs)
536349cc55cSDimitry Andric     return RuntimeSymbolAddrs.takeError();
537349cc55cSDimitry Andric 
538349cc55cSDimitry Andric   for (const auto &KV : AddrsToRecord) {
539349cc55cSDimitry Andric     auto &Name = KV.first;
540349cc55cSDimitry Andric     assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?");
541349cc55cSDimitry Andric     KV.second->setValue((*RuntimeSymbolAddrs)[Name].getAddress());
542349cc55cSDimitry Andric   }
543349cc55cSDimitry Andric 
544349cc55cSDimitry Andric   auto PJDDSOHandle = ES.lookup(
545349cc55cSDimitry Andric       {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol);
546349cc55cSDimitry Andric   if (!PJDDSOHandle)
547349cc55cSDimitry Andric     return PJDDSOHandle.takeError();
548349cc55cSDimitry Andric 
549349cc55cSDimitry Andric   if (auto Err = ES.callSPSWrapper<void(uint64_t)>(
550349cc55cSDimitry Andric           orc_rt_elfnix_platform_bootstrap, PJDDSOHandle->getAddress()))
551349cc55cSDimitry Andric     return Err;
552349cc55cSDimitry Andric 
553349cc55cSDimitry Andric   // FIXME: Ordering is fuzzy here. We're probably best off saying
554349cc55cSDimitry Andric   // "behavior is undefined if code that uses the runtime is added before
555349cc55cSDimitry Andric   // the platform constructor returns", then move all this to the constructor.
556349cc55cSDimitry Andric   RuntimeBootstrapped = true;
557349cc55cSDimitry Andric   std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs;
558349cc55cSDimitry Andric   {
559349cc55cSDimitry Andric     std::lock_guard<std::mutex> Lock(PlatformMutex);
560349cc55cSDimitry Andric     DeferredPOSRs = std::move(BootstrapPOSRs);
561349cc55cSDimitry Andric   }
562349cc55cSDimitry Andric 
563349cc55cSDimitry Andric   for (auto &D : DeferredPOSRs)
564349cc55cSDimitry Andric     if (auto Err = registerPerObjectSections(D))
565349cc55cSDimitry Andric       return Err;
566349cc55cSDimitry Andric 
567349cc55cSDimitry Andric   return Error::success();
568349cc55cSDimitry Andric }
569349cc55cSDimitry Andric 
570349cc55cSDimitry Andric Error ELFNixPlatform::registerInitInfo(
571349cc55cSDimitry Andric     JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {
572349cc55cSDimitry Andric 
573349cc55cSDimitry Andric   std::unique_lock<std::mutex> Lock(PlatformMutex);
574349cc55cSDimitry Andric 
575349cc55cSDimitry Andric   ELFNixJITDylibInitializers *InitSeq = nullptr;
576349cc55cSDimitry Andric   {
577349cc55cSDimitry Andric     auto I = InitSeqs.find(&JD);
578349cc55cSDimitry Andric     if (I == InitSeqs.end()) {
579349cc55cSDimitry Andric       // If there's no init sequence entry yet then we need to look up the
580349cc55cSDimitry Andric       // header symbol to force creation of one.
581349cc55cSDimitry Andric       Lock.unlock();
582349cc55cSDimitry Andric 
583349cc55cSDimitry Andric       auto SearchOrder =
584349cc55cSDimitry Andric           JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
585349cc55cSDimitry Andric       if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError())
586349cc55cSDimitry Andric         return Err;
587349cc55cSDimitry Andric 
588349cc55cSDimitry Andric       Lock.lock();
589349cc55cSDimitry Andric       I = InitSeqs.find(&JD);
590349cc55cSDimitry Andric       assert(I != InitSeqs.end() &&
591349cc55cSDimitry Andric              "Entry missing after header symbol lookup?");
592349cc55cSDimitry Andric     }
593349cc55cSDimitry Andric     InitSeq = &I->second;
594349cc55cSDimitry Andric   }
595349cc55cSDimitry Andric 
596349cc55cSDimitry Andric   for (auto *Sec : InitSections) {
597349cc55cSDimitry Andric     // FIXME: Avoid copy here.
598349cc55cSDimitry Andric     jitlink::SectionRange R(*Sec);
599349cc55cSDimitry Andric     InitSeq->InitSections[Sec->getName()].push_back(
600349cc55cSDimitry Andric         {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())});
601349cc55cSDimitry Andric   }
602349cc55cSDimitry Andric 
603349cc55cSDimitry Andric   return Error::success();
604349cc55cSDimitry Andric }
605349cc55cSDimitry Andric 
606349cc55cSDimitry Andric Error ELFNixPlatform::registerPerObjectSections(
607349cc55cSDimitry Andric     const ELFPerObjectSectionsToRegister &POSR) {
608349cc55cSDimitry Andric 
609349cc55cSDimitry Andric   if (!orc_rt_elfnix_register_object_sections)
610349cc55cSDimitry Andric     return make_error<StringError>("Attempting to register per-object "
611349cc55cSDimitry Andric                                    "sections, but runtime support has not "
612349cc55cSDimitry Andric                                    "been loaded yet",
613349cc55cSDimitry Andric                                    inconvertibleErrorCode());
614349cc55cSDimitry Andric 
615349cc55cSDimitry Andric   Error ErrResult = Error::success();
616349cc55cSDimitry Andric   if (auto Err = ES.callSPSWrapper<shared::SPSError(
617349cc55cSDimitry Andric                      SPSELFPerObjectSectionsToRegister)>(
618349cc55cSDimitry Andric           orc_rt_elfnix_register_object_sections, ErrResult, POSR))
619349cc55cSDimitry Andric     return Err;
620349cc55cSDimitry Andric   return ErrResult;
621349cc55cSDimitry Andric }
622349cc55cSDimitry Andric 
623349cc55cSDimitry Andric Expected<uint64_t> ELFNixPlatform::createPThreadKey() {
624349cc55cSDimitry Andric   if (!orc_rt_elfnix_create_pthread_key)
625349cc55cSDimitry Andric     return make_error<StringError>(
626349cc55cSDimitry Andric         "Attempting to create pthread key in target, but runtime support has "
627349cc55cSDimitry Andric         "not been loaded yet",
628349cc55cSDimitry Andric         inconvertibleErrorCode());
629349cc55cSDimitry Andric 
630349cc55cSDimitry Andric   Expected<uint64_t> Result(0);
631349cc55cSDimitry Andric   if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
632349cc55cSDimitry Andric           orc_rt_elfnix_create_pthread_key, Result))
633349cc55cSDimitry Andric     return std::move(Err);
634349cc55cSDimitry Andric   return Result;
635349cc55cSDimitry Andric }
636349cc55cSDimitry Andric 
637349cc55cSDimitry Andric void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig(
638349cc55cSDimitry Andric     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
639349cc55cSDimitry Andric     jitlink::PassConfiguration &Config) {
640349cc55cSDimitry Andric 
641349cc55cSDimitry Andric   // If the initializer symbol is the __dso_handle symbol then just add
642349cc55cSDimitry Andric   // the DSO handle support passes.
643349cc55cSDimitry Andric   if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) {
644349cc55cSDimitry Andric     addDSOHandleSupportPasses(MR, Config);
645349cc55cSDimitry Andric     // The DSOHandle materialization unit doesn't require any other
646349cc55cSDimitry Andric     // support, so we can bail out early.
647349cc55cSDimitry Andric     return;
648349cc55cSDimitry Andric   }
649349cc55cSDimitry Andric 
650349cc55cSDimitry Andric   // If the object contains initializers then add passes to record them.
651349cc55cSDimitry Andric   if (MR.getInitializerSymbol())
652349cc55cSDimitry Andric     addInitializerSupportPasses(MR, Config);
653349cc55cSDimitry Andric 
654349cc55cSDimitry Andric   // Add passes for eh-frame and TLV support.
655349cc55cSDimitry Andric   addEHAndTLVSupportPasses(MR, Config);
656349cc55cSDimitry Andric }
657349cc55cSDimitry Andric 
658349cc55cSDimitry Andric ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
659349cc55cSDimitry Andric ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies(
660349cc55cSDimitry Andric     MaterializationResponsibility &MR) {
661349cc55cSDimitry Andric   std::lock_guard<std::mutex> Lock(PluginMutex);
662349cc55cSDimitry Andric   auto I = InitSymbolDeps.find(&MR);
663349cc55cSDimitry Andric   if (I != InitSymbolDeps.end()) {
664349cc55cSDimitry Andric     SyntheticSymbolDependenciesMap Result;
665349cc55cSDimitry Andric     Result[MR.getInitializerSymbol()] = std::move(I->second);
666349cc55cSDimitry Andric     InitSymbolDeps.erase(&MR);
667349cc55cSDimitry Andric     return Result;
668349cc55cSDimitry Andric   }
669349cc55cSDimitry Andric   return SyntheticSymbolDependenciesMap();
670349cc55cSDimitry Andric }
671349cc55cSDimitry Andric 
672349cc55cSDimitry Andric void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses(
673349cc55cSDimitry Andric     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
674349cc55cSDimitry Andric 
675349cc55cSDimitry Andric   /// Preserve init sections.
676349cc55cSDimitry Andric   Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {
677349cc55cSDimitry Andric     if (auto Err = preserveInitSections(G, MR))
678349cc55cSDimitry Andric       return Err;
679349cc55cSDimitry Andric     return Error::success();
680349cc55cSDimitry Andric   });
681349cc55cSDimitry Andric 
682349cc55cSDimitry Andric   Config.PostFixupPasses.push_back(
683349cc55cSDimitry Andric       [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
684349cc55cSDimitry Andric         return registerInitSections(G, JD);
685349cc55cSDimitry Andric       });
686349cc55cSDimitry Andric }
687349cc55cSDimitry Andric 
688349cc55cSDimitry Andric void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses(
689349cc55cSDimitry Andric     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
690349cc55cSDimitry Andric 
691349cc55cSDimitry Andric   Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](
692349cc55cSDimitry Andric                                             jitlink::LinkGraph &G) -> Error {
693349cc55cSDimitry Andric     auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
694349cc55cSDimitry Andric       return Sym->getName() == *MP.DSOHandleSymbol;
695349cc55cSDimitry Andric     });
696349cc55cSDimitry Andric     assert(I != G.defined_symbols().end() && "Missing DSO handle symbol");
697349cc55cSDimitry Andric     {
698349cc55cSDimitry Andric       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
69904eeddc0SDimitry Andric       auto HandleAddr = (*I)->getAddress();
700349cc55cSDimitry Andric       MP.HandleAddrToJITDylib[HandleAddr] = &JD;
701349cc55cSDimitry Andric       assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists");
702349cc55cSDimitry Andric       MP.InitSeqs.insert(std::make_pair(
70304eeddc0SDimitry Andric           &JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr)));
704349cc55cSDimitry Andric     }
705349cc55cSDimitry Andric     return Error::success();
706349cc55cSDimitry Andric   });
707349cc55cSDimitry Andric }
708349cc55cSDimitry Andric 
709349cc55cSDimitry Andric void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses(
710349cc55cSDimitry Andric     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
711349cc55cSDimitry Andric 
712349cc55cSDimitry Andric   // Insert TLV lowering at the start of the PostPrunePasses, since we want
713349cc55cSDimitry Andric   // it to run before GOT/PLT lowering.
714349cc55cSDimitry Andric 
715349cc55cSDimitry Andric   // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build
716349cc55cSDimitry Andric   // pass has done. Because the TLS descriptor need to be allocate in GOT.
717349cc55cSDimitry Andric   Config.PostPrunePasses.push_back(
718349cc55cSDimitry Andric       [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
719349cc55cSDimitry Andric         return fixTLVSectionsAndEdges(G, JD);
720349cc55cSDimitry Andric       });
721349cc55cSDimitry Andric 
722349cc55cSDimitry Andric   // Add a pass to register the final addresses of the eh-frame and TLV sections
723349cc55cSDimitry Andric   // with the runtime.
724349cc55cSDimitry Andric   Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
725349cc55cSDimitry Andric     ELFPerObjectSectionsToRegister POSR;
726349cc55cSDimitry Andric 
727349cc55cSDimitry Andric     if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) {
728349cc55cSDimitry Andric       jitlink::SectionRange R(*EHFrameSection);
729349cc55cSDimitry Andric       if (!R.empty())
730349cc55cSDimitry Andric         POSR.EHFrameSection = {ExecutorAddr(R.getStart()),
731349cc55cSDimitry Andric                                ExecutorAddr(R.getEnd())};
732349cc55cSDimitry Andric     }
733349cc55cSDimitry Andric 
734349cc55cSDimitry Andric     // Get a pointer to the thread data section if there is one. It will be used
735349cc55cSDimitry Andric     // below.
736349cc55cSDimitry Andric     jitlink::Section *ThreadDataSection =
737349cc55cSDimitry Andric         G.findSectionByName(ThreadDataSectionName);
738349cc55cSDimitry Andric 
739349cc55cSDimitry Andric     // Handle thread BSS section if there is one.
740349cc55cSDimitry Andric     if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) {
741349cc55cSDimitry Andric       // If there's already a thread data section in this graph then merge the
742349cc55cSDimitry Andric       // thread BSS section content into it, otherwise just treat the thread
743349cc55cSDimitry Andric       // BSS section as the thread data section.
744349cc55cSDimitry Andric       if (ThreadDataSection)
745349cc55cSDimitry Andric         G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
746349cc55cSDimitry Andric       else
747349cc55cSDimitry Andric         ThreadDataSection = ThreadBSSSection;
748349cc55cSDimitry Andric     }
749349cc55cSDimitry Andric 
750349cc55cSDimitry Andric     // Having merged thread BSS (if present) and thread data (if present),
751349cc55cSDimitry Andric     // record the resulting section range.
752349cc55cSDimitry Andric     if (ThreadDataSection) {
753349cc55cSDimitry Andric       jitlink::SectionRange R(*ThreadDataSection);
754349cc55cSDimitry Andric       if (!R.empty())
755349cc55cSDimitry Andric         POSR.ThreadDataSection = {ExecutorAddr(R.getStart()),
756349cc55cSDimitry Andric                                   ExecutorAddr(R.getEnd())};
757349cc55cSDimitry Andric     }
758349cc55cSDimitry Andric 
759349cc55cSDimitry Andric     if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
760349cc55cSDimitry Andric 
761349cc55cSDimitry Andric       // If we're still bootstrapping the runtime then just record this
762349cc55cSDimitry Andric       // frame for now.
763349cc55cSDimitry Andric       if (!MP.RuntimeBootstrapped) {
764349cc55cSDimitry Andric         std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
765349cc55cSDimitry Andric         MP.BootstrapPOSRs.push_back(POSR);
766349cc55cSDimitry Andric         return Error::success();
767349cc55cSDimitry Andric       }
768349cc55cSDimitry Andric 
769349cc55cSDimitry Andric       // Otherwise register it immediately.
770349cc55cSDimitry Andric       if (auto Err = MP.registerPerObjectSections(POSR))
771349cc55cSDimitry Andric         return Err;
772349cc55cSDimitry Andric     }
773349cc55cSDimitry Andric 
774349cc55cSDimitry Andric     return Error::success();
775349cc55cSDimitry Andric   });
776349cc55cSDimitry Andric }
777349cc55cSDimitry Andric 
778349cc55cSDimitry Andric Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
779349cc55cSDimitry Andric     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
780349cc55cSDimitry Andric 
781349cc55cSDimitry Andric   JITLinkSymbolSet InitSectionSymbols;
78281ad6265SDimitry Andric   for (auto &InitSection : G.sections()) {
783349cc55cSDimitry Andric     // Skip non-init sections.
78481ad6265SDimitry Andric     if (!isInitializerSection(InitSection.getName()))
785349cc55cSDimitry Andric       continue;
786349cc55cSDimitry Andric 
787349cc55cSDimitry Andric     // Make a pass over live symbols in the section: those blocks are already
788349cc55cSDimitry Andric     // preserved.
789349cc55cSDimitry Andric     DenseSet<jitlink::Block *> AlreadyLiveBlocks;
79081ad6265SDimitry Andric     for (auto &Sym : InitSection.symbols()) {
791349cc55cSDimitry Andric       auto &B = Sym->getBlock();
792349cc55cSDimitry Andric       if (Sym->isLive() && Sym->getOffset() == 0 &&
793349cc55cSDimitry Andric           Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
794349cc55cSDimitry Andric         InitSectionSymbols.insert(Sym);
795349cc55cSDimitry Andric         AlreadyLiveBlocks.insert(&B);
796349cc55cSDimitry Andric       }
797349cc55cSDimitry Andric     }
798349cc55cSDimitry Andric 
799349cc55cSDimitry Andric     // Add anonymous symbols to preserve any not-already-preserved blocks.
80081ad6265SDimitry Andric     for (auto *B : InitSection.blocks())
801349cc55cSDimitry Andric       if (!AlreadyLiveBlocks.count(B))
802349cc55cSDimitry Andric         InitSectionSymbols.insert(
803349cc55cSDimitry Andric             &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
804349cc55cSDimitry Andric   }
805349cc55cSDimitry Andric 
806349cc55cSDimitry Andric   if (!InitSectionSymbols.empty()) {
807349cc55cSDimitry Andric     std::lock_guard<std::mutex> Lock(PluginMutex);
808349cc55cSDimitry Andric     InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
809349cc55cSDimitry Andric   }
810349cc55cSDimitry Andric 
811349cc55cSDimitry Andric   return Error::success();
812349cc55cSDimitry Andric }
813349cc55cSDimitry Andric 
814349cc55cSDimitry Andric Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections(
815349cc55cSDimitry Andric     jitlink::LinkGraph &G, JITDylib &JD) {
816349cc55cSDimitry Andric 
817349cc55cSDimitry Andric   SmallVector<jitlink::Section *> InitSections;
818349cc55cSDimitry Andric 
819349cc55cSDimitry Andric   LLVM_DEBUG({ dbgs() << "ELFNixPlatform::registerInitSections\n"; });
820349cc55cSDimitry Andric 
82181ad6265SDimitry Andric   for (auto &Sec : G.sections()) {
82281ad6265SDimitry Andric     if (isInitializerSection(Sec.getName())) {
82381ad6265SDimitry Andric       InitSections.push_back(&Sec);
824349cc55cSDimitry Andric     }
825349cc55cSDimitry Andric   }
826349cc55cSDimitry Andric 
827349cc55cSDimitry Andric   // Dump the scraped inits.
828349cc55cSDimitry Andric   LLVM_DEBUG({
829349cc55cSDimitry Andric     dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n";
830349cc55cSDimitry Andric     for (auto *Sec : InitSections) {
831349cc55cSDimitry Andric       jitlink::SectionRange R(*Sec);
832349cc55cSDimitry Andric       dbgs() << "  " << Sec->getName() << ": "
833349cc55cSDimitry Andric              << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n";
834349cc55cSDimitry Andric     }
835349cc55cSDimitry Andric   });
836349cc55cSDimitry Andric 
837349cc55cSDimitry Andric   return MP.registerInitInfo(JD, InitSections);
838349cc55cSDimitry Andric }
839349cc55cSDimitry Andric 
840349cc55cSDimitry Andric Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
841349cc55cSDimitry Andric     jitlink::LinkGraph &G, JITDylib &JD) {
842349cc55cSDimitry Andric 
843753f127fSDimitry Andric   for (auto *Sym : G.external_symbols()) {
844349cc55cSDimitry Andric     if (Sym->getName() == "__tls_get_addr") {
845349cc55cSDimitry Andric       Sym->setName("___orc_rt_elfnix_tls_get_addr");
846753f127fSDimitry Andric     } else if (Sym->getName() == "__tlsdesc_resolver") {
847753f127fSDimitry Andric       Sym->setName("___orc_rt_elfnix_tlsdesc_resolver");
848753f127fSDimitry Andric     }
849349cc55cSDimitry Andric   }
850349cc55cSDimitry Andric 
851349cc55cSDimitry Andric   auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO");
852349cc55cSDimitry Andric 
853349cc55cSDimitry Andric   if (TLSInfoEntrySection) {
854*bdd1243dSDimitry Andric     std::optional<uint64_t> Key;
855349cc55cSDimitry Andric     {
856349cc55cSDimitry Andric       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
857349cc55cSDimitry Andric       auto I = MP.JITDylibToPThreadKey.find(&JD);
858349cc55cSDimitry Andric       if (I != MP.JITDylibToPThreadKey.end())
859349cc55cSDimitry Andric         Key = I->second;
860349cc55cSDimitry Andric     }
861349cc55cSDimitry Andric     if (!Key) {
862349cc55cSDimitry Andric       if (auto KeyOrErr = MP.createPThreadKey())
863349cc55cSDimitry Andric         Key = *KeyOrErr;
864349cc55cSDimitry Andric       else
865349cc55cSDimitry Andric         return KeyOrErr.takeError();
866349cc55cSDimitry Andric     }
867349cc55cSDimitry Andric 
868349cc55cSDimitry Andric     uint64_t PlatformKeyBits =
869349cc55cSDimitry Andric         support::endian::byte_swap(*Key, G.getEndianness());
870349cc55cSDimitry Andric 
871349cc55cSDimitry Andric     for (auto *B : TLSInfoEntrySection->blocks()) {
872349cc55cSDimitry Andric       // FIXME: The TLS descriptor byte length may different with different
873349cc55cSDimitry Andric       // ISA
874349cc55cSDimitry Andric       assert(B->getSize() == (G.getPointerSize() * 2) &&
875349cc55cSDimitry Andric              "TLS descriptor must be 2 words length");
876349cc55cSDimitry Andric       auto TLSInfoEntryContent = B->getMutableContent(G);
877349cc55cSDimitry Andric       memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize());
878349cc55cSDimitry Andric     }
879349cc55cSDimitry Andric   }
880349cc55cSDimitry Andric 
881349cc55cSDimitry Andric   return Error::success();
882349cc55cSDimitry Andric }
883349cc55cSDimitry Andric 
884349cc55cSDimitry Andric } // End namespace orc.
885349cc55cSDimitry Andric } // End namespace llvm.
886