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
] = std::move(KV
.second
);
45 // Register dependencies for all symbols contained in this set.
46 auto RegisterDependencies
= [&](const SymbolDependenceMap
&Deps
) {
47 MR
.addDependenciesForAll(Deps
);
50 JITDylibSearchOrder LinkOrder
;
51 MR
.getTargetJITDylib().withLinkOrderDo(
52 [&](const JITDylibSearchOrder
&LO
) { LinkOrder
= LO
; });
53 ES
.lookup(LookupKind::Static
, LinkOrder
, InternedSymbols
,
54 SymbolState::Resolved
, std::move(OnResolvedWithUnwrap
),
55 RegisterDependencies
);
58 Expected
<LookupSet
> getResponsibilitySet(const LookupSet
&Symbols
) override
{
61 for (auto &KV
: MR
.getSymbols()) {
62 if (Symbols
.count(*KV
.first
))
63 Result
.insert(*KV
.first
);
70 MaterializationResponsibility
&MR
;
73 } // end anonymous namespace
78 char RTDyldObjectLinkingLayer::ID
;
80 using BaseT
= RTTIExtends
<RTDyldObjectLinkingLayer
, ObjectLayer
>;
82 RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(
83 ExecutionSession
&ES
, GetMemoryManagerFunction GetMemoryManager
)
84 : BaseT(ES
), GetMemoryManager(GetMemoryManager
) {
85 ES
.registerResourceManager(*this);
88 RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {
89 assert(MemMgrs
.empty() && "Layer destroyed with resources still attached");
92 void RTDyldObjectLinkingLayer::emit(
93 std::unique_ptr
<MaterializationResponsibility
> R
,
94 std::unique_ptr
<MemoryBuffer
> O
) {
95 assert(O
&& "Object must not be null");
97 auto &ES
= getExecutionSession();
99 auto Obj
= object::ObjectFile::createObjectFile(*O
);
102 getExecutionSession().reportError(Obj
.takeError());
103 R
->failMaterialization();
107 // Collect the internal symbols from the object file: We will need to
108 // filter these later.
109 auto InternalSymbols
= std::make_shared
<std::set
<StringRef
>>();
111 for (auto &Sym
: (*Obj
)->symbols()) {
113 // Skip file symbols.
114 if (auto SymType
= Sym
.getType()) {
115 if (*SymType
== object::SymbolRef::ST_File
)
118 ES
.reportError(SymType
.takeError());
119 R
->failMaterialization();
123 Expected
<uint32_t> SymFlagsOrErr
= Sym
.getFlags();
124 if (!SymFlagsOrErr
) {
125 // TODO: Test this error.
126 ES
.reportError(SymFlagsOrErr
.takeError());
127 R
->failMaterialization();
131 // Don't include symbols that aren't global.
132 if (!(*SymFlagsOrErr
& object::BasicSymbolRef::SF_Global
)) {
133 if (auto SymName
= Sym
.getName())
134 InternalSymbols
->insert(*SymName
);
136 ES
.reportError(SymName
.takeError());
137 R
->failMaterialization();
144 auto MemMgr
= GetMemoryManager();
145 auto &MemMgrRef
= *MemMgr
;
147 // Switch to shared ownership of MR so that it can be captured by both
149 std::shared_ptr
<MaterializationResponsibility
> SharedR(std::move(R
));
151 JITDylibSearchOrderResolver
Resolver(*SharedR
);
154 object::OwningBinary
<object::ObjectFile
>(std::move(*Obj
), std::move(O
)),
155 MemMgrRef
, Resolver
, ProcessAllSections
,
156 [this, SharedR
, &MemMgrRef
, InternalSymbols
](
157 const object::ObjectFile
&Obj
,
158 RuntimeDyld::LoadedObjectInfo
&LoadedObjInfo
,
159 std::map
<StringRef
, JITEvaluatedSymbol
> ResolvedSymbols
) {
160 return onObjLoad(*SharedR
, Obj
, MemMgrRef
, LoadedObjInfo
,
161 ResolvedSymbols
, *InternalSymbols
);
163 [this, SharedR
, MemMgr
= std::move(MemMgr
)](
164 object::OwningBinary
<object::ObjectFile
> Obj
,
165 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
> LoadedObjInfo
,
167 onObjEmit(*SharedR
, std::move(Obj
), std::move(MemMgr
),
168 std::move(LoadedObjInfo
), std::move(Err
));
172 void RTDyldObjectLinkingLayer::registerJITEventListener(JITEventListener
&L
) {
173 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
174 assert(!llvm::is_contained(EventListeners
, &L
) &&
175 "Listener has already been registered");
176 EventListeners
.push_back(&L
);
179 void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener
&L
) {
180 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
181 auto I
= llvm::find(EventListeners
, &L
);
182 assert(I
!= EventListeners
.end() && "Listener not registered");
183 EventListeners
.erase(I
);
186 Error
RTDyldObjectLinkingLayer::onObjLoad(
187 MaterializationResponsibility
&R
, const object::ObjectFile
&Obj
,
188 RuntimeDyld::MemoryManager
&MemMgr
,
189 RuntimeDyld::LoadedObjectInfo
&LoadedObjInfo
,
190 std::map
<StringRef
, JITEvaluatedSymbol
> Resolved
,
191 std::set
<StringRef
> &InternalSymbols
) {
192 SymbolFlagsMap ExtraSymbolsToClaim
;
195 // Hack to support COFF constant pool comdats introduced during compilation:
196 // (See http://llvm.org/PR40074)
197 if (auto *COFFObj
= dyn_cast
<object::COFFObjectFile
>(&Obj
)) {
198 auto &ES
= getExecutionSession();
200 // For all resolved symbols that are not already in the responsibilty set:
201 // check whether the symbol is in a comdat section and if so mark it as
203 for (auto &Sym
: COFFObj
->symbols()) {
204 // getFlags() on COFF symbols can't fail.
205 uint32_t SymFlags
= cantFail(Sym
.getFlags());
206 if (SymFlags
& object::BasicSymbolRef::SF_Undefined
)
208 auto Name
= Sym
.getName();
210 return Name
.takeError();
211 auto I
= Resolved
.find(*Name
);
213 // Skip unresolved symbols, internal symbols, and symbols that are
214 // already in the responsibility set.
215 if (I
== Resolved
.end() || InternalSymbols
.count(*Name
) ||
216 R
.getSymbols().count(ES
.intern(*Name
)))
218 auto Sec
= Sym
.getSection();
220 return Sec
.takeError();
221 if (*Sec
== COFFObj
->section_end())
223 auto &COFFSec
= *COFFObj
->getCOFFSection(**Sec
);
224 if (COFFSec
.Characteristics
& COFF::IMAGE_SCN_LNK_COMDAT
)
225 I
->second
.setFlags(I
->second
.getFlags() | JITSymbolFlags::Weak
);
229 for (auto &KV
: Resolved
) {
230 // Scan the symbols and add them to the Symbols map for resolution.
232 // We never claim internal symbols.
233 if (InternalSymbols
.count(KV
.first
))
236 auto InternedName
= getExecutionSession().intern(KV
.first
);
237 auto Flags
= KV
.second
.getFlags();
239 // Override object flags and claim responsibility for symbols if
241 if (OverrideObjectFlags
|| AutoClaimObjectSymbols
) {
242 auto I
= R
.getSymbols().find(InternedName
);
244 if (OverrideObjectFlags
&& I
!= R
.getSymbols().end())
246 else if (AutoClaimObjectSymbols
&& I
== R
.getSymbols().end())
247 ExtraSymbolsToClaim
[InternedName
] = Flags
;
250 Symbols
[InternedName
] = JITEvaluatedSymbol(KV
.second
.getAddress(), Flags
);
253 if (!ExtraSymbolsToClaim
.empty()) {
254 if (auto Err
= R
.defineMaterializing(ExtraSymbolsToClaim
))
257 // If we claimed responsibility for any weak symbols but were rejected then
258 // we need to remove them from the resolved set.
259 for (auto &KV
: ExtraSymbolsToClaim
)
260 if (KV
.second
.isWeak() && !R
.getSymbols().count(KV
.first
))
261 Symbols
.erase(KV
.first
);
264 if (auto Err
= R
.notifyResolved(Symbols
)) {
265 R
.failMaterialization();
270 NotifyLoaded(R
, Obj
, LoadedObjInfo
);
272 return Error::success();
275 void RTDyldObjectLinkingLayer::onObjEmit(
276 MaterializationResponsibility
&R
,
277 object::OwningBinary
<object::ObjectFile
> O
,
278 std::unique_ptr
<RuntimeDyld::MemoryManager
> MemMgr
,
279 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
> LoadedObjInfo
, Error Err
) {
281 getExecutionSession().reportError(std::move(Err
));
282 R
.failMaterialization();
286 if (auto Err
= R
.notifyEmitted()) {
287 getExecutionSession().reportError(std::move(Err
));
288 R
.failMaterialization();
292 std::unique_ptr
<object::ObjectFile
> Obj
;
293 std::unique_ptr
<MemoryBuffer
> ObjBuffer
;
294 std::tie(Obj
, ObjBuffer
) = O
.takeBinary();
296 // Run EventListener notifyLoaded callbacks.
298 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
299 for (auto *L
: EventListeners
)
300 L
->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr
.get()), *Obj
,
305 NotifyEmitted(R
, std::move(ObjBuffer
));
307 if (auto Err
= R
.withResourceKeyDo(
308 [&](ResourceKey K
) { MemMgrs
[K
].push_back(std::move(MemMgr
)); })) {
309 getExecutionSession().reportError(std::move(Err
));
310 R
.failMaterialization();
314 Error
RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K
) {
316 std::vector
<MemoryManagerUP
> MemMgrsToRemove
;
318 getExecutionSession().runSessionLocked([&] {
319 auto I
= MemMgrs
.find(K
);
320 if (I
!= MemMgrs
.end()) {
321 std::swap(MemMgrsToRemove
, I
->second
);
327 std::lock_guard
<std::mutex
> Lock(RTDyldLayerMutex
);
328 for (auto &MemMgr
: MemMgrsToRemove
) {
329 for (auto *L
: EventListeners
)
330 L
->notifyFreeingObject(pointerToJITTargetAddress(MemMgr
.get()));
331 MemMgr
->deregisterEHFrames();
335 return Error::success();
338 void RTDyldObjectLinkingLayer::handleTransferResources(ResourceKey DstKey
,
339 ResourceKey SrcKey
) {
340 auto I
= MemMgrs
.find(SrcKey
);
341 if (I
!= MemMgrs
.end()) {
342 auto &SrcMemMgrs
= I
->second
;
343 auto &DstMemMgrs
= MemMgrs
[DstKey
];
344 DstMemMgrs
.reserve(DstMemMgrs
.size() + SrcMemMgrs
.size());
345 for (auto &MemMgr
: SrcMemMgrs
)
346 DstMemMgrs
.push_back(std::move(MemMgr
));
348 // Erase SrcKey entry using value rather than iterator I: I may have been
349 // invalidated when we looked up DstKey.
350 MemMgrs
.erase(SrcKey
);
354 } // End namespace orc.
355 } // End namespace llvm.