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: SymbolNameSpec::verbatim(Name: "__scrt_initialize_crt"),
119 A: &jit_scrt_initialize),
120 recordAddr(Name: SymbolNameSpec::verbatim(
121 Name: "__scrt_dllmain_before_initialize_c"),
122 A: &jit_scrt_dllmain_before_initialize_c),
123 recordAddr(Name: SymbolNameSpec::verbatim(
124 Name: "?__scrt_initialize_type_info@@YAXXZ"),
125 A: &jit_scrt_initialize_type_info),
126 recordAddr(Name: SymbolNameSpec::verbatim(
127 Name: "__scrt_initialize_default_local_stdio_options"),
128 A: &jit_scrt_initialize_default_local_stdio_options)}))
129 return Err;
130
131 CallInt32VoidProxy CallInt32Void;
132 CallInt32Int32Proxy CallInt32Int32;
133 if (auto Err = lookupAndApply(
134 JD&: ES.getBootstrapJITDylib(),
135 PrepareFns: {recordProxy<sps::CallInt32VoidProxySpec>(P: &CallInt32Void),
136 recordProxy<sps::CallInt32Int32ProxySpec>(P: &CallInt32Int32)}))
137 return Err;
138
139 auto R = CallInt32Int32(ES, jit_scrt_initialize, 0);
140 if (!R)
141 return R.takeError();
142
143 if (auto Err =
144 CallInt32Void(ES, jit_scrt_dllmain_before_initialize_c).takeError())
145 return Err;
146
147 if (auto Err = CallInt32Void(ES, jit_scrt_initialize_type_info).takeError())
148 return Err;
149
150 if (auto Err =
151 CallInt32Void(ES, jit_scrt_initialize_default_local_stdio_options)
152 .takeError())
153 return Err;
154
155 SymbolAliasMap Alias;
156 Alias[ES.intern(SymName: "__run_after_c_init")] = {
157 ES.intern(SymName: "__scrt_dllmain_after_initialize_c"), JITSymbolFlags::Exported};
158 if (auto Err = JD.define(MU: symbolAliases(Aliases: Alias)))
159 return Err;
160
161 return Error::success();
162}
163
164Expected<COFFVCRuntimeBootstrapper::MSVCToolchainPath>
165COFFVCRuntimeBootstrapper::getMSVCToolchainPath() {
166 std::string VCToolChainPath;
167 ToolsetLayout VSLayout;
168 IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
169 if (!findVCToolChainViaCommandLine(VFS&: *VFS, VCToolsDir: std::nullopt, VCToolsVersion: std::nullopt,
170 WinSysRoot: std::nullopt, Path&: VCToolChainPath, VSLayout) &&
171 !findVCToolChainViaEnvironment(VFS&: *VFS, Path&: VCToolChainPath, VSLayout) &&
172 !findVCToolChainViaSetupConfig(VFS&: *VFS, VCToolsVersion: {}, Path&: VCToolChainPath, VSLayout) &&
173 !findVCToolChainViaRegistry(Path&: VCToolChainPath, VSLayout))
174 return make_error<StringError>(Args: "Couldn't find msvc toolchain.",
175 Args: inconvertibleErrorCode());
176
177 std::string UniversalCRTSdkPath;
178 std::string UCRTVersion;
179 if (!getUniversalCRTSdkDir(VFS&: *VFS, WinSdkDir: std::nullopt, WinSdkVersion: std::nullopt, WinSysRoot: std::nullopt,
180 Path&: UniversalCRTSdkPath, UCRTVersion))
181 return make_error<StringError>(Args: "Couldn't find universal sdk.",
182 Args: inconvertibleErrorCode());
183
184 MSVCToolchainPath ToolchainPath;
185 SmallString<256> VCToolchainLib(VCToolChainPath);
186 sys::path::append(path&: VCToolchainLib, a: "lib", b: "x64");
187 ToolchainPath.VCToolchainLib = std::move(VCToolchainLib);
188
189 SmallString<256> UCRTSdkLib(UniversalCRTSdkPath);
190 sys::path::append(path&: UCRTSdkLib, a: "Lib", b: UCRTVersion, c: "ucrt", d: "x64");
191 ToolchainPath.UCRTSdkLib = std::move(UCRTSdkLib);
192 return ToolchainPath;
193}
194