LLVM  7.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"
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 
35 namespace llvm {
36 namespace orc {
37 
39 public:
40 
41  using ObjectPtr =
42  std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
43 
44 protected:
45 
46  /// @brief Holds an object to be allocated/linked as a unit in the JIT.
47  ///
48  /// An instance of this class will be created for each object added
49  /// via JITObjectLayer::addObject. Deleting the instance (via
50  /// removeObject) frees its memory, removing all symbol definitions that
51  /// had been provided by this instance. Higher level layers are responsible
52  /// for taking any action required to handle the missing symbols.
53  class LinkedObject {
54  public:
55  LinkedObject() = default;
56  LinkedObject(const LinkedObject&) = delete;
57  void operator=(const LinkedObject&) = delete;
58  virtual ~LinkedObject() = default;
59 
60  virtual Error finalize() = 0;
61 
63  getSymbolMaterializer(std::string Name) = 0;
64 
65  virtual void mapSectionAddress(const void *LocalAddress,
66  JITTargetAddress TargetAddr) const = 0;
67 
68  JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
69  auto SymEntry = SymbolTable.find(Name);
70  if (SymEntry == SymbolTable.end())
71  return nullptr;
72  if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
73  return nullptr;
74  if (!Finalized)
75  return JITSymbol(getSymbolMaterializer(Name),
76  SymEntry->second.getFlags());
77  return JITSymbol(SymEntry->second);
78  }
79 
80  protected:
82  bool Finalized = false;
83  };
84 };
85 
86 /// @brief Bare bones object linking layer.
87 ///
88 /// This class is intended to be used as the base layer for a JIT. It allows
89 /// object files to be loaded into memory, linked, and the addresses of their
90 /// symbols queried. All objects added to this layer can see each other's
91 /// symbols.
93 public:
94 
96 
97  /// @brief Functor for receiving object-loaded notifications.
98  using NotifyLoadedFtor = std::function<void(
100 
101  /// @brief Functor for receiving finalization notifications.
102  using NotifyFinalizedFtor = std::function<void(VModuleKey)>;
103 
104 private:
105  template <typename MemoryManagerPtrT, typename FinalizerFtor>
106  class ConcreteLinkedObject : public LinkedObject {
107  public:
108  ConcreteLinkedObject(ExecutionSession &ES, ObjectPtr Obj,
109  MemoryManagerPtrT MemMgr,
110  std::shared_ptr<SymbolResolver> Resolver,
111  FinalizerFtor Finalizer, bool ProcessAllSections)
112  : MemMgr(std::move(MemMgr)),
113  PFC(llvm::make_unique<PreFinalizeContents>(
114  ES, std::move(Obj), std::move(Resolver), std::move(Finalizer),
115  ProcessAllSections)) {
116  buildInitialSymbolTable(PFC->Obj);
117  }
118 
119  ~ConcreteLinkedObject() override {
120  MemMgr->deregisterEHFrames();
121  }
122 
123  Error finalize() override {
124  assert(PFC && "mapSectionAddress called on finalized LinkedObject");
125 
126  JITSymbolResolverAdapter ResolverAdapter(PFC->ES, *PFC->Resolver);
127  RuntimeDyld RTDyld(*MemMgr, ResolverAdapter);
128  RTDyld.setProcessAllSections(PFC->ProcessAllSections);
129  PFC->RTDyld = &RTDyld;
130 
131  this->Finalized = true;
132  auto Err = PFC->Finalizer(RTDyld, std::move(PFC->Obj),
133  [&]() { this->updateSymbolTable(RTDyld); });
134 
135  // Release resources.
136  PFC = nullptr;
137  return Err;
138  }
139 
141  return [this, Name]() -> Expected<JITTargetAddress> {
142  // The symbol may be materialized between the creation of this lambda
143  // and its execution, so we need to double check.
144  if (!this->Finalized)
145  if (auto Err = this->finalize())
146  return std::move(Err);
147  return this->getSymbol(Name, false).getAddress();
148  };
149  }
150 
151  void mapSectionAddress(const void *LocalAddress,
152  JITTargetAddress TargetAddr) const override {
153  assert(PFC && "mapSectionAddress called on finalized LinkedObject");
154  assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
155  PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
156  }
157 
158  private:
159 
160  void buildInitialSymbolTable(const ObjectPtr &Obj) {
161  for (auto &Symbol : Obj->getBinary()->symbols()) {
162  if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
163  continue;
165  // FIXME: Raise an error for bad symbols.
166  if (!SymbolName) {
167  consumeError(SymbolName.takeError());
168  continue;
169  }
171  SymbolTable.insert(
172  std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
173  }
174  }
175 
176  void updateSymbolTable(const RuntimeDyld &RTDyld) {
177  for (auto &SymEntry : SymbolTable)
178  SymEntry.second = RTDyld.getSymbol(SymEntry.first());
179  }
180 
181  // Contains the information needed prior to finalization: the object files,
182  // memory manager, resolver, and flags needed for RuntimeDyld.
183  struct PreFinalizeContents {
184  PreFinalizeContents(ExecutionSession &ES, ObjectPtr Obj,
185  std::shared_ptr<SymbolResolver> Resolver,
186  FinalizerFtor Finalizer, bool ProcessAllSections)
187  : ES(ES), Obj(std::move(Obj)), Resolver(std::move(Resolver)),
188  Finalizer(std::move(Finalizer)),
189  ProcessAllSections(ProcessAllSections) {}
190 
191  ExecutionSession &ES;
192  ObjectPtr Obj;
193  std::shared_ptr<SymbolResolver> Resolver;
194  FinalizerFtor Finalizer;
195  bool ProcessAllSections;
196  RuntimeDyld *RTDyld;
197  };
198 
199  MemoryManagerPtrT MemMgr;
200  std::unique_ptr<PreFinalizeContents> PFC;
201  };
202 
203  template <typename MemoryManagerPtrT, typename FinalizerFtor>
204  std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT, FinalizerFtor>>
205  createLinkedObject(ExecutionSession &ES, ObjectPtr Obj,
206  MemoryManagerPtrT MemMgr,
207  std::shared_ptr<SymbolResolver> Resolver,
208  FinalizerFtor Finalizer, bool ProcessAllSections) {
209  using LOS = ConcreteLinkedObject<MemoryManagerPtrT, FinalizerFtor>;
210  return llvm::make_unique<LOS>(ES, std::move(Obj), std::move(MemMgr),
211  std::move(Resolver), std::move(Finalizer),
212  ProcessAllSections);
213  }
214 
215 public:
216  struct Resources {
217  std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
218  std::shared_ptr<SymbolResolver> Resolver;
219  };
220 
221  using ResourcesGetter = std::function<Resources(VModuleKey)>;
222 
223  /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
224  /// and NotifyFinalized functors.
226  ExecutionSession &ES, ResourcesGetter GetResources,
227  NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
228  NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
229  : ES(ES), GetResources(std::move(GetResources)),
230  NotifyLoaded(std::move(NotifyLoaded)),
231  NotifyFinalized(std::move(NotifyFinalized)), ProcessAllSections(false) {
232  }
233 
234  /// @brief Set the 'ProcessAllSections' flag.
235  ///
236  /// If set to true, all sections in each object file will be allocated using
237  /// the memory manager, rather than just the sections required for execution.
238  ///
239  /// This is kludgy, and may be removed in the future.
240  void setProcessAllSections(bool ProcessAllSections) {
241  this->ProcessAllSections = ProcessAllSections;
242  }
243 
244  /// @brief Add an object to the JIT.
246  auto Finalizer = [&, K](RuntimeDyld &RTDyld, const ObjectPtr &ObjToLoad,
247  std::function<void()> LOSHandleLoad) -> Error {
248  std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
249  RTDyld.loadObject(*ObjToLoad->getBinary());
250 
251  LOSHandleLoad();
252 
253  if (this->NotifyLoaded)
254  this->NotifyLoaded(K, ObjToLoad, *Info);
255 
257 
258  if (RTDyld.hasError())
259  return make_error<StringError>(RTDyld.getErrorString(),
261 
262  if (this->NotifyFinalized)
263  this->NotifyFinalized(K);
264 
265  return Error::success();
266  };
267 
268  assert(!LinkedObjects.count(K) && "VModuleKey already in use");
269 
270  auto R = GetResources(K);
271 
272  LinkedObjects[K] = createLinkedObject(
273  ES, std::move(Obj), std::move(R.MemMgr), std::move(R.Resolver),
274  std::move(Finalizer), ProcessAllSections);
275 
276  return Error::success();
277  }
278 
279  /// @brief Remove the object associated with VModuleKey K.
280  ///
281  /// All memory allocated for the object will be freed, and the sections and
282  /// symbols it provided will no longer be available. No attempt is made to
283  /// re-emit the missing symbols, and any use of these symbols (directly or
284  /// indirectly) will result in undefined behavior. If dependence tracking is
285  /// required to detect or resolve such issues it should be added at a higher
286  /// layer.
288  assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
289  // How do we invalidate the symbols in H?
290  LinkedObjects.erase(K);
291  return Error::success();
292  }
293 
294  /// @brief Search for the given named symbol.
295  /// @param Name The name of the symbol to search for.
296  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
297  /// @return A handle for the given named symbol, if it exists.
298  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
299  for (auto &KV : LinkedObjects)
300  if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
301  return Sym;
302  else if (auto Err = Sym.takeError())
303  return std::move(Err);
304 
305  return nullptr;
306  }
307 
308  /// @brief Search for the given named symbol in the context of the loaded
309  /// object represented by the VModuleKey K.
310  /// @param K The VModuleKey for the object to search in.
311  /// @param Name The name of the symbol to search for.
312  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
313  /// @return A handle for the given named symbol, if it is found in the
314  /// given object.
316  bool ExportedSymbolsOnly) {
317  assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
318  return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
319  }
320 
321  /// @brief Map section addresses for the object associated with the
322  /// VModuleKey K.
323  void mapSectionAddress(VModuleKey K, const void *LocalAddress,
324  JITTargetAddress TargetAddr) {
325  assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
326  LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
327  }
328 
329  /// @brief Immediately emit and finalize the object represented by the given
330  /// VModuleKey.
331  /// @param K VModuleKey for object to emit/finalize.
333  assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
334  return LinkedObjects[K]->finalize();
335  }
336 
337 private:
338  ExecutionSession &ES;
339 
340  std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
341  ResourcesGetter GetResources;
342  NotifyLoadedFtor NotifyLoaded;
343  NotifyFinalizedFtor NotifyFinalized;
344  bool ProcessAllSections = false;
345 };
346 
347 } // end namespace orc
348 } // end namespace llvm
349 
350 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
Information about the loaded object.
Definition: RuntimeDyld.h:69
std::unique_ptr< LoadedObjectInfo > loadObject(const object::ObjectFile &O)
Add the referenced object file to the list of objects to be loaded and relocated. ...
Represents a symbol in the JIT.
Definition: JITSymbol.h:180
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.
Error emitAndFinalize(VModuleKey K)
Immediately emit and finalize the object represented by the given VModuleKey.
StringRef getErrorString()
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.
uint64_t VModuleKey
VModuleKey provides a unique identifier (allocated and managed by ExecutionSessions) for a module add...
Definition: Core.h:30
Definition: BitVector.h:921
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
void mapSectionAddress(VModuleKey K, const void *LocalAddress, JITTargetAddress TargetAddr)
Map section addresses for the object associated with the VModuleKey K.
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
R600 Control Flow Finalizer
std::function< void(VModuleKey)> NotifyFinalizedFtor
Functor for receiving finalization notifications.
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:40
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
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
std::function< Resources(VModuleKey)> ResourcesGetter
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:256
An ExecutionSession represents a running JIT program.
Definition: Core.h:310
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:222
void setProcessAllSections(bool ProcessAllSections)
Set the &#39;ProcessAllSections&#39; flag.
Represents a symbol that has been evaluated to an address already.
Definition: JITSymbol.h:154
JITSymbol findSymbolIn(VModuleKey K, StringRef Name, bool ExportedSymbolsOnly)
Search for the given named symbol in the context of the loaded object represented by the VModuleKey K...
virtual JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name)=0
std::function< Expected< JITTargetAddress >()> GetAddressFtor
Definition: JITSymbol.h:182
RTDyldObjectLinkingLayer(ExecutionSession &ES, ResourcesGetter GetResources, NotifyLoadedFtor NotifyLoaded=NotifyLoadedFtor(), NotifyFinalizedFtor NotifyFinalized=NotifyFinalizedFtor())
Construct an ObjectLinkingLayer with the given NotifyLoaded, and NotifyFinalized functors.
std::shared_ptr< RuntimeDyld::MemoryManager > MemMgr
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly)
Search for the given named symbol.
void finalizeWithMemoryManagerLocking()
Perform all actions needed to make the code owned by this RuntimeDyld instance executable: ...
std::shared_ptr< object::OwningBinary< object::ObjectFile > > ObjectPtr
Error removeObject(VModuleKey K)
Remove the object associated with VModuleKey K.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Error addObject(VModuleKey K, ObjectPtr Obj)
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(VModuleKey, const ObjectPtr &Obj, const RuntimeDyld::LoadedObjectInfo &)> NotifyLoadedFtor
Functor for receiving object-loaded notifications.
void operator=(const LinkedObject &)=delete
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:73