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