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