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/Orc/Core.h"
     22 #include "llvm/ExecutionEngine/Orc/Layer.h"
     23 #include "llvm/ExecutionEngine/Orc/Legacy.h"
     24 #include "llvm/ExecutionEngine/RuntimeDyld.h"
     25 #include "llvm/Object/ObjectFile.h"
     26 #include "llvm/Support/Error.h"
     27 #include <algorithm>
     28 #include <cassert>
     29 #include <functional>
     30 #include <list>
     31 #include <memory>
     32 #include <string>
     33 #include <utility>
     34 #include <vector>
     35 
     36 namespace llvm {
     37 namespace orc {
     38 
     39 class RTDyldObjectLinkingLayer2 : public ObjectLayer {
     40 public:
     41   /// Functor for receiving object-loaded notifications.
     42   using NotifyLoadedFunction =
     43       std::function<void(VModuleKey, const object::ObjectFile &Obj,
     44                          const RuntimeDyld::LoadedObjectInfo &)>;
     45 
     46   /// Functor for receiving finalization notifications.
     47   using NotifyFinalizedFunction = std::function<void(VModuleKey)>;
     48 
     49   using GetMemoryManagerFunction =
     50       std::function<std::shared_ptr<RuntimeDyld::MemoryManager>(VModuleKey)>;
     51 
     52   /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
     53   ///        and NotifyFinalized functors.
     54   RTDyldObjectLinkingLayer2(
     55       ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager,
     56       NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
     57       NotifyFinalizedFunction NotifyFinalized = NotifyFinalizedFunction());
     58 
     59   /// Emit the object.
     60   void emit(MaterializationResponsibility R, VModuleKey K,
     61             std::unique_ptr<MemoryBuffer> O) override;
     62 
     63   /// Map section addresses for the object associated with the
     64   ///        VModuleKey K.
     65   void mapSectionAddress(VModuleKey K, const void *LocalAddress,
     66                          JITTargetAddress TargetAddr) const;
     67 
     68   /// Set the 'ProcessAllSections' flag.
     69   ///
     70   /// If set to true, all sections in each object file will be allocated using
     71   /// the memory manager, rather than just the sections required for execution.
     72   ///
     73   /// This is kludgy, and may be removed in the future.
     74   void setProcessAllSections(bool ProcessAllSections) {
     75     this->ProcessAllSections = ProcessAllSections;
     76   }
     77 
     78 private:
     79   mutable std::mutex RTDyldLayerMutex;
     80   GetMemoryManagerFunction GetMemoryManager;
     81   NotifyLoadedFunction NotifyLoaded;
     82   NotifyFinalizedFunction NotifyFinalized;
     83   bool ProcessAllSections;
     84   std::map<VModuleKey, RuntimeDyld *> ActiveRTDylds;
     85   std::map<VModuleKey, std::shared_ptr<RuntimeDyld::MemoryManager>> MemMgrs;
     86 };
     87 
     88 class RTDyldObjectLinkingLayerBase {
     89 public:
     90   using ObjectPtr = std::unique_ptr<MemoryBuffer>;
     91 
     92 protected:
     93 
     94   /// Holds an object to be allocated/linked as a unit in the JIT.
     95   ///
     96   /// An instance of this class will be created for each object added
     97   /// via JITObjectLayer::addObject. Deleting the instance (via
     98   /// removeObject) frees its memory, removing all symbol definitions that
     99   /// had been provided by this instance. Higher level layers are responsible
    100   /// for taking any action required to handle the missing symbols.
    101   class LinkedObject {
    102   public:
    103     LinkedObject() = default;
    104     LinkedObject(const LinkedObject&) = delete;
    105     void operator=(const LinkedObject&) = delete;
    106     virtual ~LinkedObject() = default;
    107 
    108     virtual Error finalize() = 0;
    109 
    110     virtual JITSymbol::GetAddressFtor
    111     getSymbolMaterializer(std::string Name) = 0;
    112 
    113     virtual void mapSectionAddress(const void *LocalAddress,
    114                                    JITTargetAddress TargetAddr) const = 0;
    115 
    116     JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
    117       auto SymEntry = SymbolTable.find(Name);
    118       if (SymEntry == SymbolTable.end())
    119         return nullptr;
    120       if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
    121         return nullptr;
    122       if (!Finalized)
    123         return JITSymbol(getSymbolMaterializer(Name),
    124                          SymEntry->second.getFlags());
    125       return JITSymbol(SymEntry->second);
    126     }
    127 
    128   protected:
    129     StringMap<JITEvaluatedSymbol> SymbolTable;
    130     bool Finalized = false;
    131   };
    132 };
    133 
    134 /// Bare bones object linking layer.
    135 ///
    136 ///   This class is intended to be used as the base layer for a JIT. It allows
    137 /// object files to be loaded into memory, linked, and the addresses of their
    138 /// symbols queried. All objects added to this layer can see each other's
    139 /// symbols.
    140 class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
    141 public:
    142 
    143   using RTDyldObjectLinkingLayerBase::ObjectPtr;
    144 
    145   /// Functor for receiving object-loaded notifications.
    146   using NotifyLoadedFtor =
    147       std::function<void(VModuleKey, const object::ObjectFile &Obj,
    148                          const RuntimeDyld::LoadedObjectInfo &)>;
    149 
    150   /// Functor for receiving finalization notifications.
    151   using NotifyFinalizedFtor =
    152       std::function<void(VModuleKey, const object::ObjectFile &Obj,
    153                          const RuntimeDyld::LoadedObjectInfo &)>;
    154 
    155   /// Functor for receiving deallocation notifications.
    156   using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
    157 
    158 private:
    159   using OwnedObject = object::OwningBinary<object::ObjectFile>;
    160 
    161   template <typename MemoryManagerPtrT>
    162   class ConcreteLinkedObject : public LinkedObject {
    163   public:
    164     ConcreteLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
    165                          OwnedObject Obj, MemoryManagerPtrT MemMgr,
    166                          std::shared_ptr<SymbolResolver> Resolver,
    167                          bool ProcessAllSections)
    168         : K(std::move(K)),
    169           Parent(Parent),
    170           MemMgr(std::move(MemMgr)),
    171           PFC(llvm::make_unique<PreFinalizeContents>(
    172               std::move(Obj), std::move(Resolver),
    173               ProcessAllSections)) {
    174       buildInitialSymbolTable(PFC->Obj);
    175     }
    176 
    177     ~ConcreteLinkedObject() override {
    178       if (this->Parent.NotifyFreed)
    179         this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
    180 
    181       MemMgr->deregisterEHFrames();
    182     }
    183 
    184     Error finalize() override {
    185       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
    186 
    187       JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
    188 					       nullptr);
    189       PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
    190       PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
    191 
    192       Finalized = true;
    193 
    194       std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
    195           PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
    196 
    197       // Copy the symbol table out of the RuntimeDyld instance.
    198       {
    199         auto SymTab = PFC->RTDyld->getSymbolTable();
    200         for (auto &KV : SymTab)
    201           SymbolTable[KV.first] = KV.second;
    202       }
    203 
    204       if (Parent.NotifyLoaded)
    205         Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
    206 
    207       PFC->RTDyld->finalizeWithMemoryManagerLocking();
    208 
    209       if (PFC->RTDyld->hasError())
    210         return make_error<StringError>(PFC->RTDyld->getErrorString(),
    211                                        inconvertibleErrorCode());
    212 
    213       if (Parent.NotifyFinalized)
    214         Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
    215 
    216       // Release resources.
    217       if (this->Parent.NotifyFreed)
    218         ObjForNotify = std::move(PFC->Obj); // needed for callback
    219       PFC = nullptr;
    220       return Error::success();
    221     }
    222 
    223     JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
    224       return [this, Name]() -> Expected<JITTargetAddress> {
    225         // The symbol may be materialized between the creation of this lambda
    226         // and its execution, so we need to double check.
    227         if (!this->Finalized)
    228           if (auto Err = this->finalize())
    229             return std::move(Err);
    230         return this->getSymbol(Name, false).getAddress();
    231       };
    232     }
    233 
    234     void mapSectionAddress(const void *LocalAddress,
    235                            JITTargetAddress TargetAddr) const override {
    236       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
    237       assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
    238       PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
    239     }
    240 
    241   private:
    242     void buildInitialSymbolTable(const OwnedObject &Obj) {
    243       for (auto &Symbol : Obj.getBinary()->symbols()) {
    244         if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
    245           continue;
    246         Expected<StringRef> SymbolName = Symbol.getName();
    247         // FIXME: Raise an error for bad symbols.
    248         if (!SymbolName) {
    249           consumeError(SymbolName.takeError());
    250           continue;
    251         }
    252         auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
    253         SymbolTable.insert(
    254           std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
    255       }
    256     }
    257 
    258     // Contains the information needed prior to finalization: the object files,
    259     // memory manager, resolver, and flags needed for RuntimeDyld.
    260     struct PreFinalizeContents {
    261       PreFinalizeContents(OwnedObject Obj,
    262                           std::shared_ptr<SymbolResolver> Resolver,
    263                           bool ProcessAllSections)
    264           : Obj(std::move(Obj)),
    265             Resolver(std::move(Resolver)),
    266             ProcessAllSections(ProcessAllSections) {}
    267 
    268       OwnedObject Obj;
    269       std::shared_ptr<SymbolResolver> Resolver;
    270       bool ProcessAllSections;
    271       std::unique_ptr<RuntimeDyld> RTDyld;
    272     };
    273 
    274     VModuleKey K;
    275     RTDyldObjectLinkingLayer &Parent;
    276     MemoryManagerPtrT MemMgr;
    277     OwnedObject ObjForNotify;
    278     std::unique_ptr<PreFinalizeContents> PFC;
    279   };
    280 
    281   template <typename MemoryManagerPtrT>
    282   std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
    283   createLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
    284                      OwnedObject Obj, MemoryManagerPtrT MemMgr,
    285                      std::shared_ptr<SymbolResolver> Resolver,
    286                      bool ProcessAllSections) {
    287     using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
    288     return llvm::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
    289                                   std::move(MemMgr), std::move(Resolver),
    290                                   ProcessAllSections);
    291   }
    292 
    293 public:
    294   struct Resources {
    295     std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
    296     std::shared_ptr<SymbolResolver> Resolver;
    297   };
    298 
    299   using ResourcesGetter = std::function<Resources(VModuleKey)>;
    300 
    301   /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
    302   ///        and NotifyFinalized functors.
    303   RTDyldObjectLinkingLayer(
    304       ExecutionSession &ES, ResourcesGetter GetResources,
    305       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
    306       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
    307       NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
    308       : ES(ES), GetResources(std::move(GetResources)),
    309         NotifyLoaded(std::move(NotifyLoaded)),
    310         NotifyFinalized(std::move(NotifyFinalized)),
    311         NotifyFreed(std::move(NotifyFreed)),
    312         ProcessAllSections(false) {
    313   }
    314 
    315   /// Set the 'ProcessAllSections' flag.
    316   ///
    317   /// If set to true, all sections in each object file will be allocated using
    318   /// the memory manager, rather than just the sections required for execution.
    319   ///
    320   /// This is kludgy, and may be removed in the future.
    321   void setProcessAllSections(bool ProcessAllSections) {
    322     this->ProcessAllSections = ProcessAllSections;
    323   }
    324 
    325   /// Add an object to the JIT.
    326   Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
    327 
    328     auto Obj =
    329         object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
    330     if (!Obj)
    331       return Obj.takeError();
    332 
    333     assert(!LinkedObjects.count(K) && "VModuleKey already in use");
    334 
    335     auto R = GetResources(K);
    336 
    337     LinkedObjects[K] = createLinkedObject(
    338         *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
    339         std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
    340 
    341     return Error::success();
    342   }
    343 
    344   /// Remove the object associated with VModuleKey K.
    345   ///
    346   ///   All memory allocated for the object will be freed, and the sections and
    347   /// symbols it provided will no longer be available. No attempt is made to
    348   /// re-emit the missing symbols, and any use of these symbols (directly or
    349   /// indirectly) will result in undefined behavior. If dependence tracking is
    350   /// required to detect or resolve such issues it should be added at a higher
    351   /// layer.
    352   Error removeObject(VModuleKey K) {
    353     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
    354     // How do we invalidate the symbols in H?
    355     LinkedObjects.erase(K);
    356     return Error::success();
    357   }
    358 
    359   /// Search for the given named symbol.
    360   /// @param Name The name of the symbol to search for.
    361   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
    362   /// @return A handle for the given named symbol, if it exists.
    363   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
    364     for (auto &KV : LinkedObjects)
    365       if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
    366         return Sym;
    367       else if (auto Err = Sym.takeError())
    368         return std::move(Err);
    369 
    370     return nullptr;
    371   }
    372 
    373   /// Search for the given named symbol in the context of the loaded
    374   ///        object represented by the VModuleKey K.
    375   /// @param K The VModuleKey for the object to search in.
    376   /// @param Name The name of the symbol to search for.
    377   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
    378   /// @return A handle for the given named symbol, if it is found in the
    379   ///         given object.
    380   JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
    381                          bool ExportedSymbolsOnly) {
    382     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
    383     return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
    384   }
    385 
    386   /// Map section addresses for the object associated with the
    387   ///        VModuleKey K.
    388   void mapSectionAddress(VModuleKey K, const void *LocalAddress,
    389                          JITTargetAddress TargetAddr) {
    390     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
    391     LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
    392   }
    393 
    394   /// Immediately emit and finalize the object represented by the given
    395   ///        VModuleKey.
    396   /// @param K VModuleKey for object to emit/finalize.
    397   Error emitAndFinalize(VModuleKey K) {
    398     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
    399     return LinkedObjects[K]->finalize();
    400   }
    401 
    402 private:
    403   ExecutionSession &ES;
    404 
    405   std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
    406   ResourcesGetter GetResources;
    407   NotifyLoadedFtor NotifyLoaded;
    408   NotifyFinalizedFtor NotifyFinalized;
    409   NotifyFreedFtor NotifyFreed;
    410   bool ProcessAllSections = false;
    411 };
    412 
    413 } // end namespace orc
    414 } // end namespace llvm
    415 
    416 #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
    417