1 | //===-- RTDyldObjectLinkingLayer.cpp - RuntimeDyld backed ORC ObjectLayer -===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" |
10 | #include "llvm/Object/COFF.h" |
11 | |
12 | namespace { |
13 | |
14 | using namespace llvm; |
15 | using namespace llvm::orc; |
16 | |
17 | class JITDylibSearchOrderResolver : public JITSymbolResolver { |
18 | public: |
19 | JITDylibSearchOrderResolver(MaterializationResponsibility &MR, |
20 | SymbolDependenceMap &Deps) |
21 | : MR(MR), Deps(Deps) {} |
22 | |
23 | void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override { |
24 | auto &ES = MR.getTargetJITDylib().getExecutionSession(); |
25 | SymbolLookupSet InternedSymbols; |
26 | |
27 | // Intern the requested symbols: lookup takes interned strings. |
28 | for (auto &S : Symbols) |
29 | InternedSymbols.add(Name: ES.intern(SymName: S)); |
30 | |
31 | // Build an OnResolve callback to unwrap the interned strings and pass them |
32 | // to the OnResolved callback. |
33 | auto OnResolvedWithUnwrap = |
34 | [OnResolved = std::move(OnResolved)]( |
35 | Expected<SymbolMap> InternedResult) mutable { |
36 | if (!InternedResult) { |
37 | OnResolved(InternedResult.takeError()); |
38 | return; |
39 | } |
40 | |
41 | LookupResult Result; |
42 | for (auto &KV : *InternedResult) |
43 | Result[*KV.first] = {KV.second.getAddress().getValue(), |
44 | KV.second.getFlags()}; |
45 | OnResolved(Result); |
46 | }; |
47 | |
48 | JITDylibSearchOrder LinkOrder; |
49 | MR.getTargetJITDylib().withLinkOrderDo( |
50 | F: [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; }); |
51 | ES.lookup( |
52 | K: LookupKind::Static, SearchOrder: LinkOrder, Symbols: InternedSymbols, RequiredState: SymbolState::Resolved, |
53 | NotifyComplete: std::move(OnResolvedWithUnwrap), |
54 | RegisterDependencies: [this](const SymbolDependenceMap &LookupDeps) { Deps = LookupDeps; }); |
55 | } |
56 | |
57 | Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override { |
58 | LookupSet Result; |
59 | |
60 | for (auto &KV : MR.getSymbols()) { |
61 | if (Symbols.count(x: *KV.first)) |
62 | Result.insert(x: *KV.first); |
63 | } |
64 | |
65 | return Result; |
66 | } |
67 | |
68 | private: |
69 | MaterializationResponsibility &MR; |
70 | SymbolDependenceMap &Deps; |
71 | }; |
72 | |
73 | } // end anonymous namespace |
74 | |
75 | namespace llvm { |
76 | namespace orc { |
77 | |
78 | char RTDyldObjectLinkingLayer::ID; |
79 | |
80 | using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>; |
81 | |
82 | RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer( |
83 | ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager) |
84 | : BaseT(ES), GetMemoryManager(std::move(GetMemoryManager)) { |
85 | ES.registerResourceManager(RM&: *this); |
86 | } |
87 | |
88 | RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() { |
89 | assert(MemMgrs.empty() && "Layer destroyed with resources still attached" ); |
90 | } |
91 | |
92 | void RTDyldObjectLinkingLayer::emit( |
93 | std::unique_ptr<MaterializationResponsibility> R, |
94 | std::unique_ptr<MemoryBuffer> O) { |
95 | assert(O && "Object must not be null" ); |
96 | |
97 | auto &ES = getExecutionSession(); |
98 | |
99 | auto Obj = object::ObjectFile::createObjectFile(Object: *O); |
100 | |
101 | if (!Obj) { |
102 | getExecutionSession().reportError(Err: Obj.takeError()); |
103 | R->failMaterialization(); |
104 | return; |
105 | } |
106 | |
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>>(); |
110 | { |
111 | SymbolFlagsMap ; |
112 | for (auto &Sym : (*Obj)->symbols()) { |
113 | |
114 | // Skip file symbols. |
115 | if (auto SymType = Sym.getType()) { |
116 | if (*SymType == object::SymbolRef::ST_File) |
117 | continue; |
118 | } else { |
119 | ES.reportError(Err: SymType.takeError()); |
120 | R->failMaterialization(); |
121 | return; |
122 | } |
123 | |
124 | Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); |
125 | if (!SymFlagsOrErr) { |
126 | // TODO: Test this error. |
127 | ES.reportError(Err: SymFlagsOrErr.takeError()); |
128 | R->failMaterialization(); |
129 | return; |
130 | } |
131 | |
132 | // Try to claim responsibility of weak symbols |
133 | // if AutoClaimObjectSymbols flag is set. |
134 | if (AutoClaimObjectSymbols && |
135 | (*SymFlagsOrErr & object::BasicSymbolRef::SF_Weak)) { |
136 | auto SymName = Sym.getName(); |
137 | if (!SymName) { |
138 | ES.reportError(Err: SymName.takeError()); |
139 | R->failMaterialization(); |
140 | return; |
141 | } |
142 | |
143 | // Already included in responsibility set, skip it |
144 | SymbolStringPtr SymbolName = ES.intern(SymName: *SymName); |
145 | if (R->getSymbols().count(Val: SymbolName)) |
146 | continue; |
147 | |
148 | auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym); |
149 | if (!SymFlags) { |
150 | ES.reportError(Err: SymFlags.takeError()); |
151 | R->failMaterialization(); |
152 | return; |
153 | } |
154 | |
155 | ExtraSymbolsToClaim[SymbolName] = *SymFlags; |
156 | continue; |
157 | } |
158 | |
159 | // Don't include symbols that aren't global. |
160 | if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) { |
161 | if (auto SymName = Sym.getName()) |
162 | InternalSymbols->insert(x: *SymName); |
163 | else { |
164 | ES.reportError(Err: SymName.takeError()); |
165 | R->failMaterialization(); |
166 | return; |
167 | } |
168 | } |
169 | } |
170 | |
171 | if (!ExtraSymbolsToClaim.empty()) { |
172 | if (auto Err = R->defineMaterializing(SymbolFlags: ExtraSymbolsToClaim)) { |
173 | ES.reportError(Err: std::move(Err)); |
174 | R->failMaterialization(); |
175 | } |
176 | } |
177 | } |
178 | |
179 | auto MemMgr = GetMemoryManager(); |
180 | auto &MemMgrRef = *MemMgr; |
181 | |
182 | // Switch to shared ownership of MR so that it can be captured by both |
183 | // lambdas below. |
184 | std::shared_ptr<MaterializationResponsibility> SharedR(std::move(R)); |
185 | auto Deps = std::make_unique<SymbolDependenceMap>(); |
186 | |
187 | JITDylibSearchOrderResolver Resolver(*SharedR, *Deps); |
188 | |
189 | jitLinkForORC( |
190 | O: object::OwningBinary<object::ObjectFile>(std::move(*Obj), std::move(O)), |
191 | MemMgr&: MemMgrRef, Resolver, ProcessAllSections, |
192 | OnLoaded: [this, SharedR, &MemMgrRef, InternalSymbols]( |
193 | const object::ObjectFile &Obj, |
194 | RuntimeDyld::LoadedObjectInfo &LoadedObjInfo, |
195 | std::map<StringRef, JITEvaluatedSymbol> ResolvedSymbols) { |
196 | return onObjLoad(R&: *SharedR, Obj, MemMgr&: MemMgrRef, LoadedObjInfo, |
197 | Resolved: ResolvedSymbols, InternalSymbols&: *InternalSymbols); |
198 | }, |
199 | OnEmitted: [this, SharedR, MemMgr = std::move(MemMgr), Deps = std::move(Deps)]( |
200 | object::OwningBinary<object::ObjectFile> Obj, |
201 | std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo, |
202 | Error Err) mutable { |
203 | onObjEmit(R&: *SharedR, O: std::move(Obj), MemMgr: std::move(MemMgr), |
204 | LoadedObjInfo: std::move(LoadedObjInfo), Deps: std::move(Deps), Err: std::move(Err)); |
205 | }); |
206 | } |
207 | |
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(x: &L); |
213 | } |
214 | |
215 | void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener &L) { |
216 | std::lock_guard<std::mutex> Lock(RTDyldLayerMutex); |
217 | auto I = llvm::find(Range&: EventListeners, Val: &L); |
218 | assert(I != EventListeners.end() && "Listener not registered" ); |
219 | EventListeners.erase(position: I); |
220 | } |
221 | |
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 ; |
229 | SymbolMap Symbols; |
230 | |
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>(Val: &Obj)) { |
234 | auto &ES = getExecutionSession(); |
235 | |
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 |
238 | // weak. |
239 | for (auto &Sym : COFFObj->symbols()) { |
240 | // getFlags() on COFF symbols can't fail. |
241 | uint32_t SymFlags = cantFail(ValOrErr: Sym.getFlags()); |
242 | if (SymFlags & object::BasicSymbolRef::SF_Undefined) |
243 | continue; |
244 | auto Name = Sym.getName(); |
245 | if (!Name) |
246 | return Name.takeError(); |
247 | auto I = Resolved.find(x: *Name); |
248 | |
249 | // Skip unresolved symbols, internal symbols, and symbols that are |
250 | // already in the responsibility set. |
251 | if (I == Resolved.end() || InternalSymbols.count(x: *Name) || |
252 | R.getSymbols().count(Val: ES.intern(SymName: *Name))) |
253 | continue; |
254 | auto Sec = Sym.getSection(); |
255 | if (!Sec) |
256 | return Sec.takeError(); |
257 | if (*Sec == COFFObj->section_end()) |
258 | continue; |
259 | auto &COFFSec = *COFFObj->getCOFFSection(Section: **Sec); |
260 | if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT) |
261 | I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak); |
262 | } |
263 | |
264 | // Handle any aliases. |
265 | for (auto &Sym : COFFObj->symbols()) { |
266 | uint32_t SymFlags = cantFail(ValOrErr: Sym.getFlags()); |
267 | if (SymFlags & object::BasicSymbolRef::SF_Undefined) |
268 | continue; |
269 | auto Name = Sym.getName(); |
270 | if (!Name) |
271 | return Name.takeError(); |
272 | auto I = Resolved.find(x: *Name); |
273 | |
274 | // Skip already-resolved symbols, and symbols that we're not responsible |
275 | // for. |
276 | if (I != Resolved.end() || !R.getSymbols().count(Val: ES.intern(SymName: *Name))) |
277 | continue; |
278 | |
279 | // Skip anything other than weak externals. |
280 | auto COFFSym = COFFObj->getCOFFSymbol(Symbol: Sym); |
281 | if (!COFFSym.isWeakExternal()) |
282 | continue; |
283 | auto *WeakExternal = COFFSym.getAux<object::coff_aux_weak_external>(); |
284 | if (WeakExternal->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS) |
285 | continue; |
286 | |
287 | // We found an alias. Reuse the resolution of the alias target for the |
288 | // alias itself. |
289 | Expected<object::COFFSymbolRef> TargetSymbol = |
290 | COFFObj->getSymbol(index: WeakExternal->TagIndex); |
291 | if (!TargetSymbol) |
292 | return TargetSymbol.takeError(); |
293 | Expected<StringRef> TargetName = COFFObj->getSymbolName(Symbol: *TargetSymbol); |
294 | if (!TargetName) |
295 | return TargetName.takeError(); |
296 | auto J = Resolved.find(x: *TargetName); |
297 | if (J == Resolved.end()) |
298 | return make_error<StringError>(Args: "Could alias target " + *TargetName + |
299 | " not resolved" , |
300 | Args: inconvertibleErrorCode()); |
301 | Resolved[*Name] = J->second; |
302 | } |
303 | } |
304 | |
305 | for (auto &KV : Resolved) { |
306 | // Scan the symbols and add them to the Symbols map for resolution. |
307 | |
308 | // We never claim internal symbols. |
309 | if (InternalSymbols.count(x: KV.first)) |
310 | continue; |
311 | |
312 | auto InternedName = getExecutionSession().intern(SymName: KV.first); |
313 | auto Flags = KV.second.getFlags(); |
314 | auto I = R.getSymbols().find(Val: InternedName); |
315 | if (I != R.getSymbols().end()) { |
316 | // Override object flags and claim responsibility for symbols if |
317 | // requested. |
318 | if (OverrideObjectFlags) |
319 | Flags = I->second; |
320 | else { |
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; |
326 | } |
327 | } else if (AutoClaimObjectSymbols) |
328 | ExtraSymbolsToClaim[InternedName] = Flags; |
329 | |
330 | Symbols[InternedName] = {ExecutorAddr(KV.second.getAddress()), Flags}; |
331 | } |
332 | |
333 | if (!ExtraSymbolsToClaim.empty()) { |
334 | if (auto Err = R.defineMaterializing(SymbolFlags: ExtraSymbolsToClaim)) |
335 | return Err; |
336 | |
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(Val: KV.first)) |
341 | Symbols.erase(Val: KV.first); |
342 | } |
343 | |
344 | if (auto Err = R.notifyResolved(Symbols)) { |
345 | R.failMaterialization(); |
346 | return Err; |
347 | } |
348 | |
349 | if (NotifyLoaded) |
350 | NotifyLoaded(R, Obj, LoadedObjInfo); |
351 | |
352 | return Error::success(); |
353 | } |
354 | |
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, |
360 | std::unique_ptr<SymbolDependenceMap> Deps, Error Err) { |
361 | if (Err) { |
362 | getExecutionSession().reportError(Err: std::move(Err)); |
363 | R.failMaterialization(); |
364 | return; |
365 | } |
366 | |
367 | SymbolDependenceGroup SDG; |
368 | for (auto &[Sym, Flags] : R.getSymbols()) |
369 | SDG.Symbols.insert(V: Sym); |
370 | SDG.Dependencies = std::move(*Deps); |
371 | |
372 | if (auto Err = R.notifyEmitted(EmittedDeps: SDG)) { |
373 | getExecutionSession().reportError(Err: std::move(Err)); |
374 | R.failMaterialization(); |
375 | return; |
376 | } |
377 | |
378 | std::unique_ptr<object::ObjectFile> Obj; |
379 | std::unique_ptr<MemoryBuffer> ObjBuffer; |
380 | std::tie(args&: Obj, args&: ObjBuffer) = O.takeBinary(); |
381 | |
382 | // Run EventListener notifyLoaded callbacks. |
383 | { |
384 | std::lock_guard<std::mutex> Lock(RTDyldLayerMutex); |
385 | for (auto *L : EventListeners) |
386 | L->notifyObjectLoaded(K: pointerToJITTargetAddress(Ptr: MemMgr.get()), Obj: *Obj, |
387 | L: *LoadedObjInfo); |
388 | } |
389 | |
390 | if (NotifyEmitted) |
391 | NotifyEmitted(R, std::move(ObjBuffer)); |
392 | |
393 | if (auto Err = R.withResourceKeyDo( |
394 | F: [&](ResourceKey K) { MemMgrs[K].push_back(x: std::move(MemMgr)); })) { |
395 | getExecutionSession().reportError(Err: std::move(Err)); |
396 | R.failMaterialization(); |
397 | } |
398 | } |
399 | |
400 | Error RTDyldObjectLinkingLayer::handleRemoveResources(JITDylib &JD, |
401 | ResourceKey K) { |
402 | |
403 | std::vector<MemoryManagerUP> MemMgrsToRemove; |
404 | |
405 | getExecutionSession().runSessionLocked(F: [&] { |
406 | auto I = MemMgrs.find(Val: K); |
407 | if (I != MemMgrs.end()) { |
408 | std::swap(x&: MemMgrsToRemove, y&: I->second); |
409 | MemMgrs.erase(I); |
410 | } |
411 | }); |
412 | |
413 | { |
414 | std::lock_guard<std::mutex> Lock(RTDyldLayerMutex); |
415 | for (auto &MemMgr : MemMgrsToRemove) { |
416 | for (auto *L : EventListeners) |
417 | L->notifyFreeingObject(K: pointerToJITTargetAddress(Ptr: MemMgr.get())); |
418 | MemMgr->deregisterEHFrames(); |
419 | } |
420 | } |
421 | |
422 | return Error::success(); |
423 | } |
424 | |
425 | void RTDyldObjectLinkingLayer::handleTransferResources(JITDylib &JD, |
426 | ResourceKey DstKey, |
427 | ResourceKey SrcKey) { |
428 | auto I = MemMgrs.find(Val: SrcKey); |
429 | if (I != MemMgrs.end()) { |
430 | auto &SrcMemMgrs = I->second; |
431 | auto &DstMemMgrs = MemMgrs[DstKey]; |
432 | DstMemMgrs.reserve(n: DstMemMgrs.size() + SrcMemMgrs.size()); |
433 | for (auto &MemMgr : SrcMemMgrs) |
434 | DstMemMgrs.push_back(x: std::move(MemMgr)); |
435 | |
436 | // Erase SrcKey entry using value rather than iterator I: I may have been |
437 | // invalidated when we looked up DstKey. |
438 | MemMgrs.erase(Val: SrcKey); |
439 | } |
440 | } |
441 | |
442 | } // End namespace orc. |
443 | } // End namespace llvm. |
444 | |