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/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