• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
20 #include "llvm/ExecutionEngine/JITSymbol.h"
21 #include "llvm/ExecutionEngine/Orc/Core.h"
22 #include "llvm/ExecutionEngine/Orc/Layer.h"
23 #include "llvm/ExecutionEngine/Orc/Legacy.h"
24 #include "llvm/ExecutionEngine/RuntimeDyld.h"
25 #include "llvm/Object/ObjectFile.h"
26 #include "llvm/Support/Error.h"
27 #include <algorithm>
28 #include <cassert>
29 #include <functional>
30 #include <list>
31 #include <memory>
32 #include <string>
33 #include <utility>
34 #include <vector>
35 
36 namespace llvm {
37 namespace orc {
38 
39 class RTDyldObjectLinkingLayer2 : public ObjectLayer {
40 public:
41   /// Functor for receiving object-loaded notifications.
42   using NotifyLoadedFunction =
43       std::function<void(VModuleKey, const object::ObjectFile &Obj,
44                          const RuntimeDyld::LoadedObjectInfo &)>;
45 
46   /// Functor for receiving finalization notifications.
47   using NotifyFinalizedFunction = std::function<void(VModuleKey)>;
48 
49   using GetMemoryManagerFunction =
50       std::function<std::shared_ptr<RuntimeDyld::MemoryManager>(VModuleKey)>;
51 
52   /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
53   ///        and NotifyFinalized functors.
54   RTDyldObjectLinkingLayer2(
55       ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager,
56       NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
57       NotifyFinalizedFunction NotifyFinalized = NotifyFinalizedFunction());
58 
59   /// Emit the object.
60   void emit(MaterializationResponsibility R, VModuleKey K,
61             std::unique_ptr<MemoryBuffer> O) override;
62 
63   /// Map section addresses for the object associated with the
64   ///        VModuleKey K.
65   void mapSectionAddress(VModuleKey K, const void *LocalAddress,
66                          JITTargetAddress TargetAddr) const;
67 
68   /// Set the 'ProcessAllSections' flag.
69   ///
70   /// If set to true, all sections in each object file will be allocated using
71   /// the memory manager, rather than just the sections required for execution.
72   ///
73   /// This is kludgy, and may be removed in the future.
setProcessAllSections(bool ProcessAllSections)74   void setProcessAllSections(bool ProcessAllSections) {
75     this->ProcessAllSections = ProcessAllSections;
76   }
77 
78 private:
79   mutable std::mutex RTDyldLayerMutex;
80   GetMemoryManagerFunction GetMemoryManager;
81   NotifyLoadedFunction NotifyLoaded;
82   NotifyFinalizedFunction NotifyFinalized;
83   bool ProcessAllSections;
84   std::map<VModuleKey, RuntimeDyld *> ActiveRTDylds;
85   std::map<VModuleKey, std::shared_ptr<RuntimeDyld::MemoryManager>> MemMgrs;
86 };
87 
88 class RTDyldObjectLinkingLayerBase {
89 public:
90   using ObjectPtr = std::unique_ptr<MemoryBuffer>;
91 
92 protected:
93 
94   /// Holds an object to be allocated/linked as a unit in the JIT.
95   ///
96   /// An instance of this class will be created for each object added
97   /// via JITObjectLayer::addObject. Deleting the instance (via
98   /// removeObject) frees its memory, removing all symbol definitions that
99   /// had been provided by this instance. Higher level layers are responsible
100   /// for taking any action required to handle the missing symbols.
101   class LinkedObject {
102   public:
103     LinkedObject() = default;
104     LinkedObject(const LinkedObject&) = delete;
105     void operator=(const LinkedObject&) = delete;
106     virtual ~LinkedObject() = default;
107 
108     virtual Error finalize() = 0;
109 
110     virtual JITSymbol::GetAddressFtor
111     getSymbolMaterializer(std::string Name) = 0;
112 
113     virtual void mapSectionAddress(const void *LocalAddress,
114                                    JITTargetAddress TargetAddr) const = 0;
115 
getSymbol(StringRef Name,bool ExportedSymbolsOnly)116     JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
117       auto SymEntry = SymbolTable.find(Name);
118       if (SymEntry == SymbolTable.end())
119         return nullptr;
120       if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
121         return nullptr;
122       if (!Finalized)
123         return JITSymbol(getSymbolMaterializer(Name),
124                          SymEntry->second.getFlags());
125       return JITSymbol(SymEntry->second);
126     }
127 
128   protected:
129     StringMap<JITEvaluatedSymbol> SymbolTable;
130     bool Finalized = false;
131   };
132 };
133 
134 /// Bare bones object linking layer.
135 ///
136 ///   This class is intended to be used as the base layer for a JIT. It allows
137 /// object files to be loaded into memory, linked, and the addresses of their
138 /// symbols queried. All objects added to this layer can see each other's
139 /// symbols.
140 class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
141 public:
142 
143   using RTDyldObjectLinkingLayerBase::ObjectPtr;
144 
145   /// Functor for receiving object-loaded notifications.
146   using NotifyLoadedFtor =
147       std::function<void(VModuleKey, const object::ObjectFile &Obj,
148                          const RuntimeDyld::LoadedObjectInfo &)>;
149 
150   /// Functor for receiving finalization notifications.
151   using NotifyFinalizedFtor =
152       std::function<void(VModuleKey, const object::ObjectFile &Obj,
153                          const RuntimeDyld::LoadedObjectInfo &)>;
154 
155   /// Functor for receiving deallocation notifications.
156   using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
157 
158 private:
159   using OwnedObject = object::OwningBinary<object::ObjectFile>;
160 
161   template <typename MemoryManagerPtrT>
162   class ConcreteLinkedObject : public LinkedObject {
163   public:
ConcreteLinkedObject(RTDyldObjectLinkingLayer & Parent,VModuleKey K,OwnedObject Obj,MemoryManagerPtrT MemMgr,std::shared_ptr<SymbolResolver> Resolver,bool ProcessAllSections)164     ConcreteLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
165                          OwnedObject Obj, MemoryManagerPtrT MemMgr,
166                          std::shared_ptr<SymbolResolver> Resolver,
167                          bool ProcessAllSections)
168         : K(std::move(K)),
169           Parent(Parent),
170           MemMgr(std::move(MemMgr)),
171           PFC(llvm::make_unique<PreFinalizeContents>(
172               std::move(Obj), std::move(Resolver),
173               ProcessAllSections)) {
174       buildInitialSymbolTable(PFC->Obj);
175     }
176 
~ConcreteLinkedObject()177     ~ConcreteLinkedObject() override {
178       if (this->Parent.NotifyFreed)
179         this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
180 
181       MemMgr->deregisterEHFrames();
182     }
183 
finalize()184     Error finalize() override {
185       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
186 
187       JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
188 					       nullptr);
189       PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
190       PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
191 
192       Finalized = true;
193 
194       std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
195           PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
196 
197       // Copy the symbol table out of the RuntimeDyld instance.
198       {
199         auto SymTab = PFC->RTDyld->getSymbolTable();
200         for (auto &KV : SymTab)
201           SymbolTable[KV.first] = KV.second;
202       }
203 
204       if (Parent.NotifyLoaded)
205         Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
206 
207       PFC->RTDyld->finalizeWithMemoryManagerLocking();
208 
209       if (PFC->RTDyld->hasError())
210         return make_error<StringError>(PFC->RTDyld->getErrorString(),
211                                        inconvertibleErrorCode());
212 
213       if (Parent.NotifyFinalized)
214         Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
215 
216       // Release resources.
217       if (this->Parent.NotifyFreed)
218         ObjForNotify = std::move(PFC->Obj); // needed for callback
219       PFC = nullptr;
220       return Error::success();
221     }
222 
getSymbolMaterializer(std::string Name)223     JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
224       return [this, Name]() -> Expected<JITTargetAddress> {
225         // The symbol may be materialized between the creation of this lambda
226         // and its execution, so we need to double check.
227         if (!this->Finalized)
228           if (auto Err = this->finalize())
229             return std::move(Err);
230         return this->getSymbol(Name, false).getAddress();
231       };
232     }
233 
mapSectionAddress(const void * LocalAddress,JITTargetAddress TargetAddr)234     void mapSectionAddress(const void *LocalAddress,
235                            JITTargetAddress TargetAddr) const override {
236       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
237       assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
238       PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
239     }
240 
241   private:
buildInitialSymbolTable(const OwnedObject & Obj)242     void buildInitialSymbolTable(const OwnedObject &Obj) {
243       for (auto &Symbol : Obj.getBinary()->symbols()) {
244         if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
245           continue;
246         Expected<StringRef> SymbolName = Symbol.getName();
247         // FIXME: Raise an error for bad symbols.
248         if (!SymbolName) {
249           consumeError(SymbolName.takeError());
250           continue;
251         }
252         auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
253         SymbolTable.insert(
254           std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
255       }
256     }
257 
258     // Contains the information needed prior to finalization: the object files,
259     // memory manager, resolver, and flags needed for RuntimeDyld.
260     struct PreFinalizeContents {
PreFinalizeContentsPreFinalizeContents261       PreFinalizeContents(OwnedObject Obj,
262                           std::shared_ptr<SymbolResolver> Resolver,
263                           bool ProcessAllSections)
264           : Obj(std::move(Obj)),
265             Resolver(std::move(Resolver)),
266             ProcessAllSections(ProcessAllSections) {}
267 
268       OwnedObject Obj;
269       std::shared_ptr<SymbolResolver> Resolver;
270       bool ProcessAllSections;
271       std::unique_ptr<RuntimeDyld> RTDyld;
272     };
273 
274     VModuleKey K;
275     RTDyldObjectLinkingLayer &Parent;
276     MemoryManagerPtrT MemMgr;
277     OwnedObject ObjForNotify;
278     std::unique_ptr<PreFinalizeContents> PFC;
279   };
280 
281   template <typename MemoryManagerPtrT>
282   std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
createLinkedObject(RTDyldObjectLinkingLayer & Parent,VModuleKey K,OwnedObject Obj,MemoryManagerPtrT MemMgr,std::shared_ptr<SymbolResolver> Resolver,bool ProcessAllSections)283   createLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
284                      OwnedObject Obj, MemoryManagerPtrT MemMgr,
285                      std::shared_ptr<SymbolResolver> Resolver,
286                      bool ProcessAllSections) {
287     using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
288     return llvm::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
289                                   std::move(MemMgr), std::move(Resolver),
290                                   ProcessAllSections);
291   }
292 
293 public:
294   struct Resources {
295     std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
296     std::shared_ptr<SymbolResolver> Resolver;
297   };
298 
299   using ResourcesGetter = std::function<Resources(VModuleKey)>;
300 
301   /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
302   ///        and NotifyFinalized functors.
303   RTDyldObjectLinkingLayer(
304       ExecutionSession &ES, ResourcesGetter GetResources,
305       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
306       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
307       NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
ES(ES)308       : ES(ES), GetResources(std::move(GetResources)),
309         NotifyLoaded(std::move(NotifyLoaded)),
310         NotifyFinalized(std::move(NotifyFinalized)),
311         NotifyFreed(std::move(NotifyFreed)),
312         ProcessAllSections(false) {
313   }
314 
315   /// Set the 'ProcessAllSections' flag.
316   ///
317   /// If set to true, all sections in each object file will be allocated using
318   /// the memory manager, rather than just the sections required for execution.
319   ///
320   /// This is kludgy, and may be removed in the future.
setProcessAllSections(bool ProcessAllSections)321   void setProcessAllSections(bool ProcessAllSections) {
322     this->ProcessAllSections = ProcessAllSections;
323   }
324 
325   /// Add an object to the JIT.
addObject(VModuleKey K,ObjectPtr ObjBuffer)326   Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
327 
328     auto Obj =
329         object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
330     if (!Obj)
331       return Obj.takeError();
332 
333     assert(!LinkedObjects.count(K) && "VModuleKey already in use");
334 
335     auto R = GetResources(K);
336 
337     LinkedObjects[K] = createLinkedObject(
338         *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
339         std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
340 
341     return Error::success();
342   }
343 
344   /// Remove the object associated with VModuleKey K.
345   ///
346   ///   All memory allocated for the object will be freed, and the sections and
347   /// symbols it provided will no longer be available. No attempt is made to
348   /// re-emit the missing symbols, and any use of these symbols (directly or
349   /// indirectly) will result in undefined behavior. If dependence tracking is
350   /// required to detect or resolve such issues it should be added at a higher
351   /// layer.
removeObject(VModuleKey K)352   Error removeObject(VModuleKey K) {
353     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
354     // How do we invalidate the symbols in H?
355     LinkedObjects.erase(K);
356     return Error::success();
357   }
358 
359   /// Search for the given named symbol.
360   /// @param Name The name of the symbol to search for.
361   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
362   /// @return A handle for the given named symbol, if it exists.
findSymbol(StringRef Name,bool ExportedSymbolsOnly)363   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
364     for (auto &KV : LinkedObjects)
365       if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
366         return Sym;
367       else if (auto Err = Sym.takeError())
368         return std::move(Err);
369 
370     return nullptr;
371   }
372 
373   /// Search for the given named symbol in the context of the loaded
374   ///        object represented by the VModuleKey K.
375   /// @param K The VModuleKey for the object to search in.
376   /// @param Name The name of the symbol to search for.
377   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
378   /// @return A handle for the given named symbol, if it is found in the
379   ///         given object.
findSymbolIn(VModuleKey K,StringRef Name,bool ExportedSymbolsOnly)380   JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
381                          bool ExportedSymbolsOnly) {
382     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
383     return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
384   }
385 
386   /// Map section addresses for the object associated with the
387   ///        VModuleKey K.
mapSectionAddress(VModuleKey K,const void * LocalAddress,JITTargetAddress TargetAddr)388   void mapSectionAddress(VModuleKey K, const void *LocalAddress,
389                          JITTargetAddress TargetAddr) {
390     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
391     LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
392   }
393 
394   /// Immediately emit and finalize the object represented by the given
395   ///        VModuleKey.
396   /// @param K VModuleKey for object to emit/finalize.
emitAndFinalize(VModuleKey K)397   Error emitAndFinalize(VModuleKey K) {
398     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
399     return LinkedObjects[K]->finalize();
400   }
401 
402 private:
403   ExecutionSession &ES;
404 
405   std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
406   ResourcesGetter GetResources;
407   NotifyLoadedFtor NotifyLoaded;
408   NotifyFinalizedFtor NotifyFinalized;
409   NotifyFreedFtor NotifyFreed;
410   bool ProcessAllSections = false;
411 };
412 
413 } // end namespace orc
414 } // end namespace llvm
415 
416 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
417