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, ArrayRef(VCLibs),
45                                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, ArrayRef(VCLibs),
57                                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(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 
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>
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