//===------- COFFVCRuntimeSupport.cpp - VC runtime support in ORC ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/WindowsDriver/MSVCPaths.h" #define DEBUG_TYPE "orc" using namespace llvm; using namespace llvm::orc; using namespace llvm::orc::shared; Expected> COFFVCRuntimeBootstrapper::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, const char *RuntimePath) { return std::unique_ptr( new COFFVCRuntimeBootstrapper(ES, ObjLinkingLayer, RuntimePath)); } COFFVCRuntimeBootstrapper::COFFVCRuntimeBootstrapper( ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, const char *RuntimePath) : ES(ES), ObjLinkingLayer(ObjLinkingLayer) { if (RuntimePath) this->RuntimePath = RuntimePath; } Expected> COFFVCRuntimeBootstrapper::loadStaticVCRuntime(JITDylib &JD, bool DebugVersion) { StringRef VCLibs[] = {"libvcruntime.lib", "libcmt.lib", "libcpmt.lib"}; StringRef UCRTLibs[] = {"libucrt.lib"}; std::vector ImportedLibraries; if (auto Err = loadVCRuntime(JD, ImportedLibraries, ArrayRef(VCLibs), ArrayRef(UCRTLibs))) return std::move(Err); return ImportedLibraries; } Expected> COFFVCRuntimeBootstrapper::loadDynamicVCRuntime(JITDylib &JD, bool DebugVersion) { StringRef VCLibs[] = {"vcruntime.lib", "msvcrt.lib", "msvcprt.lib"}; StringRef UCRTLibs[] = {"ucrt.lib"}; std::vector ImportedLibraries; if (auto Err = loadVCRuntime(JD, ImportedLibraries, ArrayRef(VCLibs), ArrayRef(UCRTLibs))) return std::move(Err); return ImportedLibraries; } Error COFFVCRuntimeBootstrapper::loadVCRuntime( JITDylib &JD, std::vector &ImportedLibraries, ArrayRef VCLibs, ArrayRef UCRTLibs) { MSVCToolchainPath Path; if (!RuntimePath.empty()) { Path.UCRTSdkLib = RuntimePath; Path.VCToolchainLib = RuntimePath; } else { auto ToolchainPath = getMSVCToolchainPath(); if (!ToolchainPath) return ToolchainPath.takeError(); Path = *ToolchainPath; } LLVM_DEBUG({ dbgs() << "Using VC toolchain pathes\n"; dbgs() << " VC toolchain path: " << Path.VCToolchainLib << "\n"; dbgs() << " UCRT path: " << Path.UCRTSdkLib << "\n"; }); auto LoadLibrary = [&](SmallString<256> LibPath, StringRef LibName) -> Error { sys::path::append(LibPath, LibName); auto G = StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, LibPath.c_str()); if (!G) return G.takeError(); for (auto &Lib : (*G)->getImportedDynamicLibraries()) ImportedLibraries.push_back(Lib); JD.addGenerator(std::move(*G)); return Error::success(); }; for (auto &Lib : UCRTLibs) if (auto Err = LoadLibrary(Path.UCRTSdkLib, Lib)) return Err; for (auto &Lib : VCLibs) if (auto Err = LoadLibrary(Path.VCToolchainLib, Lib)) return Err; ImportedLibraries.push_back("ntdll.dll"); ImportedLibraries.push_back("Kernel32.dll"); return Error::success(); } Error COFFVCRuntimeBootstrapper::initializeStaticVCRuntime(JITDylib &JD) { ExecutorAddr jit_scrt_initialize, jit_scrt_dllmain_before_initialize_c, jit_scrt_initialize_type_info, jit_scrt_initialize_default_local_stdio_options; if (auto Err = lookupAndRecordAddrs( ES, LookupKind::Static, makeJITDylibSearchOrder(&JD), {{ES.intern("__scrt_initialize_crt"), &jit_scrt_initialize}, {ES.intern("__scrt_dllmain_before_initialize_c"), &jit_scrt_dllmain_before_initialize_c}, {ES.intern("?__scrt_initialize_type_info@@YAXXZ"), &jit_scrt_initialize_type_info}, {ES.intern("__scrt_initialize_default_local_stdio_options"), &jit_scrt_initialize_default_local_stdio_options}})) return Err; auto RunVoidInitFunc = [&](ExecutorAddr Addr) -> Error { if (auto Res = ES.getExecutorProcessControl().runAsVoidFunction(Addr)) return Error::success(); else return Res.takeError(); }; auto R = ES.getExecutorProcessControl().runAsIntFunction(jit_scrt_initialize, 0); if (!R) return R.takeError(); if (auto Err = RunVoidInitFunc(jit_scrt_dllmain_before_initialize_c)) return Err; if (auto Err = RunVoidInitFunc(jit_scrt_initialize_type_info)) return Err; if (auto Err = RunVoidInitFunc(jit_scrt_initialize_default_local_stdio_options)) return Err; SymbolAliasMap Alias; Alias[ES.intern("__run_after_c_init")] = { ES.intern("__scrt_dllmain_after_initialize_c"), JITSymbolFlags::Exported}; if (auto Err = JD.define(symbolAliases(Alias))) return Err; return Error::success(); } Expected COFFVCRuntimeBootstrapper::getMSVCToolchainPath() { std::string VCToolChainPath; ToolsetLayout VSLayout; IntrusiveRefCntPtr VFS = vfs::getRealFileSystem(); if (!findVCToolChainViaCommandLine(*VFS, std::nullopt, std::nullopt, std::nullopt, VCToolChainPath, VSLayout) && !findVCToolChainViaEnvironment(*VFS, VCToolChainPath, VSLayout) && !findVCToolChainViaSetupConfig(*VFS, {}, VCToolChainPath, VSLayout) && !findVCToolChainViaRegistry(VCToolChainPath, VSLayout)) return make_error("Couldn't find msvc toolchain.", inconvertibleErrorCode()); std::string UniversalCRTSdkPath; std::string UCRTVersion; if (!getUniversalCRTSdkDir(*VFS, std::nullopt, std::nullopt, std::nullopt, UniversalCRTSdkPath, UCRTVersion)) return make_error("Couldn't find universal sdk.", inconvertibleErrorCode()); MSVCToolchainPath ToolchainPath; SmallString<256> VCToolchainLib(VCToolChainPath); sys::path::append(VCToolchainLib, "lib", "x64"); ToolchainPath.VCToolchainLib = VCToolchainLib; SmallString<256> UCRTSdkLib(UniversalCRTSdkPath); sys::path::append(UCRTSdkLib, "Lib", UCRTVersion, "ucrt", "x64"); ToolchainPath.UCRTSdkLib = UCRTSdkLib; return ToolchainPath; }