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