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/AbsoluteSymbols.h"
11 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
12 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
13 #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
14 #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
16 #include "llvm/Object/COFF.h"
18 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
20 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
22 #define DEBUG_TYPE "orc"
25 using namespace llvm::orc
;
26 using namespace llvm::orc::shared
;
32 using SPSCOFFJITDylibDepInfo
= SPSSequence
<SPSExecutorAddr
>;
33 using SPSCOFFJITDylibDepInfoMap
=
34 SPSSequence
<SPSTuple
<SPSExecutorAddr
, SPSCOFFJITDylibDepInfo
>>;
35 using SPSCOFFObjectSectionsMap
=
36 SPSSequence
<SPSTuple
<SPSString
, SPSExecutorAddrRange
>>;
37 using SPSCOFFRegisterObjectSectionsArgs
=
38 SPSArgList
<SPSExecutorAddr
, SPSCOFFObjectSectionsMap
, bool>;
39 using SPSCOFFDeregisterObjectSectionsArgs
=
40 SPSArgList
<SPSExecutorAddr
, SPSCOFFObjectSectionsMap
>;
47 class COFFHeaderMaterializationUnit
: public MaterializationUnit
{
49 COFFHeaderMaterializationUnit(COFFPlatform
&CP
,
50 const SymbolStringPtr
&HeaderStartSymbol
)
51 : MaterializationUnit(createHeaderInterface(CP
, HeaderStartSymbol
)),
54 StringRef
getName() const override
{ return "COFFHeaderMU"; }
56 void materialize(std::unique_ptr
<MaterializationResponsibility
> R
) override
{
58 llvm::endianness Endianness
;
59 const auto &TT
= CP
.getExecutionSession().getTargetTriple();
61 switch (TT
.getArch()) {
64 Endianness
= llvm::endianness::little
;
67 llvm_unreachable("Unrecognized architecture");
70 auto G
= std::make_unique
<jitlink::LinkGraph
>(
71 "<COFFHeaderMU>", CP
.getExecutionSession().getSymbolStringPool(), TT
,
72 PointerSize
, Endianness
, jitlink::getGenericEdgeKindName
);
73 auto &HeaderSection
= G
->createSection("__header", MemProt::Read
);
74 auto &HeaderBlock
= createHeaderBlock(*G
, HeaderSection
);
76 // Init symbol is __ImageBase symbol.
77 auto &ImageBaseSymbol
= G
->addDefinedSymbol(
78 HeaderBlock
, 0, *R
->getInitializerSymbol(), HeaderBlock
.getSize(),
79 jitlink::Linkage::Strong
, jitlink::Scope::Default
, false, true);
81 addImageBaseRelocationEdge(HeaderBlock
, ImageBaseSymbol
);
83 CP
.getObjectLinkingLayer().emit(std::move(R
), std::move(G
));
86 void discard(const JITDylib
&JD
, const SymbolStringPtr
&Sym
) override
{}
95 support::ulittle32_t PEMagic
;
96 object::coff_file_header FileHeader
;
98 object::pe32plus_header Header
;
99 object::data_directory DataDirectory
[COFF::NUM_DATA_DIRECTORIES
+ 1];
103 struct HeaderBlockContent
{
104 object::dos_header DOSHeader
;
105 COFFHeaderMaterializationUnit::NTHeader NTHeader
;
108 static jitlink::Block
&createHeaderBlock(jitlink::LinkGraph
&G
,
109 jitlink::Section
&HeaderSection
) {
110 HeaderBlockContent Hdr
= {};
113 Hdr
.DOSHeader
.Magic
[0] = 'M';
114 Hdr
.DOSHeader
.Magic
[1] = 'Z';
115 Hdr
.DOSHeader
.AddressOfNewExeHeader
=
116 offsetof(HeaderBlockContent
, NTHeader
);
117 uint32_t PEMagic
= *reinterpret_cast<const uint32_t *>(COFF::PEMagic
);
118 Hdr
.NTHeader
.PEMagic
= PEMagic
;
119 Hdr
.NTHeader
.OptionalHeader
.Header
.Magic
= COFF::PE32Header::PE32_PLUS
;
121 switch (G
.getTargetTriple().getArch()) {
123 Hdr
.NTHeader
.FileHeader
.Machine
= COFF::IMAGE_FILE_MACHINE_AMD64
;
126 llvm_unreachable("Unrecognized architecture");
129 auto HeaderContent
= G
.allocateContent(
130 ArrayRef
<char>(reinterpret_cast<const char *>(&Hdr
), sizeof(Hdr
)));
132 return G
.createContentBlock(HeaderSection
, HeaderContent
, ExecutorAddr(), 8,
136 static void addImageBaseRelocationEdge(jitlink::Block
&B
,
137 jitlink::Symbol
&ImageBase
) {
138 auto ImageBaseOffset
= offsetof(HeaderBlockContent
, NTHeader
) +
139 offsetof(NTHeader
, OptionalHeader
) +
140 offsetof(object::pe32plus_header
, ImageBase
);
141 B
.addEdge(jitlink::x86_64::Pointer64
, ImageBaseOffset
, ImageBase
, 0);
144 static MaterializationUnit::Interface
145 createHeaderInterface(COFFPlatform
&MOP
,
146 const SymbolStringPtr
&HeaderStartSymbol
) {
147 SymbolFlagsMap HeaderSymbolFlags
;
149 HeaderSymbolFlags
[HeaderStartSymbol
] = JITSymbolFlags::Exported
;
151 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags
),
158 } // end anonymous namespace
163 Expected
<std::unique_ptr
<COFFPlatform
>>
164 COFFPlatform::Create(ObjectLinkingLayer
&ObjLinkingLayer
, JITDylib
&PlatformJD
,
165 std::unique_ptr
<MemoryBuffer
> OrcRuntimeArchiveBuffer
,
166 LoadDynamicLibrary LoadDynLibrary
, bool StaticVCRuntime
,
167 const char *VCRuntimePath
,
168 std::optional
<SymbolAliasMap
> RuntimeAliases
) {
170 auto &ES
= ObjLinkingLayer
.getExecutionSession();
172 // If the target is not supported then bail out immediately.
173 if (!supportedTarget(ES
.getTargetTriple()))
174 return make_error
<StringError
>("Unsupported COFFPlatform triple: " +
175 ES
.getTargetTriple().str(),
176 inconvertibleErrorCode());
178 auto &EPC
= ES
.getExecutorProcessControl();
180 auto GeneratorArchive
=
181 object::Archive::create(OrcRuntimeArchiveBuffer
->getMemBufferRef());
182 if (!GeneratorArchive
)
183 return GeneratorArchive
.takeError();
185 auto OrcRuntimeArchiveGenerator
= StaticLibraryDefinitionGenerator::Create(
186 ObjLinkingLayer
, nullptr, std::move(*GeneratorArchive
));
187 if (!OrcRuntimeArchiveGenerator
)
188 return OrcRuntimeArchiveGenerator
.takeError();
190 // We need a second instance of the archive (for now) for the Platform. We
191 // can `cantFail` this call, since if it were going to fail it would have
193 auto RuntimeArchive
= cantFail(
194 object::Archive::create(OrcRuntimeArchiveBuffer
->getMemBufferRef()));
196 // Create default aliases if the caller didn't supply any.
198 RuntimeAliases
= standardPlatformAliases(ES
);
200 // Define the aliases.
201 if (auto Err
= PlatformJD
.define(symbolAliases(std::move(*RuntimeAliases
))))
202 return std::move(Err
);
204 auto &HostFuncJD
= ES
.createBareJITDylib("$<PlatformRuntimeHostFuncJD>");
206 // Add JIT-dispatch function support symbols.
207 if (auto Err
= HostFuncJD
.define(
208 absoluteSymbols({{ES
.intern("__orc_rt_jit_dispatch"),
209 {EPC
.getJITDispatchInfo().JITDispatchFunction
,
210 JITSymbolFlags::Exported
}},
211 {ES
.intern("__orc_rt_jit_dispatch_ctx"),
212 {EPC
.getJITDispatchInfo().JITDispatchContext
,
213 JITSymbolFlags::Exported
}}})))
214 return std::move(Err
);
216 PlatformJD
.addToLinkOrder(HostFuncJD
);
218 // Create the instance.
219 Error Err
= Error::success();
220 auto P
= std::unique_ptr
<COFFPlatform
>(new COFFPlatform(
221 ObjLinkingLayer
, PlatformJD
, std::move(*OrcRuntimeArchiveGenerator
),
222 std::move(OrcRuntimeArchiveBuffer
), std::move(RuntimeArchive
),
223 std::move(LoadDynLibrary
), StaticVCRuntime
, VCRuntimePath
, Err
));
225 return std::move(Err
);
229 Expected
<std::unique_ptr
<COFFPlatform
>>
230 COFFPlatform::Create(ObjectLinkingLayer
&ObjLinkingLayer
, JITDylib
&PlatformJD
,
231 const char *OrcRuntimePath
,
232 LoadDynamicLibrary LoadDynLibrary
, bool StaticVCRuntime
,
233 const char *VCRuntimePath
,
234 std::optional
<SymbolAliasMap
> RuntimeAliases
) {
236 auto ArchiveBuffer
= MemoryBuffer::getFile(OrcRuntimePath
);
238 return createFileError(OrcRuntimePath
, ArchiveBuffer
.getError());
240 return Create(ObjLinkingLayer
, PlatformJD
, std::move(*ArchiveBuffer
),
241 std::move(LoadDynLibrary
), StaticVCRuntime
, VCRuntimePath
,
242 std::move(RuntimeAliases
));
245 Expected
<MemoryBufferRef
> COFFPlatform::getPerJDObjectFile() {
246 auto PerJDObj
= OrcRuntimeArchive
->findSym("__orc_rt_coff_per_jd_marker");
248 return PerJDObj
.takeError();
251 return make_error
<StringError
>("Could not find per jd object file",
252 inconvertibleErrorCode());
254 auto Buffer
= (*PerJDObj
)->getAsBinary();
256 return Buffer
.takeError();
258 return (*Buffer
)->getMemoryBufferRef();
261 static void addAliases(ExecutionSession
&ES
, SymbolAliasMap
&Aliases
,
262 ArrayRef
<std::pair
<const char *, const char *>> AL
) {
263 for (auto &KV
: AL
) {
264 auto AliasName
= ES
.intern(KV
.first
);
265 assert(!Aliases
.count(AliasName
) && "Duplicate symbol name in alias map");
266 Aliases
[std::move(AliasName
)] = {ES
.intern(KV
.second
),
267 JITSymbolFlags::Exported
};
271 Error
COFFPlatform::setupJITDylib(JITDylib
&JD
) {
272 if (auto Err
= JD
.define(std::make_unique
<COFFHeaderMaterializationUnit
>(
273 *this, COFFHeaderStartSymbol
)))
276 if (auto Err
= ES
.lookup({&JD
}, COFFHeaderStartSymbol
).takeError())
279 // Define the CXX aliases.
280 SymbolAliasMap CXXAliases
;
281 addAliases(ES
, CXXAliases
, requiredCXXAliases());
282 if (auto Err
= JD
.define(symbolAliases(std::move(CXXAliases
))))
285 auto PerJDObj
= getPerJDObjectFile();
287 return PerJDObj
.takeError();
289 auto I
= getObjectFileInterface(ES
, *PerJDObj
);
291 return I
.takeError();
293 if (auto Err
= ObjLinkingLayer
.add(
294 JD
, MemoryBuffer::getMemBuffer(*PerJDObj
, false), std::move(*I
)))
297 if (!Bootstrapping
) {
298 auto ImportedLibs
= StaticVCRuntime
299 ? VCRuntimeBootstrap
->loadStaticVCRuntime(JD
)
300 : VCRuntimeBootstrap
->loadDynamicVCRuntime(JD
);
302 return ImportedLibs
.takeError();
303 for (auto &Lib
: *ImportedLibs
)
304 if (auto Err
= LoadDynLibrary(JD
, Lib
))
307 if (auto Err
= VCRuntimeBootstrap
->initializeStaticVCRuntime(JD
))
311 JD
.addGenerator(DLLImportDefinitionGenerator::Create(ES
, ObjLinkingLayer
));
312 return Error::success();
315 Error
COFFPlatform::teardownJITDylib(JITDylib
&JD
) {
316 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
317 auto I
= JITDylibToHeaderAddr
.find(&JD
);
318 if (I
!= JITDylibToHeaderAddr
.end()) {
319 assert(HeaderAddrToJITDylib
.count(I
->second
) &&
320 "HeaderAddrToJITDylib missing entry");
321 HeaderAddrToJITDylib
.erase(I
->second
);
322 JITDylibToHeaderAddr
.erase(I
);
324 return Error::success();
327 Error
COFFPlatform::notifyAdding(ResourceTracker
&RT
,
328 const MaterializationUnit
&MU
) {
329 auto &JD
= RT
.getJITDylib();
330 const auto &InitSym
= MU
.getInitializerSymbol();
332 return Error::success();
334 RegisteredInitSymbols
[&JD
].add(InitSym
,
335 SymbolLookupFlags::WeaklyReferencedSymbol
);
338 dbgs() << "COFFPlatform: Registered init symbol " << *InitSym
<< " for MU "
339 << MU
.getName() << "\n";
341 return Error::success();
344 Error
COFFPlatform::notifyRemoving(ResourceTracker
&RT
) {
345 llvm_unreachable("Not supported yet");
348 SymbolAliasMap
COFFPlatform::standardPlatformAliases(ExecutionSession
&ES
) {
349 SymbolAliasMap Aliases
;
350 addAliases(ES
, Aliases
, standardRuntimeUtilityAliases());
354 ArrayRef
<std::pair
<const char *, const char *>>
355 COFFPlatform::requiredCXXAliases() {
356 static const std::pair
<const char *, const char *> RequiredCXXAliases
[] = {
357 {"_CxxThrowException", "__orc_rt_coff_cxx_throw_exception"},
358 {"_onexit", "__orc_rt_coff_onexit_per_jd"},
359 {"atexit", "__orc_rt_coff_atexit_per_jd"}};
361 return ArrayRef
<std::pair
<const char *, const char *>>(RequiredCXXAliases
);
364 ArrayRef
<std::pair
<const char *, const char *>>
365 COFFPlatform::standardRuntimeUtilityAliases() {
366 static const std::pair
<const char *, const char *>
367 StandardRuntimeUtilityAliases
[] = {
368 {"__orc_rt_run_program", "__orc_rt_coff_run_program"},
369 {"__orc_rt_jit_dlerror", "__orc_rt_coff_jit_dlerror"},
370 {"__orc_rt_jit_dlopen", "__orc_rt_coff_jit_dlopen"},
371 {"__orc_rt_jit_dlclose", "__orc_rt_coff_jit_dlclose"},
372 {"__orc_rt_jit_dlsym", "__orc_rt_coff_jit_dlsym"},
373 {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
375 return ArrayRef
<std::pair
<const char *, const char *>>(
376 StandardRuntimeUtilityAliases
);
379 bool COFFPlatform::supportedTarget(const Triple
&TT
) {
380 switch (TT
.getArch()) {
388 COFFPlatform::COFFPlatform(
389 ObjectLinkingLayer
&ObjLinkingLayer
, JITDylib
&PlatformJD
,
390 std::unique_ptr
<StaticLibraryDefinitionGenerator
> OrcRuntimeGenerator
,
391 std::unique_ptr
<MemoryBuffer
> OrcRuntimeArchiveBuffer
,
392 std::unique_ptr
<object::Archive
> OrcRuntimeArchive
,
393 LoadDynamicLibrary LoadDynLibrary
, bool StaticVCRuntime
,
394 const char *VCRuntimePath
, Error
&Err
)
395 : ES(ObjLinkingLayer
.getExecutionSession()),
396 ObjLinkingLayer(ObjLinkingLayer
),
397 LoadDynLibrary(std::move(LoadDynLibrary
)),
398 OrcRuntimeArchiveBuffer(std::move(OrcRuntimeArchiveBuffer
)),
399 OrcRuntimeArchive(std::move(OrcRuntimeArchive
)),
400 StaticVCRuntime(StaticVCRuntime
),
401 COFFHeaderStartSymbol(ES
.intern("__ImageBase")) {
402 ErrorAsOutParameter
_(Err
);
404 Bootstrapping
.store(true);
405 ObjLinkingLayer
.addPlugin(std::make_unique
<COFFPlatformPlugin
>(*this));
409 COFFVCRuntimeBootstrapper::Create(ES
, ObjLinkingLayer
, VCRuntimePath
);
411 Err
= VCRT
.takeError();
414 VCRuntimeBootstrap
= std::move(*VCRT
);
416 for (auto &Lib
: OrcRuntimeGenerator
->getImportedDynamicLibraries())
417 DylibsToPreload
.insert(Lib
);
420 StaticVCRuntime
? VCRuntimeBootstrap
->loadStaticVCRuntime(PlatformJD
)
421 : VCRuntimeBootstrap
->loadDynamicVCRuntime(PlatformJD
);
423 Err
= ImportedLibs
.takeError();
427 for (auto &Lib
: *ImportedLibs
)
428 DylibsToPreload
.insert(Lib
);
430 PlatformJD
.addGenerator(std::move(OrcRuntimeGenerator
));
432 // PlatformJD hasn't been set up by the platform yet (since we're creating
433 // the platform now), so set it up.
434 if (auto E2
= setupJITDylib(PlatformJD
)) {
439 for (auto& Lib
: DylibsToPreload
)
440 if (auto E2
= this->LoadDynLibrary(PlatformJD
, Lib
)) {
446 if (auto E2
= VCRuntimeBootstrap
->initializeStaticVCRuntime(PlatformJD
)) {
451 // Associate wrapper function tags with JIT-side function implementations.
452 if (auto E2
= associateRuntimeSupportFunctions(PlatformJD
)) {
457 // Lookup addresses of runtime functions callable by the platform,
458 // call the platform bootstrap function to initialize the platform-state
459 // object in the executor.
460 if (auto E2
= bootstrapCOFFRuntime(PlatformJD
)) {
465 Bootstrapping
.store(false);
466 JDBootstrapStates
.clear();
469 Expected
<COFFPlatform::JITDylibDepMap
>
470 COFFPlatform::buildJDDepMap(JITDylib
&JD
) {
471 return ES
.runSessionLocked([&]() -> Expected
<JITDylibDepMap
> {
472 JITDylibDepMap JDDepMap
;
474 SmallVector
<JITDylib
*, 16> Worklist({&JD
});
475 while (!Worklist
.empty()) {
476 auto CurJD
= Worklist
.back();
479 auto &DM
= JDDepMap
[CurJD
];
480 CurJD
->withLinkOrderDo([&](const JITDylibSearchOrder
&O
) {
481 DM
.reserve(O
.size());
483 if (KV
.first
== CurJD
)
486 // Bare jitdylibs not known to the platform
487 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
488 if (!JITDylibToHeaderAddr
.count(KV
.first
)) {
490 dbgs() << "JITDylib unregistered to COFFPlatform detected in "
492 << CurJD
->getName() << "\n";
497 DM
.push_back(KV
.first
);
498 // Push unvisited entry.
499 if (!JDDepMap
.count(KV
.first
)) {
500 Worklist
.push_back(KV
.first
);
501 JDDepMap
[KV
.first
] = {};
506 return std::move(JDDepMap
);
510 void COFFPlatform::pushInitializersLoop(PushInitializersSendResultFn SendResult
,
512 JITDylibDepMap
&JDDepMap
) {
513 SmallVector
<JITDylib
*, 16> Worklist({JD
.get()});
514 DenseSet
<JITDylib
*> Visited({JD
.get()});
515 DenseMap
<JITDylib
*, SymbolLookupSet
> NewInitSymbols
;
516 ES
.runSessionLocked([&]() {
517 while (!Worklist
.empty()) {
518 auto CurJD
= Worklist
.back();
521 auto RISItr
= RegisteredInitSymbols
.find(CurJD
);
522 if (RISItr
!= RegisteredInitSymbols
.end()) {
523 NewInitSymbols
[CurJD
] = std::move(RISItr
->second
);
524 RegisteredInitSymbols
.erase(RISItr
);
527 for (auto *DepJD
: JDDepMap
[CurJD
])
528 if (Visited
.insert(DepJD
).second
)
529 Worklist
.push_back(DepJD
);
533 // If there are no further init symbols to look up then send the link order
534 // (as a list of header addresses) to the caller.
535 if (NewInitSymbols
.empty()) {
536 // Build the dep info map to return.
537 COFFJITDylibDepInfoMap DIM
;
538 DIM
.reserve(JDDepMap
.size());
539 for (auto &KV
: JDDepMap
) {
540 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
541 COFFJITDylibDepInfo DepInfo
;
542 DepInfo
.reserve(KV
.second
.size());
543 for (auto &Dep
: KV
.second
) {
544 DepInfo
.push_back(JITDylibToHeaderAddr
[Dep
]);
546 auto H
= JITDylibToHeaderAddr
[KV
.first
];
547 DIM
.push_back(std::make_pair(H
, std::move(DepInfo
)));
553 // Otherwise issue a lookup and re-run this phase when it completes.
554 lookupInitSymbolsAsync(
555 [this, SendResult
= std::move(SendResult
), &JD
,
556 JDDepMap
= std::move(JDDepMap
)](Error Err
) mutable {
558 SendResult(std::move(Err
));
560 pushInitializersLoop(std::move(SendResult
), JD
, JDDepMap
);
562 ES
, std::move(NewInitSymbols
));
565 void COFFPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult
,
566 ExecutorAddr JDHeaderAddr
) {
569 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
570 auto I
= HeaderAddrToJITDylib
.find(JDHeaderAddr
);
571 if (I
!= HeaderAddrToJITDylib
.end())
576 dbgs() << "COFFPlatform::rt_pushInitializers(" << JDHeaderAddr
<< ") ";
578 dbgs() << "pushing initializers for " << JD
->getName() << "\n";
580 dbgs() << "No JITDylib for header address.\n";
584 SendResult(make_error
<StringError
>("No JITDylib with header addr " +
585 formatv("{0:x}", JDHeaderAddr
),
586 inconvertibleErrorCode()));
590 auto JDDepMap
= buildJDDepMap(*JD
);
592 SendResult(JDDepMap
.takeError());
596 pushInitializersLoop(std::move(SendResult
), JD
, *JDDepMap
);
599 void COFFPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult
,
600 ExecutorAddr Handle
, StringRef SymbolName
) {
601 LLVM_DEBUG(dbgs() << "COFFPlatform::rt_lookupSymbol(\"" << Handle
<< "\")\n");
603 JITDylib
*JD
= nullptr;
606 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
607 auto I
= HeaderAddrToJITDylib
.find(Handle
);
608 if (I
!= HeaderAddrToJITDylib
.end())
613 LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle
<< "\n");
614 SendResult(make_error
<StringError
>("No JITDylib associated with handle " +
615 formatv("{0:x}", Handle
),
616 inconvertibleErrorCode()));
620 // Use functor class to work around XL build compiler issue on AIX.
621 class RtLookupNotifyComplete
{
623 RtLookupNotifyComplete(SendSymbolAddressFn
&&SendResult
)
624 : SendResult(std::move(SendResult
)) {}
625 void operator()(Expected
<SymbolMap
> Result
) {
627 assert(Result
->size() == 1 && "Unexpected result map count");
628 SendResult(Result
->begin()->second
.getAddress());
630 SendResult(Result
.takeError());
635 SendSymbolAddressFn SendResult
;
639 LookupKind::DLSym
, {{JD
, JITDylibLookupFlags::MatchExportedSymbolsOnly
}},
640 SymbolLookupSet(ES
.intern(SymbolName
)), SymbolState::Ready
,
641 RtLookupNotifyComplete(std::move(SendResult
)), NoDependenciesToRegister
);
644 Error
COFFPlatform::associateRuntimeSupportFunctions(JITDylib
&PlatformJD
) {
645 ExecutionSession::JITDispatchHandlerAssociationMap WFs
;
647 using LookupSymbolSPSSig
=
648 SPSExpected
<SPSExecutorAddr
>(SPSExecutorAddr
, SPSString
);
649 WFs
[ES
.intern("__orc_rt_coff_symbol_lookup_tag")] =
650 ES
.wrapAsyncWithSPS
<LookupSymbolSPSSig
>(this,
651 &COFFPlatform::rt_lookupSymbol
);
652 using PushInitializersSPSSig
=
653 SPSExpected
<SPSCOFFJITDylibDepInfoMap
>(SPSExecutorAddr
);
654 WFs
[ES
.intern("__orc_rt_coff_push_initializers_tag")] =
655 ES
.wrapAsyncWithSPS
<PushInitializersSPSSig
>(
656 this, &COFFPlatform::rt_pushInitializers
);
658 return ES
.registerJITDispatchHandlers(PlatformJD
, std::move(WFs
));
661 Error
COFFPlatform::runBootstrapInitializers(JDBootstrapState
&BState
) {
662 llvm::sort(BState
.Initializers
);
664 runBootstrapSubsectionInitializers(BState
, ".CRT$XIA", ".CRT$XIZ"))
667 if (auto Err
= runSymbolIfExists(*BState
.JD
, "__run_after_c_init"))
671 runBootstrapSubsectionInitializers(BState
, ".CRT$XCA", ".CRT$XCZ"))
673 return Error::success();
676 Error
COFFPlatform::runBootstrapSubsectionInitializers(JDBootstrapState
&BState
,
679 for (auto &Initializer
: BState
.Initializers
)
680 if (Initializer
.first
>= Start
&& Initializer
.first
<= End
&&
681 Initializer
.second
) {
683 ES
.getExecutorProcessControl().runAsVoidFunction(Initializer
.second
);
685 return Res
.takeError();
687 return Error::success();
690 Error
COFFPlatform::bootstrapCOFFRuntime(JITDylib
&PlatformJD
) {
691 // Lookup of runtime symbols causes the collection of initializers if
692 // it's static linking setting.
693 if (auto Err
= lookupAndRecordAddrs(
694 ES
, LookupKind::Static
, makeJITDylibSearchOrder(&PlatformJD
),
696 {ES
.intern("__orc_rt_coff_platform_bootstrap"),
697 &orc_rt_coff_platform_bootstrap
},
698 {ES
.intern("__orc_rt_coff_platform_shutdown"),
699 &orc_rt_coff_platform_shutdown
},
700 {ES
.intern("__orc_rt_coff_register_jitdylib"),
701 &orc_rt_coff_register_jitdylib
},
702 {ES
.intern("__orc_rt_coff_deregister_jitdylib"),
703 &orc_rt_coff_deregister_jitdylib
},
704 {ES
.intern("__orc_rt_coff_register_object_sections"),
705 &orc_rt_coff_register_object_sections
},
706 {ES
.intern("__orc_rt_coff_deregister_object_sections"),
707 &orc_rt_coff_deregister_object_sections
},
711 // Call bootstrap functions
712 if (auto Err
= ES
.callSPSWrapper
<void()>(orc_rt_coff_platform_bootstrap
))
715 // Do the pending jitdylib registration actions that we couldn't do
716 // because orc runtime was not linked fully.
717 for (auto KV
: JDBootstrapStates
) {
718 auto &JDBState
= KV
.second
;
719 if (auto Err
= ES
.callSPSWrapper
<void(SPSString
, SPSExecutorAddr
)>(
720 orc_rt_coff_register_jitdylib
, JDBState
.JDName
,
721 JDBState
.HeaderAddr
))
724 for (auto &ObjSectionMap
: JDBState
.ObjectSectionsMaps
)
725 if (auto Err
= ES
.callSPSWrapper
<void(SPSExecutorAddr
,
726 SPSCOFFObjectSectionsMap
, bool)>(
727 orc_rt_coff_register_object_sections
, JDBState
.HeaderAddr
,
728 ObjSectionMap
, false))
732 // Run static initializers collected in bootstrap stage.
733 for (auto KV
: JDBootstrapStates
) {
734 auto &JDBState
= KV
.second
;
735 if (auto Err
= runBootstrapInitializers(JDBState
))
739 return Error::success();
742 Error
COFFPlatform::runSymbolIfExists(JITDylib
&PlatformJD
,
743 StringRef SymbolName
) {
744 ExecutorAddr jit_function
;
745 auto AfterCLookupErr
= lookupAndRecordAddrs(
746 ES
, LookupKind::Static
, makeJITDylibSearchOrder(&PlatformJD
),
747 {{ES
.intern(SymbolName
), &jit_function
}});
748 if (!AfterCLookupErr
) {
749 auto Res
= ES
.getExecutorProcessControl().runAsVoidFunction(jit_function
);
751 return Res
.takeError();
752 return Error::success();
754 if (!AfterCLookupErr
.isA
<SymbolsNotFound
>())
755 return AfterCLookupErr
;
756 consumeError(std::move(AfterCLookupErr
));
757 return Error::success();
760 void COFFPlatform::COFFPlatformPlugin::modifyPassConfig(
761 MaterializationResponsibility
&MR
, jitlink::LinkGraph
&LG
,
762 jitlink::PassConfiguration
&Config
) {
764 bool IsBootstrapping
= CP
.Bootstrapping
.load();
766 if (auto InitSymbol
= MR
.getInitializerSymbol()) {
767 if (InitSymbol
== CP
.COFFHeaderStartSymbol
) {
768 Config
.PostAllocationPasses
.push_back(
769 [this, &MR
, IsBootstrapping
](jitlink::LinkGraph
&G
) {
770 return associateJITDylibHeaderSymbol(G
, MR
, IsBootstrapping
);
774 Config
.PrePrunePasses
.push_back([this, &MR
](jitlink::LinkGraph
&G
) {
775 return preserveInitializerSections(G
, MR
);
779 if (!IsBootstrapping
)
780 Config
.PostFixupPasses
.push_back(
781 [this, &JD
= MR
.getTargetJITDylib()](jitlink::LinkGraph
&G
) {
782 return registerObjectPlatformSections(G
, JD
);
785 Config
.PostFixupPasses
.push_back(
786 [this, &JD
= MR
.getTargetJITDylib()](jitlink::LinkGraph
&G
) {
787 return registerObjectPlatformSectionsInBootstrap(G
, JD
);
791 Error
COFFPlatform::COFFPlatformPlugin::associateJITDylibHeaderSymbol(
792 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
,
793 bool IsBootstraping
) {
794 auto I
= llvm::find_if(G
.defined_symbols(), [this](jitlink::Symbol
*Sym
) {
795 return *Sym
->getName() == *CP
.COFFHeaderStartSymbol
;
797 assert(I
!= G
.defined_symbols().end() && "Missing COFF header start symbol");
799 auto &JD
= MR
.getTargetJITDylib();
800 std::lock_guard
<std::mutex
> Lock(CP
.PlatformMutex
);
801 auto HeaderAddr
= (*I
)->getAddress();
802 CP
.JITDylibToHeaderAddr
[&JD
] = HeaderAddr
;
803 CP
.HeaderAddrToJITDylib
[HeaderAddr
] = &JD
;
804 if (!IsBootstraping
) {
805 G
.allocActions().push_back(
806 {cantFail(WrapperFunctionCall::Create
<
807 SPSArgList
<SPSString
, SPSExecutorAddr
>>(
808 CP
.orc_rt_coff_register_jitdylib
, JD
.getName(), HeaderAddr
)),
809 cantFail(WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddr
>>(
810 CP
.orc_rt_coff_deregister_jitdylib
, HeaderAddr
))});
812 G
.allocActions().push_back(
814 cantFail(WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddr
>>(
815 CP
.orc_rt_coff_deregister_jitdylib
, HeaderAddr
))});
816 JDBootstrapState BState
;
818 BState
.JDName
= JD
.getName();
819 BState
.HeaderAddr
= HeaderAddr
;
820 CP
.JDBootstrapStates
.emplace(&JD
, BState
);
823 return Error::success();
826 Error
COFFPlatform::COFFPlatformPlugin::registerObjectPlatformSections(
827 jitlink::LinkGraph
&G
, JITDylib
&JD
) {
828 COFFObjectSectionsMap ObjSecs
;
829 auto HeaderAddr
= CP
.JITDylibToHeaderAddr
[&JD
];
830 assert(HeaderAddr
&& "Must be registered jitdylib");
831 for (auto &S
: G
.sections()) {
832 jitlink::SectionRange
Range(S
);
834 ObjSecs
.push_back(std::make_pair(S
.getName().str(), Range
.getRange()));
837 G
.allocActions().push_back(
838 {cantFail(WrapperFunctionCall::Create
<SPSCOFFRegisterObjectSectionsArgs
>(
839 CP
.orc_rt_coff_register_object_sections
, HeaderAddr
, ObjSecs
, true)),
841 WrapperFunctionCall::Create
<SPSCOFFDeregisterObjectSectionsArgs
>(
842 CP
.orc_rt_coff_deregister_object_sections
, HeaderAddr
,
845 return Error::success();
848 Error
COFFPlatform::COFFPlatformPlugin::preserveInitializerSections(
849 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
851 if (const auto &InitSymName
= MR
.getInitializerSymbol()) {
853 jitlink::Symbol
*InitSym
= nullptr;
855 for (auto &InitSection
: G
.sections()) {
856 // Skip non-init sections.
857 if (!isCOFFInitializerSection(InitSection
.getName()) ||
861 // Create the init symbol if it has not been created already and attach it
862 // to the first block.
864 auto &B
= **InitSection
.blocks().begin();
865 InitSym
= &G
.addDefinedSymbol(
866 B
, 0, *InitSymName
, B
.getSize(), jitlink::Linkage::Strong
,
867 jitlink::Scope::SideEffectsOnly
, false, true);
870 // Add keep-alive edges to anonymous symbols in all other init blocks.
871 for (auto *B
: InitSection
.blocks()) {
872 if (B
== &InitSym
->getBlock())
875 auto &S
= G
.addAnonymousSymbol(*B
, 0, B
->getSize(), false, true);
876 InitSym
->getBlock().addEdge(jitlink::Edge::KeepAlive
, 0, S
, 0);
881 return Error::success();
884 Error
COFFPlatform::COFFPlatformPlugin::
885 registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph
&G
,
887 std::lock_guard
<std::mutex
> Lock(CP
.PlatformMutex
);
888 auto HeaderAddr
= CP
.JITDylibToHeaderAddr
[&JD
];
889 COFFObjectSectionsMap ObjSecs
;
890 for (auto &S
: G
.sections()) {
891 jitlink::SectionRange
Range(S
);
893 ObjSecs
.push_back(std::make_pair(S
.getName().str(), Range
.getRange()));
896 G
.allocActions().push_back(
899 WrapperFunctionCall::Create
<SPSCOFFDeregisterObjectSectionsArgs
>(
900 CP
.orc_rt_coff_deregister_object_sections
, HeaderAddr
,
903 auto &BState
= CP
.JDBootstrapStates
[&JD
];
904 BState
.ObjectSectionsMaps
.push_back(std::move(ObjSecs
));
906 // Collect static initializers
907 for (auto &S
: G
.sections())
908 if (isCOFFInitializerSection(S
.getName()))
909 for (auto *B
: S
.blocks()) {
910 if (B
->edges_empty())
912 for (auto &E
: B
->edges())
913 BState
.Initializers
.push_back(std::make_pair(
914 S
.getName().str(), E
.getTarget().getAddress() + E
.getAddend()));
917 return Error::success();
920 } // End namespace orc.
921 } // End namespace llvm.