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