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