1//===------- COFFVCRuntimeSupport.cpp - VC runtime support in ORC ---------===//
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#include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h"
10
11#include "llvm/ExecutionEngine/Orc/COFF.h"
12#include "llvm/ExecutionEngine/Orc/CallProxiesSPS.h"
13#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
14#include "llvm/ExecutionEngine/Orc/LookupAndApply.h"
15#include "llvm/ExecutionEngine/Orc/RecordProxy.h"
16#include "llvm/Support/VirtualFileSystem.h"
17#include "llvm/WindowsDriver/MSVCPaths.h"
18
19#define DEBUG_TYPE "orc"
20
21using namespace llvm;
22using namespace llvm::orc;
23using namespace llvm::orc::shared;
24
25Expected<std::unique_ptr<COFFVCRuntimeBootstrapper>>
26COFFVCRuntimeBootstrapper::Create(ExecutionSession &ES,
27 ObjectLinkingLayer &ObjLinkingLayer,
28 const char *RuntimePath) {
29 return std::unique_ptr<COFFVCRuntimeBootstrapper>(
30 new COFFVCRuntimeBootstrapper(ES, ObjLinkingLayer, RuntimePath));
31}
32
33COFFVCRuntimeBootstrapper::COFFVCRuntimeBootstrapper(
34 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
35 const char *RuntimePath)
36 : ES(ES), ObjLinkingLayer(ObjLinkingLayer) {
37 if (RuntimePath)
38 this->RuntimePath = RuntimePath;
39}
40
41Expected<std::vector<std::string>>
42COFFVCRuntimeBootstrapper::loadStaticVCRuntime(JITDylib &JD,
43 bool DebugVersion) {
44 StringRef VCLibs[] = {"libvcruntime.lib", "libcmt.lib", "libcpmt.lib"};
45 StringRef UCRTLibs[] = {"libucrt.lib"};
46 std::vector<std::string> ImportedLibraries;
47 if (auto Err = loadVCRuntime(JD, ImportedLibraries, VCLibs: ArrayRef(VCLibs),
48 UCRTLibs: ArrayRef(UCRTLibs)))
49 return std::move(Err);
50 return ImportedLibraries;
51}
52
53Expected<std::vector<std::string>>
54COFFVCRuntimeBootstrapper::loadDynamicVCRuntime(JITDylib &JD,
55 bool DebugVersion) {
56 StringRef VCLibs[] = {"vcruntime.lib", "msvcrt.lib", "msvcprt.lib"};
57 StringRef UCRTLibs[] = {"ucrt.lib"};
58 std::vector<std::string> ImportedLibraries;
59 if (auto Err = loadVCRuntime(JD, ImportedLibraries, VCLibs: ArrayRef(VCLibs),
60 UCRTLibs: ArrayRef(UCRTLibs)))
61 return std::move(Err);
62 return ImportedLibraries;
63}
64
65Error COFFVCRuntimeBootstrapper::loadVCRuntime(
66 JITDylib &JD, std::vector<std::string> &ImportedLibraries,
67 ArrayRef<StringRef> VCLibs, ArrayRef<StringRef> UCRTLibs) {
68 MSVCToolchainPath Path;
69 if (!RuntimePath.empty()) {
70 Path.UCRTSdkLib = RuntimePath;
71 Path.VCToolchainLib = RuntimePath;
72 } else {
73 auto ToolchainPath = getMSVCToolchainPath();
74 if (!ToolchainPath)
75 return ToolchainPath.takeError();
76 Path = *ToolchainPath;
77 }
78 LLVM_DEBUG({
79 dbgs() << "Using VC toolchain pathes\n";
80 dbgs() << " VC toolchain path: " << Path.VCToolchainLib << "\n";
81 dbgs() << " UCRT path: " << Path.UCRTSdkLib << "\n";
82 });
83
84 auto LoadLibrary = [&](SmallString<256> LibPath, StringRef LibName) -> Error {
85 sys::path::append(path&: LibPath, a: LibName);
86
87 std::set<std::string> NewImportedLibraries;
88 auto G = StaticLibraryDefinitionGenerator::Load(
89 L&: ObjLinkingLayer, FileName: LibPath.c_str(),
90 VisitMembers: COFFImportFileScanner(NewImportedLibraries));
91 if (!G)
92 return G.takeError();
93
94 llvm::append_range(C&: ImportedLibraries, R&: NewImportedLibraries);
95
96 JD.addGenerator(DefGenerator: std::move(*G));
97
98 return Error::success();
99 };
100 for (auto &Lib : UCRTLibs)
101 if (auto Err = LoadLibrary(Path.UCRTSdkLib, Lib))
102 return Err;
103
104 for (auto &Lib : VCLibs)
105 if (auto Err = LoadLibrary(Path.VCToolchainLib, Lib))
106 return Err;
107 ImportedLibraries.push_back(x: "ntdll.dll");
108 ImportedLibraries.push_back(x: "Kernel32.dll");
109
110 return Error::success();
111}
112
113Error COFFVCRuntimeBootstrapper::initializeStaticVCRuntime(JITDylib &JD) {
114 ExecutorAddr jit_scrt_initialize, jit_scrt_dllmain_before_initialize_c,
115 jit_scrt_initialize_type_info,
116 jit_scrt_initialize_default_local_stdio_options;
117 if (auto Err = lookupAndApply(
118 JD, PrepareFns: {recordAddr(Name: "__scrt_initialize_crt", A: &jit_scrt_initialize),
119 recordAddr(Name: "__scrt_dllmain_before_initialize_c",
120 A: &jit_scrt_dllmain_before_initialize_c),
121 recordAddr(Name: "?__scrt_initialize_type_info@@YAXXZ",
122 A: &jit_scrt_initialize_type_info),
123 recordAddr(Name: "__scrt_initialize_default_local_stdio_options",
124 A: &jit_scrt_initialize_default_local_stdio_options)}))
125 return Err;
126
127 CallInt32VoidProxy CallInt32Void;
128 CallInt32Int32Proxy CallInt32Int32;
129 if (auto Err = lookupAndApply(
130 JD&: ES.getBootstrapJITDylib(),
131 PrepareFns: {recordProxy<sps::CallInt32VoidProxySpec>(P: &CallInt32Void),
132 recordProxy<sps::CallInt32Int32ProxySpec>(P: &CallInt32Int32)}))
133 return Err;
134
135 auto R = CallInt32Int32(ES, jit_scrt_initialize, 0);
136 if (!R)
137 return R.takeError();
138
139 if (auto Err =
140 CallInt32Void(ES, jit_scrt_dllmain_before_initialize_c).takeError())
141 return Err;
142
143 if (auto Err = CallInt32Void(ES, jit_scrt_initialize_type_info).takeError())
144 return Err;
145
146 if (auto Err =
147 CallInt32Void(ES, jit_scrt_initialize_default_local_stdio_options)
148 .takeError())
149 return Err;
150
151 SymbolAliasMap Alias;
152 Alias[ES.intern(SymName: "__run_after_c_init")] = {
153 ES.intern(SymName: "__scrt_dllmain_after_initialize_c"), JITSymbolFlags::Exported};
154 if (auto Err = JD.define(MU: symbolAliases(Aliases: Alias)))
155 return Err;
156
157 return Error::success();
158}
159
160Expected<COFFVCRuntimeBootstrapper::MSVCToolchainPath>
161COFFVCRuntimeBootstrapper::getMSVCToolchainPath() {
162 std::string VCToolChainPath;
163 ToolsetLayout VSLayout;
164 IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
165 if (!findVCToolChainViaCommandLine(VFS&: *VFS, VCToolsDir: std::nullopt, VCToolsVersion: std::nullopt,
166 WinSysRoot: std::nullopt, Path&: VCToolChainPath, VSLayout) &&
167 !findVCToolChainViaEnvironment(VFS&: *VFS, Path&: VCToolChainPath, VSLayout) &&
168 !findVCToolChainViaSetupConfig(VFS&: *VFS, VCToolsVersion: {}, Path&: VCToolChainPath, VSLayout) &&
169 !findVCToolChainViaRegistry(Path&: VCToolChainPath, VSLayout))
170 return make_error<StringError>(Args: "Couldn't find msvc toolchain.",
171 Args: inconvertibleErrorCode());
172
173 std::string UniversalCRTSdkPath;
174 std::string UCRTVersion;
175 if (!getUniversalCRTSdkDir(VFS&: *VFS, WinSdkDir: std::nullopt, WinSdkVersion: std::nullopt, WinSysRoot: std::nullopt,
176 Path&: UniversalCRTSdkPath, UCRTVersion))
177 return make_error<StringError>(Args: "Couldn't find universal sdk.",
178 Args: inconvertibleErrorCode());
179
180 MSVCToolchainPath ToolchainPath;
181 SmallString<256> VCToolchainLib(VCToolChainPath);
182 sys::path::append(path&: VCToolchainLib, a: "lib", b: "x64");
183 ToolchainPath.VCToolchainLib = std::move(VCToolchainLib);
184
185 SmallString<256> UCRTSdkLib(UniversalCRTSdkPath);
186 sys::path::append(path&: UCRTSdkLib, a: "Lib", b: UCRTVersion, c: "ucrt", d: "x64");
187 ToolchainPath.UCRTSdkLib = std::move(UCRTSdkLib);
188 return ToolchainPath;
189}
190