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 <cassert> 27 #include <algorithm> 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 void setHandle(ObjSetHandleT H) { 124 PFC->Handle = H; 125 } 126 127 void finalize() override { 128 assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); 129 130 RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver); 131 RTDyld.setProcessAllSections(PFC->ProcessAllSections); 132 PFC->RTDyld = &RTDyld; 133 134 this->Finalized = true; 135 PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Objects), 136 [&]() { 137 this->updateSymbolTable(RTDyld); 138 }); 139 140 // Release resources. 141 PFC = nullptr; 142 } 143 144 JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override { 145 return 146 [this, Name]() { 147 // The symbol may be materialized between the creation of this lambda 148 // and its execution, so we need to double check. 149 if (!this->Finalized) 150 this->finalize(); 151 return this->getSymbol(Name, false).getAddress(); 152 }; 153 } 154 155 void mapSectionAddress(const void *LocalAddress, 156 JITTargetAddress TargetAddr) const override { 157 assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); 158 assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObjectSet"); 159 PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr); 160 } 161 162 private: 163 void buildInitialSymbolTable(const ObjSetT &Objects) { 164 for (const auto &Obj : Objects) 165 for (auto &Symbol : getObject(*Obj).symbols()) { 166 if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) 167 continue; 168 Expected<StringRef> SymbolName = Symbol.getName(); 169 // FIXME: Raise an error for bad symbols. 170 if (!SymbolName) { 171 consumeError(SymbolName.takeError()); 172 continue; 173 } 174 auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol); 175 SymbolTable.insert( 176 std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags))); 177 } 178 } 179 180 void updateSymbolTable(const RuntimeDyld &RTDyld) { 181 for (auto &SymEntry : SymbolTable) 182 SymEntry.second = RTDyld.getSymbol(SymEntry.first()); 183 } 184 185 // Contains the information needed prior to finalization: the object files, 186 // memory manager, resolver, and flags needed for RuntimeDyld. 187 struct PreFinalizeContents { 188 PreFinalizeContents(ObjSetT Objects, SymbolResolverPtrT Resolver, 189 FinalizerFtor Finalizer, bool ProcessAllSections) 190 : Objects(std::move(Objects)), Resolver(std::move(Resolver)), 191 Finalizer(std::move(Finalizer)), 192 ProcessAllSections(ProcessAllSections) {} 193 194 ObjSetT Objects; 195 SymbolResolverPtrT Resolver; 196 FinalizerFtor Finalizer; 197 bool ProcessAllSections; 198 ObjSetHandleT Handle; 199 RuntimeDyld *RTDyld; 200 }; 201 202 MemoryManagerPtrT MemMgr; 203 std::unique_ptr<PreFinalizeContents> PFC; 204 }; 205 206 template <typename ObjSetT, typename MemoryManagerPtrT, 207 typename SymbolResolverPtrT, typename FinalizerFtor> 208 std::unique_ptr< 209 ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT, 210 SymbolResolverPtrT, FinalizerFtor>> 211 createLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, 212 SymbolResolverPtrT Resolver, 213 FinalizerFtor Finalizer, 214 bool ProcessAllSections) { 215 typedef ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT, 216 SymbolResolverPtrT, FinalizerFtor> LOS; 217 return llvm::make_unique<LOS>(std::move(Objects), std::move(MemMgr), 218 std::move(Resolver), std::move(Finalizer), 219 ProcessAllSections); 220 } 221 222 public: 223 /// @brief LoadedObjectInfo list. Contains a list of owning pointers to 224 /// RuntimeDyld::LoadedObjectInfo instances. 225 typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>> 226 LoadedObjInfoList; 227 228 /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, 229 /// and NotifyFinalized functors. 230 RTDyldObjectLinkingLayer( 231 NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), 232 NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) 233 : NotifyLoaded(std::move(NotifyLoaded)), 234 NotifyFinalized(std::move(NotifyFinalized)), 235 ProcessAllSections(false) {} 236 237 /// @brief Set the 'ProcessAllSections' flag. 238 /// 239 /// If set to true, all sections in each object file will be allocated using 240 /// the memory manager, rather than just the sections required for execution. 241 /// 242 /// This is kludgy, and may be removed in the future. 243 void setProcessAllSections(bool ProcessAllSections) { 244 this->ProcessAllSections = ProcessAllSections; 245 } 246 247 /// @brief Add a set of objects (or archives) that will be treated as a unit 248 /// for the purposes of symbol lookup and memory management. 249 /// 250 /// @return A handle that can be used to refer to the loaded objects (for 251 /// symbol searching, finalization, freeing memory, etc.). 252 template <typename ObjSetT, 253 typename MemoryManagerPtrT, 254 typename SymbolResolverPtrT> 255 ObjSetHandleT addObjectSet(ObjSetT Objects, 256 MemoryManagerPtrT MemMgr, 257 SymbolResolverPtrT Resolver) { 258 auto Finalizer = [&](ObjSetHandleT H, RuntimeDyld &RTDyld, 259 const ObjSetT &Objs, 260 std::function<void()> LOSHandleLoad) { 261 LoadedObjInfoList LoadedObjInfos; 262 263 for (auto &Obj : Objs) 264 LoadedObjInfos.push_back(RTDyld.loadObject(this->getObject(*Obj))); 265 266 LOSHandleLoad(); 267 268 this->NotifyLoaded(H, Objs, LoadedObjInfos); 269 270 RTDyld.finalizeWithMemoryManagerLocking(); 271 272 if (this->NotifyFinalized) 273 this->NotifyFinalized(H); 274 }; 275 276 auto LOS = 277 createLinkedObjectSet(std::move(Objects), std::move(MemMgr), 278 std::move(Resolver), std::move(Finalizer), 279 ProcessAllSections); 280 // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle 281 // below. 282 auto *LOSPtr = LOS.get(); 283 284 ObjSetHandleT Handle = LinkedObjSetList.insert(LinkedObjSetList.end(), 285 std::move(LOS)); 286 LOSPtr->setHandle(Handle); 287 288 return Handle; 289 } 290 291 /// @brief Remove the set of objects associated with handle H. 292 /// 293 /// All memory allocated for the objects will be freed, and the sections and 294 /// symbols they provided will no longer be available. No attempt is made to 295 /// re-emit the missing symbols, and any use of these symbols (directly or 296 /// indirectly) will result in undefined behavior. If dependence tracking is 297 /// required to detect or resolve such issues it should be added at a higher 298 /// layer. 299 void removeObjectSet(ObjSetHandleT H) { 300 // How do we invalidate the symbols in H? 301 LinkedObjSetList.erase(H); 302 } 303 304 /// @brief Search for the given named symbol. 305 /// @param Name The name of the symbol to search for. 306 /// @param ExportedSymbolsOnly If true, search only for exported symbols. 307 /// @return A handle for the given named symbol, if it exists. 308 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { 309 for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E; 310 ++I) 311 if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly)) 312 return Symbol; 313 314 return nullptr; 315 } 316 317 /// @brief Search for the given named symbol in the context of the set of 318 /// loaded objects represented by the handle H. 319 /// @param H The handle for the object set to search in. 320 /// @param Name The name of the symbol to search for. 321 /// @param ExportedSymbolsOnly If true, search only for exported symbols. 322 /// @return A handle for the given named symbol, if it is found in the 323 /// given object set. 324 JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name, 325 bool ExportedSymbolsOnly) { 326 return (*H)->getSymbol(Name, ExportedSymbolsOnly); 327 } 328 329 /// @brief Map section addresses for the objects associated with the handle H. 330 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress, 331 JITTargetAddress TargetAddr) { 332 (*H)->mapSectionAddress(LocalAddress, TargetAddr); 333 } 334 335 /// @brief Immediately emit and finalize the object set represented by the 336 /// given handle. 337 /// @param H Handle for object set to emit/finalize. 338 void emitAndFinalize(ObjSetHandleT H) { 339 (*H)->finalize(); 340 } 341 342 private: 343 static const object::ObjectFile& getObject(const object::ObjectFile &Obj) { 344 return Obj; 345 } 346 347 template <typename ObjT> 348 static const object::ObjectFile& 349 getObject(const object::OwningBinary<ObjT> &Obj) { 350 return *Obj.getBinary(); 351 } 352 353 LinkedObjectSetListT LinkedObjSetList; 354 NotifyLoadedFtor NotifyLoaded; 355 NotifyFinalizedFtor NotifyFinalized; 356 bool ProcessAllSections; 357 }; 358 359 } // end namespace orc 360 } // end namespace llvm 361 362 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H 363