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