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