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, ArrayRef(VCLibs), 46 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, ArrayRef(VCLibs), 58 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(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 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> 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