LLVM  6.0.0svn
RTDyldObjectLinkingLayer.h
Go to the documentation of this file.
1 //===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking ---*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Contains the definition for an RTDyld-based, in-process object linking layer.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
15 #define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
16 
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Object/ObjectFile.h"
23 #include "llvm/Support/Error.h"
24 #include <algorithm>
25 #include <cassert>
26 #include <functional>
27 #include <list>
28 #include <memory>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 namespace llvm {
34 namespace orc {
35 
37 public:
38 
39  using ObjectPtr =
40  std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
41 
42 protected:
43 
44  /// @brief Holds an object to be allocated/linked as a unit in the JIT.
45  ///
46  /// An instance of this class will be created for each object added
47  /// via JITObjectLayer::addObject. Deleting the instance (via
48  /// removeObject) frees its memory, removing all symbol definitions that
49  /// had been provided by this instance. Higher level layers are responsible
50  /// for taking any action required to handle the missing symbols.
51  class LinkedObject {
52  public:
53  LinkedObject() = default;
54  LinkedObject(const LinkedObject&) = delete;
55  void operator=(const LinkedObject&) = delete;
56  virtual ~LinkedObject() = default;
57 
58  virtual void finalize() = 0;
59 
61  getSymbolMaterializer(std::string Name) = 0;
62 
63  virtual void mapSectionAddress(const void *LocalAddress,
64  JITTargetAddress TargetAddr) const = 0;
65 
66  JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
67  auto SymEntry = SymbolTable.find(Name);
68  if (SymEntry == SymbolTable.end())
69  return nullptr;
70  if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
71  return nullptr;
72  if (!Finalized)
73  return JITSymbol(getSymbolMaterializer(Name),
74  SymEntry->second.getFlags());
75  return JITSymbol(SymEntry->second);
76  }
77 
78  protected:
80  bool Finalized = false;
81  };
82 
83  using LinkedObjectListT = std::list<std::unique_ptr<LinkedObject>>;
84 
85 public:
86  /// @brief Handle to a loaded object.
87  using ObjHandleT = LinkedObjectListT::iterator;
88 };
89 
90 /// @brief Bare bones object linking layer.
91 ///
92 /// This class is intended to be used as the base layer for a JIT. It allows
93 /// object files to be loaded into memory, linked, and the addresses of their
94 /// symbols queried. All objects added to this layer can see each other's
95 /// symbols.
97 public:
98 
100 
101  /// @brief Functor for receiving object-loaded notifications.
102  using NotifyLoadedFtor =
103  std::function<void(ObjHandleT, const ObjectPtr &Obj,
105 
106  /// @brief Functor for receiving finalization notifications.
107  using NotifyFinalizedFtor = std::function<void(ObjHandleT)>;
108 
109 private:
110 
111 
112  template <typename MemoryManagerPtrT, typename SymbolResolverPtrT,
113  typename FinalizerFtor>
114  class ConcreteLinkedObject : public LinkedObject {
115  public:
116  ConcreteLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr,
117  SymbolResolverPtrT Resolver,
118  FinalizerFtor Finalizer,
119  bool ProcessAllSections)
120  : MemMgr(std::move(MemMgr)),
121  PFC(llvm::make_unique<PreFinalizeContents>(std::move(Obj),
122  std::move(Resolver),
123  std::move(Finalizer),
124  ProcessAllSections)) {
125  buildInitialSymbolTable(PFC->Obj);
126  }
127 
128  ~ConcreteLinkedObject() override {
129  MemMgr->deregisterEHFrames();
130  }
131 
132  void setHandle(ObjHandleT H) {
133  PFC->Handle = H;
134  }
135 
136  void finalize() override {
137  assert(PFC && "mapSectionAddress called on finalized LinkedObject");
138 
139  RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver);
140  RTDyld.setProcessAllSections(PFC->ProcessAllSections);
141  PFC->RTDyld = &RTDyld;
142 
143  this->Finalized = true;
144  PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Obj),
145  [&]() {
146  this->updateSymbolTable(RTDyld);
147  });
148 
149  // Release resources.
150  PFC = nullptr;
151  }
152 
154  return
155  [this, Name]() {
156  // The symbol may be materialized between the creation of this lambda
157  // and its execution, so we need to double check.
158  if (!this->Finalized)
159  this->finalize();
160  return this->getSymbol(Name, false).getAddress();
161  };
162  }
163 
164  void mapSectionAddress(const void *LocalAddress,
165  JITTargetAddress TargetAddr) const override {
166  assert(PFC && "mapSectionAddress called on finalized LinkedObject");
167  assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
168  PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
169  }
170 
171  private:
172 
173  void buildInitialSymbolTable(const ObjectPtr &Obj) {
174  for (auto &Symbol : Obj->getBinary()->symbols()) {
175  if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
176  continue;
178  // FIXME: Raise an error for bad symbols.
179  if (!SymbolName) {
180  consumeError(SymbolName.takeError());
181  continue;
182  }
184  SymbolTable.insert(
185  std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
186  }
187  }
188 
189  void updateSymbolTable(const RuntimeDyld &RTDyld) {
190  for (auto &SymEntry : SymbolTable)
191  SymEntry.second = RTDyld.getSymbol(SymEntry.first());
192  }
193 
194  // Contains the information needed prior to finalization: the object files,
195  // memory manager, resolver, and flags needed for RuntimeDyld.
196  struct PreFinalizeContents {
197  PreFinalizeContents(ObjectPtr Obj, SymbolResolverPtrT Resolver,
198  FinalizerFtor Finalizer, bool ProcessAllSections)
199  : Obj(std::move(Obj)), Resolver(std::move(Resolver)),
200  Finalizer(std::move(Finalizer)),
201  ProcessAllSections(ProcessAllSections) {}
202 
203  ObjectPtr Obj;
204  SymbolResolverPtrT Resolver;
205  FinalizerFtor Finalizer;
206  bool ProcessAllSections;
207  ObjHandleT Handle;
208  RuntimeDyld *RTDyld;
209  };
210 
211  MemoryManagerPtrT MemMgr;
212  std::unique_ptr<PreFinalizeContents> PFC;
213  };
214 
215  template <typename MemoryManagerPtrT, typename SymbolResolverPtrT,
216  typename FinalizerFtor>
217  std::unique_ptr<
218  ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT, FinalizerFtor>>
219  createLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr,
220  SymbolResolverPtrT Resolver,
221  FinalizerFtor Finalizer,
222  bool ProcessAllSections) {
223  using LOS = ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT,
224  FinalizerFtor>;
225  return llvm::make_unique<LOS>(std::move(Obj), std::move(MemMgr),
226  std::move(Resolver), std::move(Finalizer),
227  ProcessAllSections);
228  }
229 
230 public:
231 
232  /// @brief Functor for creating memory managers.
233  using MemoryManagerGetter =
234  std::function<std::shared_ptr<RuntimeDyld::MemoryManager>()>;
235 
236  /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
237  /// and NotifyFinalized functors.
239  MemoryManagerGetter GetMemMgr,
240  NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
241  NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
242  : GetMemMgr(GetMemMgr),
243  NotifyLoaded(std::move(NotifyLoaded)),
244  NotifyFinalized(std::move(NotifyFinalized)),
245  ProcessAllSections(false) {}
246 
247  /// @brief Set the 'ProcessAllSections' flag.
248  ///
249  /// If set to true, all sections in each object file will be allocated using
250  /// the memory manager, rather than just the sections required for execution.
251  ///
252  /// This is kludgy, and may be removed in the future.
253  void setProcessAllSections(bool ProcessAllSections) {
254  this->ProcessAllSections = ProcessAllSections;
255  }
256 
257  /// @brief Add an object to the JIT.
258  ///
259  /// @return A handle that can be used to refer to the loaded object (for
260  /// symbol searching, finalization, freeing memory, etc.).
262  std::shared_ptr<JITSymbolResolver> Resolver) {
263  auto Finalizer = [&](ObjHandleT H, RuntimeDyld &RTDyld,
264  const ObjectPtr &ObjToLoad,
265  std::function<void()> LOSHandleLoad) {
266  std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
267  RTDyld.loadObject(*ObjToLoad->getBinary());
268 
269  LOSHandleLoad();
270 
271  if (this->NotifyLoaded)
272  this->NotifyLoaded(H, ObjToLoad, *Info);
273 
274  RTDyld.finalizeWithMemoryManagerLocking();
275 
276  if (this->NotifyFinalized)
277  this->NotifyFinalized(H);
278  };
279 
280  auto LO =
281  createLinkedObject(std::move(Obj), GetMemMgr(),
282  std::move(Resolver), std::move(Finalizer),
283  ProcessAllSections);
284  // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle
285  // below.
286  auto *LOPtr = LO.get();
287 
288  ObjHandleT Handle = LinkedObjList.insert(LinkedObjList.end(), std::move(LO));
289  LOPtr->setHandle(Handle);
290 
291  return Handle;
292  }
293 
294  /// @brief Remove the object associated with handle H.
295  ///
296  /// All memory allocated for the object will be freed, and the sections and
297  /// symbols it provided will no longer be available. No attempt is made to
298  /// re-emit the missing symbols, and any use of these symbols (directly or
299  /// indirectly) will result in undefined behavior. If dependence tracking is
300  /// required to detect or resolve such issues it should be added at a higher
301  /// layer.
303  // How do we invalidate the symbols in H?
304  LinkedObjList.erase(H);
305  return Error::success();
306  }
307 
308  /// @brief Search for the given named symbol.
309  /// @param Name The name of the symbol to search for.
310  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
311  /// @return A handle for the given named symbol, if it exists.
312  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
313  for (auto I = LinkedObjList.begin(), E = LinkedObjList.end(); I != E;
314  ++I)
315  if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
316  return Symbol;
317 
318  return nullptr;
319  }
320 
321  /// @brief Search for the given named symbol in the context of the loaded
322  /// object represented by the handle H.
323  /// @param H The handle for the object to search in.
324  /// @param Name The name of the symbol to search for.
325  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
326  /// @return A handle for the given named symbol, if it is found in the
327  /// given object.
329  bool ExportedSymbolsOnly) {
330  return (*H)->getSymbol(Name, ExportedSymbolsOnly);
331  }
332 
333  /// @brief Map section addresses for the object associated with the handle H.
334  void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
335  JITTargetAddress TargetAddr) {
336  (*H)->mapSectionAddress(LocalAddress, TargetAddr);
337  }
338 
339  /// @brief Immediately emit and finalize the object represented by the given
340  /// handle.
341  /// @param H Handle for object to emit/finalize.
343  (*H)->finalize();
344  return Error::success();
345  }
346 
347 private:
348 
349  LinkedObjectListT LinkedObjList;
350  MemoryManagerGetter GetMemMgr;
351  NotifyLoadedFtor NotifyLoaded;
352  NotifyFinalizedFtor NotifyFinalized;
353  bool ProcessAllSections = false;
354 };
355 
356 } // end namespace orc
357 } // end namespace llvm
358 
359 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
Information about the loaded object.
Definition: RuntimeDyld.h:69
Error emitAndFinalize(ObjHandleT H)
Immediately emit and finalize the object represented by the given handle.
std::function< void(ObjHandleT, const ObjectPtr &Obj, const RuntimeDyld::LoadedObjectInfo &)> NotifyLoadedFtor
Functor for receiving object-loaded notifications.
Represents a symbol in the JIT.
Definition: JITSymbol.h:159
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly)
Holds an object to be allocated/linked as a unit in the JIT.
std::list< std::unique_ptr< LinkedObject > > LinkedObjectListT
Bare bones object linking layer.
Error takeError()
Take ownership of the stored error.
Definition: Error.h:537
JITEvaluatedSymbol getSymbol(StringRef Name) const
Get the target address and flags for the named symbol.
LinkedObjectListT::iterator ObjHandleT
Handle to a loaded object.
Definition: BitVector.h:920
void mapSectionAddress(ObjHandleT H, const void *LocalAddress, JITTargetAddress TargetAddr)
Map section addresses for the object associated with the handle H.
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
std::function< std::shared_ptr< RuntimeDyld::MemoryManager >()> MemoryManagerGetter
Functor for creating memory managers.
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
Error removeObject(ObjHandleT H)
Remove the object associated with handle H.
R600 Control Flow Finalizer
JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly)
Search for the given named symbol in the context of the loaded object represented by the handle H...
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:37
void setProcessAllSections(bool ProcessAllSections)
By default, only sections that are "required for execution" are passed to the RTDyldMemoryManager, and other sections are discarded.
Definition: RuntimeDyld.h:221
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define H(x, y, z)
Definition: MD5.cpp:57
virtual void mapSectionAddress(const void *LocalAddress, JITTargetAddress TargetAddr) const =0
static JITSymbolFlags fromObjectSymbol(const object::BasicSymbolRef &Symbol)
Construct a JITSymbolFlags value based on the flags of the given libobject symbol.
Definition: JITSymbol.cpp:32
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:962
static ErrorSuccess success()
Create a success value.
Definition: Error.h:313
Expected< JITTargetAddress > getAddress()
Get the address of the symbol in the target address space.
Definition: JITSymbol.h:235
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:224
void setProcessAllSections(bool ProcessAllSections)
Set the &#39;ProcessAllSections&#39; flag.
Represents a symbol that has been evaluated to an address already.
Definition: JITSymbol.h:135
virtual JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name)=0
std::function< Expected< JITTargetAddress >()> GetAddressFtor
Definition: JITSymbol.h:161
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly)
Search for the given named symbol.
#define I(x, y, z)
Definition: MD5.cpp:58
RTDyldObjectLinkingLayer(MemoryManagerGetter GetMemMgr, NotifyLoadedFtor NotifyLoaded=NotifyLoadedFtor(), NotifyFinalizedFtor NotifyFinalized=NotifyFinalizedFtor())
Construct an ObjectLinkingLayer with the given NotifyLoaded, and NotifyFinalized functors.
std::shared_ptr< object::OwningBinary< object::ObjectFile > > ObjectPtr
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Expected< ObjHandleT > addObject(ObjectPtr Obj, std::shared_ptr< JITSymbolResolver > Resolver)
Add an object to the JIT.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
print Print MemDeps of function
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
std::function< void(ObjHandleT)> NotifyFinalizedFtor
Functor for receiving finalization notifications.
void operator=(const LinkedObject &)=delete