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