ELFNixPlatform.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- ELFNixPlatform.h -- Utilities for executing ELF in Orc --*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Linux/BSD support for executing JIT'd ELF in Orc.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
  18. #define LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
  19. #include "llvm/ADT/StringRef.h"
  20. #include "llvm/ExecutionEngine/Orc/Core.h"
  21. #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
  22. #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
  23. #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
  24. #include <future>
  25. #include <thread>
  26. #include <vector>
  27. namespace llvm {
  28. namespace orc {
  29. struct ELFPerObjectSectionsToRegister {
  30. ExecutorAddrRange EHFrameSection;
  31. ExecutorAddrRange ThreadDataSection;
  32. };
  33. struct ELFNixJITDylibInitializers {
  34. using SectionList = std::vector<ExecutorAddrRange>;
  35. ELFNixJITDylibInitializers(std::string Name, ExecutorAddr DSOHandleAddress)
  36. : Name(std::move(Name)), DSOHandleAddress(std::move(DSOHandleAddress)) {}
  37. std::string Name;
  38. ExecutorAddr DSOHandleAddress;
  39. StringMap<SectionList> InitSections;
  40. };
  41. class ELFNixJITDylibDeinitializers {};
  42. using ELFNixJITDylibInitializerSequence =
  43. std::vector<ELFNixJITDylibInitializers>;
  44. using ELFNixJITDylibDeinitializerSequence =
  45. std::vector<ELFNixJITDylibDeinitializers>;
  46. /// Mediates between ELFNix initialization and ExecutionSession state.
  47. class ELFNixPlatform : public Platform {
  48. public:
  49. /// Try to create a ELFNixPlatform instance, adding the ORC runtime to the
  50. /// given JITDylib.
  51. ///
  52. /// The ORC runtime requires access to a number of symbols in
  53. /// libc++. It is up to the caller to ensure that the requried
  54. /// symbols can be referenced by code added to PlatformJD. The
  55. /// standard way to achieve this is to first attach dynamic library
  56. /// search generators for either the given process, or for the
  57. /// specific required libraries, to PlatformJD, then to create the
  58. /// platform instance:
  59. ///
  60. /// \code{.cpp}
  61. /// auto &PlatformJD = ES.createBareJITDylib("stdlib");
  62. /// PlatformJD.addGenerator(
  63. /// ExitOnErr(EPCDynamicLibrarySearchGenerator
  64. /// ::GetForTargetProcess(EPC)));
  65. /// ES.setPlatform(
  66. /// ExitOnErr(ELFNixPlatform::Create(ES, ObjLayer, EPC, PlatformJD,
  67. /// "/path/to/orc/runtime")));
  68. /// \endcode
  69. ///
  70. /// Alternatively, these symbols could be added to another JITDylib that
  71. /// PlatformJD links against.
  72. ///
  73. /// Clients are also responsible for ensuring that any JIT'd code that
  74. /// depends on runtime functions (including any code using TLV or static
  75. /// destructors) can reference the runtime symbols. This is usually achieved
  76. /// by linking any JITDylibs containing regular code against
  77. /// PlatformJD.
  78. ///
  79. /// By default, ELFNixPlatform will add the set of aliases returned by the
  80. /// standardPlatformAliases function. This includes both required aliases
  81. /// (e.g. __cxa_atexit -> __orc_rt_elf_cxa_atexit for static destructor
  82. /// support), and optional aliases that provide JIT versions of common
  83. /// functions (e.g. dlopen -> __orc_rt_elf_jit_dlopen). Clients can
  84. /// override these defaults by passing a non-None value for the
  85. /// RuntimeAliases function, in which case the client is responsible for
  86. /// setting up all aliases (including the required ones).
  87. static Expected<std::unique_ptr<ELFNixPlatform>>
  88. Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
  89. JITDylib &PlatformJD, const char *OrcRuntimePath,
  90. std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
  91. ExecutionSession &getExecutionSession() const { return ES; }
  92. ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
  93. Error setupJITDylib(JITDylib &JD) override;
  94. Error teardownJITDylib(JITDylib &JD) override;
  95. Error notifyAdding(ResourceTracker &RT,
  96. const MaterializationUnit &MU) override;
  97. Error notifyRemoving(ResourceTracker &RT) override;
  98. /// Returns an AliasMap containing the default aliases for the ELFNixPlatform.
  99. /// This can be modified by clients when constructing the platform to add
  100. /// or remove aliases.
  101. static Expected<SymbolAliasMap> standardPlatformAliases(ExecutionSession &ES,
  102. JITDylib &PlatformJD);
  103. /// Returns the array of required CXX aliases.
  104. static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
  105. /// Returns the array of standard runtime utility aliases for ELF.
  106. static ArrayRef<std::pair<const char *, const char *>>
  107. standardRuntimeUtilityAliases();
  108. /// Returns true if the given section name is an initializer section.
  109. static bool isInitializerSection(StringRef SecName);
  110. private:
  111. // The ELFNixPlatformPlugin scans/modifies LinkGraphs to support ELF
  112. // platform features including initializers, exceptions, TLV, and language
  113. // runtime registration.
  114. class ELFNixPlatformPlugin : public ObjectLinkingLayer::Plugin {
  115. public:
  116. ELFNixPlatformPlugin(ELFNixPlatform &MP) : MP(MP) {}
  117. void modifyPassConfig(MaterializationResponsibility &MR,
  118. jitlink::LinkGraph &G,
  119. jitlink::PassConfiguration &Config) override;
  120. SyntheticSymbolDependenciesMap
  121. getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
  122. // FIXME: We should be tentatively tracking scraped sections and discarding
  123. // if the MR fails.
  124. Error notifyFailed(MaterializationResponsibility &MR) override {
  125. return Error::success();
  126. }
  127. Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
  128. return Error::success();
  129. }
  130. void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
  131. ResourceKey SrcKey) override {}
  132. private:
  133. using InitSymbolDepMap =
  134. DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
  135. void addInitializerSupportPasses(MaterializationResponsibility &MR,
  136. jitlink::PassConfiguration &Config);
  137. void addDSOHandleSupportPasses(MaterializationResponsibility &MR,
  138. jitlink::PassConfiguration &Config);
  139. void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
  140. jitlink::PassConfiguration &Config);
  141. Error preserveInitSections(jitlink::LinkGraph &G,
  142. MaterializationResponsibility &MR);
  143. Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD);
  144. Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
  145. std::mutex PluginMutex;
  146. ELFNixPlatform &MP;
  147. InitSymbolDepMap InitSymbolDeps;
  148. };
  149. using SendInitializerSequenceFn =
  150. unique_function<void(Expected<ELFNixJITDylibInitializerSequence>)>;
  151. using SendDeinitializerSequenceFn =
  152. unique_function<void(Expected<ELFNixJITDylibDeinitializerSequence>)>;
  153. using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
  154. static bool supportedTarget(const Triple &TT);
  155. ELFNixPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
  156. JITDylib &PlatformJD,
  157. std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
  158. Error &Err);
  159. // Associate ELFNixPlatform JIT-side runtime support functions with handlers.
  160. Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
  161. void getInitializersBuildSequencePhase(SendInitializerSequenceFn SendResult,
  162. JITDylib &JD,
  163. std::vector<JITDylibSP> DFSLinkOrder);
  164. void getInitializersLookupPhase(SendInitializerSequenceFn SendResult,
  165. JITDylib &JD);
  166. void rt_getInitializers(SendInitializerSequenceFn SendResult,
  167. StringRef JDName);
  168. void rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
  169. ExecutorAddr Handle);
  170. void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
  171. StringRef SymbolName);
  172. // Records the addresses of runtime symbols used by the platform.
  173. Error bootstrapELFNixRuntime(JITDylib &PlatformJD);
  174. Error registerInitInfo(JITDylib &JD,
  175. ArrayRef<jitlink::Section *> InitSections);
  176. Error registerPerObjectSections(const ELFPerObjectSectionsToRegister &POSR);
  177. Expected<uint64_t> createPThreadKey();
  178. ExecutionSession &ES;
  179. ObjectLinkingLayer &ObjLinkingLayer;
  180. SymbolStringPtr DSOHandleSymbol;
  181. std::atomic<bool> RuntimeBootstrapped{false};
  182. ExecutorAddr orc_rt_elfnix_platform_bootstrap;
  183. ExecutorAddr orc_rt_elfnix_platform_shutdown;
  184. ExecutorAddr orc_rt_elfnix_register_object_sections;
  185. ExecutorAddr orc_rt_elfnix_create_pthread_key;
  186. DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
  187. // InitSeqs gets its own mutex to avoid locking the whole session when
  188. // aggregating data from the jitlink.
  189. std::mutex PlatformMutex;
  190. DenseMap<JITDylib *, ELFNixJITDylibInitializers> InitSeqs;
  191. std::vector<ELFPerObjectSectionsToRegister> BootstrapPOSRs;
  192. DenseMap<ExecutorAddr, JITDylib *> HandleAddrToJITDylib;
  193. DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
  194. };
  195. namespace shared {
  196. using SPSELFPerObjectSectionsToRegister =
  197. SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
  198. template <>
  199. class SPSSerializationTraits<SPSELFPerObjectSectionsToRegister,
  200. ELFPerObjectSectionsToRegister> {
  201. public:
  202. static size_t size(const ELFPerObjectSectionsToRegister &MOPOSR) {
  203. return SPSELFPerObjectSectionsToRegister::AsArgList::size(
  204. MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
  205. }
  206. static bool serialize(SPSOutputBuffer &OB,
  207. const ELFPerObjectSectionsToRegister &MOPOSR) {
  208. return SPSELFPerObjectSectionsToRegister::AsArgList::serialize(
  209. OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
  210. }
  211. static bool deserialize(SPSInputBuffer &IB,
  212. ELFPerObjectSectionsToRegister &MOPOSR) {
  213. return SPSELFPerObjectSectionsToRegister::AsArgList::deserialize(
  214. IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
  215. }
  216. };
  217. using SPSNamedExecutorAddrRangeSequenceMap =
  218. SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
  219. using SPSELFNixJITDylibInitializers =
  220. SPSTuple<SPSString, SPSExecutorAddr, SPSNamedExecutorAddrRangeSequenceMap>;
  221. using SPSELFNixJITDylibInitializerSequence =
  222. SPSSequence<SPSELFNixJITDylibInitializers>;
  223. /// Serialization traits for ELFNixJITDylibInitializers.
  224. template <>
  225. class SPSSerializationTraits<SPSELFNixJITDylibInitializers,
  226. ELFNixJITDylibInitializers> {
  227. public:
  228. static size_t size(const ELFNixJITDylibInitializers &MOJDIs) {
  229. return SPSELFNixJITDylibInitializers::AsArgList::size(
  230. MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
  231. }
  232. static bool serialize(SPSOutputBuffer &OB,
  233. const ELFNixJITDylibInitializers &MOJDIs) {
  234. return SPSELFNixJITDylibInitializers::AsArgList::serialize(
  235. OB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
  236. }
  237. static bool deserialize(SPSInputBuffer &IB,
  238. ELFNixJITDylibInitializers &MOJDIs) {
  239. return SPSELFNixJITDylibInitializers::AsArgList::deserialize(
  240. IB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
  241. }
  242. };
  243. using SPSELFJITDylibDeinitializers = SPSEmpty;
  244. using SPSELFJITDylibDeinitializerSequence =
  245. SPSSequence<SPSELFJITDylibDeinitializers>;
  246. template <>
  247. class SPSSerializationTraits<SPSELFJITDylibDeinitializers,
  248. ELFNixJITDylibDeinitializers> {
  249. public:
  250. static size_t size(const ELFNixJITDylibDeinitializers &MOJDDs) { return 0; }
  251. static bool serialize(SPSOutputBuffer &OB,
  252. const ELFNixJITDylibDeinitializers &MOJDDs) {
  253. return true;
  254. }
  255. static bool deserialize(SPSInputBuffer &IB,
  256. ELFNixJITDylibDeinitializers &MOJDDs) {
  257. MOJDDs = ELFNixJITDylibDeinitializers();
  258. return true;
  259. }
  260. };
  261. } // end namespace shared
  262. } // end namespace orc
  263. } // end namespace llvm
  264. #endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
  265. #ifdef __GNUC__
  266. #pragma GCC diagnostic pop
  267. #endif