RTDyldObjectLinkingLayer.h revision 360784
1//===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking  ---*- C++ -*-===//
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// Contains the definition for an RTDyld-based, in-process object linking layer.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
14#define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
15
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/StringMap.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ExecutionEngine/JITSymbol.h"
20#include "llvm/ExecutionEngine/Orc/Core.h"
21#include "llvm/ExecutionEngine/Orc/Layer.h"
22#include "llvm/ExecutionEngine/Orc/Legacy.h"
23#include "llvm/ExecutionEngine/RuntimeDyld.h"
24#include "llvm/Object/ObjectFile.h"
25#include "llvm/Support/Error.h"
26#include <algorithm>
27#include <cassert>
28#include <functional>
29#include <list>
30#include <memory>
31#include <string>
32#include <utility>
33#include <vector>
34
35namespace llvm {
36namespace orc {
37
38class RTDyldObjectLinkingLayer : public ObjectLayer {
39public:
40  /// Functor for receiving object-loaded notifications.
41  using NotifyLoadedFunction =
42      std::function<void(VModuleKey, const object::ObjectFile &Obj,
43                         const RuntimeDyld::LoadedObjectInfo &)>;
44
45  /// Functor for receiving finalization notifications.
46  using NotifyEmittedFunction =
47      std::function<void(VModuleKey, std::unique_ptr<MemoryBuffer>)>;
48
49  using GetMemoryManagerFunction =
50      std::function<std::unique_ptr<RuntimeDyld::MemoryManager>()>;
51
52  /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
53  ///        and NotifyEmitted functors.
54  RTDyldObjectLinkingLayer(ExecutionSession &ES,
55                           GetMemoryManagerFunction GetMemoryManager);
56
57  ~RTDyldObjectLinkingLayer();
58
59  /// Emit the object.
60  void emit(MaterializationResponsibility R,
61            std::unique_ptr<MemoryBuffer> O) override;
62
63  /// Set the NotifyLoaded callback.
64  RTDyldObjectLinkingLayer &setNotifyLoaded(NotifyLoadedFunction NotifyLoaded) {
65    this->NotifyLoaded = std::move(NotifyLoaded);
66    return *this;
67  }
68
69  /// Set the NotifyEmitted callback.
70  RTDyldObjectLinkingLayer &
71  setNotifyEmitted(NotifyEmittedFunction NotifyEmitted) {
72    this->NotifyEmitted = std::move(NotifyEmitted);
73    return *this;
74  }
75
76  /// Set the 'ProcessAllSections' flag.
77  ///
78  /// If set to true, all sections in each object file will be allocated using
79  /// the memory manager, rather than just the sections required for execution.
80  ///
81  /// This is kludgy, and may be removed in the future.
82  RTDyldObjectLinkingLayer &setProcessAllSections(bool ProcessAllSections) {
83    this->ProcessAllSections = ProcessAllSections;
84    return *this;
85  }
86
87  /// Instructs this RTDyldLinkingLayer2 instance to override the symbol flags
88  /// returned by RuntimeDyld for any given object file with the flags supplied
89  /// by the MaterializationResponsibility instance. This is a workaround to
90  /// support symbol visibility in COFF, which does not use the libObject's
91  /// SF_Exported flag. Use only when generating / adding COFF object files.
92  ///
93  /// FIXME: We should be able to remove this if/when COFF properly tracks
94  /// exported symbols.
95  RTDyldObjectLinkingLayer &
96  setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
97    this->OverrideObjectFlags = OverrideObjectFlags;
98    return *this;
99  }
100
101  /// If set, this RTDyldObjectLinkingLayer instance will claim responsibility
102  /// for any symbols provided by a given object file that were not already in
103  /// the MaterializationResponsibility instance. Setting this flag allows
104  /// higher-level program representations (e.g. LLVM IR) to be added based on
105  /// only a subset of the symbols they provide, without having to write
106  /// intervening layers to scan and add the additional symbols. This trades
107  /// diagnostic quality for convenience however: If all symbols are enumerated
108  /// up-front then clashes can be detected and reported early (and usually
109  /// deterministically). If this option is set, clashes for the additional
110  /// symbols may not be detected until late, and detection may depend on
111  /// the flow of control through JIT'd code. Use with care.
112  RTDyldObjectLinkingLayer &
113  setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
114    this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
115    return *this;
116  }
117
118private:
119  Error onObjLoad(VModuleKey K, MaterializationResponsibility &R,
120                  object::ObjectFile &Obj,
121                  std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
122                  std::map<StringRef, JITEvaluatedSymbol> Resolved,
123                  std::set<StringRef> &InternalSymbols);
124
125  void onObjEmit(VModuleKey K, std::unique_ptr<MemoryBuffer> ObjBuffer,
126                 MaterializationResponsibility &R, Error Err);
127
128  mutable std::mutex RTDyldLayerMutex;
129  GetMemoryManagerFunction GetMemoryManager;
130  NotifyLoadedFunction NotifyLoaded;
131  NotifyEmittedFunction NotifyEmitted;
132  bool ProcessAllSections = false;
133  bool OverrideObjectFlags = false;
134  bool AutoClaimObjectSymbols = false;
135  std::vector<std::unique_ptr<RuntimeDyld::MemoryManager>> MemMgrs;
136};
137
138class LegacyRTDyldObjectLinkingLayerBase {
139public:
140  using ObjectPtr = std::unique_ptr<MemoryBuffer>;
141
142protected:
143
144  /// Holds an object to be allocated/linked as a unit in the JIT.
145  ///
146  /// An instance of this class will be created for each object added
147  /// via JITObjectLayer::addObject. Deleting the instance (via
148  /// removeObject) frees its memory, removing all symbol definitions that
149  /// had been provided by this instance. Higher level layers are responsible
150  /// for taking any action required to handle the missing symbols.
151  class LinkedObject {
152  public:
153    LinkedObject() = default;
154    LinkedObject(const LinkedObject&) = delete;
155    void operator=(const LinkedObject&) = delete;
156    virtual ~LinkedObject() = default;
157
158    virtual Error finalize() = 0;
159
160    virtual JITSymbol::GetAddressFtor
161    getSymbolMaterializer(std::string Name) = 0;
162
163    virtual void mapSectionAddress(const void *LocalAddress,
164                                   JITTargetAddress TargetAddr) const = 0;
165
166    JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
167      auto SymEntry = SymbolTable.find(Name);
168      if (SymEntry == SymbolTable.end())
169        return nullptr;
170      if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
171        return nullptr;
172      if (!Finalized)
173        return JITSymbol(getSymbolMaterializer(Name),
174                         SymEntry->second.getFlags());
175      return JITSymbol(SymEntry->second);
176    }
177
178  protected:
179    StringMap<JITEvaluatedSymbol> SymbolTable;
180    bool Finalized = false;
181  };
182};
183
184/// Bare bones object linking layer.
185///
186///   This class is intended to be used as the base layer for a JIT. It allows
187/// object files to be loaded into memory, linked, and the addresses of their
188/// symbols queried. All objects added to this layer can see each other's
189/// symbols.
190class LegacyRTDyldObjectLinkingLayer : public LegacyRTDyldObjectLinkingLayerBase {
191public:
192
193  using LegacyRTDyldObjectLinkingLayerBase::ObjectPtr;
194
195  /// Functor for receiving object-loaded notifications.
196  using NotifyLoadedFtor =
197      std::function<void(VModuleKey, const object::ObjectFile &Obj,
198                         const RuntimeDyld::LoadedObjectInfo &)>;
199
200  /// Functor for receiving finalization notifications.
201  using NotifyFinalizedFtor =
202      std::function<void(VModuleKey, const object::ObjectFile &Obj,
203                         const RuntimeDyld::LoadedObjectInfo &)>;
204
205  /// Functor for receiving deallocation notifications.
206  using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
207
208private:
209  using OwnedObject = object::OwningBinary<object::ObjectFile>;
210
211  template <typename MemoryManagerPtrT>
212  class ConcreteLinkedObject : public LinkedObject {
213  public:
214    ConcreteLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K,
215                         OwnedObject Obj, MemoryManagerPtrT MemMgr,
216                         std::shared_ptr<SymbolResolver> Resolver,
217                         bool ProcessAllSections)
218        : K(std::move(K)),
219          Parent(Parent),
220          MemMgr(std::move(MemMgr)),
221          PFC(std::make_unique<PreFinalizeContents>(
222              std::move(Obj), std::move(Resolver),
223              ProcessAllSections)) {
224      buildInitialSymbolTable(PFC->Obj);
225    }
226
227    ~ConcreteLinkedObject() override {
228      if (this->Parent.NotifyFreed && ObjForNotify.getBinary())
229        this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
230
231      MemMgr->deregisterEHFrames();
232    }
233
234    Error finalize() override {
235      assert(PFC && "mapSectionAddress called on finalized LinkedObject");
236
237      JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
238					       nullptr);
239      PFC->RTDyld = std::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
240      PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
241
242      Finalized = true;
243
244      std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
245          PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
246
247      // Copy the symbol table out of the RuntimeDyld instance.
248      {
249        auto SymTab = PFC->RTDyld->getSymbolTable();
250        for (auto &KV : SymTab)
251          SymbolTable[KV.first] = KV.second;
252      }
253
254      if (Parent.NotifyLoaded)
255        Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
256
257      PFC->RTDyld->finalizeWithMemoryManagerLocking();
258
259      if (PFC->RTDyld->hasError())
260        return make_error<StringError>(PFC->RTDyld->getErrorString(),
261                                       inconvertibleErrorCode());
262
263      if (Parent.NotifyFinalized)
264        Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
265
266      // Release resources.
267      if (this->Parent.NotifyFreed)
268        ObjForNotify = std::move(PFC->Obj); // needed for callback
269      PFC = nullptr;
270      return Error::success();
271    }
272
273    JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
274      return [this, Name]() -> Expected<JITTargetAddress> {
275        // The symbol may be materialized between the creation of this lambda
276        // and its execution, so we need to double check.
277        if (!this->Finalized)
278          if (auto Err = this->finalize())
279            return std::move(Err);
280        return this->getSymbol(Name, false).getAddress();
281      };
282    }
283
284    void mapSectionAddress(const void *LocalAddress,
285                           JITTargetAddress TargetAddr) const override {
286      assert(PFC && "mapSectionAddress called on finalized LinkedObject");
287      assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
288      PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
289    }
290
291  private:
292    void buildInitialSymbolTable(const OwnedObject &Obj) {
293      for (auto &Symbol : Obj.getBinary()->symbols()) {
294        if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
295          continue;
296        Expected<StringRef> SymbolName = Symbol.getName();
297        // FIXME: Raise an error for bad symbols.
298        if (!SymbolName) {
299          consumeError(SymbolName.takeError());
300          continue;
301        }
302        // FIXME: Raise an error for bad symbols.
303        auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
304        if (!Flags) {
305          consumeError(Flags.takeError());
306          continue;
307        }
308        SymbolTable.insert(
309            std::make_pair(*SymbolName, JITEvaluatedSymbol(0, *Flags)));
310      }
311    }
312
313    // Contains the information needed prior to finalization: the object files,
314    // memory manager, resolver, and flags needed for RuntimeDyld.
315    struct PreFinalizeContents {
316      PreFinalizeContents(OwnedObject Obj,
317                          std::shared_ptr<SymbolResolver> Resolver,
318                          bool ProcessAllSections)
319          : Obj(std::move(Obj)),
320            Resolver(std::move(Resolver)),
321            ProcessAllSections(ProcessAllSections) {}
322
323      OwnedObject Obj;
324      std::shared_ptr<SymbolResolver> Resolver;
325      bool ProcessAllSections;
326      std::unique_ptr<RuntimeDyld> RTDyld;
327    };
328
329    VModuleKey K;
330    LegacyRTDyldObjectLinkingLayer &Parent;
331    MemoryManagerPtrT MemMgr;
332    OwnedObject ObjForNotify;
333    std::unique_ptr<PreFinalizeContents> PFC;
334  };
335
336  template <typename MemoryManagerPtrT>
337  std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
338  createLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K,
339                     OwnedObject Obj, MemoryManagerPtrT MemMgr,
340                     std::shared_ptr<SymbolResolver> Resolver,
341                     bool ProcessAllSections) {
342    using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
343    return std::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
344                                  std::move(MemMgr), std::move(Resolver),
345                                  ProcessAllSections);
346  }
347
348public:
349  struct Resources {
350    std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
351    std::shared_ptr<SymbolResolver> Resolver;
352  };
353
354  using ResourcesGetter = std::function<Resources(VModuleKey)>;
355
356  /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
357  ///        and NotifyFinalized functors.
358  LLVM_ATTRIBUTE_DEPRECATED(
359      LegacyRTDyldObjectLinkingLayer(
360          ExecutionSession &ES, ResourcesGetter GetResources,
361          NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
362          NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
363          NotifyFreedFtor NotifyFreed = NotifyFreedFtor()),
364      "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
365      "use "
366      "ORCv2 (see docs/ORCv2.rst)");
367
368  // Legacy layer constructor with deprecation acknowledgement.
369  LegacyRTDyldObjectLinkingLayer(
370      ORCv1DeprecationAcknowledgement, ExecutionSession &ES,
371      ResourcesGetter GetResources,
372      NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
373      NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
374      NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
375      : ES(ES), GetResources(std::move(GetResources)),
376        NotifyLoaded(std::move(NotifyLoaded)),
377        NotifyFinalized(std::move(NotifyFinalized)),
378        NotifyFreed(std::move(NotifyFreed)), ProcessAllSections(false) {}
379
380  /// Set the 'ProcessAllSections' flag.
381  ///
382  /// If set to true, all sections in each object file will be allocated using
383  /// the memory manager, rather than just the sections required for execution.
384  ///
385  /// This is kludgy, and may be removed in the future.
386  void setProcessAllSections(bool ProcessAllSections) {
387    this->ProcessAllSections = ProcessAllSections;
388  }
389
390  /// Add an object to the JIT.
391  Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
392
393    auto Obj =
394        object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
395    if (!Obj)
396      return Obj.takeError();
397
398    assert(!LinkedObjects.count(K) && "VModuleKey already in use");
399
400    auto R = GetResources(K);
401
402    LinkedObjects[K] = createLinkedObject(
403        *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
404        std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
405
406    return Error::success();
407  }
408
409  /// Remove the object associated with VModuleKey K.
410  ///
411  ///   All memory allocated for the object will be freed, and the sections and
412  /// symbols it provided will no longer be available. No attempt is made to
413  /// re-emit the missing symbols, and any use of these symbols (directly or
414  /// indirectly) will result in undefined behavior. If dependence tracking is
415  /// required to detect or resolve such issues it should be added at a higher
416  /// layer.
417  Error removeObject(VModuleKey K) {
418    assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
419    // How do we invalidate the symbols in H?
420    LinkedObjects.erase(K);
421    return Error::success();
422  }
423
424  /// Search for the given named symbol.
425  /// @param Name The name of the symbol to search for.
426  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
427  /// @return A handle for the given named symbol, if it exists.
428  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
429    for (auto &KV : LinkedObjects)
430      if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
431        return Sym;
432      else if (auto Err = Sym.takeError())
433        return std::move(Err);
434
435    return nullptr;
436  }
437
438  /// Search for the given named symbol in the context of the loaded
439  ///        object represented by the VModuleKey K.
440  /// @param K The VModuleKey for the object to search in.
441  /// @param Name The name of the symbol to search for.
442  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
443  /// @return A handle for the given named symbol, if it is found in the
444  ///         given object.
445  JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
446                         bool ExportedSymbolsOnly) {
447    assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
448    return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
449  }
450
451  /// Map section addresses for the object associated with the
452  ///        VModuleKey K.
453  void mapSectionAddress(VModuleKey K, const void *LocalAddress,
454                         JITTargetAddress TargetAddr) {
455    assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
456    LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
457  }
458
459  /// Immediately emit and finalize the object represented by the given
460  ///        VModuleKey.
461  /// @param K VModuleKey for object to emit/finalize.
462  Error emitAndFinalize(VModuleKey K) {
463    assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
464    return LinkedObjects[K]->finalize();
465  }
466
467private:
468  ExecutionSession &ES;
469
470  ResourcesGetter GetResources;
471  NotifyLoadedFtor NotifyLoaded;
472  NotifyFinalizedFtor NotifyFinalized;
473  NotifyFreedFtor NotifyFreed;
474
475  // NB!  `LinkedObjects` needs to be destroyed before `NotifyFreed` because
476  // `~ConcreteLinkedObject` calls `NotifyFreed`
477  std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
478  bool ProcessAllSections = false;
479};
480
481} // end namespace orc
482} // end namespace llvm
483
484#endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
485