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