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 <memory>
26 #include <thread>
27 #include <vector>
28 
29 namespace llvm {
30 namespace orc {
31 
32 /// Mediates between COFF initialization and ExecutionSession state.
33 class COFFPlatform : public Platform {
34 public:
35   /// A function that will be called with the name of dll file that must be
36   /// loaded.
37   using LoadDynamicLibrary =
38       unique_function<Error(JITDylib &JD, StringRef DLLFileName)>;
39 
40   /// Try to create a COFFPlatform instance, adding the ORC runtime to the
41   /// given JITDylib.
42   static Expected<std::unique_ptr<COFFPlatform>>
43   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
44          JITDylib &PlatformJD, const char *OrcRuntimePath,
45          LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime = false,
46          const char *VCRuntimePath = nullptr,
47          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
48 
49   ExecutionSession &getExecutionSession() const { return ES; }
50   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
51 
52   Error setupJITDylib(JITDylib &JD) override;
53   Error teardownJITDylib(JITDylib &JD) override;
54   Error notifyAdding(ResourceTracker &RT,
55                      const MaterializationUnit &MU) override;
56   Error notifyRemoving(ResourceTracker &RT) override;
57 
58   /// Returns an AliasMap containing the default aliases for the COFFPlatform.
59   /// This can be modified by clients when constructing the platform to add
60   /// or remove aliases.
61   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
62 
63   /// Returns the array of required CXX aliases.
64   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
65 
66   /// Returns the array of standard runtime utility aliases for COFF.
67   static ArrayRef<std::pair<const char *, const char *>>
68   standardRuntimeUtilityAliases();
69 
70   static bool isInitializerSection(StringRef Name) {
71     return Name.startswith(".CRT");
72   }
73 
74   static StringRef getSEHFrameSectionName() { return ".pdata"; }
75 
76 private:
77   using COFFJITDylibDepInfo = std::vector<ExecutorAddr>;
78   using COFFJITDylibDepInfoMap =
79       std::vector<std::pair<ExecutorAddr, COFFJITDylibDepInfo>>;
80   using COFFObjectSectionsMap =
81       SmallVector<std::pair<std::string, ExecutorAddrRange>>;
82   using PushInitializersSendResultFn =
83       unique_function<void(Expected<COFFJITDylibDepInfoMap>)>;
84   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
85   using JITDylibDepMap = DenseMap<JITDylib *, SmallVector<JITDylib *>>;
86 
87   // The COFFPlatformPlugin scans/modifies LinkGraphs to support COFF
88   // platform features including initializers, exceptions, and language
89   // runtime registration.
90   class COFFPlatformPlugin : public ObjectLinkingLayer::Plugin {
91   public:
92     COFFPlatformPlugin(COFFPlatform &CP) : CP(CP) {}
93 
94     void modifyPassConfig(MaterializationResponsibility &MR,
95                           jitlink::LinkGraph &G,
96                           jitlink::PassConfiguration &Config) override;
97 
98     SyntheticSymbolDependenciesMap
99     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) 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     using InitSymbolDepMap =
116         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
117 
118     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
119                                         MaterializationResponsibility &MR,
120                                         bool Bootstrap);
121 
122     Error preserveInitializerSections(jitlink::LinkGraph &G,
123                                       MaterializationResponsibility &MR);
124     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD);
125     Error registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph &G,
126                                                     JITDylib &JD);
127 
128     std::mutex PluginMutex;
129     COFFPlatform &CP;
130     InitSymbolDepMap InitSymbolDeps;
131   };
132 
133   struct JDBootstrapState {
134     JITDylib *JD = nullptr;
135     std::string JDName;
136     ExecutorAddr HeaderAddr;
137     std::list<COFFObjectSectionsMap> ObjectSectionsMaps;
138     SmallVector<std::pair<std::string, ExecutorAddr>> Initializers;
139   };
140 
141   static bool supportedTarget(const Triple &TT);
142 
143   COFFPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
144                JITDylib &PlatformJD, const char *OrcRuntimePath,
145                LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
146                const char *VCRuntimePath, Error &Err);
147 
148   // Associate COFFPlatform JIT-side runtime support functions with handlers.
149   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
150 
151   // Records the addresses of runtime symbols used by the platform.
152   Error bootstrapCOFFRuntime(JITDylib &PlatformJD);
153 
154   // Run a specific void function if it exists.
155   Error runSymbolIfExists(JITDylib &PlatformJD, StringRef SymbolName);
156 
157   // Run collected initializers in boostrap stage.
158   Error runBootstrapInitializers(JDBootstrapState &BState);
159   Error runBootstrapSubsectionInitializers(JDBootstrapState &BState,
160                                            StringRef Start, StringRef End);
161 
162   // Build dependency graph of a JITDylib
163   Expected<JITDylibDepMap> buildJDDepMap(JITDylib &JD);
164 
165   Expected<MemoryBufferRef> getPerJDObjectFile();
166 
167   // Implements rt_pushInitializers by making repeat async lookups for
168   // initializer symbols (each lookup may spawn more initializer symbols if
169   // it pulls in new materializers, e.g. from objects in a static library).
170   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
171                             JITDylibSP JD, JITDylibDepMap &JDDepMap);
172 
173   void rt_pushInitializers(PushInitializersSendResultFn SendResult,
174                            ExecutorAddr JDHeaderAddr);
175 
176   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
177                        StringRef SymbolName);
178 
179   ExecutionSession &ES;
180   ObjectLinkingLayer &ObjLinkingLayer;
181 
182   LoadDynamicLibrary LoadDynLibrary;
183   std::unique_ptr<COFFVCRuntimeBootstrapper> VCRuntimeBootstrap;
184   std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer;
185   std::unique_ptr<object::Archive> OrcRuntimeArchive;
186   bool StaticVCRuntime;
187 
188   SymbolStringPtr COFFHeaderStartSymbol;
189 
190   // State of bootstrap in progress
191   std::map<JITDylib *, JDBootstrapState> JDBootstrapStates;
192   std::atomic<bool> Bootstrapping;
193 
194   ExecutorAddr orc_rt_coff_platform_bootstrap;
195   ExecutorAddr orc_rt_coff_platform_shutdown;
196   ExecutorAddr orc_rt_coff_register_object_sections;
197   ExecutorAddr orc_rt_coff_deregister_object_sections;
198   ExecutorAddr orc_rt_coff_register_jitdylib;
199   ExecutorAddr orc_rt_coff_deregister_jitdylib;
200 
201   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr;
202   DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
203 
204   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
205 
206   std::set<std::string> DylibsToPreload;
207 
208   std::mutex PlatformMutex;
209 };
210 
211 } // end namespace orc
212 } // end namespace llvm
213 
214 #endif // LLVM_EXECUTIONENGINE_ORC_COFFPLATFORM_H
215