1 //===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking ---*- C++ -*-===//
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 // Contains the definition for an RTDyld-based, in-process object linking layer.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
14 #define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ExecutionEngine/JITSymbol.h"
20 #include "llvm/ExecutionEngine/Orc/Core.h"
21 #include "llvm/ExecutionEngine/Orc/Layer.h"
22 #include "llvm/ExecutionEngine/Orc/Legacy.h"
23 #include "llvm/ExecutionEngine/RuntimeDyld.h"
24 #include "llvm/Object/ObjectFile.h"
25 #include "llvm/Support/Error.h"
38 class RTDyldObjectLinkingLayer
: public ObjectLayer
{
40 /// Functor for receiving object-loaded notifications.
41 using NotifyLoadedFunction
=
42 std::function
<void(VModuleKey
, const object::ObjectFile
&Obj
,
43 const RuntimeDyld::LoadedObjectInfo
&)>;
45 /// Functor for receiving finalization notifications.
46 using NotifyEmittedFunction
=
47 std::function
<void(VModuleKey
, std::unique_ptr
<MemoryBuffer
>)>;
49 using GetMemoryManagerFunction
=
50 std::function
<std::unique_ptr
<RuntimeDyld::MemoryManager
>()>;
52 /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
53 /// and NotifyEmitted functors.
54 RTDyldObjectLinkingLayer(ExecutionSession
&ES
,
55 GetMemoryManagerFunction GetMemoryManager
);
58 void emit(MaterializationResponsibility R
,
59 std::unique_ptr
<MemoryBuffer
> O
) override
;
61 /// Set the NotifyLoaded callback.
62 RTDyldObjectLinkingLayer
&setNotifyLoaded(NotifyLoadedFunction NotifyLoaded
) {
63 this->NotifyLoaded
= std::move(NotifyLoaded
);
67 /// Set the NotifyEmitted callback.
68 RTDyldObjectLinkingLayer
&
69 setNotifyEmitted(NotifyEmittedFunction NotifyEmitted
) {
70 this->NotifyEmitted
= std::move(NotifyEmitted
);
74 /// Set the 'ProcessAllSections' flag.
76 /// If set to true, all sections in each object file will be allocated using
77 /// the memory manager, rather than just the sections required for execution.
79 /// This is kludgy, and may be removed in the future.
80 RTDyldObjectLinkingLayer
&setProcessAllSections(bool ProcessAllSections
) {
81 this->ProcessAllSections
= ProcessAllSections
;
85 /// Instructs this RTDyldLinkingLayer2 instance to override the symbol flags
86 /// returned by RuntimeDyld for any given object file with the flags supplied
87 /// by the MaterializationResponsibility instance. This is a workaround to
88 /// support symbol visibility in COFF, which does not use the libObject's
89 /// SF_Exported flag. Use only when generating / adding COFF object files.
91 /// FIXME: We should be able to remove this if/when COFF properly tracks
93 RTDyldObjectLinkingLayer
&
94 setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags
) {
95 this->OverrideObjectFlags
= OverrideObjectFlags
;
99 /// If set, this RTDyldObjectLinkingLayer instance will claim responsibility
100 /// for any symbols provided by a given object file that were not already in
101 /// the MaterializationResponsibility instance. Setting this flag allows
102 /// higher-level program representations (e.g. LLVM IR) to be added based on
103 /// only a subset of the symbols they provide, without having to write
104 /// intervening layers to scan and add the additional symbols. This trades
105 /// diagnostic quality for convenience however: If all symbols are enumerated
106 /// up-front then clashes can be detected and reported early (and usually
107 /// deterministically). If this option is set, clashes for the additional
108 /// symbols may not be detected until late, and detection may depend on
109 /// the flow of control through JIT'd code. Use with care.
110 RTDyldObjectLinkingLayer
&
111 setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols
) {
112 this->AutoClaimObjectSymbols
= AutoClaimObjectSymbols
;
117 Error
onObjLoad(VModuleKey K
, MaterializationResponsibility
&R
,
118 object::ObjectFile
&Obj
,
119 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
> LoadedObjInfo
,
120 std::map
<StringRef
, JITEvaluatedSymbol
> Resolved
,
121 std::set
<StringRef
> &InternalSymbols
);
123 void onObjEmit(VModuleKey K
, std::unique_ptr
<MemoryBuffer
> ObjBuffer
,
124 MaterializationResponsibility
&R
, Error Err
);
126 mutable std::mutex RTDyldLayerMutex
;
127 GetMemoryManagerFunction GetMemoryManager
;
128 NotifyLoadedFunction NotifyLoaded
;
129 NotifyEmittedFunction NotifyEmitted
;
130 bool ProcessAllSections
= false;
131 bool OverrideObjectFlags
= false;
132 bool AutoClaimObjectSymbols
= false;
133 std::vector
<std::unique_ptr
<RuntimeDyld::MemoryManager
>> MemMgrs
;
136 class LegacyRTDyldObjectLinkingLayerBase
{
138 using ObjectPtr
= std::unique_ptr
<MemoryBuffer
>;
142 /// Holds an object to be allocated/linked as a unit in the JIT.
144 /// An instance of this class will be created for each object added
145 /// via JITObjectLayer::addObject. Deleting the instance (via
146 /// removeObject) frees its memory, removing all symbol definitions that
147 /// had been provided by this instance. Higher level layers are responsible
148 /// for taking any action required to handle the missing symbols.
151 LinkedObject() = default;
152 LinkedObject(const LinkedObject
&) = delete;
153 void operator=(const LinkedObject
&) = delete;
154 virtual ~LinkedObject() = default;
156 virtual Error
finalize() = 0;
158 virtual JITSymbol::GetAddressFtor
159 getSymbolMaterializer(std::string Name
) = 0;
161 virtual void mapSectionAddress(const void *LocalAddress
,
162 JITTargetAddress TargetAddr
) const = 0;
164 JITSymbol
getSymbol(StringRef Name
, bool ExportedSymbolsOnly
) {
165 auto SymEntry
= SymbolTable
.find(Name
);
166 if (SymEntry
== SymbolTable
.end())
168 if (!SymEntry
->second
.getFlags().isExported() && ExportedSymbolsOnly
)
171 return JITSymbol(getSymbolMaterializer(Name
),
172 SymEntry
->second
.getFlags());
173 return JITSymbol(SymEntry
->second
);
177 StringMap
<JITEvaluatedSymbol
> SymbolTable
;
178 bool Finalized
= false;
182 /// Bare bones object linking layer.
184 /// This class is intended to be used as the base layer for a JIT. It allows
185 /// object files to be loaded into memory, linked, and the addresses of their
186 /// symbols queried. All objects added to this layer can see each other's
188 class LegacyRTDyldObjectLinkingLayer
: public LegacyRTDyldObjectLinkingLayerBase
{
191 using LegacyRTDyldObjectLinkingLayerBase::ObjectPtr
;
193 /// Functor for receiving object-loaded notifications.
194 using NotifyLoadedFtor
=
195 std::function
<void(VModuleKey
, const object::ObjectFile
&Obj
,
196 const RuntimeDyld::LoadedObjectInfo
&)>;
198 /// Functor for receiving finalization notifications.
199 using NotifyFinalizedFtor
=
200 std::function
<void(VModuleKey
, const object::ObjectFile
&Obj
,
201 const RuntimeDyld::LoadedObjectInfo
&)>;
203 /// Functor for receiving deallocation notifications.
204 using NotifyFreedFtor
= std::function
<void(VModuleKey
, const object::ObjectFile
&Obj
)>;
207 using OwnedObject
= object::OwningBinary
<object::ObjectFile
>;
209 template <typename MemoryManagerPtrT
>
210 class ConcreteLinkedObject
: public LinkedObject
{
212 ConcreteLinkedObject(LegacyRTDyldObjectLinkingLayer
&Parent
, VModuleKey K
,
213 OwnedObject Obj
, MemoryManagerPtrT MemMgr
,
214 std::shared_ptr
<SymbolResolver
> Resolver
,
215 bool ProcessAllSections
)
218 MemMgr(std::move(MemMgr
)),
219 PFC(std::make_unique
<PreFinalizeContents
>(
220 std::move(Obj
), std::move(Resolver
),
221 ProcessAllSections
)) {
222 buildInitialSymbolTable(PFC
->Obj
);
225 ~ConcreteLinkedObject() override
{
226 if (this->Parent
.NotifyFreed
&& ObjForNotify
.getBinary())
227 this->Parent
.NotifyFreed(K
, *ObjForNotify
.getBinary());
229 MemMgr
->deregisterEHFrames();
232 Error
finalize() override
{
233 assert(PFC
&& "mapSectionAddress called on finalized LinkedObject");
235 JITSymbolResolverAdapter
ResolverAdapter(Parent
.ES
, *PFC
->Resolver
,
237 PFC
->RTDyld
= std::make_unique
<RuntimeDyld
>(*MemMgr
, ResolverAdapter
);
238 PFC
->RTDyld
->setProcessAllSections(PFC
->ProcessAllSections
);
242 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
> Info
=
243 PFC
->RTDyld
->loadObject(*PFC
->Obj
.getBinary());
245 // Copy the symbol table out of the RuntimeDyld instance.
247 auto SymTab
= PFC
->RTDyld
->getSymbolTable();
248 for (auto &KV
: SymTab
)
249 SymbolTable
[KV
.first
] = KV
.second
;
252 if (Parent
.NotifyLoaded
)
253 Parent
.NotifyLoaded(K
, *PFC
->Obj
.getBinary(), *Info
);
255 PFC
->RTDyld
->finalizeWithMemoryManagerLocking();
257 if (PFC
->RTDyld
->hasError())
258 return make_error
<StringError
>(PFC
->RTDyld
->getErrorString(),
259 inconvertibleErrorCode());
261 if (Parent
.NotifyFinalized
)
262 Parent
.NotifyFinalized(K
, *PFC
->Obj
.getBinary(), *Info
);
264 // Release resources.
265 if (this->Parent
.NotifyFreed
)
266 ObjForNotify
= std::move(PFC
->Obj
); // needed for callback
268 return Error::success();
271 JITSymbol::GetAddressFtor
getSymbolMaterializer(std::string Name
) override
{
272 return [this, Name
]() -> Expected
<JITTargetAddress
> {
273 // The symbol may be materialized between the creation of this lambda
274 // and its execution, so we need to double check.
275 if (!this->Finalized
)
276 if (auto Err
= this->finalize())
277 return std::move(Err
);
278 return this->getSymbol(Name
, false).getAddress();
282 void mapSectionAddress(const void *LocalAddress
,
283 JITTargetAddress TargetAddr
) const override
{
284 assert(PFC
&& "mapSectionAddress called on finalized LinkedObject");
285 assert(PFC
->RTDyld
&& "mapSectionAddress called on raw LinkedObject");
286 PFC
->RTDyld
->mapSectionAddress(LocalAddress
, TargetAddr
);
290 void buildInitialSymbolTable(const OwnedObject
&Obj
) {
291 for (auto &Symbol
: Obj
.getBinary()->symbols()) {
292 if (Symbol
.getFlags() & object::SymbolRef::SF_Undefined
)
294 Expected
<StringRef
> SymbolName
= Symbol
.getName();
295 // FIXME: Raise an error for bad symbols.
297 consumeError(SymbolName
.takeError());
300 // FIXME: Raise an error for bad symbols.
301 auto Flags
= JITSymbolFlags::fromObjectSymbol(Symbol
);
303 consumeError(Flags
.takeError());
307 std::make_pair(*SymbolName
, JITEvaluatedSymbol(0, *Flags
)));
311 // Contains the information needed prior to finalization: the object files,
312 // memory manager, resolver, and flags needed for RuntimeDyld.
313 struct PreFinalizeContents
{
314 PreFinalizeContents(OwnedObject Obj
,
315 std::shared_ptr
<SymbolResolver
> Resolver
,
316 bool ProcessAllSections
)
317 : Obj(std::move(Obj
)),
318 Resolver(std::move(Resolver
)),
319 ProcessAllSections(ProcessAllSections
) {}
322 std::shared_ptr
<SymbolResolver
> Resolver
;
323 bool ProcessAllSections
;
324 std::unique_ptr
<RuntimeDyld
> RTDyld
;
328 LegacyRTDyldObjectLinkingLayer
&Parent
;
329 MemoryManagerPtrT MemMgr
;
330 OwnedObject ObjForNotify
;
331 std::unique_ptr
<PreFinalizeContents
> PFC
;
334 template <typename MemoryManagerPtrT
>
335 std::unique_ptr
<ConcreteLinkedObject
<MemoryManagerPtrT
>>
336 createLinkedObject(LegacyRTDyldObjectLinkingLayer
&Parent
, VModuleKey K
,
337 OwnedObject Obj
, MemoryManagerPtrT MemMgr
,
338 std::shared_ptr
<SymbolResolver
> Resolver
,
339 bool ProcessAllSections
) {
340 using LOS
= ConcreteLinkedObject
<MemoryManagerPtrT
>;
341 return std::make_unique
<LOS
>(Parent
, std::move(K
), std::move(Obj
),
342 std::move(MemMgr
), std::move(Resolver
),
348 std::shared_ptr
<RuntimeDyld::MemoryManager
> MemMgr
;
349 std::shared_ptr
<SymbolResolver
> Resolver
;
352 using ResourcesGetter
= std::function
<Resources(VModuleKey
)>;
354 /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
355 /// and NotifyFinalized functors.
356 LLVM_ATTRIBUTE_DEPRECATED(
357 LegacyRTDyldObjectLinkingLayer(
358 ExecutionSession
&ES
, ResourcesGetter GetResources
,
359 NotifyLoadedFtor NotifyLoaded
= NotifyLoadedFtor(),
360 NotifyFinalizedFtor NotifyFinalized
= NotifyFinalizedFtor(),
361 NotifyFreedFtor NotifyFreed
= NotifyFreedFtor()),
362 "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
364 "ORCv2 (see docs/ORCv2.rst)");
366 // Legacy layer constructor with deprecation acknowledgement.
367 LegacyRTDyldObjectLinkingLayer(
368 ORCv1DeprecationAcknowledgement
, ExecutionSession
&ES
,
369 ResourcesGetter GetResources
,
370 NotifyLoadedFtor NotifyLoaded
= NotifyLoadedFtor(),
371 NotifyFinalizedFtor NotifyFinalized
= NotifyFinalizedFtor(),
372 NotifyFreedFtor NotifyFreed
= NotifyFreedFtor())
373 : ES(ES
), GetResources(std::move(GetResources
)),
374 NotifyLoaded(std::move(NotifyLoaded
)),
375 NotifyFinalized(std::move(NotifyFinalized
)),
376 NotifyFreed(std::move(NotifyFreed
)), ProcessAllSections(false) {}
378 /// Set the 'ProcessAllSections' flag.
380 /// If set to true, all sections in each object file will be allocated using
381 /// the memory manager, rather than just the sections required for execution.
383 /// This is kludgy, and may be removed in the future.
384 void setProcessAllSections(bool ProcessAllSections
) {
385 this->ProcessAllSections
= ProcessAllSections
;
388 /// Add an object to the JIT.
389 Error
addObject(VModuleKey K
, ObjectPtr ObjBuffer
) {
392 object::ObjectFile::createObjectFile(ObjBuffer
->getMemBufferRef());
394 return Obj
.takeError();
396 assert(!LinkedObjects
.count(K
) && "VModuleKey already in use");
398 auto R
= GetResources(K
);
400 LinkedObjects
[K
] = createLinkedObject(
401 *this, K
, OwnedObject(std::move(*Obj
), std::move(ObjBuffer
)),
402 std::move(R
.MemMgr
), std::move(R
.Resolver
), ProcessAllSections
);
404 return Error::success();
407 /// Remove the object associated with VModuleKey K.
409 /// All memory allocated for the object will be freed, and the sections and
410 /// symbols it provided will no longer be available. No attempt is made to
411 /// re-emit the missing symbols, and any use of these symbols (directly or
412 /// indirectly) will result in undefined behavior. If dependence tracking is
413 /// required to detect or resolve such issues it should be added at a higher
415 Error
removeObject(VModuleKey K
) {
416 assert(LinkedObjects
.count(K
) && "VModuleKey not associated with object");
417 // How do we invalidate the symbols in H?
418 LinkedObjects
.erase(K
);
419 return Error::success();
422 /// Search for the given named symbol.
423 /// @param Name The name of the symbol to search for.
424 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
425 /// @return A handle for the given named symbol, if it exists.
426 JITSymbol
findSymbol(StringRef Name
, bool ExportedSymbolsOnly
) {
427 for (auto &KV
: LinkedObjects
)
428 if (auto Sym
= KV
.second
->getSymbol(Name
, ExportedSymbolsOnly
))
430 else if (auto Err
= Sym
.takeError())
431 return std::move(Err
);
436 /// Search for the given named symbol in the context of the loaded
437 /// object represented by the VModuleKey K.
438 /// @param K The VModuleKey for the object to search in.
439 /// @param Name The name of the symbol to search for.
440 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
441 /// @return A handle for the given named symbol, if it is found in the
443 JITSymbol
findSymbolIn(VModuleKey K
, StringRef Name
,
444 bool ExportedSymbolsOnly
) {
445 assert(LinkedObjects
.count(K
) && "VModuleKey not associated with object");
446 return LinkedObjects
[K
]->getSymbol(Name
, ExportedSymbolsOnly
);
449 /// Map section addresses for the object associated with the
451 void mapSectionAddress(VModuleKey K
, const void *LocalAddress
,
452 JITTargetAddress TargetAddr
) {
453 assert(LinkedObjects
.count(K
) && "VModuleKey not associated with object");
454 LinkedObjects
[K
]->mapSectionAddress(LocalAddress
, TargetAddr
);
457 /// Immediately emit and finalize the object represented by the given
459 /// @param K VModuleKey for object to emit/finalize.
460 Error
emitAndFinalize(VModuleKey K
) {
461 assert(LinkedObjects
.count(K
) && "VModuleKey not associated with object");
462 return LinkedObjects
[K
]->finalize();
466 ExecutionSession
&ES
;
468 ResourcesGetter GetResources
;
469 NotifyLoadedFtor NotifyLoaded
;
470 NotifyFinalizedFtor NotifyFinalized
;
471 NotifyFreedFtor NotifyFreed
;
473 // NB! `LinkedObjects` needs to be destroyed before `NotifyFreed` because
474 // `~ConcreteLinkedObject` calls `NotifyFreed`
475 std::map
<VModuleKey
, std::unique_ptr
<LinkedObject
>> LinkedObjects
;
476 bool ProcessAllSections
= false;
479 } // end namespace orc
480 } // end namespace llvm
482 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H