1 //===------- COFFPlatform.cpp - Utilities for executing COFF in Orc -------===//
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
7 //===----------------------------------------------------------------------===//
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"
15 #include "llvm/Object/COFF.h"
17 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
19 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
21 #define DEBUG_TYPE "orc"
24 using namespace llvm::orc
;
25 using namespace llvm::orc::shared
;
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
>;
46 class COFFHeaderMaterializationUnit
: public MaterializationUnit
{
48 COFFHeaderMaterializationUnit(COFFPlatform
&CP
,
49 const SymbolStringPtr
&HeaderStartSymbol
)
50 : MaterializationUnit(createHeaderInterface(CP
, HeaderStartSymbol
)),
53 StringRef
getName() const override
{ return "COFFHeaderMU"; }
55 void materialize(std::unique_ptr
<MaterializationResponsibility
> R
) override
{
57 llvm::endianness Endianness
;
58 const auto &TT
= CP
.getExecutionSession().getTargetTriple();
60 switch (TT
.getArch()) {
63 Endianness
= llvm::endianness::little
;
66 llvm_unreachable("Unrecognized architecture");
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
);
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);
80 addImageBaseRelocationEdge(HeaderBlock
, ImageBaseSymbol
);
82 CP
.getObjectLinkingLayer().emit(std::move(R
), std::move(G
));
85 void discard(const JITDylib
&JD
, const SymbolStringPtr
&Sym
) override
{}
94 support::ulittle32_t PEMagic
;
95 object::coff_file_header FileHeader
;
97 object::pe32plus_header Header
;
98 object::data_directory DataDirectory
[COFF::NUM_DATA_DIRECTORIES
+ 1];
102 struct HeaderBlockContent
{
103 object::dos_header DOSHeader
;
104 COFFHeaderMaterializationUnit::NTHeader NTHeader
;
107 static jitlink::Block
&createHeaderBlock(jitlink::LinkGraph
&G
,
108 jitlink::Section
&HeaderSection
) {
109 HeaderBlockContent Hdr
= {};
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
;
120 switch (G
.getTargetTriple().getArch()) {
122 Hdr
.NTHeader
.FileHeader
.Machine
= COFF::IMAGE_FILE_MACHINE_AMD64
;
125 llvm_unreachable("Unrecognized architecture");
128 auto HeaderContent
= G
.allocateContent(
129 ArrayRef
<char>(reinterpret_cast<const char *>(&Hdr
), sizeof(Hdr
)));
131 return G
.createContentBlock(HeaderSection
, HeaderContent
, ExecutorAddr(), 8,
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);
143 static MaterializationUnit::Interface
144 createHeaderInterface(COFFPlatform
&MOP
,
145 const SymbolStringPtr
&HeaderStartSymbol
) {
146 SymbolFlagsMap HeaderSymbolFlags
;
148 HeaderSymbolFlags
[HeaderStartSymbol
] = JITSymbolFlags::Exported
;
150 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags
),
157 } // end anonymous namespace
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
) {
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());
174 auto &EPC
= ES
.getExecutorProcessControl();
176 auto GeneratorArchive
=
177 object::Archive::create(OrcRuntimeArchiveBuffer
->getMemBufferRef());
178 if (!GeneratorArchive
)
179 return GeneratorArchive
.takeError();
181 auto OrcRuntimeArchiveGenerator
= StaticLibraryDefinitionGenerator::Create(
182 ObjLinkingLayer
, nullptr, std::move(*GeneratorArchive
));
183 if (!OrcRuntimeArchiveGenerator
)
184 return OrcRuntimeArchiveGenerator
.takeError();
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
189 auto RuntimeArchive
= cantFail(
190 object::Archive::create(OrcRuntimeArchiveBuffer
->getMemBufferRef()));
192 // Create default aliases if the caller didn't supply any.
194 RuntimeAliases
= standardPlatformAliases(ES
);
196 // Define the aliases.
197 if (auto Err
= PlatformJD
.define(symbolAliases(std::move(*RuntimeAliases
))))
198 return std::move(Err
);
200 auto &HostFuncJD
= ES
.createBareJITDylib("$<PlatformRuntimeHostFuncJD>");
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
);
212 PlatformJD
.addToLinkOrder(HostFuncJD
);
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
));
221 return std::move(Err
);
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
) {
232 auto ArchiveBuffer
= MemoryBuffer::getFile(OrcRuntimePath
);
234 return createFileError(OrcRuntimePath
, ArchiveBuffer
.getError());
236 return Create(ES
, ObjLinkingLayer
, PlatformJD
, std::move(*ArchiveBuffer
),
237 std::move(LoadDynLibrary
), StaticVCRuntime
, VCRuntimePath
,
238 std::move(RuntimeAliases
));
241 Expected
<MemoryBufferRef
> COFFPlatform::getPerJDObjectFile() {
242 auto PerJDObj
= OrcRuntimeArchive
->findSym("__orc_rt_coff_per_jd_marker");
244 return PerJDObj
.takeError();
247 return make_error
<StringError
>("Could not find per jd object file",
248 inconvertibleErrorCode());
250 auto Buffer
= (*PerJDObj
)->getAsBinary();
252 return Buffer
.takeError();
254 return (*Buffer
)->getMemoryBufferRef();
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
};
267 Error
COFFPlatform::setupJITDylib(JITDylib
&JD
) {
268 if (auto Err
= JD
.define(std::make_unique
<COFFHeaderMaterializationUnit
>(
269 *this, COFFHeaderStartSymbol
)))
272 if (auto Err
= ES
.lookup({&JD
}, COFFHeaderStartSymbol
).takeError())
275 // Define the CXX aliases.
276 SymbolAliasMap CXXAliases
;
277 addAliases(ES
, CXXAliases
, requiredCXXAliases());
278 if (auto Err
= JD
.define(symbolAliases(std::move(CXXAliases
))))
281 auto PerJDObj
= getPerJDObjectFile();
283 return PerJDObj
.takeError();
285 auto I
= getObjectFileInterface(ES
, *PerJDObj
);
287 return I
.takeError();
289 if (auto Err
= ObjLinkingLayer
.add(
290 JD
, MemoryBuffer::getMemBuffer(*PerJDObj
, false), std::move(*I
)))
293 if (!Bootstrapping
) {
294 auto ImportedLibs
= StaticVCRuntime
295 ? VCRuntimeBootstrap
->loadStaticVCRuntime(JD
)
296 : VCRuntimeBootstrap
->loadDynamicVCRuntime(JD
);
298 return ImportedLibs
.takeError();
299 for (auto &Lib
: *ImportedLibs
)
300 if (auto Err
= LoadDynLibrary(JD
, Lib
))
303 if (auto Err
= VCRuntimeBootstrap
->initializeStaticVCRuntime(JD
))
307 JD
.addGenerator(DLLImportDefinitionGenerator::Create(ES
, ObjLinkingLayer
));
308 return Error::success();
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
);
320 return Error::success();
323 Error
COFFPlatform::notifyAdding(ResourceTracker
&RT
,
324 const MaterializationUnit
&MU
) {
325 auto &JD
= RT
.getJITDylib();
326 const auto &InitSym
= MU
.getInitializerSymbol();
328 return Error::success();
330 RegisteredInitSymbols
[&JD
].add(InitSym
,
331 SymbolLookupFlags::WeaklyReferencedSymbol
);
334 dbgs() << "COFFPlatform: Registered init symbol " << *InitSym
<< " for MU "
335 << MU
.getName() << "\n";
337 return Error::success();
340 Error
COFFPlatform::notifyRemoving(ResourceTracker
&RT
) {
341 llvm_unreachable("Not supported yet");
344 SymbolAliasMap
COFFPlatform::standardPlatformAliases(ExecutionSession
&ES
) {
345 SymbolAliasMap Aliases
;
346 addAliases(ES
, Aliases
, standardRuntimeUtilityAliases());
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"}};
357 return ArrayRef
<std::pair
<const char *, const char *>>(RequiredCXXAliases
);
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"}};
371 return ArrayRef
<std::pair
<const char *, const char *>>(
372 StandardRuntimeUtilityAliases
);
375 bool COFFPlatform::supportedTarget(const Triple
&TT
) {
376 switch (TT
.getArch()) {
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
);
400 Bootstrapping
.store(true);
401 ObjLinkingLayer
.addPlugin(std::make_unique
<COFFPlatformPlugin
>(*this));
405 COFFVCRuntimeBootstrapper::Create(ES
, ObjLinkingLayer
, VCRuntimePath
);
407 Err
= VCRT
.takeError();
410 VCRuntimeBootstrap
= std::move(*VCRT
);
412 for (auto &Lib
: OrcRuntimeGenerator
->getImportedDynamicLibraries())
413 DylibsToPreload
.insert(Lib
);
416 StaticVCRuntime
? VCRuntimeBootstrap
->loadStaticVCRuntime(PlatformJD
)
417 : VCRuntimeBootstrap
->loadDynamicVCRuntime(PlatformJD
);
419 Err
= ImportedLibs
.takeError();
423 for (auto &Lib
: *ImportedLibs
)
424 DylibsToPreload
.insert(Lib
);
426 PlatformJD
.addGenerator(std::move(OrcRuntimeGenerator
));
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
)) {
435 for (auto& Lib
: DylibsToPreload
)
436 if (auto E2
= this->LoadDynLibrary(PlatformJD
, Lib
)) {
442 if (auto E2
= VCRuntimeBootstrap
->initializeStaticVCRuntime(PlatformJD
)) {
447 // Associate wrapper function tags with JIT-side function implementations.
448 if (auto E2
= associateRuntimeSupportFunctions(PlatformJD
)) {
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
)) {
461 Bootstrapping
.store(false);
462 JDBootstrapStates
.clear();
465 Expected
<COFFPlatform::JITDylibDepMap
>
466 COFFPlatform::buildJDDepMap(JITDylib
&JD
) {
467 return ES
.runSessionLocked([&]() -> Expected
<JITDylibDepMap
> {
468 JITDylibDepMap JDDepMap
;
470 SmallVector
<JITDylib
*, 16> Worklist({&JD
});
471 while (!Worklist
.empty()) {
472 auto CurJD
= Worklist
.back();
475 auto &DM
= JDDepMap
[CurJD
];
476 CurJD
->withLinkOrderDo([&](const JITDylibSearchOrder
&O
) {
477 DM
.reserve(O
.size());
479 if (KV
.first
== CurJD
)
482 // Bare jitdylibs not known to the platform
483 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
484 if (!JITDylibToHeaderAddr
.count(KV
.first
)) {
486 dbgs() << "JITDylib unregistered to COFFPlatform detected in "
488 << CurJD
->getName() << "\n";
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
] = {};
502 return std::move(JDDepMap
);
506 void COFFPlatform::pushInitializersLoop(PushInitializersSendResultFn SendResult
,
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();
517 auto RISItr
= RegisteredInitSymbols
.find(CurJD
);
518 if (RISItr
!= RegisteredInitSymbols
.end()) {
519 NewInitSymbols
[CurJD
] = std::move(RISItr
->second
);
520 RegisteredInitSymbols
.erase(RISItr
);
523 for (auto *DepJD
: JDDepMap
[CurJD
])
524 if (!Visited
.count(DepJD
)) {
525 Worklist
.push_back(DepJD
);
526 Visited
.insert(DepJD
);
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
]);
544 auto H
= JITDylibToHeaderAddr
[KV
.first
];
545 DIM
.push_back(std::make_pair(H
, std::move(DepInfo
)));
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 {
556 SendResult(std::move(Err
));
558 pushInitializersLoop(std::move(SendResult
), JD
, JDDepMap
);
560 ES
, std::move(NewInitSymbols
));
563 void COFFPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult
,
564 ExecutorAddr JDHeaderAddr
) {
567 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
568 auto I
= HeaderAddrToJITDylib
.find(JDHeaderAddr
);
569 if (I
!= HeaderAddrToJITDylib
.end())
574 dbgs() << "COFFPlatform::rt_pushInitializers(" << JDHeaderAddr
<< ") ";
576 dbgs() << "pushing initializers for " << JD
->getName() << "\n";
578 dbgs() << "No JITDylib for header address.\n";
582 SendResult(make_error
<StringError
>("No JITDylib with header addr " +
583 formatv("{0:x}", JDHeaderAddr
),
584 inconvertibleErrorCode()));
588 auto JDDepMap
= buildJDDepMap(*JD
);
590 SendResult(JDDepMap
.takeError());
594 pushInitializersLoop(std::move(SendResult
), JD
, *JDDepMap
);
597 void COFFPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult
,
598 ExecutorAddr Handle
, StringRef SymbolName
) {
599 LLVM_DEBUG(dbgs() << "COFFPlatform::rt_lookupSymbol(\"" << Handle
<< "\")\n");
601 JITDylib
*JD
= nullptr;
604 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
605 auto I
= HeaderAddrToJITDylib
.find(Handle
);
606 if (I
!= HeaderAddrToJITDylib
.end())
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()));
618 // Use functor class to work around XL build compiler issue on AIX.
619 class RtLookupNotifyComplete
{
621 RtLookupNotifyComplete(SendSymbolAddressFn
&&SendResult
)
622 : SendResult(std::move(SendResult
)) {}
623 void operator()(Expected
<SymbolMap
> Result
) {
625 assert(Result
->size() == 1 && "Unexpected result map count");
626 SendResult(Result
->begin()->second
.getAddress());
628 SendResult(Result
.takeError());
633 SendSymbolAddressFn SendResult
;
637 LookupKind::DLSym
, {{JD
, JITDylibLookupFlags::MatchExportedSymbolsOnly
}},
638 SymbolLookupSet(ES
.intern(SymbolName
)), SymbolState::Ready
,
639 RtLookupNotifyComplete(std::move(SendResult
)), NoDependenciesToRegister
);
642 Error
COFFPlatform::associateRuntimeSupportFunctions(JITDylib
&PlatformJD
) {
643 ExecutionSession::JITDispatchHandlerAssociationMap WFs
;
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
);
656 return ES
.registerJITDispatchHandlers(PlatformJD
, std::move(WFs
));
659 Error
COFFPlatform::runBootstrapInitializers(JDBootstrapState
&BState
) {
660 llvm::sort(BState
.Initializers
);
662 runBootstrapSubsectionInitializers(BState
, ".CRT$XIA", ".CRT$XIZ"))
665 if (auto Err
= runSymbolIfExists(*BState
.JD
, "__run_after_c_init"))
669 runBootstrapSubsectionInitializers(BState
, ".CRT$XCA", ".CRT$XCZ"))
671 return Error::success();
674 Error
COFFPlatform::runBootstrapSubsectionInitializers(JDBootstrapState
&BState
,
677 for (auto &Initializer
: BState
.Initializers
)
678 if (Initializer
.first
>= Start
&& Initializer
.first
<= End
&&
679 Initializer
.second
) {
681 ES
.getExecutorProcessControl().runAsVoidFunction(Initializer
.second
);
683 return Res
.takeError();
685 return Error::success();
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
),
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
},
709 // Call bootstrap functions
710 if (auto Err
= ES
.callSPSWrapper
<void()>(orc_rt_coff_platform_bootstrap
))
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
))
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))
730 // Run static initializers collected in bootstrap stage.
731 for (auto KV
: JDBootstrapStates
) {
732 auto &JDBState
= KV
.second
;
733 if (auto Err
= runBootstrapInitializers(JDBState
))
737 return Error::success();
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
);
749 return Res
.takeError();
750 return Error::success();
752 if (!AfterCLookupErr
.isA
<SymbolsNotFound
>())
753 return AfterCLookupErr
;
754 consumeError(std::move(AfterCLookupErr
));
755 return Error::success();
758 void COFFPlatform::COFFPlatformPlugin::modifyPassConfig(
759 MaterializationResponsibility
&MR
, jitlink::LinkGraph
&LG
,
760 jitlink::PassConfiguration
&Config
) {
762 bool IsBootstrapping
= CP
.Bootstrapping
.load();
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
);
772 Config
.PrePrunePasses
.push_back([this, &MR
](jitlink::LinkGraph
&G
) {
773 return preserveInitializerSections(G
, MR
);
777 if (!IsBootstrapping
)
778 Config
.PostFixupPasses
.push_back(
779 [this, &JD
= MR
.getTargetJITDylib()](jitlink::LinkGraph
&G
) {
780 return registerObjectPlatformSections(G
, JD
);
783 Config
.PostFixupPasses
.push_back(
784 [this, &JD
= MR
.getTargetJITDylib()](jitlink::LinkGraph
&G
) {
785 return registerObjectPlatformSectionsInBootstrap(G
, JD
);
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
);
800 return SyntheticSymbolDependenciesMap();
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
;
809 assert(I
!= G
.defined_symbols().end() && "Missing COFF header start symbol");
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
))});
824 G
.allocActions().push_back(
826 cantFail(WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddr
>>(
827 CP
.orc_rt_coff_deregister_jitdylib
, HeaderAddr
))});
828 JDBootstrapState BState
;
830 BState
.JDName
= JD
.getName();
831 BState
.HeaderAddr
= HeaderAddr
;
832 CP
.JDBootstrapStates
.emplace(&JD
, BState
);
835 return Error::success();
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
);
846 ObjSecs
.push_back(std::make_pair(S
.getName().str(), Range
.getRange()));
849 G
.allocActions().push_back(
850 {cantFail(WrapperFunctionCall::Create
<SPSCOFFRegisterObjectSectionsArgs
>(
851 CP
.orc_rt_coff_register_object_sections
, HeaderAddr
, ObjSecs
, true)),
853 WrapperFunctionCall::Create
<SPSCOFFDeregisterObjectSectionsArgs
>(
854 CP
.orc_rt_coff_deregister_object_sections
, HeaderAddr
,
857 return Error::success();
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));
870 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
871 InitSymbolDeps
[&MR
] = InitSectionSymbols
;
872 return Error::success();
875 Error
COFFPlatform::COFFPlatformPlugin::
876 registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph
&G
,
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
);
884 ObjSecs
.push_back(std::make_pair(S
.getName().str(), Range
.getRange()));
887 G
.allocActions().push_back(
890 WrapperFunctionCall::Create
<SPSCOFFDeregisterObjectSectionsArgs
>(
891 CP
.orc_rt_coff_deregister_object_sections
, HeaderAddr
,
894 auto &BState
= CP
.JDBootstrapStates
[&JD
];
895 BState
.ObjectSectionsMaps
.push_back(std::move(ObjSecs
));
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())
903 for (auto &E
: B
->edges())
904 BState
.Initializers
.push_back(std::make_pair(
905 S
.getName().str(), E
.getTarget().getAddress() + E
.getAddend()));
908 return Error::success();
911 } // End namespace orc.
912 } // End namespace llvm.