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