LLVM 24.0.0git
COFFPlatform.cpp
Go to the documentation of this file.
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
10
19#include "llvm/Object/COFF.h"
20
22
24
25#define DEBUG_TYPE "orc"
26
27using namespace llvm;
28using namespace llvm::orc;
29using namespace llvm::orc::shared;
30
31namespace llvm {
32namespace orc {
33namespace shared {
34
44
45} // namespace shared
46} // namespace orc
47} // namespace llvm
48namespace {
49
50class COFFHeaderMaterializationUnit : public MaterializationUnit {
51public:
52 COFFHeaderMaterializationUnit(COFFPlatform &CP,
53 const SymbolStringPtr &HeaderStartSymbol)
54 : MaterializationUnit(createHeaderInterface(CP, HeaderStartSymbol)),
55 CP(CP) {}
56
57 StringRef getName() const override { return "COFFHeaderMU"; }
58
59 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
60 auto G = std::make_unique<jitlink::LinkGraph>(
61 "<COFFHeaderMU>", CP.getExecutionSession().getSymbolStringPool(),
62 CP.getExecutionSession().getTargetTriple(), SubtargetFeatures(),
64 auto &HeaderSection = G->createSection("__header", MemProt::Read);
65 auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
66
67 // Init symbol is __ImageBase symbol.
68 auto &ImageBaseSymbol = G->addDefinedSymbol(
69 HeaderBlock, 0, *R->getInitializerSymbol(), HeaderBlock.getSize(),
70 jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
71
72 addImageBaseRelocationEdge(HeaderBlock, ImageBaseSymbol);
73
74 CP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
75 }
76
77 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
78
79private:
80 struct HeaderSymbol {
81 const char *Name;
82 uint64_t Offset;
83 };
84
85 struct NTHeader {
87 object::coff_file_header FileHeader;
88 struct PEHeader {
89 object::pe32plus_header Header;
90 object::data_directory DataDirectory[COFF::NUM_DATA_DIRECTORIES + 1];
91 } OptionalHeader;
92 };
93
94 struct HeaderBlockContent {
95 object::dos_header DOSHeader;
96 COFFHeaderMaterializationUnit::NTHeader NTHeader;
97 };
98
99 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
100 jitlink::Section &HeaderSection) {
101 HeaderBlockContent Hdr = {};
102
103 // Set up magic
104 Hdr.DOSHeader.Magic[0] = 'M';
105 Hdr.DOSHeader.Magic[1] = 'Z';
106 Hdr.DOSHeader.AddressOfNewExeHeader =
107 offsetof(HeaderBlockContent, NTHeader);
108 uint32_t PEMagic = *reinterpret_cast<const uint32_t *>(COFF::PEMagic);
109 Hdr.NTHeader.PEMagic = PEMagic;
110 Hdr.NTHeader.OptionalHeader.Header.Magic = COFF::PE32Header::PE32_PLUS;
111
112 switch (G.getTargetTriple().getArch()) {
113 case Triple::x86_64:
114 Hdr.NTHeader.FileHeader.Machine = COFF::IMAGE_FILE_MACHINE_AMD64;
115 break;
116 default:
117 llvm_unreachable("Unrecognized architecture");
118 }
119
120 auto HeaderContent = G.allocateContent(
121 ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
122
123 return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
124 0);
125 }
126
127 static void addImageBaseRelocationEdge(jitlink::Block &B,
128 jitlink::Symbol &ImageBase) {
129 auto ImageBaseOffset = offsetof(HeaderBlockContent, NTHeader) +
130 offsetof(NTHeader, OptionalHeader) +
131 offsetof(object::pe32plus_header, ImageBase);
132 B.addEdge(jitlink::x86_64::Pointer64, ImageBaseOffset, ImageBase, 0);
133 }
134
135 static MaterializationUnit::Interface
136 createHeaderInterface(COFFPlatform &MOP,
137 const SymbolStringPtr &HeaderStartSymbol) {
138 SymbolFlagsMap HeaderSymbolFlags;
139
140 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
141
142 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
143 HeaderStartSymbol);
144 }
145
146 COFFPlatform &CP;
147};
148
149} // end anonymous namespace
150
151namespace llvm {
152namespace orc {
153
154Expected<std::unique_ptr<COFFPlatform>>
156 std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
157 LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
158 const char *VCRuntimePath,
159 std::optional<SymbolAliasMap> RuntimeAliases) {
160
161 auto &ES = ObjLinkingLayer.getExecutionSession();
162
163 // If the target is not supported then bail out immediately.
164 if (!supportedTarget(ES.getTargetTriple()))
165 return make_error<StringError>("Unsupported COFFPlatform triple: " +
166 ES.getTargetTriple().str(),
168
169 auto GeneratorArchive =
170 object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef());
171 if (!GeneratorArchive)
172 return GeneratorArchive.takeError();
173
174 std::set<std::string> DylibsToPreload;
175 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Create(
176 ObjLinkingLayer, nullptr, std::move(*GeneratorArchive),
177 COFFImportFileScanner(DylibsToPreload));
178 if (!OrcRuntimeArchiveGenerator)
179 return OrcRuntimeArchiveGenerator.takeError();
180
181 // We need a second instance of the archive (for now) for the Platform. We
182 // can `cantFail` this call, since if it were going to fail it would have
183 // failed above.
184 auto RuntimeArchive = cantFail(
185 object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef()));
186
187 // Create default aliases if the caller didn't supply any.
188 if (!RuntimeAliases)
189 RuntimeAliases = standardPlatformAliases(ES);
190
191 // Define the aliases.
192 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
193 return std::move(Err);
194
195 {
196 // Add JIT dispatch reexports from bootstrap JITDylib.
197 auto Exports = buildSimpleReexportsAliasMap(
198 ES.getBootstrapJITDylib(),
199 {{ES.intern(rt::DispatchName), ES.intern(rt::DispatchCtxName)}});
200 if (!Exports)
201 return Exports.takeError();
202 if (auto Err =
203 PlatformJD.define(reexports(ES.getBootstrapJITDylib(), *Exports)))
204 return Err;
205 }
206
207 // Create the instance.
208 Error Err = Error::success();
209 auto P = std::unique_ptr<COFFPlatform>(new COFFPlatform(
210 ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator),
211 std::move(DylibsToPreload), std::move(OrcRuntimeArchiveBuffer),
212 std::move(RuntimeArchive), std::move(LoadDynLibrary), StaticVCRuntime,
213 VCRuntimePath, Err));
214 if (Err)
215 return std::move(Err);
216 return std::move(P);
217}
218
221 const char *OrcRuntimePath,
222 LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
223 const char *VCRuntimePath,
224 std::optional<SymbolAliasMap> RuntimeAliases) {
225
226 auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
227 if (!ArchiveBuffer)
228 return createFileError(OrcRuntimePath, ArchiveBuffer.getError());
229
230 return Create(ObjLinkingLayer, PlatformJD, std::move(*ArchiveBuffer),
231 std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath,
232 std::move(RuntimeAliases));
233}
234
235Expected<MemoryBufferRef> COFFPlatform::getPerJDObjectFile() {
236 auto PerJDObj = OrcRuntimeArchive->findSym("__orc_rt_coff_per_jd_marker");
237 if (!PerJDObj)
238 return PerJDObj.takeError();
239
240 if (!*PerJDObj)
241 return make_error<StringError>("Could not find per jd object file",
243
244 auto Buffer = (*PerJDObj)->getAsBinary();
245 if (!Buffer)
246 return Buffer.takeError();
247
248 return (*Buffer)->getMemoryBufferRef();
249}
250
252 ArrayRef<std::pair<const char *, const char *>> AL) {
253 for (auto &KV : AL) {
254 auto AliasName = ES.intern(KV.first);
255 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
256 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
258 }
259}
260
262 if (auto Err = JD.define(std::make_unique<COFFHeaderMaterializationUnit>(
263 *this, COFFHeaderStartSymbol)))
264 return Err;
265
266 if (auto Err = ES.lookup({&JD}, COFFHeaderStartSymbol).takeError())
267 return Err;
268
269 // Define the CXX aliases.
270 SymbolAliasMap CXXAliases;
271 addAliases(ES, CXXAliases, requiredCXXAliases());
272 if (auto Err = JD.define(symbolAliases(std::move(CXXAliases))))
273 return Err;
274
275 auto PerJDObj = getPerJDObjectFile();
276 if (!PerJDObj)
277 return PerJDObj.takeError();
278
279 auto I = getObjectFileInterface(ES, *PerJDObj);
280 if (!I)
281 return I.takeError();
282
283 if (auto Err = ObjLinkingLayer.add(
284 JD, MemoryBuffer::getMemBuffer(*PerJDObj, false), std::move(*I)))
285 return Err;
286
287 if (!Bootstrapping) {
288 auto ImportedLibs = StaticVCRuntime
289 ? VCRuntimeBootstrap->loadStaticVCRuntime(JD)
290 : VCRuntimeBootstrap->loadDynamicVCRuntime(JD);
291 if (!ImportedLibs)
292 return ImportedLibs.takeError();
293 for (auto &Lib : *ImportedLibs)
294 if (auto Err = LoadDynLibrary(JD, Lib))
295 return Err;
296 if (StaticVCRuntime)
297 if (auto Err = VCRuntimeBootstrap->initializeStaticVCRuntime(JD))
298 return Err;
299 }
300
301 JD.addGenerator(DLLImportDefinitionGenerator::Create(ES, ObjLinkingLayer));
302 return Error::success();
303}
304
306 std::lock_guard<std::mutex> Lock(PlatformMutex);
307 auto I = JITDylibToHeaderAddr.find(&JD);
308 if (I != JITDylibToHeaderAddr.end()) {
309 assert(HeaderAddrToJITDylib.count(I->second) &&
310 "HeaderAddrToJITDylib missing entry");
311 HeaderAddrToJITDylib.erase(I->second);
312 JITDylibToHeaderAddr.erase(I);
313 }
314 return Error::success();
315}
316
318 const MaterializationUnit &MU) {
319 auto &JD = RT.getJITDylib();
320 const auto &InitSym = MU.getInitializerSymbol();
321 if (!InitSym)
322 return Error::success();
323
324 RegisteredInitSymbols[&JD].add(InitSym,
326
327 LLVM_DEBUG({
328 dbgs() << "COFFPlatform: Registered init symbol " << *InitSym << " for MU "
329 << MU.getName() << "\n";
330 });
331 return Error::success();
332}
333
337
343
346 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
347 {"_CxxThrowException", "__orc_rt_coff_cxx_throw_exception"},
348 {"_onexit", "__orc_rt_coff_onexit_per_jd"},
349 {"atexit", "__orc_rt_coff_atexit_per_jd"}};
350
351 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
352}
353
356 static const std::pair<const char *, const char *>
357 StandardRuntimeUtilityAliases[] = {
358 {"__orc_rt_run_program", "__orc_rt_coff_run_program"},
359 {"__orc_rt_jit_dlerror", "__orc_rt_coff_jit_dlerror"},
360 {"__orc_rt_jit_dlopen", "__orc_rt_coff_jit_dlopen"},
361 {"__orc_rt_jit_dlupdate", "__orc_rt_coff_jit_dlupdate"},
362 {"__orc_rt_jit_dlclose", "__orc_rt_coff_jit_dlclose"},
363 {"__orc_rt_jit_dlsym", "__orc_rt_coff_jit_dlsym"},
364 {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
365
367 StandardRuntimeUtilityAliases);
368}
369
370bool COFFPlatform::supportedTarget(const Triple &TT) {
371 switch (TT.getArch()) {
372 case Triple::x86_64:
373 return true;
374 default:
375 return false;
376 }
377}
378
379COFFPlatform::COFFPlatform(
380 ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
381 std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
382 std::set<std::string> DylibsToPreload,
383 std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
384 std::unique_ptr<object::Archive> OrcRuntimeArchive,
385 LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
386 const char *VCRuntimePath, Error &Err)
387 : ES(ObjLinkingLayer.getExecutionSession()),
388 ObjLinkingLayer(ObjLinkingLayer),
389 LoadDynLibrary(std::move(LoadDynLibrary)),
390 OrcRuntimeArchiveBuffer(std::move(OrcRuntimeArchiveBuffer)),
391 OrcRuntimeArchive(std::move(OrcRuntimeArchive)),
392 StaticVCRuntime(StaticVCRuntime),
393 COFFHeaderStartSymbol(ES.intern("__ImageBase")) {
395
396 Bootstrapping.store(true);
397 ObjLinkingLayer.addPlugin(std::make_unique<COFFPlatformPlugin>(*this));
398
399 // Load vc runtime
400 auto VCRT =
401 COFFVCRuntimeBootstrapper::Create(ES, ObjLinkingLayer, VCRuntimePath);
402 if (!VCRT) {
403 Err = VCRT.takeError();
404 return;
405 }
406 VCRuntimeBootstrap = std::move(*VCRT);
407
408 auto ImportedLibs =
409 StaticVCRuntime ? VCRuntimeBootstrap->loadStaticVCRuntime(PlatformJD)
410 : VCRuntimeBootstrap->loadDynamicVCRuntime(PlatformJD);
411 if (!ImportedLibs) {
412 Err = ImportedLibs.takeError();
413 return;
414 }
415
416 for (auto &Lib : *ImportedLibs)
417 DylibsToPreload.insert(Lib);
418
419 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
420
421 // PlatformJD hasn't been set up by the platform yet (since we're creating
422 // the platform now), so set it up.
423 if (auto E2 = setupJITDylib(PlatformJD)) {
424 Err = std::move(E2);
425 return;
426 }
427
428 for (auto& Lib : DylibsToPreload)
429 if (auto E2 = this->LoadDynLibrary(PlatformJD, Lib)) {
430 Err = std::move(E2);
431 return;
432 }
433
434 if (StaticVCRuntime)
435 if (auto E2 = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD)) {
436 Err = std::move(E2);
437 return;
438 }
439
440 // Associate wrapper function tags with JIT-side function implementations.
441 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
442 Err = std::move(E2);
443 return;
444 }
445
446 // Lookup addresses of runtime functions callable by the platform,
447 // call the platform bootstrap function to initialize the platform-state
448 // object in the executor.
449 if (auto E2 = bootstrapCOFFRuntime(PlatformJD)) {
450 Err = std::move(E2);
451 return;
452 }
453
454 Bootstrapping.store(false);
455 JDBootstrapStates.clear();
456}
457
458Expected<COFFPlatform::JITDylibDepMap>
459COFFPlatform::buildJDDepMap(JITDylib &JD) {
460 return ES.runSessionLocked([&]() -> Expected<JITDylibDepMap> {
461 JITDylibDepMap JDDepMap;
462
463 SmallVector<JITDylib *, 16> Worklist({&JD});
464 while (!Worklist.empty()) {
465 auto CurJD = Worklist.back();
466 Worklist.pop_back();
467
468 auto &DM = JDDepMap[CurJD];
469 CurJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
470 DM.reserve(O.size());
471 for (auto &KV : O) {
472 if (KV.first == CurJD)
473 continue;
474 {
475 // Bare jitdylibs not known to the platform
476 std::lock_guard<std::mutex> Lock(PlatformMutex);
477 if (!JITDylibToHeaderAddr.count(KV.first)) {
478 LLVM_DEBUG({
479 dbgs() << "JITDylib unregistered to COFFPlatform detected in "
480 "LinkOrder: "
481 << CurJD->getName() << "\n";
482 });
483 continue;
484 }
485 }
486 DM.push_back(KV.first);
487 // Push unvisited entry.
488 if (JDDepMap.try_emplace(KV.first).second)
489 Worklist.push_back(KV.first);
490 }
491 });
492 }
493 return std::move(JDDepMap);
494 });
495}
496
497void COFFPlatform::pushInitializersLoop(PushInitializersSendResultFn SendResult,
498 JITDylibSP JD,
499 JITDylibDepMap &JDDepMap) {
500 SmallVector<JITDylib *, 16> Worklist({JD.get()});
501 DenseSet<JITDylib *> Visited({JD.get()});
502 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
503 ES.runSessionLocked([&]() {
504 while (!Worklist.empty()) {
505 auto CurJD = Worklist.back();
506 Worklist.pop_back();
507
508 auto RISItr = RegisteredInitSymbols.find(CurJD);
509 if (RISItr != RegisteredInitSymbols.end()) {
510 NewInitSymbols[CurJD] = std::move(RISItr->second);
511 RegisteredInitSymbols.erase(RISItr);
512 }
513
514 for (auto *DepJD : JDDepMap[CurJD])
515 if (Visited.insert(DepJD).second)
516 Worklist.push_back(DepJD);
517 }
518 });
519
520 // If there are no further init symbols to look up then send the link order
521 // (as a list of header addresses) to the caller.
522 if (NewInitSymbols.empty()) {
523 // Build the dep info map to return.
524 COFFJITDylibDepInfoMap DIM;
525 DIM.reserve(JDDepMap.size());
526 for (auto &KV : JDDepMap) {
527 std::lock_guard<std::mutex> Lock(PlatformMutex);
528 COFFJITDylibDepInfo DepInfo;
529 DepInfo.reserve(KV.second.size());
530 for (auto &Dep : KV.second) {
531 DepInfo.push_back(JITDylibToHeaderAddr[Dep]);
532 }
533 auto H = JITDylibToHeaderAddr[KV.first];
534 DIM.push_back(std::make_pair(H, std::move(DepInfo)));
535 }
536 SendResult(DIM);
537 return;
538 }
539
540 // Otherwise issue a lookup and re-run this phase when it completes.
542 [this, SendResult = std::move(SendResult), &JD,
543 JDDepMap = std::move(JDDepMap)](Error Err) mutable {
544 if (Err)
545 SendResult(std::move(Err));
546 else
547 pushInitializersLoop(std::move(SendResult), JD, JDDepMap);
548 },
549 ES, std::move(NewInitSymbols));
550}
551
552void COFFPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
553 ExecutorAddr JDHeaderAddr) {
554 JITDylibSP JD;
555 {
556 std::lock_guard<std::mutex> Lock(PlatformMutex);
557 auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
558 if (I != HeaderAddrToJITDylib.end())
559 JD = I->second;
560 }
561
562 LLVM_DEBUG({
563 dbgs() << "COFFPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
564 if (JD)
565 dbgs() << "pushing initializers for " << JD->getName() << "\n";
566 else
567 dbgs() << "No JITDylib for header address.\n";
568 });
569
570 if (!JD) {
571 SendResult(make_error<StringError>("No JITDylib with header addr " +
572 formatv("{0:x}", JDHeaderAddr),
574 return;
575 }
576
577 auto JDDepMap = buildJDDepMap(*JD);
578 if (!JDDepMap) {
579 SendResult(JDDepMap.takeError());
580 return;
581 }
582
583 pushInitializersLoop(std::move(SendResult), JD, *JDDepMap);
584}
585
586void COFFPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
587 ExecutorAddr Handle, StringRef SymbolName) {
588 LLVM_DEBUG(dbgs() << "COFFPlatform::rt_lookupSymbol(\"" << Handle << "\")\n");
589
590 JITDylib *JD = nullptr;
591
592 {
593 std::lock_guard<std::mutex> Lock(PlatformMutex);
594 auto I = HeaderAddrToJITDylib.find(Handle);
595 if (I != HeaderAddrToJITDylib.end())
596 JD = I->second;
597 }
598
599 if (!JD) {
600 LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n");
601 SendResult(make_error<StringError>("No JITDylib associated with handle " +
602 formatv("{0:x}", Handle),
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(Result->begin()->second.getAddress());
616 } else {
617 SendResult(Result.takeError());
618 }
619 }
620
621 private:
622 SendSymbolAddressFn SendResult;
623 };
624
625 ES.lookup(
627 SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,
628 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
629}
630
631Error COFFPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
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
648Error 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
663Error COFFPlatform::runBootstrapSubsectionInitializers(JDBootstrapState &BState,
664 StringRef Start,
665 StringRef End) {
666 auto CallInitializer = rt::sps::Int32VoidCaller::Create(ES);
667 if (!CallInitializer)
668 return CallInitializer.takeError();
669 for (auto &Initializer : BState.Initializers)
670 if (Initializer.first >= Start && Initializer.first <= End &&
671 Initializer.second) {
672 auto Res = (*CallInitializer)(Initializer.second);
673 if (!Res)
674 return Res.takeError();
675 }
676 return Error::success();
677}
678
679Error COFFPlatform::bootstrapCOFFRuntime(JITDylib &PlatformJD) {
680 // Lookup of runtime symbols causes the collection of initializers if
681 // it's static linking setting.
682 if (auto Err = lookupAndRecordAddrs(
684 {
685 {ES.intern("__orc_rt_coff_platform_bootstrap"),
686 &orc_rt_coff_platform_bootstrap},
687 {ES.intern("__orc_rt_coff_platform_shutdown"),
688 &orc_rt_coff_platform_shutdown},
689 {ES.intern("__orc_rt_coff_register_jitdylib"),
690 &orc_rt_coff_register_jitdylib},
691 {ES.intern("__orc_rt_coff_deregister_jitdylib"),
692 &orc_rt_coff_deregister_jitdylib},
693 {ES.intern("__orc_rt_coff_register_object_sections"),
694 &orc_rt_coff_register_object_sections},
695 {ES.intern("__orc_rt_coff_deregister_object_sections"),
696 &orc_rt_coff_deregister_object_sections},
697 }))
698 return Err;
699
700 // Call bootstrap functions
701 if (auto Err = ES.callSPSWrapper<void()>(orc_rt_coff_platform_bootstrap))
702 return Err;
703
704 // Do the pending jitdylib registration actions that we couldn't do
705 // because orc runtime was not linked fully.
706 for (auto KV : JDBootstrapStates) {
707 auto &JDBState = KV.second;
708 if (auto Err = ES.callSPSWrapper<void(SPSString, SPSExecutorAddr)>(
709 orc_rt_coff_register_jitdylib, JDBState.JDName,
710 JDBState.HeaderAddr))
711 return Err;
712
713 for (auto &ObjSectionMap : JDBState.ObjectSectionsMaps)
714 if (auto Err = ES.callSPSWrapper<void(SPSExecutorAddr,
716 orc_rt_coff_register_object_sections, JDBState.HeaderAddr,
717 ObjSectionMap, false))
718 return Err;
719 }
720
721 // Run static initializers collected in bootstrap stage.
722 for (auto KV : JDBootstrapStates) {
723 auto &JDBState = KV.second;
724 if (auto Err = runBootstrapInitializers(JDBState))
725 return Err;
726 }
727
728 return Error::success();
729}
730
731Error COFFPlatform::runSymbolIfExists(JITDylib &PlatformJD,
732 StringRef SymbolName) {
733 ExecutorAddr jit_function;
734 auto AfterCLookupErr = lookupAndRecordAddrs(
736 {{ES.intern(SymbolName), &jit_function}});
737 if (!AfterCLookupErr) {
738 auto CallFn = rt::sps::Int32VoidCaller::Create(ES);
739 if (!CallFn)
740 return CallFn.takeError();
741 auto Res = (*CallFn)(jit_function);
742 if (!Res)
743 return Res.takeError();
744 return Error::success();
745 }
746 if (!AfterCLookupErr.isA<SymbolsNotFound>())
747 return AfterCLookupErr;
748 consumeError(std::move(AfterCLookupErr));
749 return Error::success();
750}
751
752void COFFPlatform::COFFPlatformPlugin::modifyPassConfig(
753 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
754 jitlink::PassConfiguration &Config) {
755
756 bool IsBootstrapping = CP.Bootstrapping.load();
757
758 if (auto InitSymbol = MR.getInitializerSymbol()) {
759 if (InitSymbol == CP.COFFHeaderStartSymbol) {
760 Config.PostAllocationPasses.push_back(
761 [this, &MR, IsBootstrapping](jitlink::LinkGraph &G) {
762 return associateJITDylibHeaderSymbol(G, MR, IsBootstrapping);
763 });
764 return;
765 }
766 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
767 return preserveInitializerSections(G, MR);
768 });
769 }
770
771 if (!IsBootstrapping)
772 Config.PostFixupPasses.push_back(
773 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
774 return registerObjectPlatformSections(G, JD);
775 });
776 else
777 Config.PostFixupPasses.push_back(
778 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
779 return registerObjectPlatformSectionsInBootstrap(G, JD);
780 });
781}
782
783Error COFFPlatform::COFFPlatformPlugin::associateJITDylibHeaderSymbol(
784 jitlink::LinkGraph &G, MaterializationResponsibility &MR,
785 bool IsBootstraping) {
786 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
787 return *Sym->getName() == *CP.COFFHeaderStartSymbol;
788 });
789 assert(I != G.defined_symbols().end() && "Missing COFF header start symbol");
790
791 auto &JD = MR.getTargetJITDylib();
792 std::lock_guard<std::mutex> Lock(CP.PlatformMutex);
793 auto HeaderAddr = (*I)->getAddress();
794 CP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
795 CP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
796 if (!IsBootstraping) {
797 G.allocActions().push_back(
799 SPSArgList<SPSString, SPSExecutorAddr>>(
800 CP.orc_rt_coff_register_jitdylib, JD.getName(), HeaderAddr)),
801 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
802 CP.orc_rt_coff_deregister_jitdylib, HeaderAddr))});
803 } else {
804 G.allocActions().push_back(
805 {{},
806 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
807 CP.orc_rt_coff_deregister_jitdylib, HeaderAddr))});
808 JDBootstrapState BState;
809 BState.JD = &JD;
810 BState.JDName = JD.getName();
811 BState.HeaderAddr = HeaderAddr;
812 CP.JDBootstrapStates.emplace(&JD, BState);
813 }
814
815 return Error::success();
816}
817
818Error COFFPlatform::COFFPlatformPlugin::registerObjectPlatformSections(
819 jitlink::LinkGraph &G, JITDylib &JD) {
820 COFFObjectSectionsMap ObjSecs;
821 auto HeaderAddr = CP.JITDylibToHeaderAddr[&JD];
822 assert(HeaderAddr && "Must be registered jitdylib");
823 for (auto &S : G.sections()) {
824 jitlink::SectionRange Range(S);
825 if (Range.getSize())
826 ObjSecs.push_back(std::make_pair(S.getName().str(), Range.getRange()));
827 }
828
829 G.allocActions().push_back(
831 CP.orc_rt_coff_register_object_sections, HeaderAddr, ObjSecs, true)),
832 cantFail(
834 CP.orc_rt_coff_deregister_object_sections, HeaderAddr,
835 ObjSecs))});
836
837 return Error::success();
838}
839
840Error COFFPlatform::COFFPlatformPlugin::preserveInitializerSections(
841 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
842
843 if (const auto &InitSymName = MR.getInitializerSymbol()) {
844
845 jitlink::Symbol *InitSym = nullptr;
846
847 for (auto &InitSection : G.sections()) {
848 // Skip non-init sections.
849 if (!isCOFFInitializerSection(InitSection.getName()) ||
850 InitSection.empty())
851 continue;
852
853 // Create the init symbol if it has not been created already and attach it
854 // to the first block.
855 if (!InitSym) {
856 auto &B = **InitSection.blocks().begin();
857 InitSym = &G.addDefinedSymbol(
858 B, 0, *InitSymName, B.getSize(), jitlink::Linkage::Strong,
860 }
861
862 // Add keep-alive edges to anonymous symbols in all other init blocks.
863 for (auto *B : InitSection.blocks()) {
864 if (B == &InitSym->getBlock())
865 continue;
866
867 auto &S = G.addAnonymousSymbol(*B, 0, B->getSize(), false, true);
868 InitSym->getBlock().addEdge(jitlink::Edge::KeepAlive, 0, S, 0);
869 }
870 }
871 }
872
873 return Error::success();
874}
875
876Error COFFPlatform::COFFPlatformPlugin::
877 registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph &G,
878 JITDylib &JD) {
879 std::lock_guard<std::mutex> Lock(CP.PlatformMutex);
880 auto HeaderAddr = CP.JITDylibToHeaderAddr[&JD];
881 COFFObjectSectionsMap ObjSecs;
882 for (auto &S : G.sections()) {
883 jitlink::SectionRange Range(S);
884 if (Range.getSize())
885 ObjSecs.push_back(std::make_pair(S.getName().str(), Range.getRange()));
886 }
887
888 G.allocActions().push_back(
889 {{},
890 cantFail(
892 CP.orc_rt_coff_deregister_object_sections, HeaderAddr,
893 ObjSecs))});
894
895 auto &BState = CP.JDBootstrapStates[&JD];
896 BState.ObjectSectionsMaps.push_back(std::move(ObjSecs));
897
898 // Collect static initializers
899 for (auto &S : G.sections())
900 if (isCOFFInitializerSection(S.getName()))
901 for (auto *B : S.blocks()) {
902 if (B->edges_empty())
903 continue;
904 for (auto &E : B->edges())
905 BState.Initializers.push_back(std::make_pair(
906 S.getName().str(), E.getTarget().getAddress() + E.getAddend()));
907 }
908
909 return Error::success();
910}
911
912} // End namespace orc.
913} // End namespace llvm.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
#define _
#define offsetof(TYPE, MEMBER)
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
#define H(x, y, z)
Definition MD5.cpp:56
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
static StringRef getName(Value *V)
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:219
Helper for Errors used as out-parameters.
Definition Error.h:1160
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
static Expected< std::unique_ptr< Archive > > create(MemoryBufferRef Source)
Definition Archive.cpp:785
Mediates between COFF initialization and ExecutionSession state.
Error setupJITDylib(JITDylib &JD) override
This method will be called outside the session lock each time a JITDylib is created (unless it is cre...
static Expected< std::unique_ptr< COFFPlatform > > Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, std::unique_ptr< MemoryBuffer > OrcRuntimeArchiveBuffer, LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime=false, const char *VCRuntimePath=nullptr, std::optional< SymbolAliasMap > RuntimeAliases=std::nullopt)
Try to create a COFFPlatform instance, adding the ORC runtime to the given JITDylib.
unique_function< Error(JITDylib &JD, StringRef DLLFileName)> LoadDynamicLibrary
A function that will be called with the name of dll file that must be loaded.
static ArrayRef< std::pair< const char *, const char * > > standardRuntimeUtilityAliases()
Returns the array of standard runtime utility aliases for COFF.
Error teardownJITDylib(JITDylib &JD) override
This method will be called outside the session lock each time a JITDylib is removed to allow the Plat...
static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES)
Returns an AliasMap containing the default aliases for the COFFPlatform.
Error notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) override
This method will be called under the ExecutionSession lock each time a MaterializationUnit is added t...
static ArrayRef< std::pair< const char *, const char * > > requiredCXXAliases()
Returns the array of required CXX aliases.
Error notifyRemoving(ResourceTracker &RT) override
This method will be called under the ExecutionSession lock when a ResourceTracker is removed.
static LLVM_ABI Expected< std::unique_ptr< COFFVCRuntimeBootstrapper > > Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, const char *RuntimePath=nullptr)
Try to create a COFFVCRuntimeBootstrapper instance.
static std::unique_ptr< DLLImportDefinitionGenerator > Create(ExecutionSession &ES, ObjectLinkingLayer &L)
Creates a DLLImportDefinitionGenerator instance.
An ExecutionSession represents a running JIT program.
Definition Core.h:1111
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition Core.h:1165
DenseMap< SymbolStringPtr, JITDispatchHandlerFunction > JITDispatchHandlerAssociationMap
A map associating tag names with asynchronous wrapper function implementations in the JIT.
Definition Core.h:1134
Represents an address in the executor process.
Represents a JIT'd dynamic library.
Definition Core.h:675
Error define(std::unique_ptr< MaterializationUnitType > &&MU, ResourceTrackerSP RT=nullptr)
Define all symbols provided by the materialization unit to be part of this JITDylib.
Definition Core.h:1649
GeneratorT & addGenerator(std::unique_ptr< GeneratorT > DefGenerator)
Adds a definition generator to this JITDylib and returns a referenece to it.
Definition Core.h:1632
LinkGraphLinkingLayer & addPlugin(std::shared_ptr< Plugin > P)
Add a plugin.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition Core.h:349
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization pseudo-symbol, if any.
Definition Core.h:388
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
Definition Core.h:374
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
virtual StringRef getName() const =0
Return the name of this materialization unit.
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization symbol for this MaterializationUnit (if any).
An ObjectLayer implementation built on JITLink.
static void lookupInitSymbolsAsync(unique_function< void(Error)> OnComplete, ExecutionSession &ES, const DenseMap< JITDylib *, SymbolLookupSet > &InitSyms)
Performs an async lookup for the given symbols in each of the given JITDylibs, calling the given hand...
Definition Core.cpp:1489
API to remove / transfer ownership of JIT resources.
Definition Core.h:63
JITDylib & getJITDylib() const
Return the JITDylib targeted by this tracker.
Definition Core.h:78
static Expected< std::unique_ptr< StaticLibraryDefinitionGenerator > > Create(ObjectLayer &L, std::unique_ptr< MemoryBuffer > ArchiveBuffer, std::unique_ptr< object::Archive > Archive, VisitMembersFunction VisitMembers=VisitMembersFunction(), GetObjectFileInterface GetObjFileInterface=GetObjectFileInterface())
Try to create a StaticLibrarySearchGenerator from the given memory buffer and Archive object.
Pointer to a pooled string representing a symbol name.
A utility class for serializing to a blob from a variadic list.
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ IMAGE_FILE_MACHINE_AMD64
Definition COFF.h:98
@ NUM_DATA_DIRECTORIES
Definition COFF.h:647
static const char PEMagic[]
Definition COFF.h:36
SPSSequence< SPSExecutorAddr > SPSCOFFJITDylibDepInfo
SPSSequence< char > SPSString
SPS tag type for strings, which are equivalent to sequences of chars.
SPSArgList< SPSExecutorAddr, SPSCOFFObjectSectionsMap, bool > SPSCOFFRegisterObjectSectionsArgs
SPSSequence< SPSTuple< SPSString, SPSExecutorAddrRange > > SPSCOFFObjectSectionsMap
SPSSequence< SPSTuple< SPSExecutorAddr, SPSCOFFJITDylibDepInfo > > SPSCOFFJITDylibDepInfoMap
SPSArgList< SPSExecutorAddr, SPSCOFFObjectSectionsMap > SPSCOFFDeregisterObjectSectionsArgs
JITDylibSearchOrder makeJITDylibSearchOrder(ArrayRef< JITDylib * > JDs, JITDylibLookupFlags Flags=JITDylibLookupFlags::MatchExportedSymbolsOnly)
Convenience function for creating a search order from an ArrayRef of JITDylib*, all with the same fla...
Definition Core.h:153
std::vector< std::pair< JITDylib *, JITDylibLookupFlags > > JITDylibSearchOrder
A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search order during symbol lookup.
Definition Core.h:148
IntrusiveRefCntPtr< JITDylib > JITDylibSP
Definition Core.h:58
std::unique_ptr< ReExportsMaterializationUnit > symbolAliases(SymbolAliasMap Aliases)
Create a ReExportsMaterializationUnit with the given aliases.
Definition Core.h:523
std::unique_ptr< ReExportsMaterializationUnit > reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, JITDylibLookupFlags SourceJDLookupFlags=JITDylibLookupFlags::MatchExportedSymbolsOnly)
Create a materialization unit for re-exporting symbols from another JITDylib with alternative names/f...
Definition Core.h:532
LLVM_ABI void lookupAndRecordAddrs(unique_function< void(Error)> OnRecorded, ExecutionSession &ES, LookupKind K, const JITDylibSearchOrder &SearchOrder, std::vector< std::pair< SymbolStringPtr, ExecutorAddr * > > Pairs, SymbolLookupFlags LookupFlags=SymbolLookupFlags::RequiredSymbol)
Record addresses of the given symbols in the given ExecutorAddrs.
static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, ArrayRef< std::pair< const char *, const char * > > AL)
LLVM_ABI Expected< MaterializationUnit::Interface > getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer)
Returns a MaterializationUnit::Interface for the object file contained in the given buffer,...
jitlink::Block & createHeaderBlock(MachOPlatform &MOP, const MachOPlatform::HeaderOptions &Opts, JITDylib &JD, jitlink::LinkGraph &G, jitlink::Section &HeaderSection)
LLVM_ABI RegisterDependenciesFunction NoDependenciesToRegister
This can be used as the value for a RegisterDependenciesFunction if there are no dependants to regist...
Definition Core.cpp:40
LLVM_ABI bool isCOFFInitializerSection(StringRef Name)
@ Ready
Emitted to memory, but waiting on transitive dependencies.
Definition Core.h:551
DenseMap< SymbolStringPtr, SymbolAliasMapEntry > SymbolAliasMap
A map of Symbols to (Symbol, Flags) pairs.
Definition Core.h:173
LLVM_ABI Expected< SymbolAliasMap > buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols)
Build a SymbolAliasMap for the common case where you want to re-export symbols from another JITDylib ...
Definition Core.cpp:482
DenseMap< SymbolStringPtr, JITSymbolFlags > SymbolFlagsMap
A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
Definition Endian.h:290
This is an optimization pass for GlobalISel generic memory operations.
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition Error.h:1415
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition Error.h:769
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1772
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878