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>> |
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 | |
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>> |
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, VCLibs: ArrayRef(VCLibs), |
45 | UCRTLibs: ArrayRef(UCRTLibs))) |
46 | return std::move(Err); |
47 | return ImportedLibraries; |
48 | } |
49 | |
50 | Expected<std::vector<std::string>> |
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, VCLibs: ArrayRef(VCLibs), |
57 | UCRTLibs: ArrayRef(UCRTLibs))) |
58 | return std::move(Err); |
59 | return ImportedLibraries; |
60 | } |
61 | |
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(path&: LibPath, a: LibName); |
83 | |
84 | auto G = StaticLibraryDefinitionGenerator::Load(L&: ObjLinkingLayer, |
85 | FileName: LibPath.c_str()); |
86 | if (!G) |
87 | return G.takeError(); |
88 | |
89 | for (auto &Lib : (*G)->getImportedDynamicLibraries()) |
90 | ImportedLibraries.push_back(x: Lib); |
91 | |
92 | JD.addGenerator(DefGenerator: 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(x: "ntdll.dll" ); |
104 | ImportedLibraries.push_back(x: "Kernel32.dll" ); |
105 | |
106 | return Error::success(); |
107 | } |
108 | |
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, K: LookupKind::Static, SearchOrder: makeJITDylibSearchOrder(JDs: &JD), |
115 | Pairs: {{ES.intern(SymName: "__scrt_initialize_crt" ), &jit_scrt_initialize}, |
116 | {ES.intern(SymName: "__scrt_dllmain_before_initialize_c" ), |
117 | &jit_scrt_dllmain_before_initialize_c}, |
118 | {ES.intern(SymName: "?__scrt_initialize_type_info@@YAXXZ" ), |
119 | &jit_scrt_initialize_type_info}, |
120 | {ES.intern(SymName: "__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(VoidFnAddr: Addr)) |
126 | return Error::success(); |
127 | else |
128 | return Res.takeError(); |
129 | }; |
130 | |
131 | auto R = |
132 | ES.getExecutorProcessControl().runAsIntFunction(IntFnAddr: jit_scrt_initialize, Arg: 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(SymName: "__run_after_c_init" )] = { |
148 | ES.intern(SymName: "__scrt_dllmain_after_initialize_c" ), JITSymbolFlags::Exported}; |
149 | if (auto Err = JD.define(MU: symbolAliases(Aliases: Alias))) |
150 | return Err; |
151 | |
152 | return Error::success(); |
153 | } |
154 | |
155 | Expected<COFFVCRuntimeBootstrapper::MSVCToolchainPath> |
156 | COFFVCRuntimeBootstrapper::getMSVCToolchainPath() { |
157 | std::string VCToolChainPath; |
158 | ToolsetLayout VSLayout; |
159 | IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem(); |
160 | if (!findVCToolChainViaCommandLine(VFS&: *VFS, VCToolsDir: std::nullopt, VCToolsVersion: std::nullopt, |
161 | WinSysRoot: std::nullopt, Path&: VCToolChainPath, VSLayout) && |
162 | !findVCToolChainViaEnvironment(VFS&: *VFS, Path&: VCToolChainPath, VSLayout) && |
163 | !findVCToolChainViaSetupConfig(VFS&: *VFS, VCToolsVersion: {}, Path&: VCToolChainPath, VSLayout) && |
164 | !findVCToolChainViaRegistry(Path&: VCToolChainPath, VSLayout)) |
165 | return make_error<StringError>(Args: "Couldn't find msvc toolchain." , |
166 | Args: inconvertibleErrorCode()); |
167 | |
168 | std::string UniversalCRTSdkPath; |
169 | std::string UCRTVersion; |
170 | if (!getUniversalCRTSdkDir(VFS&: *VFS, WinSdkDir: std::nullopt, WinSdkVersion: std::nullopt, WinSysRoot: std::nullopt, |
171 | Path&: UniversalCRTSdkPath, UCRTVersion)) |
172 | return make_error<StringError>(Args: "Couldn't find universal sdk." , |
173 | Args: inconvertibleErrorCode()); |
174 | |
175 | MSVCToolchainPath ToolchainPath; |
176 | SmallString<256> VCToolchainLib(VCToolChainPath); |
177 | sys::path::append(path&: VCToolchainLib, a: "lib" , b: "x64" ); |
178 | ToolchainPath.VCToolchainLib = VCToolchainLib; |
179 | |
180 | SmallString<256> UCRTSdkLib(UniversalCRTSdkPath); |
181 | sys::path::append(path&: UCRTSdkLib, a: "Lib" , b: UCRTVersion, c: "ucrt" , d: "x64" ); |
182 | ToolchainPath.UCRTSdkLib = UCRTSdkLib; |
183 | return ToolchainPath; |
184 | } |
185 | |