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