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
18using namespace llvm;
19using namespace llvm::orc;
20using namespace llvm::orc::shared;
21
22Expected<std::unique_ptr<COFFVCRuntimeBootstrapper>>
23COFFVCRuntimeBootstrapper::Create(ExecutionSession &ES,
24                                  ObjectLinkingLayer &ObjLinkingLayer,
25                                  const char *RuntimePath) {
26  return std::unique_ptr<COFFVCRuntimeBootstrapper>(
27      new COFFVCRuntimeBootstrapper(ES, ObjLinkingLayer, RuntimePath));
28}
29
30COFFVCRuntimeBootstrapper::COFFVCRuntimeBootstrapper(
31    ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
32    const char *RuntimePath)
33    : ES(ES), ObjLinkingLayer(ObjLinkingLayer) {
34  if (RuntimePath)
35    this->RuntimePath = RuntimePath;
36}
37
38Expected<std::vector<std::string>>
39COFFVCRuntimeBootstrapper::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
50Expected<std::vector<std::string>>
51COFFVCRuntimeBootstrapper::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
62Error 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
109Error 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
155Expected<COFFVCRuntimeBootstrapper::MSVCToolchainPath>
156COFFVCRuntimeBootstrapper::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