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 /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT. 30 /// 31 /// An instance of this class will be created for each set of objects added 32 /// via JITObjectLayer::addObjectSet. Deleting the instance (via 33 /// removeObjectSet) frees its memory, removing all symbol definitions that 34 /// had been provided by this instance. Higher level layers are responsible 35 /// for taking any action required to handle the missing symbols. 36 class LinkedObjectSet { 37 LinkedObjectSet(const LinkedObjectSet&) = delete; 38 void operator=(const LinkedObjectSet&) = delete; 39 public: 40 LinkedObjectSet() = default; ~LinkedObjectSet()41 virtual ~LinkedObjectSet() {} 42 43 virtual void finalize() = 0; 44 45 virtual JITSymbol::GetAddressFtor 46 getSymbolMaterializer(std::string Name) = 0; 47 48 virtual void mapSectionAddress(const void *LocalAddress, 49 TargetAddress TargetAddr) const = 0; 50 getSymbol(StringRef Name,bool ExportedSymbolsOnly)51 JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) { 52 auto SymEntry = SymbolTable.find(Name); 53 if (SymEntry == SymbolTable.end()) 54 return nullptr; 55 if (!SymEntry->second.isExported() && ExportedSymbolsOnly) 56 return nullptr; 57 if (!Finalized) 58 return JITSymbol(getSymbolMaterializer(Name), 59 SymEntry->second.getFlags()); 60 return JITSymbol(SymEntry->second); 61 } 62 protected: 63 StringMap<RuntimeDyld::SymbolInfo> SymbolTable; 64 bool Finalized = false; 65 }; 66 67 typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT; 68 69 public: 70 /// @brief Handle to a set of loaded objects. 71 typedef LinkedObjectSetListT::iterator ObjSetHandleT; 72 }; 73 74 75 /// @brief Default (no-op) action to perform when loading objects. 76 class DoNothingOnNotifyLoaded { 77 public: 78 template <typename ObjSetT, typename LoadResult> operator()79 void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &, 80 const LoadResult &) {} 81 }; 82 83 /// @brief Bare bones object linking layer. 84 /// 85 /// This class is intended to be used as the base layer for a JIT. It allows 86 /// object files to be loaded into memory, linked, and the addresses of their 87 /// symbols queried. All objects added to this layer can see each other's 88 /// symbols. 89 template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded> 90 class ObjectLinkingLayer : public ObjectLinkingLayerBase { 91 public: 92 93 /// @brief Functor for receiving finalization notifications. 94 typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor; 95 96 private: 97 98 template <typename ObjSetT, typename MemoryManagerPtrT, 99 typename SymbolResolverPtrT, typename FinalizerFtor> 100 class ConcreteLinkedObjectSet : public LinkedObjectSet { 101 public: ConcreteLinkedObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver,FinalizerFtor Finalizer,bool ProcessAllSections)102 ConcreteLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, 103 SymbolResolverPtrT Resolver, 104 FinalizerFtor Finalizer, 105 bool ProcessAllSections) 106 : MemMgr(std::move(MemMgr)), 107 PFC(llvm::make_unique<PreFinalizeContents>(std::move(Objects), 108 std::move(Resolver), 109 std::move(Finalizer), 110 ProcessAllSections)) { 111 buildInitialSymbolTable(PFC->Objects); 112 } 113 setHandle(ObjSetHandleT H)114 void setHandle(ObjSetHandleT H) { 115 PFC->Handle = H; 116 } 117 finalize()118 void finalize() override { 119 assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); 120 121 RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver); 122 RTDyld.setProcessAllSections(PFC->ProcessAllSections); 123 PFC->RTDyld = &RTDyld; 124 125 PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Objects), 126 [&]() { 127 this->updateSymbolTable(RTDyld); 128 this->Finalized = true; 129 }); 130 131 // Release resources. 132 PFC = nullptr; 133 } 134 getSymbolMaterializer(std::string Name)135 JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override { 136 return 137 [this, Name]() { 138 // The symbol may be materialized between the creation of this lambda 139 // and its execution, so we need to double check. 140 if (!this->Finalized) 141 this->finalize(); 142 return this->getSymbol(Name, false).getAddress(); 143 }; 144 } 145 mapSectionAddress(const void * LocalAddress,TargetAddress TargetAddr)146 void mapSectionAddress(const void *LocalAddress, 147 TargetAddress TargetAddr) const override { 148 assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); 149 assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObjectSet"); 150 PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr); 151 } 152 153 private: 154 buildInitialSymbolTable(const ObjSetT & Objects)155 void buildInitialSymbolTable(const ObjSetT &Objects) { 156 for (const auto &Obj : Objects) 157 for (auto &Symbol : getObject(*Obj).symbols()) { 158 if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) 159 continue; 160 Expected<StringRef> SymbolName = Symbol.getName(); 161 // FIXME: Raise an error for bad symbols. 162 if (!SymbolName) { 163 consumeError(SymbolName.takeError()); 164 continue; 165 } 166 auto Flags = JITSymbol::flagsFromObjectSymbol(Symbol); 167 SymbolTable.insert( 168 std::make_pair(*SymbolName, RuntimeDyld::SymbolInfo(0, Flags))); 169 } 170 } 171 updateSymbolTable(const RuntimeDyld & RTDyld)172 void updateSymbolTable(const RuntimeDyld &RTDyld) { 173 for (auto &SymEntry : SymbolTable) 174 SymEntry.second = RTDyld.getSymbol(SymEntry.first()); 175 } 176 177 // Contains the information needed prior to finalization: the object files, 178 // memory manager, resolver, and flags needed for RuntimeDyld. 179 struct PreFinalizeContents { PreFinalizeContentsPreFinalizeContents180 PreFinalizeContents(ObjSetT Objects, SymbolResolverPtrT Resolver, 181 FinalizerFtor Finalizer, bool ProcessAllSections) 182 : Objects(std::move(Objects)), Resolver(std::move(Resolver)), 183 Finalizer(std::move(Finalizer)), 184 ProcessAllSections(ProcessAllSections) {} 185 186 ObjSetT Objects; 187 SymbolResolverPtrT Resolver; 188 FinalizerFtor Finalizer; 189 bool ProcessAllSections; 190 ObjSetHandleT Handle; 191 RuntimeDyld *RTDyld; 192 }; 193 194 MemoryManagerPtrT MemMgr; 195 std::unique_ptr<PreFinalizeContents> PFC; 196 }; 197 198 template <typename ObjSetT, typename MemoryManagerPtrT, 199 typename SymbolResolverPtrT, typename FinalizerFtor> 200 std::unique_ptr< 201 ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT, 202 SymbolResolverPtrT, FinalizerFtor>> createLinkedObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver,FinalizerFtor Finalizer,bool ProcessAllSections)203 createLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, 204 SymbolResolverPtrT Resolver, 205 FinalizerFtor Finalizer, 206 bool ProcessAllSections) { 207 typedef ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT, 208 SymbolResolverPtrT, FinalizerFtor> LOS; 209 return llvm::make_unique<LOS>(std::move(Objects), std::move(MemMgr), 210 std::move(Resolver), std::move(Finalizer), 211 ProcessAllSections); 212 } 213 214 public: 215 216 /// @brief LoadedObjectInfo list. Contains a list of owning pointers to 217 /// RuntimeDyld::LoadedObjectInfo instances. 218 typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>> 219 LoadedObjInfoList; 220 221 /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, 222 /// and NotifyFinalized functors. 223 ObjectLinkingLayer( 224 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), 225 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) NotifyLoaded(std::move (NotifyLoaded))226 : NotifyLoaded(std::move(NotifyLoaded)), 227 NotifyFinalized(std::move(NotifyFinalized)), 228 ProcessAllSections(false) {} 229 230 /// @brief Set the 'ProcessAllSections' flag. 231 /// 232 /// If set to true, all sections in each object file will be allocated using 233 /// the memory manager, rather than just the sections required for execution. 234 /// 235 /// This is kludgy, and may be removed in the future. setProcessAllSections(bool ProcessAllSections)236 void setProcessAllSections(bool ProcessAllSections) { 237 this->ProcessAllSections = ProcessAllSections; 238 } 239 240 /// @brief Add a set of objects (or archives) that will be treated as a unit 241 /// for the purposes of symbol lookup and memory management. 242 /// 243 /// @return A handle that can be used to refer to the loaded objects (for 244 /// symbol searching, finalization, freeing memory, etc.). 245 template <typename ObjSetT, 246 typename MemoryManagerPtrT, 247 typename SymbolResolverPtrT> addObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver)248 ObjSetHandleT addObjectSet(ObjSetT Objects, 249 MemoryManagerPtrT MemMgr, 250 SymbolResolverPtrT Resolver) { 251 252 auto Finalizer = [&](ObjSetHandleT H, RuntimeDyld &RTDyld, 253 const ObjSetT &Objs, 254 std::function<void()> LOSHandleLoad) { 255 LoadedObjInfoList LoadedObjInfos; 256 257 for (auto &Obj : Objs) 258 LoadedObjInfos.push_back(RTDyld.loadObject(this->getObject(*Obj))); 259 260 LOSHandleLoad(); 261 262 this->NotifyLoaded(H, Objs, LoadedObjInfos); 263 264 RTDyld.finalizeWithMemoryManagerLocking(); 265 266 if (this->NotifyFinalized) 267 this->NotifyFinalized(H); 268 }; 269 270 auto LOS = 271 createLinkedObjectSet(std::move(Objects), std::move(MemMgr), 272 std::move(Resolver), std::move(Finalizer), 273 ProcessAllSections); 274 // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle 275 // below. 276 auto *LOSPtr = LOS.get(); 277 278 ObjSetHandleT Handle = LinkedObjSetList.insert(LinkedObjSetList.end(), 279 std::move(LOS)); 280 LOSPtr->setHandle(Handle); 281 282 return Handle; 283 } 284 285 /// @brief Remove the set of objects associated with handle H. 286 /// 287 /// All memory allocated for the objects will be freed, and the sections and 288 /// symbols they provided will no longer be available. No attempt is made to 289 /// re-emit the missing symbols, and any use of these symbols (directly or 290 /// indirectly) will result in undefined behavior. If dependence tracking is 291 /// required to detect or resolve such issues it should be added at a higher 292 /// layer. removeObjectSet(ObjSetHandleT H)293 void removeObjectSet(ObjSetHandleT H) { 294 // How do we invalidate the symbols in H? 295 LinkedObjSetList.erase(H); 296 } 297 298 /// @brief Search for the given named symbol. 299 /// @param Name The name of the symbol to search for. 300 /// @param ExportedSymbolsOnly If true, search only for exported symbols. 301 /// @return A handle for the given named symbol, if it exists. findSymbol(StringRef Name,bool ExportedSymbolsOnly)302 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { 303 for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E; 304 ++I) 305 if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly)) 306 return Symbol; 307 308 return nullptr; 309 } 310 311 /// @brief Search for the given named symbol in the context of the set of 312 /// loaded objects represented by the handle H. 313 /// @param H The handle for the object set to search in. 314 /// @param Name The name of the symbol to search for. 315 /// @param ExportedSymbolsOnly If true, search only for exported symbols. 316 /// @return A handle for the given named symbol, if it is found in the 317 /// given object set. findSymbolIn(ObjSetHandleT H,StringRef Name,bool ExportedSymbolsOnly)318 JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name, 319 bool ExportedSymbolsOnly) { 320 return (*H)->getSymbol(Name, ExportedSymbolsOnly); 321 } 322 323 /// @brief Map section addresses for the objects associated with the handle H. mapSectionAddress(ObjSetHandleT H,const void * LocalAddress,TargetAddress TargetAddr)324 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress, 325 TargetAddress TargetAddr) { 326 (*H)->mapSectionAddress(LocalAddress, TargetAddr); 327 } 328 329 /// @brief Immediately emit and finalize the object set represented by the 330 /// given handle. 331 /// @param H Handle for object set to emit/finalize. emitAndFinalize(ObjSetHandleT H)332 void emitAndFinalize(ObjSetHandleT H) { 333 (*H)->finalize(); 334 } 335 336 private: 337 getObject(const object::ObjectFile & Obj)338 static const object::ObjectFile& getObject(const object::ObjectFile &Obj) { 339 return Obj; 340 } 341 342 template <typename ObjT> 343 static const object::ObjectFile& getObject(const object::OwningBinary<ObjT> & Obj)344 getObject(const object::OwningBinary<ObjT> &Obj) { 345 return *Obj.getBinary(); 346 } 347 348 LinkedObjectSetListT LinkedObjSetList; 349 NotifyLoadedFtor NotifyLoaded; 350 NotifyFinalizedFtor NotifyFinalized; 351 bool ProcessAllSections; 352 }; 353 354 } // End namespace orc. 355 } // End namespace llvm 356 357 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H 358