1 //===------- COFFPlatform.cpp - Utilities for executing COFF 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/COFFPlatform.h"
10 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
11 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
12 #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
13 #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
14 
15 #include "llvm/Object/COFF.h"
16 
17 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
18 
19 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
20 
21 #define DEBUG_TYPE "orc"
22 
23 using namespace llvm;
24 using namespace llvm::orc;
25 using namespace llvm::orc::shared;
26 
27 namespace llvm {
28 namespace orc {
29 namespace shared {
30 
31 using SPSCOFFJITDylibDepInfo = SPSSequence<SPSExecutorAddr>;
32 using SPSCOFFJITDylibDepInfoMap =
33     SPSSequence<SPSTuple<SPSExecutorAddr, SPSCOFFJITDylibDepInfo>>;
34 using SPSCOFFObjectSectionsMap =
35     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
36 using SPSCOFFRegisterObjectSectionsArgs =
37     SPSArgList<SPSExecutorAddr, SPSCOFFObjectSectionsMap, bool>;
38 using SPSCOFFDeregisterObjectSectionsArgs =
39     SPSArgList<SPSExecutorAddr, SPSCOFFObjectSectionsMap>;
40 
41 } // namespace shared
42 } // namespace orc
43 } // namespace llvm
44 namespace {
45 
46 class COFFHeaderMaterializationUnit : public MaterializationUnit {
47 public:
48   COFFHeaderMaterializationUnit(COFFPlatform &CP,
49                                 const SymbolStringPtr &HeaderStartSymbol)
50       : MaterializationUnit(createHeaderInterface(CP, HeaderStartSymbol)),
51         CP(CP) {}
52 
53   StringRef getName() const override { return "COFFHeaderMU"; }
54 
55   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
56     unsigned PointerSize;
57     support::endianness Endianness;
58     const auto &TT = CP.getExecutionSession().getTargetTriple();
59 
60     switch (TT.getArch()) {
61     case Triple::x86_64:
62       PointerSize = 8;
63       Endianness = support::endianness::little;
64       break;
65     default:
66       llvm_unreachable("Unrecognized architecture");
67     }
68 
69     auto G = std::make_unique<jitlink::LinkGraph>(
70         "<COFFHeaderMU>", TT, PointerSize, Endianness,
71         jitlink::getGenericEdgeKindName);
72     auto &HeaderSection = G->createSection("__header", MemProt::Read);
73     auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
74 
75     // Init symbol is __ImageBase symbol.
76     auto &ImageBaseSymbol = G->addDefinedSymbol(
77         HeaderBlock, 0, *R->getInitializerSymbol(), HeaderBlock.getSize(),
78         jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
79 
80     addImageBaseRelocationEdge(HeaderBlock, ImageBaseSymbol);
81 
82     CP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
83   }
84 
85   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
86 
87 private:
88   struct HeaderSymbol {
89     const char *Name;
90     uint64_t Offset;
91   };
92 
93   struct NTHeader {
94     support::ulittle32_t PEMagic;
95     object::coff_file_header FileHeader;
96     struct PEHeader {
97       object::pe32plus_header Header;
98       object::data_directory DataDirectory[COFF::NUM_DATA_DIRECTORIES + 1];
99     } OptionalHeader;
100   };
101 
102   struct HeaderBlockContent {
103     object::dos_header DOSHeader;
104     COFFHeaderMaterializationUnit::NTHeader NTHeader;
105   };
106 
107   static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
108                                            jitlink::Section &HeaderSection) {
109     HeaderBlockContent Hdr = {};
110 
111     // Set up magic
112     Hdr.DOSHeader.Magic[0] = 'M';
113     Hdr.DOSHeader.Magic[1] = 'Z';
114     Hdr.DOSHeader.AddressOfNewExeHeader =
115         offsetof(HeaderBlockContent, NTHeader);
116     uint32_t PEMagic = *reinterpret_cast<const uint32_t *>(COFF::PEMagic);
117     Hdr.NTHeader.PEMagic = PEMagic;
118     Hdr.NTHeader.OptionalHeader.Header.Magic = COFF::PE32Header::PE32_PLUS;
119 
120     switch (G.getTargetTriple().getArch()) {
121     case Triple::x86_64:
122       Hdr.NTHeader.FileHeader.Machine = COFF::IMAGE_FILE_MACHINE_AMD64;
123       break;
124     default:
125       llvm_unreachable("Unrecognized architecture");
126     }
127 
128     auto HeaderContent = G.allocateContent(
129         ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
130 
131     return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
132                                 0);
133   }
134 
135   static void addImageBaseRelocationEdge(jitlink::Block &B,
136                                          jitlink::Symbol &ImageBase) {
137     auto ImageBaseOffset = offsetof(HeaderBlockContent, NTHeader) +
138                            offsetof(NTHeader, OptionalHeader) +
139                            offsetof(object::pe32plus_header, ImageBase);
140     B.addEdge(jitlink::x86_64::Pointer64, ImageBaseOffset, ImageBase, 0);
141   }
142 
143   static MaterializationUnit::Interface
144   createHeaderInterface(COFFPlatform &MOP,
145                         const SymbolStringPtr &HeaderStartSymbol) {
146     SymbolFlagsMap HeaderSymbolFlags;
147 
148     HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
149 
150     return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
151                                           HeaderStartSymbol);
152   }
153 
154   COFFPlatform &CP;
155 };
156 
157 } // end anonymous namespace
158 
159 namespace llvm {
160 namespace orc {
161 
162 Expected<std::unique_ptr<COFFPlatform>> COFFPlatform::Create(
163     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
164     JITDylib &PlatformJD, std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
165     LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
166     const char *VCRuntimePath, std::optional<SymbolAliasMap> RuntimeAliases) {
167 
168   // If the target is not supported then bail out immediately.
169   if (!supportedTarget(ES.getTargetTriple()))
170     return make_error<StringError>("Unsupported COFFPlatform triple: " +
171                                        ES.getTargetTriple().str(),
172                                    inconvertibleErrorCode());
173 
174   auto &EPC = ES.getExecutorProcessControl();
175 
176   auto GeneratorArchive =
177       object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef());
178   if (!GeneratorArchive)
179     return GeneratorArchive.takeError();
180 
181   auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Create(
182       ObjLinkingLayer, nullptr, std::move(*GeneratorArchive));
183   if (!OrcRuntimeArchiveGenerator)
184     return OrcRuntimeArchiveGenerator.takeError();
185 
186   // We need a second instance of the archive (for now) for the Platform. We
187   // can `cantFail` this call, since if it were going to fail it would have
188   // failed above.
189   auto RuntimeArchive = cantFail(
190       object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef()));
191 
192   // Create default aliases if the caller didn't supply any.
193   if (!RuntimeAliases)
194     RuntimeAliases = standardPlatformAliases(ES);
195 
196   // Define the aliases.
197   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
198     return std::move(Err);
199 
200   auto &HostFuncJD = ES.createBareJITDylib("$<PlatformRuntimeHostFuncJD>");
201 
202   // Add JIT-dispatch function support symbols.
203   if (auto Err = HostFuncJD.define(
204           absoluteSymbols({{ES.intern("__orc_rt_jit_dispatch"),
205                             {EPC.getJITDispatchInfo().JITDispatchFunction,
206                              JITSymbolFlags::Exported}},
207                            {ES.intern("__orc_rt_jit_dispatch_ctx"),
208                             {EPC.getJITDispatchInfo().JITDispatchContext,
209                              JITSymbolFlags::Exported}}})))
210     return std::move(Err);
211 
212   PlatformJD.addToLinkOrder(HostFuncJD);
213 
214   // Create the instance.
215   Error Err = Error::success();
216   auto P = std::unique_ptr<COFFPlatform>(new COFFPlatform(
217       ES, ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator),
218       std::move(OrcRuntimeArchiveBuffer), std::move(RuntimeArchive),
219       std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath, Err));
220   if (Err)
221     return std::move(Err);
222   return std::move(P);
223 }
224 
225 Expected<std::unique_ptr<COFFPlatform>>
226 COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
227                      JITDylib &PlatformJD, const char *OrcRuntimePath,
228                      LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
229                      const char *VCRuntimePath,
230                      std::optional<SymbolAliasMap> RuntimeAliases) {
231 
232   auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
233   if (!ArchiveBuffer)
234     return createFileError(OrcRuntimePath, ArchiveBuffer.getError());
235 
236   return Create(ES, ObjLinkingLayer, PlatformJD, std::move(*ArchiveBuffer),
237                 std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath,
238                 std::move(RuntimeAliases));
239 }
240 
241 Expected<MemoryBufferRef> COFFPlatform::getPerJDObjectFile() {
242   auto PerJDObj = OrcRuntimeArchive->findSym("__orc_rt_coff_per_jd_marker");
243   if (!PerJDObj)
244     return PerJDObj.takeError();
245 
246   if (!*PerJDObj)
247     return make_error<StringError>("Could not find per jd object file",
248                                    inconvertibleErrorCode());
249 
250   auto Buffer = (*PerJDObj)->getAsBinary();
251   if (!Buffer)
252     return Buffer.takeError();
253 
254   return (*Buffer)->getMemoryBufferRef();
255 }
256 
257 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
258                        ArrayRef<std::pair<const char *, const char *>> AL) {
259   for (auto &KV : AL) {
260     auto AliasName = ES.intern(KV.first);
261     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
262     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
263                                      JITSymbolFlags::Exported};
264   }
265 }
266 
267 Error COFFPlatform::setupJITDylib(JITDylib &JD) {
268   if (auto Err = JD.define(std::make_unique<COFFHeaderMaterializationUnit>(
269           *this, COFFHeaderStartSymbol)))
270     return Err;
271 
272   if (auto Err = ES.lookup({&JD}, COFFHeaderStartSymbol).takeError())
273     return Err;
274 
275   // Define the CXX aliases.
276   SymbolAliasMap CXXAliases;
277   addAliases(ES, CXXAliases, requiredCXXAliases());
278   if (auto Err = JD.define(symbolAliases(std::move(CXXAliases))))
279     return Err;
280 
281   auto PerJDObj = getPerJDObjectFile();
282   if (!PerJDObj)
283     return PerJDObj.takeError();
284 
285   auto I = getObjectFileInterface(ES, *PerJDObj);
286   if (!I)
287     return I.takeError();
288 
289   if (auto Err = ObjLinkingLayer.add(
290           JD, MemoryBuffer::getMemBuffer(*PerJDObj, false), std::move(*I)))
291     return Err;
292 
293   if (!Bootstrapping) {
294     auto ImportedLibs = StaticVCRuntime
295                             ? VCRuntimeBootstrap->loadStaticVCRuntime(JD)
296                             : VCRuntimeBootstrap->loadDynamicVCRuntime(JD);
297     if (!ImportedLibs)
298       return ImportedLibs.takeError();
299     for (auto &Lib : *ImportedLibs)
300       if (auto Err = LoadDynLibrary(JD, Lib))
301         return Err;
302     if (StaticVCRuntime)
303       if (auto Err = VCRuntimeBootstrap->initializeStaticVCRuntime(JD))
304         return Err;
305   }
306 
307   JD.addGenerator(DLLImportDefinitionGenerator::Create(ES, ObjLinkingLayer));
308   return Error::success();
309 }
310 
311 Error COFFPlatform::teardownJITDylib(JITDylib &JD) {
312   std::lock_guard<std::mutex> Lock(PlatformMutex);
313   auto I = JITDylibToHeaderAddr.find(&JD);
314   if (I != JITDylibToHeaderAddr.end()) {
315     assert(HeaderAddrToJITDylib.count(I->second) &&
316            "HeaderAddrToJITDylib missing entry");
317     HeaderAddrToJITDylib.erase(I->second);
318     JITDylibToHeaderAddr.erase(I);
319   }
320   return Error::success();
321 }
322 
323 Error COFFPlatform::notifyAdding(ResourceTracker &RT,
324                                  const MaterializationUnit &MU) {
325   auto &JD = RT.getJITDylib();
326   const auto &InitSym = MU.getInitializerSymbol();
327   if (!InitSym)
328     return Error::success();
329 
330   RegisteredInitSymbols[&JD].add(InitSym,
331                                  SymbolLookupFlags::WeaklyReferencedSymbol);
332 
333   LLVM_DEBUG({
334     dbgs() << "COFFPlatform: Registered init symbol " << *InitSym << " for MU "
335            << MU.getName() << "\n";
336   });
337   return Error::success();
338 }
339 
340 Error COFFPlatform::notifyRemoving(ResourceTracker &RT) {
341   llvm_unreachable("Not supported yet");
342 }
343 
344 SymbolAliasMap COFFPlatform::standardPlatformAliases(ExecutionSession &ES) {
345   SymbolAliasMap Aliases;
346   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
347   return Aliases;
348 }
349 
350 ArrayRef<std::pair<const char *, const char *>>
351 COFFPlatform::requiredCXXAliases() {
352   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
353       {"_CxxThrowException", "__orc_rt_coff_cxx_throw_exception"},
354       {"_onexit", "__orc_rt_coff_onexit_per_jd"},
355       {"atexit", "__orc_rt_coff_atexit_per_jd"}};
356 
357   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
358 }
359 
360 ArrayRef<std::pair<const char *, const char *>>
361 COFFPlatform::standardRuntimeUtilityAliases() {
362   static const std::pair<const char *, const char *>
363       StandardRuntimeUtilityAliases[] = {
364           {"__orc_rt_run_program", "__orc_rt_coff_run_program"},
365           {"__orc_rt_jit_dlerror", "__orc_rt_coff_jit_dlerror"},
366           {"__orc_rt_jit_dlopen", "__orc_rt_coff_jit_dlopen"},
367           {"__orc_rt_jit_dlclose", "__orc_rt_coff_jit_dlclose"},
368           {"__orc_rt_jit_dlsym", "__orc_rt_coff_jit_dlsym"},
369           {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
370 
371   return ArrayRef<std::pair<const char *, const char *>>(
372       StandardRuntimeUtilityAliases);
373 }
374 
375 bool COFFPlatform::supportedTarget(const Triple &TT) {
376   switch (TT.getArch()) {
377   case Triple::x86_64:
378     return true;
379   default:
380     return false;
381   }
382 }
383 
384 COFFPlatform::COFFPlatform(
385     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
386     JITDylib &PlatformJD,
387     std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
388     std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
389     std::unique_ptr<object::Archive> OrcRuntimeArchive,
390     LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
391     const char *VCRuntimePath, Error &Err)
392     : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
393       LoadDynLibrary(std::move(LoadDynLibrary)),
394       OrcRuntimeArchiveBuffer(std::move(OrcRuntimeArchiveBuffer)),
395       OrcRuntimeArchive(std::move(OrcRuntimeArchive)),
396       StaticVCRuntime(StaticVCRuntime),
397       COFFHeaderStartSymbol(ES.intern("__ImageBase")) {
398   ErrorAsOutParameter _(&Err);
399 
400   Bootstrapping.store(true);
401   ObjLinkingLayer.addPlugin(std::make_unique<COFFPlatformPlugin>(*this));
402 
403   // Load vc runtime
404   auto VCRT =
405       COFFVCRuntimeBootstrapper::Create(ES, ObjLinkingLayer, VCRuntimePath);
406   if (!VCRT) {
407     Err = VCRT.takeError();
408     return;
409   }
410   VCRuntimeBootstrap = std::move(*VCRT);
411 
412   for (auto &Lib : OrcRuntimeGenerator->getImportedDynamicLibraries())
413     DylibsToPreload.insert(Lib);
414 
415   auto ImportedLibs =
416       StaticVCRuntime ? VCRuntimeBootstrap->loadStaticVCRuntime(PlatformJD)
417                       : VCRuntimeBootstrap->loadDynamicVCRuntime(PlatformJD);
418   if (!ImportedLibs) {
419     Err = ImportedLibs.takeError();
420     return;
421   }
422 
423   for (auto &Lib : *ImportedLibs)
424     DylibsToPreload.insert(Lib);
425 
426   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
427 
428   // PlatformJD hasn't been set up by the platform yet (since we're creating
429   // the platform now), so set it up.
430   if (auto E2 = setupJITDylib(PlatformJD)) {
431     Err = std::move(E2);
432     return;
433   }
434 
435   for (auto& Lib : DylibsToPreload)
436     if (auto E2 = this->LoadDynLibrary(PlatformJD, Lib)) {
437       Err = std::move(E2);
438       return;
439     }
440 
441   if (StaticVCRuntime)
442       if (auto E2 = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD)) {
443           Err = std::move(E2);
444           return;
445       }
446 
447   // Associate wrapper function tags with JIT-side function implementations.
448   if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
449       Err = std::move(E2);
450       return;
451   }
452 
453   // Lookup addresses of runtime functions callable by the platform,
454   // call the platform bootstrap function to initialize the platform-state
455   // object in the executor.
456   if (auto E2 = bootstrapCOFFRuntime(PlatformJD)) {
457       Err = std::move(E2);
458       return;
459   }
460 
461   Bootstrapping.store(false);
462   JDBootstrapStates.clear();
463 }
464 
465 Expected<COFFPlatform::JITDylibDepMap>
466 COFFPlatform::buildJDDepMap(JITDylib &JD) {
467   return ES.runSessionLocked([&]() -> Expected<JITDylibDepMap> {
468     JITDylibDepMap JDDepMap;
469 
470     SmallVector<JITDylib *, 16> Worklist({&JD});
471     while (!Worklist.empty()) {
472       auto CurJD = Worklist.back();
473       Worklist.pop_back();
474 
475       auto &DM = JDDepMap[CurJD];
476       CurJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
477         DM.reserve(O.size());
478         for (auto &KV : O) {
479           if (KV.first == CurJD)
480             continue;
481           {
482             // Bare jitdylibs not known to the platform
483             std::lock_guard<std::mutex> Lock(PlatformMutex);
484             if (!JITDylibToHeaderAddr.count(KV.first)) {
485               LLVM_DEBUG({
486                 dbgs() << "JITDylib unregistered to COFFPlatform detected in "
487                           "LinkOrder: "
488                        << CurJD->getName() << "\n";
489               });
490               continue;
491             }
492           }
493           DM.push_back(KV.first);
494           // Push unvisited entry.
495           if (!JDDepMap.count(KV.first)) {
496             Worklist.push_back(KV.first);
497             JDDepMap[KV.first] = {};
498           }
499         }
500       });
501     }
502     return std::move(JDDepMap);
503   });
504 }
505 
506 void COFFPlatform::pushInitializersLoop(PushInitializersSendResultFn SendResult,
507                                         JITDylibSP JD,
508                                         JITDylibDepMap &JDDepMap) {
509   SmallVector<JITDylib *, 16> Worklist({JD.get()});
510   DenseSet<JITDylib *> Visited({JD.get()});
511   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
512   ES.runSessionLocked([&]() {
513     while (!Worklist.empty()) {
514       auto CurJD = Worklist.back();
515       Worklist.pop_back();
516 
517       auto RISItr = RegisteredInitSymbols.find(CurJD);
518       if (RISItr != RegisteredInitSymbols.end()) {
519         NewInitSymbols[CurJD] = std::move(RISItr->second);
520         RegisteredInitSymbols.erase(RISItr);
521       }
522 
523       for (auto *DepJD : JDDepMap[CurJD])
524         if (!Visited.count(DepJD)) {
525           Worklist.push_back(DepJD);
526           Visited.insert(DepJD);
527         }
528     }
529   });
530 
531   // If there are no further init symbols to look up then send the link order
532   // (as a list of header addresses) to the caller.
533   if (NewInitSymbols.empty()) {
534     // Build the dep info map to return.
535     COFFJITDylibDepInfoMap DIM;
536     DIM.reserve(JDDepMap.size());
537     for (auto &KV : JDDepMap) {
538       std::lock_guard<std::mutex> Lock(PlatformMutex);
539       COFFJITDylibDepInfo DepInfo;
540       DepInfo.reserve(KV.second.size());
541       for (auto &Dep : KV.second) {
542         DepInfo.push_back(JITDylibToHeaderAddr[Dep]);
543       }
544       auto H = JITDylibToHeaderAddr[KV.first];
545       DIM.push_back(std::make_pair(H, std::move(DepInfo)));
546     }
547     SendResult(DIM);
548     return;
549   }
550 
551   // Otherwise issue a lookup and re-run this phase when it completes.
552   lookupInitSymbolsAsync(
553       [this, SendResult = std::move(SendResult), &JD,
554        JDDepMap = std::move(JDDepMap)](Error Err) mutable {
555         if (Err)
556           SendResult(std::move(Err));
557         else
558           pushInitializersLoop(std::move(SendResult), JD, JDDepMap);
559       },
560       ES, std::move(NewInitSymbols));
561 }
562 
563 void COFFPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
564                                        ExecutorAddr JDHeaderAddr) {
565   JITDylibSP JD;
566   {
567     std::lock_guard<std::mutex> Lock(PlatformMutex);
568     auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
569     if (I != HeaderAddrToJITDylib.end())
570       JD = I->second;
571   }
572 
573   LLVM_DEBUG({
574     dbgs() << "COFFPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
575     if (JD)
576       dbgs() << "pushing initializers for " << JD->getName() << "\n";
577     else
578       dbgs() << "No JITDylib for header address.\n";
579   });
580 
581   if (!JD) {
582     SendResult(make_error<StringError>("No JITDylib with header addr " +
583                                            formatv("{0:x}", JDHeaderAddr),
584                                        inconvertibleErrorCode()));
585     return;
586   }
587 
588   auto JDDepMap = buildJDDepMap(*JD);
589   if (!JDDepMap) {
590     SendResult(JDDepMap.takeError());
591     return;
592   }
593 
594   pushInitializersLoop(std::move(SendResult), JD, *JDDepMap);
595 }
596 
597 void COFFPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
598                                    ExecutorAddr Handle, StringRef SymbolName) {
599   LLVM_DEBUG(dbgs() << "COFFPlatform::rt_lookupSymbol(\"" << Handle << "\")\n");
600 
601   JITDylib *JD = nullptr;
602 
603   {
604     std::lock_guard<std::mutex> Lock(PlatformMutex);
605     auto I = HeaderAddrToJITDylib.find(Handle);
606     if (I != HeaderAddrToJITDylib.end())
607       JD = I->second;
608   }
609 
610   if (!JD) {
611     LLVM_DEBUG(dbgs() << "  No JITDylib for handle " << Handle << "\n");
612     SendResult(make_error<StringError>("No JITDylib associated with handle " +
613                                            formatv("{0:x}", Handle),
614                                        inconvertibleErrorCode()));
615     return;
616   }
617 
618   // Use functor class to work around XL build compiler issue on AIX.
619   class RtLookupNotifyComplete {
620   public:
621     RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
622         : SendResult(std::move(SendResult)) {}
623     void operator()(Expected<SymbolMap> Result) {
624       if (Result) {
625         assert(Result->size() == 1 && "Unexpected result map count");
626         SendResult(Result->begin()->second.getAddress());
627       } else {
628         SendResult(Result.takeError());
629       }
630     }
631 
632   private:
633     SendSymbolAddressFn SendResult;
634   };
635 
636   ES.lookup(
637       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
638       SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,
639       RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
640 }
641 
642 Error COFFPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
643   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
644 
645   using LookupSymbolSPSSig =
646       SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
647   WFs[ES.intern("__orc_rt_coff_symbol_lookup_tag")] =
648       ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
649                                               &COFFPlatform::rt_lookupSymbol);
650   using PushInitializersSPSSig =
651       SPSExpected<SPSCOFFJITDylibDepInfoMap>(SPSExecutorAddr);
652   WFs[ES.intern("__orc_rt_coff_push_initializers_tag")] =
653       ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
654           this, &COFFPlatform::rt_pushInitializers);
655 
656   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
657 }
658 
659 Error COFFPlatform::runBootstrapInitializers(JDBootstrapState &BState) {
660   llvm::sort(BState.Initializers);
661   if (auto Err =
662           runBootstrapSubsectionInitializers(BState, ".CRT$XIA", ".CRT$XIZ"))
663     return Err;
664 
665   if (auto Err = runSymbolIfExists(*BState.JD, "__run_after_c_init"))
666     return Err;
667 
668   if (auto Err =
669           runBootstrapSubsectionInitializers(BState, ".CRT$XCA", ".CRT$XCZ"))
670     return Err;
671   return Error::success();
672 }
673 
674 Error COFFPlatform::runBootstrapSubsectionInitializers(JDBootstrapState &BState,
675                                                        StringRef Start,
676                                                        StringRef End) {
677   for (auto &Initializer : BState.Initializers)
678     if (Initializer.first >= Start && Initializer.first <= End &&
679         Initializer.second) {
680       auto Res =
681           ES.getExecutorProcessControl().runAsVoidFunction(Initializer.second);
682       if (!Res)
683         return Res.takeError();
684     }
685   return Error::success();
686 }
687 
688 Error COFFPlatform::bootstrapCOFFRuntime(JITDylib &PlatformJD) {
689   // Lookup of runtime symbols causes the collection of initializers if
690   // it's static linking setting.
691   if (auto Err = lookupAndRecordAddrs(
692           ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
693           {
694               {ES.intern("__orc_rt_coff_platform_bootstrap"),
695                &orc_rt_coff_platform_bootstrap},
696               {ES.intern("__orc_rt_coff_platform_shutdown"),
697                &orc_rt_coff_platform_shutdown},
698               {ES.intern("__orc_rt_coff_register_jitdylib"),
699                &orc_rt_coff_register_jitdylib},
700               {ES.intern("__orc_rt_coff_deregister_jitdylib"),
701                &orc_rt_coff_deregister_jitdylib},
702               {ES.intern("__orc_rt_coff_register_object_sections"),
703                &orc_rt_coff_register_object_sections},
704               {ES.intern("__orc_rt_coff_deregister_object_sections"),
705                &orc_rt_coff_deregister_object_sections},
706           }))
707     return Err;
708 
709   // Call bootstrap functions
710   if (auto Err = ES.callSPSWrapper<void()>(orc_rt_coff_platform_bootstrap))
711     return Err;
712 
713   // Do the pending jitdylib registration actions that we couldn't do
714   // because orc runtime was not linked fully.
715   for (auto KV : JDBootstrapStates) {
716     auto &JDBState = KV.second;
717     if (auto Err = ES.callSPSWrapper<void(SPSString, SPSExecutorAddr)>(
718             orc_rt_coff_register_jitdylib, JDBState.JDName,
719             JDBState.HeaderAddr))
720       return Err;
721 
722     for (auto &ObjSectionMap : JDBState.ObjectSectionsMaps)
723       if (auto Err = ES.callSPSWrapper<void(SPSExecutorAddr,
724                                             SPSCOFFObjectSectionsMap, bool)>(
725               orc_rt_coff_register_object_sections, JDBState.HeaderAddr,
726               ObjSectionMap, false))
727         return Err;
728   }
729 
730   // Run static initializers collected in bootstrap stage.
731   for (auto KV : JDBootstrapStates) {
732     auto &JDBState = KV.second;
733     if (auto Err = runBootstrapInitializers(JDBState))
734       return Err;
735   }
736 
737   return Error::success();
738 }
739 
740 Error COFFPlatform::runSymbolIfExists(JITDylib &PlatformJD,
741                                       StringRef SymbolName) {
742   ExecutorAddr jit_function;
743   auto AfterCLookupErr = lookupAndRecordAddrs(
744       ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
745       {{ES.intern(SymbolName), &jit_function}});
746   if (!AfterCLookupErr) {
747     auto Res = ES.getExecutorProcessControl().runAsVoidFunction(jit_function);
748     if (!Res)
749       return Res.takeError();
750     return Error::success();
751   }
752   if (!AfterCLookupErr.isA<SymbolsNotFound>())
753     return AfterCLookupErr;
754   consumeError(std::move(AfterCLookupErr));
755   return Error::success();
756 }
757 
758 void COFFPlatform::COFFPlatformPlugin::modifyPassConfig(
759     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
760     jitlink::PassConfiguration &Config) {
761 
762   bool IsBootstrapping = CP.Bootstrapping.load();
763 
764   if (auto InitSymbol = MR.getInitializerSymbol()) {
765     if (InitSymbol == CP.COFFHeaderStartSymbol) {
766       Config.PostAllocationPasses.push_back(
767           [this, &MR, IsBootstrapping](jitlink::LinkGraph &G) {
768             return associateJITDylibHeaderSymbol(G, MR, IsBootstrapping);
769           });
770       return;
771     }
772     Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
773       return preserveInitializerSections(G, MR);
774     });
775   }
776 
777   if (!IsBootstrapping)
778     Config.PostFixupPasses.push_back(
779         [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
780           return registerObjectPlatformSections(G, JD);
781         });
782   else
783     Config.PostFixupPasses.push_back(
784         [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
785           return registerObjectPlatformSectionsInBootstrap(G, JD);
786         });
787 }
788 
789 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
790 COFFPlatform::COFFPlatformPlugin::getSyntheticSymbolDependencies(
791     MaterializationResponsibility &MR) {
792   std::lock_guard<std::mutex> Lock(PluginMutex);
793   auto I = InitSymbolDeps.find(&MR);
794   if (I != InitSymbolDeps.end()) {
795     SyntheticSymbolDependenciesMap Result;
796     Result[MR.getInitializerSymbol()] = std::move(I->second);
797     InitSymbolDeps.erase(&MR);
798     return Result;
799   }
800   return SyntheticSymbolDependenciesMap();
801 }
802 
803 Error COFFPlatform::COFFPlatformPlugin::associateJITDylibHeaderSymbol(
804     jitlink::LinkGraph &G, MaterializationResponsibility &MR,
805     bool IsBootstraping) {
806   auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
807     return Sym->getName() == *CP.COFFHeaderStartSymbol;
808   });
809   assert(I != G.defined_symbols().end() && "Missing COFF header start symbol");
810 
811   auto &JD = MR.getTargetJITDylib();
812   std::lock_guard<std::mutex> Lock(CP.PlatformMutex);
813   auto HeaderAddr = (*I)->getAddress();
814   CP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
815   CP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
816   if (!IsBootstraping) {
817     G.allocActions().push_back(
818         {cantFail(WrapperFunctionCall::Create<
819                   SPSArgList<SPSString, SPSExecutorAddr>>(
820              CP.orc_rt_coff_register_jitdylib, JD.getName(), HeaderAddr)),
821          cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
822              CP.orc_rt_coff_deregister_jitdylib, HeaderAddr))});
823   } else {
824     G.allocActions().push_back(
825         {{},
826          cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
827              CP.orc_rt_coff_deregister_jitdylib, HeaderAddr))});
828     JDBootstrapState BState;
829     BState.JD = &JD;
830     BState.JDName = JD.getName();
831     BState.HeaderAddr = HeaderAddr;
832     CP.JDBootstrapStates.emplace(&JD, BState);
833   }
834 
835   return Error::success();
836 }
837 
838 Error COFFPlatform::COFFPlatformPlugin::registerObjectPlatformSections(
839     jitlink::LinkGraph &G, JITDylib &JD) {
840   COFFObjectSectionsMap ObjSecs;
841   auto HeaderAddr = CP.JITDylibToHeaderAddr[&JD];
842   assert(HeaderAddr && "Must be registered jitdylib");
843   for (auto &S : G.sections()) {
844     jitlink::SectionRange Range(S);
845     if (Range.getSize())
846       ObjSecs.push_back(std::make_pair(S.getName().str(), Range.getRange()));
847   }
848 
849   G.allocActions().push_back(
850       {cantFail(WrapperFunctionCall::Create<SPSCOFFRegisterObjectSectionsArgs>(
851            CP.orc_rt_coff_register_object_sections, HeaderAddr, ObjSecs, true)),
852        cantFail(
853            WrapperFunctionCall::Create<SPSCOFFDeregisterObjectSectionsArgs>(
854                CP.orc_rt_coff_deregister_object_sections, HeaderAddr,
855                ObjSecs))});
856 
857   return Error::success();
858 }
859 
860 Error COFFPlatform::COFFPlatformPlugin::preserveInitializerSections(
861     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
862   JITLinkSymbolSet InitSectionSymbols;
863   for (auto &Sec : G.sections())
864     if (isCOFFInitializerSection(Sec.getName()))
865       for (auto *B : Sec.blocks())
866         if (!B->edges_empty())
867           InitSectionSymbols.insert(
868               &G.addAnonymousSymbol(*B, 0, 0, false, true));
869 
870   std::lock_guard<std::mutex> Lock(PluginMutex);
871   InitSymbolDeps[&MR] = InitSectionSymbols;
872   return Error::success();
873 }
874 
875 Error COFFPlatform::COFFPlatformPlugin::
876     registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph &G,
877                                               JITDylib &JD) {
878   std::lock_guard<std::mutex> Lock(CP.PlatformMutex);
879   auto HeaderAddr = CP.JITDylibToHeaderAddr[&JD];
880   COFFObjectSectionsMap ObjSecs;
881   for (auto &S : G.sections()) {
882     jitlink::SectionRange Range(S);
883     if (Range.getSize())
884       ObjSecs.push_back(std::make_pair(S.getName().str(), Range.getRange()));
885   }
886 
887   G.allocActions().push_back(
888       {{},
889        cantFail(
890            WrapperFunctionCall::Create<SPSCOFFDeregisterObjectSectionsArgs>(
891                CP.orc_rt_coff_deregister_object_sections, HeaderAddr,
892                ObjSecs))});
893 
894   auto &BState = CP.JDBootstrapStates[&JD];
895   BState.ObjectSectionsMaps.push_back(std::move(ObjSecs));
896 
897   // Collect static initializers
898   for (auto &S : G.sections())
899     if (isCOFFInitializerSection(S.getName()))
900       for (auto *B : S.blocks()) {
901         if (B->edges_empty())
902           continue;
903         for (auto &E : B->edges())
904           BState.Initializers.push_back(std::make_pair(
905               S.getName().str(), E.getTarget().getAddress() + E.getAddend()));
906       }
907 
908   return Error::success();
909 }
910 
911 } // End namespace orc.
912 } // End namespace llvm.
913