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
12namespace {
13
14using namespace llvm;
15using namespace llvm::orc;
16
17class JITDylibSearchOrderResolver : public JITSymbolResolver {
18public:
19  JITDylibSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {}
20
21  void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override {
22    auto &ES = MR.getTargetJITDylib().getExecutionSession();
23    SymbolLookupSet InternedSymbols;
24
25    // Intern the requested symbols: lookup takes interned strings.
26    for (auto &S : Symbols)
27      InternedSymbols.add(ES.intern(S));
28
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());
36            return;
37          }
38
39          LookupResult Result;
40          for (auto &KV : *InternedResult)
41            Result[*KV.first] = {KV.second.getAddress().getValue(),
42                                 KV.second.getFlags()};
43          OnResolved(Result);
44        };
45
46    // Register dependencies for all symbols contained in this set.
47    auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
48      MR.addDependenciesForAll(Deps);
49    };
50
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);
57  }
58
59  Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override {
60    LookupSet Result;
61
62    for (auto &KV : MR.getSymbols()) {
63      if (Symbols.count(*KV.first))
64        Result.insert(*KV.first);
65    }
66
67    return Result;
68  }
69
70private:
71  MaterializationResponsibility &MR;
72};
73
74} // end anonymous namespace
75
76namespace llvm {
77namespace orc {
78
79char RTDyldObjectLinkingLayer::ID;
80
81using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>;
82
83RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(
84    ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager)
85    : BaseT(ES), GetMemoryManager(std::move(GetMemoryManager)) {
86  ES.registerResourceManager(*this);
87}
88
89RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {
90  assert(MemMgrs.empty() && "Layer destroyed with resources still attached");
91}
92
93void RTDyldObjectLinkingLayer::emit(
94    std::unique_ptr<MaterializationResponsibility> R,
95    std::unique_ptr<MemoryBuffer> O) {
96  assert(O && "Object must not be null");
97
98  auto &ES = getExecutionSession();
99
100  auto Obj = object::ObjectFile::createObjectFile(*O);
101
102  if (!Obj) {
103    getExecutionSession().reportError(Obj.takeError());
104    R->failMaterialization();
105    return;
106  }
107
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>>();
111  {
112    SymbolFlagsMap ExtraSymbolsToClaim;
113    for (auto &Sym : (*Obj)->symbols()) {
114
115      // Skip file symbols.
116      if (auto SymType = Sym.getType()) {
117        if (*SymType == object::SymbolRef::ST_File)
118          continue;
119      } else {
120        ES.reportError(SymType.takeError());
121        R->failMaterialization();
122        return;
123      }
124
125      Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
126      if (!SymFlagsOrErr) {
127        // TODO: Test this error.
128        ES.reportError(SymFlagsOrErr.takeError());
129        R->failMaterialization();
130        return;
131      }
132
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();
138        if (!SymName) {
139          ES.reportError(SymName.takeError());
140          R->failMaterialization();
141          return;
142        }
143
144        // Already included in responsibility set, skip it
145        SymbolStringPtr SymbolName = ES.intern(*SymName);
146        if (R->getSymbols().count(SymbolName))
147          continue;
148
149        auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
150        if (!SymFlags) {
151          ES.reportError(SymFlags.takeError());
152          R->failMaterialization();
153          return;
154        }
155
156        ExtraSymbolsToClaim[SymbolName] = *SymFlags;
157        continue;
158      }
159
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);
164        else {
165          ES.reportError(SymName.takeError());
166          R->failMaterialization();
167          return;
168        }
169      }
170    }
171
172    if (!ExtraSymbolsToClaim.empty()) {
173      if (auto Err = R->defineMaterializing(ExtraSymbolsToClaim)) {
174        ES.reportError(std::move(Err));
175        R->failMaterialization();
176      }
177    }
178  }
179
180  auto MemMgr = GetMemoryManager();
181  auto &MemMgrRef = *MemMgr;
182
183  // Switch to shared ownership of MR so that it can be captured by both
184  // lambdas below.
185  std::shared_ptr<MaterializationResponsibility> SharedR(std::move(R));
186
187  JITDylibSearchOrderResolver Resolver(*SharedR);
188
189  jitLinkForORC(
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);
198      },
199      [this, SharedR, MemMgr = std::move(MemMgr)](
200          object::OwningBinary<object::ObjectFile> Obj,
201          std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
202          Error Err) mutable {
203        onObjEmit(*SharedR, std::move(Obj), std::move(MemMgr),
204                  std::move(LoadedObjInfo), std::move(Err));
205      });
206}
207
208void 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);
213}
214
215void 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);
220}
221
222Error 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;
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>(&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(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(*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(*Name) ||
252          R.getSymbols().count(ES.intern(*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(**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(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(*Name);
273
274      // Skip already-resolved symbols, and symbols that we're not responsible
275      // for.
276      if (I != Resolved.end() || !R.getSymbols().count(ES.intern(*Name)))
277        continue;
278
279      // Skip anything other than weak externals.
280      auto COFFSym = COFFObj->getCOFFSymbol(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(WeakExternal->TagIndex);
291      if (!TargetSymbol)
292        return TargetSymbol.takeError();
293      Expected<StringRef> TargetName = COFFObj->getSymbolName(*TargetSymbol);
294      if (!TargetName)
295        return TargetName.takeError();
296      auto J = Resolved.find(*TargetName);
297      if (J == Resolved.end())
298        return make_error<StringError>("Could alias target " + *TargetName +
299                                           " not resolved",
300                                       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(KV.first))
310      continue;
311
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
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(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(KV.first))
341        Symbols.erase(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
355void 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) {
360  if (Err) {
361    getExecutionSession().reportError(std::move(Err));
362    R.failMaterialization();
363    return;
364  }
365
366  if (auto Err = R.notifyEmitted()) {
367    getExecutionSession().reportError(std::move(Err));
368    R.failMaterialization();
369    return;
370  }
371
372  std::unique_ptr<object::ObjectFile> Obj;
373  std::unique_ptr<MemoryBuffer> ObjBuffer;
374  std::tie(Obj, ObjBuffer) = O.takeBinary();
375
376  // Run EventListener notifyLoaded callbacks.
377  {
378    std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
379    for (auto *L : EventListeners)
380      L->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr.get()), *Obj,
381                            *LoadedObjInfo);
382  }
383
384  if (NotifyEmitted)
385    NotifyEmitted(R, std::move(ObjBuffer));
386
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();
391  }
392}
393
394Error RTDyldObjectLinkingLayer::handleRemoveResources(JITDylib &JD,
395                                                      ResourceKey K) {
396
397  std::vector<MemoryManagerUP> MemMgrsToRemove;
398
399  getExecutionSession().runSessionLocked([&] {
400    auto I = MemMgrs.find(K);
401    if (I != MemMgrs.end()) {
402      std::swap(MemMgrsToRemove, I->second);
403      MemMgrs.erase(I);
404    }
405  });
406
407  {
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();
413    }
414  }
415
416  return Error::success();
417}
418
419void RTDyldObjectLinkingLayer::handleTransferResources(JITDylib &JD,
420                                                       ResourceKey DstKey,
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));
429
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);
433  }
434}
435
436} // End namespace orc.
437} // End namespace llvm.
438