1 //===- ObjectLinkingLayer.h - Add object files to a JIT process -*- 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 the object layer of the JIT.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
15 #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
16 
17 #include "JITSymbol.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ExecutionEngine/ExecutionEngine.h"
20 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
21 #include <list>
22 #include <memory>
23 
24 namespace llvm {
25 namespace orc {
26 
27 class ObjectLinkingLayerBase {
28 protected:
29 
30   /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT.
31   ///
32   /// An instance of this class will be created for each set of objects added
33   /// via JITObjectLayer::addObjectSet. Deleting the instance (via
34   /// removeObjectSet) frees its memory, removing all symbol definitions that
35   /// had been provided by this instance. Higher level layers are responsible
36   /// for taking any action required to handle the missing symbols.
37   class LinkedObjectSet {
38     LinkedObjectSet(const LinkedObjectSet&) = delete;
39     void operator=(const LinkedObjectSet&) = delete;
40   public:
LinkedObjectSet(RuntimeDyld::MemoryManager & MemMgr,RuntimeDyld::SymbolResolver & Resolver,bool ProcessAllSections)41     LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr,
42                     RuntimeDyld::SymbolResolver &Resolver,
43                     bool ProcessAllSections)
44         : RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)),
45           State(Raw) {
46       RTDyld->setProcessAllSections(ProcessAllSections);
47     }
48 
~LinkedObjectSet()49     virtual ~LinkedObjectSet() {}
50 
51     std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
addObject(const object::ObjectFile & Obj)52     addObject(const object::ObjectFile &Obj) {
53       return RTDyld->loadObject(Obj);
54     }
55 
getSymbol(StringRef Name)56     RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const {
57       return RTDyld->getSymbol(Name);
58     }
59 
NeedsFinalization()60     bool NeedsFinalization() const { return (State == Raw); }
61 
62     virtual void Finalize() = 0;
63 
mapSectionAddress(const void * LocalAddress,TargetAddress TargetAddr)64     void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) {
65       assert((State != Finalized) &&
66              "Attempting to remap sections for finalized objects.");
67       RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
68     }
69 
70   protected:
71     std::unique_ptr<RuntimeDyld> RTDyld;
72     enum { Raw, Finalizing, Finalized } State;
73   };
74 
75   typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT;
76 
77 public:
78   /// @brief Handle to a set of loaded objects.
79   typedef LinkedObjectSetListT::iterator ObjSetHandleT;
80 };
81 
82 /// @brief Default (no-op) action to perform when loading objects.
83 class DoNothingOnNotifyLoaded {
84 public:
85   template <typename ObjSetT, typename LoadResult>
operator()86   void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
87                   const LoadResult &) {}
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.
96 template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
97 class ObjectLinkingLayer : public ObjectLinkingLayerBase {
98 private:
99 
100   template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
101   class ConcreteLinkedObjectSet : public LinkedObjectSet {
102   public:
ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver,bool ProcessAllSections)103     ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr,
104                             SymbolResolverPtrT Resolver,
105                             bool ProcessAllSections)
106       : LinkedObjectSet(*MemMgr, *Resolver, ProcessAllSections),
107         MemMgr(std::move(MemMgr)), Resolver(std::move(Resolver)) { }
108 
Finalize()109     void Finalize() override {
110       State = Finalizing;
111       RTDyld->resolveRelocations();
112       RTDyld->registerEHFrames();
113       MemMgr->finalizeMemory();
114       State = Finalized;
115     }
116 
117   private:
118     MemoryManagerPtrT MemMgr;
119     SymbolResolverPtrT Resolver;
120   };
121 
122   template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
123   std::unique_ptr<LinkedObjectSet>
createLinkedObjectSet(MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver,bool ProcessAllSections)124   createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver,
125                         bool ProcessAllSections) {
126     typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS;
127     return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver),
128                                   ProcessAllSections);
129   }
130 
131 public:
132 
133   /// @brief LoadedObjectInfo list. Contains a list of owning pointers to
134   ///        RuntimeDyld::LoadedObjectInfo instances.
135   typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
136       LoadedObjInfoList;
137 
138   /// @brief Functor for receiving finalization notifications.
139   typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;
140 
141   /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
142   ///        and NotifyFinalized functors.
143   ObjectLinkingLayer(
144       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
145       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
NotifyLoaded(std::move (NotifyLoaded))146       : NotifyLoaded(std::move(NotifyLoaded)),
147         NotifyFinalized(std::move(NotifyFinalized)),
148         ProcessAllSections(false) {}
149 
150   /// @brief Set the 'ProcessAllSections' flag.
151   ///
152   /// If set to true, all sections in each object file will be allocated using
153   /// the memory manager, rather than just the sections required for execution.
154   ///
155   /// This is kludgy, and may be removed in the future.
setProcessAllSections(bool ProcessAllSections)156   void setProcessAllSections(bool ProcessAllSections) {
157     this->ProcessAllSections = ProcessAllSections;
158   }
159 
160   /// @brief Add a set of objects (or archives) that will be treated as a unit
161   ///        for the purposes of symbol lookup and memory management.
162   ///
163   /// @return A pair containing (1) A handle that can be used to free the memory
164   ///         allocated for the objects, and (2) a LoadedObjInfoList containing
165   ///         one LoadedObjInfo instance for each object at the corresponding
166   ///         index in the Objects list.
167   ///
168   ///   This version of this method allows the client to pass in an
169   /// RTDyldMemoryManager instance that will be used to allocate memory and look
170   /// up external symbol addresses for the given objects.
171   template <typename ObjSetT,
172             typename MemoryManagerPtrT,
173             typename SymbolResolverPtrT>
addObjectSet(const ObjSetT & Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver)174   ObjSetHandleT addObjectSet(const ObjSetT &Objects,
175                              MemoryManagerPtrT MemMgr,
176                              SymbolResolverPtrT Resolver) {
177     ObjSetHandleT Handle =
178       LinkedObjSetList.insert(
179         LinkedObjSetList.end(),
180         createLinkedObjectSet(std::move(MemMgr), std::move(Resolver),
181                               ProcessAllSections));
182 
183     LinkedObjectSet &LOS = **Handle;
184     LoadedObjInfoList LoadedObjInfos;
185 
186     for (auto &Obj : Objects)
187       LoadedObjInfos.push_back(LOS.addObject(*Obj));
188 
189     NotifyLoaded(Handle, Objects, LoadedObjInfos);
190 
191     return Handle;
192   }
193 
194   /// @brief Remove the set of objects associated with handle H.
195   ///
196   ///   All memory allocated for the objects will be freed, and the sections and
197   /// symbols they provided will no longer be available. No attempt is made to
198   /// re-emit the missing symbols, and any use of these symbols (directly or
199   /// indirectly) will result in undefined behavior. If dependence tracking is
200   /// required to detect or resolve such issues it should be added at a higher
201   /// layer.
removeObjectSet(ObjSetHandleT H)202   void removeObjectSet(ObjSetHandleT H) {
203     // How do we invalidate the symbols in H?
204     LinkedObjSetList.erase(H);
205   }
206 
207   /// @brief Search for the given named symbol.
208   /// @param Name The name of the symbol to search for.
209   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
210   /// @return A handle for the given named symbol, if it exists.
findSymbol(StringRef Name,bool ExportedSymbolsOnly)211   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
212     for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
213          ++I)
214       if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
215         return Symbol;
216 
217     return nullptr;
218   }
219 
220   /// @brief Search for the given named symbol in the context of the set of
221   ///        loaded objects represented by the handle H.
222   /// @param H The handle for the object set to search in.
223   /// @param Name The name of the symbol to search for.
224   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
225   /// @return A handle for the given named symbol, if it is found in the
226   ///         given object set.
findSymbolIn(ObjSetHandleT H,StringRef Name,bool ExportedSymbolsOnly)227   JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
228                          bool ExportedSymbolsOnly) {
229     if (auto Sym = (*H)->getSymbol(Name)) {
230       if (Sym.isExported() || !ExportedSymbolsOnly) {
231         auto Addr = Sym.getAddress();
232         auto Flags = Sym.getFlags();
233         if (!(*H)->NeedsFinalization()) {
234           // If this instance has already been finalized then we can just return
235           // the address.
236           return JITSymbol(Addr, Flags);
237         } else {
238           // If this instance needs finalization return a functor that will do
239           // it. The functor still needs to double-check whether finalization is
240           // required, in case someone else finalizes this set before the
241           // functor is called.
242           auto GetAddress =
243             [this, Addr, H]() {
244               if ((*H)->NeedsFinalization()) {
245                 (*H)->Finalize();
246                 if (NotifyFinalized)
247                   NotifyFinalized(H);
248               }
249               return Addr;
250             };
251           return JITSymbol(std::move(GetAddress), Flags);
252         }
253       }
254     }
255     return nullptr;
256   }
257 
258   /// @brief Map section addresses for the objects associated with the handle H.
mapSectionAddress(ObjSetHandleT H,const void * LocalAddress,TargetAddress TargetAddr)259   void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
260                          TargetAddress TargetAddr) {
261     (*H)->mapSectionAddress(LocalAddress, TargetAddr);
262   }
263 
264   /// @brief Immediately emit and finalize the object set represented by the
265   ///        given handle.
266   /// @param H Handle for object set to emit/finalize.
emitAndFinalize(ObjSetHandleT H)267   void emitAndFinalize(ObjSetHandleT H) {
268     (*H)->Finalize();
269     if (NotifyFinalized)
270       NotifyFinalized(H);
271   }
272 
273 private:
274   LinkedObjectSetListT LinkedObjSetList;
275   NotifyLoadedFtor NotifyLoaded;
276   NotifyFinalizedFtor NotifyFinalized;
277   bool ProcessAllSections;
278 };
279 
280 } // End namespace orc.
281 } // End namespace llvm
282 
283 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
284