| //===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking ---*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Contains the definition for an RTDyld-based, in-process object linking layer. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H |
| #define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H |
| |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ExecutionEngine/JITSymbol.h" |
| #include "llvm/ExecutionEngine/RuntimeDyld.h" |
| #include "llvm/Object/ObjectFile.h" |
| #include "llvm/Support/Error.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <functional> |
| #include <list> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| namespace llvm { |
| namespace orc { |
| |
| class RTDyldObjectLinkingLayerBase { |
| public: |
| |
| using ObjectPtr = |
| std::shared_ptr<object::OwningBinary<object::ObjectFile>>; |
| |
| protected: |
| |
| /// @brief Holds an object to be allocated/linked as a unit in the JIT. |
| /// |
| /// An instance of this class will be created for each object added |
| /// via JITObjectLayer::addObject. Deleting the instance (via |
| /// removeObject) frees its memory, removing all symbol definitions that |
| /// had been provided by this instance. Higher level layers are responsible |
| /// for taking any action required to handle the missing symbols. |
| class LinkedObject { |
| public: |
| LinkedObject() = default; |
| LinkedObject(const LinkedObject&) = delete; |
| void operator=(const LinkedObject&) = delete; |
| virtual ~LinkedObject() = default; |
| |
| virtual void finalize() = 0; |
| |
| virtual JITSymbol::GetAddressFtor |
| getSymbolMaterializer(std::string Name) = 0; |
| |
| virtual void mapSectionAddress(const void *LocalAddress, |
| JITTargetAddress TargetAddr) const = 0; |
| |
| JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) { |
| auto SymEntry = SymbolTable.find(Name); |
| if (SymEntry == SymbolTable.end()) |
| return nullptr; |
| if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly) |
| return nullptr; |
| if (!Finalized) |
| return JITSymbol(getSymbolMaterializer(Name), |
| SymEntry->second.getFlags()); |
| return JITSymbol(SymEntry->second); |
| } |
| |
| protected: |
| StringMap<JITEvaluatedSymbol> SymbolTable; |
| bool Finalized = false; |
| }; |
| |
| using LinkedObjectListT = std::list<std::unique_ptr<LinkedObject>>; |
| |
| public: |
| /// @brief Handle to a loaded object. |
| using ObjHandleT = LinkedObjectListT::iterator; |
| }; |
| |
| /// @brief Bare bones object linking layer. |
| /// |
| /// This class is intended to be used as the base layer for a JIT. It allows |
| /// object files to be loaded into memory, linked, and the addresses of their |
| /// symbols queried. All objects added to this layer can see each other's |
| /// symbols. |
| class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { |
| public: |
| |
| using RTDyldObjectLinkingLayerBase::ObjectPtr; |
| |
| /// @brief Functor for receiving object-loaded notifications. |
| using NotifyLoadedFtor = |
| std::function<void(ObjHandleT, const ObjectPtr &Obj, |
| const RuntimeDyld::LoadedObjectInfo &)>; |
| |
| /// @brief Functor for receiving finalization notifications. |
| using NotifyFinalizedFtor = std::function<void(ObjHandleT)>; |
| |
| private: |
| |
| |
| template <typename MemoryManagerPtrT, typename SymbolResolverPtrT, |
| typename FinalizerFtor> |
| class ConcreteLinkedObject : public LinkedObject { |
| public: |
| ConcreteLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr, |
| SymbolResolverPtrT Resolver, |
| FinalizerFtor Finalizer, |
| bool ProcessAllSections) |
| : MemMgr(std::move(MemMgr)), |
| PFC(llvm::make_unique<PreFinalizeContents>(std::move(Obj), |
| std::move(Resolver), |
| std::move(Finalizer), |
| ProcessAllSections)) { |
| buildInitialSymbolTable(PFC->Obj); |
| } |
| |
| ~ConcreteLinkedObject() override { |
| MemMgr->deregisterEHFrames(); |
| } |
| |
| void setHandle(ObjHandleT H) { |
| PFC->Handle = H; |
| } |
| |
| void finalize() override { |
| assert(PFC && "mapSectionAddress called on finalized LinkedObject"); |
| |
| RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver); |
| RTDyld.setProcessAllSections(PFC->ProcessAllSections); |
| PFC->RTDyld = &RTDyld; |
| |
| this->Finalized = true; |
| PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Obj), |
| [&]() { |
| this->updateSymbolTable(RTDyld); |
| }); |
| |
| // Release resources. |
| PFC = nullptr; |
| } |
| |
| JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override { |
| return |
| [this, Name]() { |
| // The symbol may be materialized between the creation of this lambda |
| // and its execution, so we need to double check. |
| if (!this->Finalized) |
| this->finalize(); |
| return this->getSymbol(Name, false).getAddress(); |
| }; |
| } |
| |
| void mapSectionAddress(const void *LocalAddress, |
| JITTargetAddress TargetAddr) const override { |
| assert(PFC && "mapSectionAddress called on finalized LinkedObject"); |
| assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject"); |
| PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr); |
| } |
| |
| private: |
| |
| void buildInitialSymbolTable(const ObjectPtr &Obj) { |
| for (auto &Symbol : Obj->getBinary()->symbols()) { |
| if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) |
| continue; |
| Expected<StringRef> SymbolName = Symbol.getName(); |
| // FIXME: Raise an error for bad symbols. |
| if (!SymbolName) { |
| consumeError(SymbolName.takeError()); |
| continue; |
| } |
| auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol); |
| SymbolTable.insert( |
| std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags))); |
| } |
| } |
| |
| void updateSymbolTable(const RuntimeDyld &RTDyld) { |
| for (auto &SymEntry : SymbolTable) |
| SymEntry.second = RTDyld.getSymbol(SymEntry.first()); |
| } |
| |
| // Contains the information needed prior to finalization: the object files, |
| // memory manager, resolver, and flags needed for RuntimeDyld. |
| struct PreFinalizeContents { |
| PreFinalizeContents(ObjectPtr Obj, SymbolResolverPtrT Resolver, |
| FinalizerFtor Finalizer, bool ProcessAllSections) |
| : Obj(std::move(Obj)), Resolver(std::move(Resolver)), |
| Finalizer(std::move(Finalizer)), |
| ProcessAllSections(ProcessAllSections) {} |
| |
| ObjectPtr Obj; |
| SymbolResolverPtrT Resolver; |
| FinalizerFtor Finalizer; |
| bool ProcessAllSections; |
| ObjHandleT Handle; |
| RuntimeDyld *RTDyld; |
| }; |
| |
| MemoryManagerPtrT MemMgr; |
| std::unique_ptr<PreFinalizeContents> PFC; |
| }; |
| |
| template <typename MemoryManagerPtrT, typename SymbolResolverPtrT, |
| typename FinalizerFtor> |
| std::unique_ptr< |
| ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT, FinalizerFtor>> |
| createLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr, |
| SymbolResolverPtrT Resolver, |
| FinalizerFtor Finalizer, |
| bool ProcessAllSections) { |
| using LOS = ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT, |
| FinalizerFtor>; |
| return llvm::make_unique<LOS>(std::move(Obj), std::move(MemMgr), |
| std::move(Resolver), std::move(Finalizer), |
| ProcessAllSections); |
| } |
| |
| public: |
| |
| /// @brief Functor for creating memory managers. |
| using MemoryManagerGetter = |
| std::function<std::shared_ptr<RuntimeDyld::MemoryManager>()>; |
| |
| /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, |
| /// and NotifyFinalized functors. |
| RTDyldObjectLinkingLayer( |
| MemoryManagerGetter GetMemMgr, |
| NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), |
| NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) |
| : GetMemMgr(GetMemMgr), |
| NotifyLoaded(std::move(NotifyLoaded)), |
| NotifyFinalized(std::move(NotifyFinalized)), |
| ProcessAllSections(false) {} |
| |
| /// @brief Set the 'ProcessAllSections' flag. |
| /// |
| /// If set to true, all sections in each object file will be allocated using |
| /// the memory manager, rather than just the sections required for execution. |
| /// |
| /// This is kludgy, and may be removed in the future. |
| void setProcessAllSections(bool ProcessAllSections) { |
| this->ProcessAllSections = ProcessAllSections; |
| } |
| |
| /// @brief Add an object to the JIT. |
| /// |
| /// @return A handle that can be used to refer to the loaded object (for |
| /// symbol searching, finalization, freeing memory, etc.). |
| Expected<ObjHandleT> addObject(ObjectPtr Obj, |
| std::shared_ptr<JITSymbolResolver> Resolver) { |
| auto Finalizer = [&](ObjHandleT H, RuntimeDyld &RTDyld, |
| const ObjectPtr &ObjToLoad, |
| std::function<void()> LOSHandleLoad) { |
| std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info = |
| RTDyld.loadObject(*ObjToLoad->getBinary()); |
| |
| LOSHandleLoad(); |
| |
| if (this->NotifyLoaded) |
| this->NotifyLoaded(H, ObjToLoad, *Info); |
| |
| RTDyld.finalizeWithMemoryManagerLocking(); |
| |
| if (this->NotifyFinalized) |
| this->NotifyFinalized(H); |
| }; |
| |
| auto LO = |
| createLinkedObject(std::move(Obj), GetMemMgr(), |
| std::move(Resolver), std::move(Finalizer), |
| ProcessAllSections); |
| // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle |
| // below. |
| auto *LOPtr = LO.get(); |
| |
| ObjHandleT Handle = LinkedObjList.insert(LinkedObjList.end(), std::move(LO)); |
| LOPtr->setHandle(Handle); |
| |
| return Handle; |
| } |
| |
| /// @brief Remove the object associated with handle H. |
| /// |
| /// All memory allocated for the object will be freed, and the sections and |
| /// symbols it provided will no longer be available. No attempt is made to |
| /// re-emit the missing symbols, and any use of these symbols (directly or |
| /// indirectly) will result in undefined behavior. If dependence tracking is |
| /// required to detect or resolve such issues it should be added at a higher |
| /// layer. |
| Error removeObject(ObjHandleT H) { |
| // How do we invalidate the symbols in H? |
| LinkedObjList.erase(H); |
| return Error::success(); |
| } |
| |
| /// @brief Search for the given named symbol. |
| /// @param Name The name of the symbol to search for. |
| /// @param ExportedSymbolsOnly If true, search only for exported symbols. |
| /// @return A handle for the given named symbol, if it exists. |
| JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { |
| for (auto I = LinkedObjList.begin(), E = LinkedObjList.end(); I != E; |
| ++I) |
| if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly)) |
| return Symbol; |
| |
| return nullptr; |
| } |
| |
| /// @brief Search for the given named symbol in the context of the loaded |
| /// object represented by the handle H. |
| /// @param H The handle for the object to search in. |
| /// @param Name The name of the symbol to search for. |
| /// @param ExportedSymbolsOnly If true, search only for exported symbols. |
| /// @return A handle for the given named symbol, if it is found in the |
| /// given object. |
| JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, |
| bool ExportedSymbolsOnly) { |
| return (*H)->getSymbol(Name, ExportedSymbolsOnly); |
| } |
| |
| /// @brief Map section addresses for the object associated with the handle H. |
| void mapSectionAddress(ObjHandleT H, const void *LocalAddress, |
| JITTargetAddress TargetAddr) { |
| (*H)->mapSectionAddress(LocalAddress, TargetAddr); |
| } |
| |
| /// @brief Immediately emit and finalize the object represented by the given |
| /// handle. |
| /// @param H Handle for object to emit/finalize. |
| Error emitAndFinalize(ObjHandleT H) { |
| (*H)->finalize(); |
| return Error::success(); |
| } |
| |
| private: |
| |
| LinkedObjectListT LinkedObjList; |
| MemoryManagerGetter GetMemMgr; |
| NotifyLoadedFtor NotifyLoaded; |
| NotifyFinalizedFtor NotifyFinalized; |
| bool ProcessAllSections = false; |
| }; |
| |
| } // end namespace orc |
| } // end namespace llvm |
| |
| #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H |