xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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