xref: /llvm-project/llvm/include/llvm/ExecutionEngine/Orc/COFFPlatform.h (revision b3d2548d5b04ed3b7aaedfd22e62da40875c0f31)
1 //===--- COFFPlatform.h -- Utilities for executing COFF in Orc --*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Utilities for executing JIT'd COFF in Orc.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_COFFPLATFORM_H
14 #define LLVM_EXECUTIONENGINE_ORC_COFFPLATFORM_H
15 
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h"
18 #include "llvm/ExecutionEngine/Orc/Core.h"
19 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
20 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
21 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
22 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
23 
24 #include <future>
25 #include <list>
26 #include <memory>
27 #include <thread>
28 #include <vector>
29 
30 namespace llvm {
31 namespace orc {
32 
33 /// Mediates between COFF initialization and ExecutionSession state.
34 class COFFPlatform : public Platform {
35 public:
36   /// A function that will be called with the name of dll file that must be
37   /// loaded.
38   using LoadDynamicLibrary =
39       unique_function<Error(JITDylib &JD, StringRef DLLFileName)>;
40 
41   /// Try to create a COFFPlatform instance, adding the ORC runtime to the
42   /// given JITDylib.
43   static Expected<std::unique_ptr<COFFPlatform>>
44   Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
45          std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
46          LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime = false,
47          const char *VCRuntimePath = nullptr,
48          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
49 
50   static Expected<std::unique_ptr<COFFPlatform>>
51   Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
52          const char *OrcRuntimePath, LoadDynamicLibrary LoadDynLibrary,
53          bool StaticVCRuntime = false, const char *VCRuntimePath = nullptr,
54          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
55 
56   ExecutionSession &getExecutionSession() const { return ES; }
57   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
58 
59   Error setupJITDylib(JITDylib &JD) override;
60   Error teardownJITDylib(JITDylib &JD) override;
61   Error notifyAdding(ResourceTracker &RT,
62                      const MaterializationUnit &MU) override;
63   Error notifyRemoving(ResourceTracker &RT) override;
64 
65   /// Returns an AliasMap containing the default aliases for the COFFPlatform.
66   /// This can be modified by clients when constructing the platform to add
67   /// or remove aliases.
68   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
69 
70   /// Returns the array of required CXX aliases.
71   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
72 
73   /// Returns the array of standard runtime utility aliases for COFF.
74   static ArrayRef<std::pair<const char *, const char *>>
75   standardRuntimeUtilityAliases();
76 
77   static StringRef getSEHFrameSectionName() { return ".pdata"; }
78 
79 private:
80   using COFFJITDylibDepInfo = std::vector<ExecutorAddr>;
81   using COFFJITDylibDepInfoMap =
82       std::vector<std::pair<ExecutorAddr, COFFJITDylibDepInfo>>;
83   using COFFObjectSectionsMap =
84       SmallVector<std::pair<std::string, ExecutorAddrRange>>;
85   using PushInitializersSendResultFn =
86       unique_function<void(Expected<COFFJITDylibDepInfoMap>)>;
87   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
88   using JITDylibDepMap = DenseMap<JITDylib *, SmallVector<JITDylib *>>;
89 
90   // The COFFPlatformPlugin scans/modifies LinkGraphs to support COFF
91   // platform features including initializers, exceptions, and language
92   // runtime registration.
93   class COFFPlatformPlugin : public ObjectLinkingLayer::Plugin {
94   public:
95     COFFPlatformPlugin(COFFPlatform &CP) : CP(CP) {}
96 
97     void modifyPassConfig(MaterializationResponsibility &MR,
98                           jitlink::LinkGraph &G,
99                           jitlink::PassConfiguration &Config) override;
100 
101     // FIXME: We should be tentatively tracking scraped sections and discarding
102     // if the MR fails.
103     Error notifyFailed(MaterializationResponsibility &MR) override {
104       return Error::success();
105     }
106 
107     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
108       return Error::success();
109     }
110 
111     void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
112                                      ResourceKey SrcKey) override {}
113 
114   private:
115     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
116                                         MaterializationResponsibility &MR,
117                                         bool Bootstrap);
118 
119     Error preserveInitializerSections(jitlink::LinkGraph &G,
120                                       MaterializationResponsibility &MR);
121     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD);
122     Error registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph &G,
123                                                     JITDylib &JD);
124 
125     std::mutex PluginMutex;
126     COFFPlatform &CP;
127   };
128 
129   struct JDBootstrapState {
130     JITDylib *JD = nullptr;
131     std::string JDName;
132     ExecutorAddr HeaderAddr;
133     std::list<COFFObjectSectionsMap> ObjectSectionsMaps;
134     SmallVector<std::pair<std::string, ExecutorAddr>> Initializers;
135   };
136 
137   static bool supportedTarget(const Triple &TT);
138 
139   COFFPlatform(
140       ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
141       std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
142       std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
143       std::unique_ptr<object::Archive> OrcRuntimeArchive,
144       LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
145       const char *VCRuntimePath, Error &Err);
146 
147   // Associate COFFPlatform JIT-side runtime support functions with handlers.
148   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
149 
150   // Records the addresses of runtime symbols used by the platform.
151   Error bootstrapCOFFRuntime(JITDylib &PlatformJD);
152 
153   // Run a specific void function if it exists.
154   Error runSymbolIfExists(JITDylib &PlatformJD, StringRef SymbolName);
155 
156   // Run collected initializers in boostrap stage.
157   Error runBootstrapInitializers(JDBootstrapState &BState);
158   Error runBootstrapSubsectionInitializers(JDBootstrapState &BState,
159                                            StringRef Start, StringRef End);
160 
161   // Build dependency graph of a JITDylib
162   Expected<JITDylibDepMap> buildJDDepMap(JITDylib &JD);
163 
164   Expected<MemoryBufferRef> getPerJDObjectFile();
165 
166   // Implements rt_pushInitializers by making repeat async lookups for
167   // initializer symbols (each lookup may spawn more initializer symbols if
168   // it pulls in new materializers, e.g. from objects in a static library).
169   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
170                             JITDylibSP JD, JITDylibDepMap &JDDepMap);
171 
172   void rt_pushInitializers(PushInitializersSendResultFn SendResult,
173                            ExecutorAddr JDHeaderAddr);
174 
175   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
176                        StringRef SymbolName);
177 
178   ExecutionSession &ES;
179   ObjectLinkingLayer &ObjLinkingLayer;
180 
181   LoadDynamicLibrary LoadDynLibrary;
182   std::unique_ptr<COFFVCRuntimeBootstrapper> VCRuntimeBootstrap;
183   std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer;
184   std::unique_ptr<object::Archive> OrcRuntimeArchive;
185   bool StaticVCRuntime;
186 
187   SymbolStringPtr COFFHeaderStartSymbol;
188 
189   // State of bootstrap in progress
190   std::map<JITDylib *, JDBootstrapState> JDBootstrapStates;
191   std::atomic<bool> Bootstrapping;
192 
193   ExecutorAddr orc_rt_coff_platform_bootstrap;
194   ExecutorAddr orc_rt_coff_platform_shutdown;
195   ExecutorAddr orc_rt_coff_register_object_sections;
196   ExecutorAddr orc_rt_coff_deregister_object_sections;
197   ExecutorAddr orc_rt_coff_register_jitdylib;
198   ExecutorAddr orc_rt_coff_deregister_jitdylib;
199 
200   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr;
201   DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
202 
203   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
204 
205   std::set<std::string> DylibsToPreload;
206 
207   std::mutex PlatformMutex;
208 };
209 
210 } // end namespace orc
211 } // end namespace llvm
212 
213 #endif // LLVM_EXECUTIONENGINE_ORC_COFFPLATFORM_H
214