1 //===-- RTDyldObjectLinkingLayer.cpp - RuntimeDyld backed ORC ObjectLayer -===//
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/RTDyldObjectLinkingLayer.h"
10 #include "llvm/Object/COFF.h"
15 using namespace llvm::orc
;
17 class JITDylibSearchOrderResolver
: public JITSymbolResolver
{
19 JITDylibSearchOrderResolver(MaterializationResponsibility
&MR
) : MR(MR
) {}
21 void lookup(const LookupSet
&Symbols
, OnResolvedFunction OnResolved
) override
{
22 auto &ES
= MR
.getTargetJITDylib().getExecutionSession();
23 SymbolLookupSet InternedSymbols
;
25 // Intern the requested symbols: lookup takes interned strings.
26 for (auto &S
: Symbols
)
27 InternedSymbols
.add(ES
.intern(S
));
29 // Build an OnResolve callback to unwrap the interned strings and pass them
30 // to the OnResolved callback.
31 auto OnResolvedWithUnwrap
=
32 [OnResolved
= std::move(OnResolved
)](
33 Expected
<SymbolMap
> InternedResult
) mutable {
34 if (!InternedResult
) {
35 OnResolved(InternedResult
.takeError());
40 for (auto &KV
: *InternedResult
)
41 Result
[*KV
.first
] = {KV
.second
.getAddress().getValue(),
42 KV
.second
.getFlags()};
46 // Register dependencies for all symbols contained in this set.
47 auto RegisterDependencies
= [&](const SymbolDependenceMap
&Deps
) {
48 MR
.addDependenciesForAll(Deps
);
51 JITDylibSearchOrder LinkOrder
;
52 MR
.getTargetJITDylib().withLinkOrderDo(
53 [&](const JITDylibSearchOrder
&LO
) { LinkOrder
= LO
; });
54 ES
.lookup(LookupKind::Static
, LinkOrder
, InternedSymbols
,
55 SymbolState::Resolved
, std::move(OnResolvedWithUnwrap
),
56 RegisterDependencies
);
59 Expected
<LookupSet
> getResponsibilitySet(const LookupSet
&Symbols
) override
{
62 for (auto &KV
: MR
.getSymbols()) {
63 if (Symbols
.count(*KV
.first
))
64 Result
.insert(*KV
.first
);
71 MaterializationResponsibility
&MR
;
74 } // end anonymous namespace
79 char RTDyldObjectLinkingLayer::ID
;
81 using BaseT
= RTTIExtends
<RTDyldObjectLinkingLayer
, ObjectLayer
>;
83 RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(
84 ExecutionSession
&ES
, GetMemoryManagerFunction GetMemoryManager
)
85 : BaseT(ES
), GetMemoryManager(std::move(GetMemoryManager
)) {
86 ES
.registerResourceManager(*this);
89 RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {
90 assert(MemMgrs
.empty() && "Layer destroyed with resources still attached");
93 void RTDyldObjectLinkingLayer::emit(
94 std::unique_ptr
<MaterializationResponsibility
> R
,
95 std::unique_ptr
<MemoryBuffer
> O
) {
96 assert(O
&& "Object must not be null");
98 auto &ES
= getExecutionSession();
100 auto Obj
= object::ObjectFile::createObjectFile(*O
);
103 getExecutionSession().reportError(Obj
.takeError());
104 R
->failMaterialization();
108 // Collect the internal symbols from the object file: We will need to
109 // filter these later.
110 auto InternalSymbols
= std::make_shared
<std::set
<StringRef
>>();
112 SymbolFlagsMap ExtraSymbolsToClaim
;
113 for (auto &Sym
: (*Obj
)->symbols()) {
115 // Skip file symbols.
116 if (auto SymType
= Sym
.getType()) {
117 if (*SymType
== object::SymbolRef::ST_File
)
120 ES
.reportError(SymType
.takeError());
121 R
->failMaterialization();
125 Expected
<uint32_t> SymFlagsOrErr
= Sym
.getFlags();
126 if (!SymFlagsOrErr
) {
127 // TODO: Test this error.
128 ES
.reportError(SymFlagsOrErr
.takeError());
129 R
->failMaterialization();
133 // Try to claim responsibility of weak symbols
134 // if AutoClaimObjectSymbols flag is set.
135 if (AutoClaimObjectSymbols
&&
136 (*SymFlagsOrErr
& object::BasicSymbolRef::SF_Weak
)) {
137 auto SymName
= Sym
.getName();
139 ES
.reportError(SymName
.takeError());
140 R
->failMaterialization();
144 // Already included in responsibility set, skip it
145 SymbolStringPtr SymbolName
= ES
.intern(*SymName
);
146 if (R
->getSymbols().count(SymbolName
))
149 auto SymFlags
= JITSymbolFlags::fromObjectSymbol(Sym
);
151 ES
.reportError(SymFlags
.takeError());
152 R
->failMaterialization();
156 ExtraSymbolsToClaim
[SymbolName
] = *SymFlags
;
160 // Don't include symbols that aren't global.
161 if (!(*SymFlagsOrErr
& object::BasicSymbolRef::SF_Global
)) {
162 if (auto SymName
= Sym
.getName())
163 InternalSymbols
->insert(*SymName
);
165 ES
.reportError(SymName
.takeError());
166 R
->failMaterialization();
172 if (!ExtraSymbolsToClaim
.empty()) {
173 if (auto Err
= R
->defineMaterializing(ExtraSymbolsToClaim
)) {
174 ES
.reportError(std::move(Err
));
175 R
->failMaterialization();
180 auto MemMgr
= GetMemoryManager();
181 auto &MemMgrRef
= *MemMgr
;
183 // Switch to shared ownership of MR so that it can be captured by both
185 std::shared_ptr
<MaterializationResponsibility
> SharedR(std::move(R
));
187 JITDylibSearchOrderResolver
Resolver(*SharedR
);
190 object::OwningBinary
<object::ObjectFile
>(std::move(*Obj
), std::move(O
)),
191 MemMgrRef
, Resolver
, ProcessAllSections
,
192 [this, SharedR
, &MemMgrRef
, InternalSymbols
](
193 const object::ObjectFile
&Obj
,
194 RuntimeDyld::LoadedObjectInfo
&LoadedObjInfo
,
195 std::map
<StringRef
, JITEvaluatedSymbol
> ResolvedSymbols
) {
196 return onObjLoad(*SharedR
, Obj
, MemMgrRef
, LoadedObjInfo
,
197 ResolvedSymbols
, *InternalSymbols
);
199 [this, SharedR
, MemMgr
= std::move(MemMgr
)](
200 object::OwningBinary
<object::ObjectFile
> Obj
,
201 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
> LoadedObjInfo
,
203 onObjEmit(*SharedR
, std::move(Obj
), std::move(MemMgr
),
204 std::move(LoadedObjInfo
), std::move(Err
));
208 void RTDyldObjectLinkingLayer::registerJITEventListener(JITEventListener
&L
) {
209 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
210 assert(!llvm::is_contained(EventListeners
, &L
) &&
211 "Listener has already been registered");
212 EventListeners
.push_back(&L
);
215 void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener
&L
) {
216 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
217 auto I
= llvm::find(EventListeners
, &L
);
218 assert(I
!= EventListeners
.end() && "Listener not registered");
219 EventListeners
.erase(I
);
222 Error
RTDyldObjectLinkingLayer::onObjLoad(
223 MaterializationResponsibility
&R
, const object::ObjectFile
&Obj
,
224 RuntimeDyld::MemoryManager
&MemMgr
,
225 RuntimeDyld::LoadedObjectInfo
&LoadedObjInfo
,
226 std::map
<StringRef
, JITEvaluatedSymbol
> Resolved
,
227 std::set
<StringRef
> &InternalSymbols
) {
228 SymbolFlagsMap ExtraSymbolsToClaim
;
231 // Hack to support COFF constant pool comdats introduced during compilation:
232 // (See http://llvm.org/PR40074)
233 if (auto *COFFObj
= dyn_cast
<object::COFFObjectFile
>(&Obj
)) {
234 auto &ES
= getExecutionSession();
236 // For all resolved symbols that are not already in the responsibility set:
237 // check whether the symbol is in a comdat section and if so mark it as
239 for (auto &Sym
: COFFObj
->symbols()) {
240 // getFlags() on COFF symbols can't fail.
241 uint32_t SymFlags
= cantFail(Sym
.getFlags());
242 if (SymFlags
& object::BasicSymbolRef::SF_Undefined
)
244 auto Name
= Sym
.getName();
246 return Name
.takeError();
247 auto I
= Resolved
.find(*Name
);
249 // Skip unresolved symbols, internal symbols, and symbols that are
250 // already in the responsibility set.
251 if (I
== Resolved
.end() || InternalSymbols
.count(*Name
) ||
252 R
.getSymbols().count(ES
.intern(*Name
)))
254 auto Sec
= Sym
.getSection();
256 return Sec
.takeError();
257 if (*Sec
== COFFObj
->section_end())
259 auto &COFFSec
= *COFFObj
->getCOFFSection(**Sec
);
260 if (COFFSec
.Characteristics
& COFF::IMAGE_SCN_LNK_COMDAT
)
261 I
->second
.setFlags(I
->second
.getFlags() | JITSymbolFlags::Weak
);
264 // Handle any aliases.
265 for (auto &Sym
: COFFObj
->symbols()) {
266 uint32_t SymFlags
= cantFail(Sym
.getFlags());
267 if (SymFlags
& object::BasicSymbolRef::SF_Undefined
)
269 auto Name
= Sym
.getName();
271 return Name
.takeError();
272 auto I
= Resolved
.find(*Name
);
274 // Skip already-resolved symbols, and symbols that we're not responsible
276 if (I
!= Resolved
.end() || !R
.getSymbols().count(ES
.intern(*Name
)))
279 // Skip anything other than weak externals.
280 auto COFFSym
= COFFObj
->getCOFFSymbol(Sym
);
281 if (!COFFSym
.isWeakExternal())
283 auto *WeakExternal
= COFFSym
.getAux
<object::coff_aux_weak_external
>();
284 if (WeakExternal
->Characteristics
!= COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
)
287 // We found an alias. Reuse the resolution of the alias target for the
289 Expected
<object::COFFSymbolRef
> TargetSymbol
=
290 COFFObj
->getSymbol(WeakExternal
->TagIndex
);
292 return TargetSymbol
.takeError();
293 Expected
<StringRef
> TargetName
= COFFObj
->getSymbolName(*TargetSymbol
);
295 return TargetName
.takeError();
296 auto J
= Resolved
.find(*TargetName
);
297 if (J
== Resolved
.end())
298 return make_error
<StringError
>("Could alias target " + *TargetName
+
300 inconvertibleErrorCode());
301 Resolved
[*Name
] = J
->second
;
305 for (auto &KV
: Resolved
) {
306 // Scan the symbols and add them to the Symbols map for resolution.
308 // We never claim internal symbols.
309 if (InternalSymbols
.count(KV
.first
))
312 auto InternedName
= getExecutionSession().intern(KV
.first
);
313 auto Flags
= KV
.second
.getFlags();
314 auto I
= R
.getSymbols().find(InternedName
);
315 if (I
!= R
.getSymbols().end()) {
316 // Override object flags and claim responsibility for symbols if
318 if (OverrideObjectFlags
)
321 // RuntimeDyld/MCJIT's weak tracking isn't compatible with ORC's. Even
322 // if we're not overriding flags in general we should set the weak flag
323 // according to the MaterializationResponsibility object symbol table.
324 if (I
->second
.isWeak())
325 Flags
|= JITSymbolFlags::Weak
;
327 } else if (AutoClaimObjectSymbols
)
328 ExtraSymbolsToClaim
[InternedName
] = Flags
;
330 Symbols
[InternedName
] = {ExecutorAddr(KV
.second
.getAddress()), Flags
};
333 if (!ExtraSymbolsToClaim
.empty()) {
334 if (auto Err
= R
.defineMaterializing(ExtraSymbolsToClaim
))
337 // If we claimed responsibility for any weak symbols but were rejected then
338 // we need to remove them from the resolved set.
339 for (auto &KV
: ExtraSymbolsToClaim
)
340 if (KV
.second
.isWeak() && !R
.getSymbols().count(KV
.first
))
341 Symbols
.erase(KV
.first
);
344 if (auto Err
= R
.notifyResolved(Symbols
)) {
345 R
.failMaterialization();
350 NotifyLoaded(R
, Obj
, LoadedObjInfo
);
352 return Error::success();
355 void RTDyldObjectLinkingLayer::onObjEmit(
356 MaterializationResponsibility
&R
,
357 object::OwningBinary
<object::ObjectFile
> O
,
358 std::unique_ptr
<RuntimeDyld::MemoryManager
> MemMgr
,
359 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
> LoadedObjInfo
, Error Err
) {
361 getExecutionSession().reportError(std::move(Err
));
362 R
.failMaterialization();
366 if (auto Err
= R
.notifyEmitted()) {
367 getExecutionSession().reportError(std::move(Err
));
368 R
.failMaterialization();
372 std::unique_ptr
<object::ObjectFile
> Obj
;
373 std::unique_ptr
<MemoryBuffer
> ObjBuffer
;
374 std::tie(Obj
, ObjBuffer
) = O
.takeBinary();
376 // Run EventListener notifyLoaded callbacks.
378 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
379 for (auto *L
: EventListeners
)
380 L
->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr
.get()), *Obj
,
385 NotifyEmitted(R
, std::move(ObjBuffer
));
387 if (auto Err
= R
.withResourceKeyDo(
388 [&](ResourceKey K
) { MemMgrs
[K
].push_back(std::move(MemMgr
)); })) {
389 getExecutionSession().reportError(std::move(Err
));
390 R
.failMaterialization();
394 Error
RTDyldObjectLinkingLayer::handleRemoveResources(JITDylib
&JD
,
397 std::vector
<MemoryManagerUP
> MemMgrsToRemove
;
399 getExecutionSession().runSessionLocked([&] {
400 auto I
= MemMgrs
.find(K
);
401 if (I
!= MemMgrs
.end()) {
402 std::swap(MemMgrsToRemove
, I
->second
);
408 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
409 for (auto &MemMgr
: MemMgrsToRemove
) {
410 for (auto *L
: EventListeners
)
411 L
->notifyFreeingObject(pointerToJITTargetAddress(MemMgr
.get()));
412 MemMgr
->deregisterEHFrames();
416 return Error::success();
419 void RTDyldObjectLinkingLayer::handleTransferResources(JITDylib
&JD
,
421 ResourceKey SrcKey
) {
422 auto I
= MemMgrs
.find(SrcKey
);
423 if (I
!= MemMgrs
.end()) {
424 auto &SrcMemMgrs
= I
->second
;
425 auto &DstMemMgrs
= MemMgrs
[DstKey
];
426 DstMemMgrs
.reserve(DstMemMgrs
.size() + SrcMemMgrs
.size());
427 for (auto &MemMgr
: SrcMemMgrs
)
428 DstMemMgrs
.push_back(std::move(MemMgr
));
430 // Erase SrcKey entry using value rather than iterator I: I may have been
431 // invalidated when we looked up DstKey.
432 MemMgrs
.erase(SrcKey
);
436 } // End namespace orc.
437 } // End namespace llvm.