Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:52

0001 //===-- ELFNixPlatform.h -- Utilities for executing ELF in Orc --*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Linux/BSD support for executing JIT'd ELF in Orc.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
0014 #define LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
0015 
0016 #include "llvm/ADT/StringRef.h"
0017 #include "llvm/ExecutionEngine/Orc/Core.h"
0018 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
0019 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
0020 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
0021 
0022 #include <future>
0023 #include <thread>
0024 #include <unordered_map>
0025 #include <vector>
0026 
0027 namespace llvm {
0028 namespace orc {
0029 
0030 struct ELFPerObjectSectionsToRegister {
0031   ExecutorAddrRange EHFrameSection;
0032   ExecutorAddrRange ThreadDataSection;
0033 };
0034 
0035 using ELFNixJITDylibDepInfo = std::vector<ExecutorAddr>;
0036 using ELFNixJITDylibDepInfoMap =
0037     std::vector<std::pair<ExecutorAddr, ELFNixJITDylibDepInfo>>;
0038 
0039 struct RuntimeFunction {
0040   RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {}
0041   SymbolStringPtr Name;
0042   ExecutorAddr Addr;
0043 };
0044 
0045 struct FunctionPairKeyHash {
0046   std::size_t
0047   operator()(const std::pair<RuntimeFunction *, RuntimeFunction *> &key) const {
0048     return std::hash<void *>()(key.first->Addr.toPtr<void *>()) ^
0049            std::hash<void *>()(key.second->Addr.toPtr<void *>());
0050   }
0051 };
0052 
0053 struct FunctionPairKeyEqual {
0054   std::size_t
0055   operator()(const std::pair<RuntimeFunction *, RuntimeFunction *> &lhs,
0056              const std::pair<RuntimeFunction *, RuntimeFunction *> &rhs) const {
0057     return lhs.first == rhs.first && lhs.second == rhs.second;
0058   }
0059 };
0060 
0061 using DeferredRuntimeFnMap = std::unordered_map<
0062     std::pair<RuntimeFunction *, RuntimeFunction *>,
0063     SmallVector<std::pair<shared::WrapperFunctionCall::ArgDataBufferType,
0064                           shared::WrapperFunctionCall::ArgDataBufferType>>,
0065     FunctionPairKeyHash, FunctionPairKeyEqual>;
0066 
0067 /// Mediates between ELFNix initialization and ExecutionSession state.
0068 class ELFNixPlatform : public Platform {
0069 public:
0070   /// Try to create a ELFNixPlatform instance, adding the ORC runtime to the
0071   /// given JITDylib.
0072   ///
0073   /// The ORC runtime requires access to a number of symbols in
0074   /// libc++. It is up to the caller to ensure that the required
0075   /// symbols can be referenced by code added to PlatformJD. The
0076   /// standard way to achieve this is to first attach dynamic library
0077   /// search generators for either the given process, or for the
0078   /// specific required libraries, to PlatformJD, then to create the
0079   /// platform instance:
0080   ///
0081   /// \code{.cpp}
0082   ///   auto &PlatformJD = ES.createBareJITDylib("stdlib");
0083   ///   PlatformJD.addGenerator(
0084   ///     ExitOnErr(EPCDynamicLibrarySearchGenerator
0085   ///                 ::GetForTargetProcess(EPC)));
0086   ///   ES.setPlatform(
0087   ///     ExitOnErr(ELFNixPlatform::Create(ES, ObjLayer, EPC, PlatformJD,
0088   ///                                     "/path/to/orc/runtime")));
0089   /// \endcode
0090   ///
0091   /// Alternatively, these symbols could be added to another JITDylib that
0092   /// PlatformJD links against.
0093   ///
0094   /// Clients are also responsible for ensuring that any JIT'd code that
0095   /// depends on runtime functions (including any code using TLV or static
0096   /// destructors) can reference the runtime symbols. This is usually achieved
0097   /// by linking any JITDylibs containing regular code against
0098   /// PlatformJD.
0099   ///
0100   /// By default, ELFNixPlatform will add the set of aliases returned by the
0101   /// standardPlatformAliases function. This includes both required aliases
0102   /// (e.g. __cxa_atexit -> __orc_rt_elf_cxa_atexit for static destructor
0103   /// support), and optional aliases that provide JIT versions of common
0104   /// functions (e.g. dlopen -> __orc_rt_elf_jit_dlopen). Clients can
0105   /// override these defaults by passing a non-None value for the
0106   /// RuntimeAliases function, in which case the client is responsible for
0107   /// setting up all aliases (including the required ones).
0108   static Expected<std::unique_ptr<ELFNixPlatform>>
0109   Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
0110          std::unique_ptr<DefinitionGenerator> OrcRuntime,
0111          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
0112 
0113   /// Construct using a path to the ORC runtime.
0114   static Expected<std::unique_ptr<ELFNixPlatform>>
0115   Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
0116          const char *OrcRuntimePath,
0117          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
0118 
0119   ExecutionSession &getExecutionSession() const { return ES; }
0120   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
0121 
0122   Error setupJITDylib(JITDylib &JD) override;
0123   Error teardownJITDylib(JITDylib &JD) override;
0124   Error notifyAdding(ResourceTracker &RT,
0125                      const MaterializationUnit &MU) override;
0126   Error notifyRemoving(ResourceTracker &RT) override;
0127 
0128   /// Returns an AliasMap containing the default aliases for the ELFNixPlatform.
0129   /// This can be modified by clients when constructing the platform to add
0130   /// or remove aliases.
0131   static Expected<SymbolAliasMap> standardPlatformAliases(ExecutionSession &ES,
0132                                                           JITDylib &PlatformJD);
0133 
0134   /// Returns the array of required CXX aliases.
0135   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
0136 
0137   /// Returns the array of standard runtime utility aliases for ELF.
0138   static ArrayRef<std::pair<const char *, const char *>>
0139   standardRuntimeUtilityAliases();
0140 
0141   /// Returns a list of aliases required to enable lazy compilation via the
0142   /// ORC runtime.
0143   static ArrayRef<std::pair<const char *, const char *>>
0144   standardLazyCompilationAliases();
0145 
0146 private:
0147   // Data needed for bootstrap only.
0148   struct BootstrapInfo {
0149     std::mutex Mutex;
0150     std::condition_variable CV;
0151     size_t ActiveGraphs = 0;
0152     ExecutorAddr ELFNixHeaderAddr;
0153     DeferredRuntimeFnMap DeferredRTFnMap;
0154 
0155     void addArgumentsToRTFnMap(
0156         RuntimeFunction *func1, RuntimeFunction *func2,
0157         const shared::WrapperFunctionCall::ArgDataBufferType &arg1,
0158         const shared::WrapperFunctionCall::ArgDataBufferType &arg2) {
0159       std::lock_guard<std::mutex> Lock(Mutex);
0160       auto &argList = DeferredRTFnMap[std::make_pair(func1, func2)];
0161       argList.emplace_back(arg1, arg2);
0162     }
0163   };
0164 
0165   // The ELFNixPlatformPlugin scans/modifies LinkGraphs to support ELF
0166   // platform features including initializers, exceptions, TLV, and language
0167   // runtime registration.
0168   class ELFNixPlatformPlugin : public ObjectLinkingLayer::Plugin {
0169   public:
0170     ELFNixPlatformPlugin(ELFNixPlatform &MP) : MP(MP) {}
0171 
0172     void modifyPassConfig(MaterializationResponsibility &MR,
0173                           jitlink::LinkGraph &G,
0174                           jitlink::PassConfiguration &Config) override;
0175 
0176     // FIXME: We should be tentatively tracking scraped sections and discarding
0177     // if the MR fails.
0178     Error notifyFailed(MaterializationResponsibility &MR) override {
0179       return Error::success();
0180     }
0181 
0182     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
0183       return Error::success();
0184     }
0185 
0186     void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
0187                                      ResourceKey SrcKey) override {}
0188 
0189   private:
0190     Error bootstrapPipelineStart(jitlink::LinkGraph &G);
0191     Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
0192     Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
0193 
0194     void addDSOHandleSupportPasses(MaterializationResponsibility &MR,
0195                                    jitlink::PassConfiguration &Config);
0196 
0197     void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
0198                                   jitlink::PassConfiguration &Config,
0199                                   bool IsBootstrapping);
0200 
0201     Error preserveInitSections(jitlink::LinkGraph &G,
0202                                MaterializationResponsibility &MR);
0203 
0204     Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD,
0205                                bool IsBootstrapping);
0206 
0207     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
0208 
0209     std::mutex PluginMutex;
0210     ELFNixPlatform &MP;
0211   };
0212 
0213   using PushInitializersSendResultFn =
0214       unique_function<void(Expected<ELFNixJITDylibDepInfoMap>)>;
0215 
0216   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
0217 
0218   static bool supportedTarget(const Triple &TT);
0219 
0220   ELFNixPlatform(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
0221                  std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
0222                  Error &Err);
0223 
0224   // Associate ELFNixPlatform JIT-side runtime support functions with handlers.
0225   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
0226 
0227   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
0228                             JITDylibSP JD);
0229 
0230   void rt_recordInitializers(PushInitializersSendResultFn SendResult,
0231                              ExecutorAddr JDHeader);
0232 
0233   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
0234                        StringRef SymbolName);
0235 
0236   Error registerPerObjectSections(jitlink::LinkGraph &G,
0237                                   const ELFPerObjectSectionsToRegister &POSR,
0238                                   bool IsBootstrapping);
0239 
0240   Expected<uint64_t> createPThreadKey();
0241 
0242   ExecutionSession &ES;
0243   JITDylib &PlatformJD;
0244   ObjectLinkingLayer &ObjLinkingLayer;
0245 
0246   SymbolStringPtr DSOHandleSymbol;
0247 
0248   RuntimeFunction PlatformBootstrap{
0249       ES.intern("__orc_rt_elfnix_platform_bootstrap")};
0250   RuntimeFunction PlatformShutdown{
0251       ES.intern("__orc_rt_elfnix_platform_shutdown")};
0252   RuntimeFunction RegisterJITDylib{
0253       ES.intern("__orc_rt_elfnix_register_jitdylib")};
0254   RuntimeFunction DeregisterJITDylib{
0255       ES.intern("__orc_rt_elfnix_deregister_jitdylib")};
0256   RuntimeFunction RegisterObjectSections{
0257       ES.intern("__orc_rt_elfnix_register_object_sections")};
0258   RuntimeFunction DeregisterObjectSections{
0259       ES.intern("__orc_rt_elfnix_deregister_object_sections")};
0260   RuntimeFunction RegisterInitSections{
0261       ES.intern("__orc_rt_elfnix_register_init_sections")};
0262   RuntimeFunction DeregisterInitSections{
0263       ES.intern("__orc_rt_elfnix_deregister_init_sections")};
0264   RuntimeFunction CreatePThreadKey{
0265       ES.intern("__orc_rt_elfnix_create_pthread_key")};
0266 
0267   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
0268 
0269   // InitSeqs gets its own mutex to avoid locking the whole session when
0270   // aggregating data from the jitlink.
0271   std::mutex PlatformMutex;
0272   std::vector<ELFPerObjectSectionsToRegister> BootstrapPOSRs;
0273 
0274   DenseMap<ExecutorAddr, JITDylib *> HandleAddrToJITDylib;
0275   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHandleAddr;
0276   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
0277 
0278   std::atomic<BootstrapInfo *> Bootstrap;
0279 };
0280 
0281 namespace shared {
0282 
0283 using SPSELFPerObjectSectionsToRegister =
0284     SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
0285 
0286 template <>
0287 class SPSSerializationTraits<SPSELFPerObjectSectionsToRegister,
0288                              ELFPerObjectSectionsToRegister> {
0289 
0290 public:
0291   static size_t size(const ELFPerObjectSectionsToRegister &MOPOSR) {
0292     return SPSELFPerObjectSectionsToRegister::AsArgList::size(
0293         MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
0294   }
0295 
0296   static bool serialize(SPSOutputBuffer &OB,
0297                         const ELFPerObjectSectionsToRegister &MOPOSR) {
0298     return SPSELFPerObjectSectionsToRegister::AsArgList::serialize(
0299         OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
0300   }
0301 
0302   static bool deserialize(SPSInputBuffer &IB,
0303                           ELFPerObjectSectionsToRegister &MOPOSR) {
0304     return SPSELFPerObjectSectionsToRegister::AsArgList::deserialize(
0305         IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
0306   }
0307 };
0308 
0309 using SPSELFNixJITDylibDepInfoMap =
0310     SPSSequence<SPSTuple<SPSExecutorAddr, SPSSequence<SPSExecutorAddr>>>;
0311 
0312 } // end namespace shared
0313 } // end namespace orc
0314 } // end namespace llvm
0315 
0316 #endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H