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