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