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