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