Index: llvm/include/llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h =================================================================== --- /dev/null +++ llvm/include/llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h @@ -0,0 +1,94 @@ +//===----- COFFVCRuntimeSupport.h -- VC runtime support in ORC --*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Utilities for loading and initializaing vc runtime in Orc. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_COFFCRUNTIMESUPPORT_H +#define LLVM_EXECUTIONENGINE_ORC_COFFCRUNTIMESUPPORT_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" + +#include +#include +#include +#include + +namespace llvm { +namespace orc { + +/// Bootstraps the vc runtime within jitdylibs. +class COFFVCRuntimeBootstrapper { +public: + /// A function that will be called with the name of dll file that must be + /// loaded. + using LoadDynamicLibrary = + unique_function; + + /// Try to create a COFFVCRuntimeBootstrapper instance. An optional + /// RuntimePath can be given to specify the location of directory that + /// contains all vc runtime library files such as ucrt.lib and msvcrt.lib. If + /// not path was given, it will try to search the MSVC toolchain and Windows + /// SDK installation and use the found library files automatically. + /// + /// Note that depending on the build setting, a different library + /// file must be used. In general, if vc runtime was statically linked to the + /// object file that is to be jit-linked, LoadStaticVCRuntime and + /// InitializeStaticVCRuntime must be used with libcmt.lib, libucrt.lib, + /// libvcruntimelib. If vc runtime was dynamically linked LoadDynamicVCRuntime + /// must be used along with msvcrt.lib, ucrt.lib, vcruntime.lib. + /// + /// More information is on: + /// https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features + static Expected> + Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, + LoadDynamicLibrary LoadDynLibrary, const char *RuntimePath = nullptr); + + /// Adds symbol definitions of static version of msvc runtime libraries. + Error loadStaticVCRuntime(JITDylib &JD, bool DebugVersion = false); + + /// Runs the initializer of static version of msvc runtime libraries. + /// This must be called before calling any functions requiring c runtime (e.g. + /// printf) within the jit session. Note that proper initialization of vc + /// runtime requires ability of running static initializers. Cosider setting + /// up COFFPlatform. + Error initializeStaticVCRuntime(JITDylib &JD); + + /// Adds symbol definitions of dynamic versino of msvc runtie libraries. + Error loadDynamicVCRuntime(JITDylib &JD, bool DebugVersion = false); + +private: + COFFVCRuntimeBootstrapper(ExecutionSession &ES, + ObjectLinkingLayer &ObjLinkingLayer, + LoadDynamicLibrary LoadDynLibrary, + const char *RuntimePath); + + ExecutionSession &ES; + ObjectLinkingLayer &ObjLinkingLayer; + std::string RuntimePath; + LoadDynamicLibrary LoadDynLibrary; + + struct MSVCToolchainPath { + SmallString<256> VCToolchainLib; + SmallString<256> UCRTSdkLib; + }; + + static Expected getMSVCToolchainPath(); + Error lLoadVCRuntime(JITDylib &JD, ArrayRef VCLibs, + ArrayRef UCRTLibs); +}; + +} // namespace orc +} // namespace llvm + +#endif Index: llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h =================================================================== --- llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h +++ llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h @@ -259,6 +259,13 @@ virtual Expected runAsMain(ExecutorAddr MainFnAddr, ArrayRef Args) = 0; + /// Run function with a int (*)(void) signature. + virtual Expected runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0; + + /// Run function with a int (*)(int) signature. + virtual Expected runAsIntFunction(ExecutorAddr IntFnAddr, + int Arg) = 0; + /// Run a wrapper function in the executor. The given WFRHandler will be /// called on the result when it is returned. /// @@ -397,6 +404,14 @@ llvm_unreachable("Unsupported"); } + Expected runAsVoidFunction(ExecutorAddr VoidFnAddr) override { + llvm_unreachable("Unsupported"); + } + + Expected runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override { + llvm_unreachable("Unsupported"); + } + void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef ArgBuffer) override { @@ -434,6 +449,10 @@ Expected runAsMain(ExecutorAddr MainFnAddr, ArrayRef Args) override; + Expected runAsVoidFunction(ExecutorAddr VoidFnAddr) override; + + Expected runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override; + void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef ArgBuffer) override; Index: llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h =================================================================== --- llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h +++ llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h @@ -47,6 +47,8 @@ extern const char *DeregisterEHFrameSectionWrapperName; extern const char *RunAsMainWrapperName; +extern const char *RunAsVoidFunctionWrapperName; +extern const char *RunAsIntFunctionWrapperName; using SPSSimpleExecutorDylibManagerOpenSignature = shared::SPSExpected(shared::SPSExecutorAddr, shared::SPSString, @@ -81,7 +83,8 @@ using SPSRunAsMainSignature = int64_t(shared::SPSExecutorAddr, shared::SPSSequence); - +using SPSRunAsVoidFunctionSignature = int32_t(shared::SPSExecutorAddr); +using SPSRunAsIntFunctionSignature = int32_t(shared::SPSExecutorAddr, int32_t); } // end namespace rt } // end namespace orc } // end namespace llvm Index: llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h =================================================================== --- llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h +++ llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h @@ -77,6 +77,10 @@ Expected runAsMain(ExecutorAddr MainFnAddr, ArrayRef Args) override; + Expected runAsVoidFunction(ExecutorAddr VoidFnAddr) override; + + Expected runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override; + void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef ArgBuffer) override; @@ -129,6 +133,8 @@ std::unique_ptr DylibMgr; ExecutorAddr RunAsMainAddr; + ExecutorAddr RunAsVoidFunctionAddr; + ExecutorAddr RunAsIntFunctionAddr; uint64_t NextSeqNo = 0; PendingCallWrapperResultsMap PendingCallWrapperResults; Index: llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h =================================================================== --- llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h +++ llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h @@ -32,6 +32,9 @@ int runAsMain(int (*Main)(int, char *[]), ArrayRef Args, Optional ProgramName = None); +int runAsVoidFunction(int (*Func)(void)); +int runAsIntFunction(int (*Func)(int), int Arg); + } // end namespace orc } // end namespace llvm Index: llvm/lib/ExecutionEngine/Orc/CMakeLists.txt =================================================================== --- llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -3,6 +3,7 @@ endif() add_llvm_component_library(LLVMOrcJIT + COFFVCRuntimeSupport.cpp CompileOnDemandLayer.cpp CompileUtils.cpp Core.cpp @@ -59,6 +60,7 @@ Object OrcShared OrcTargetProcess + WindowsDriver MC MCDisassembler Passes Index: llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp =================================================================== --- /dev/null +++ llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp @@ -0,0 +1,186 @@ +//===------- 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, + LoadDynamicLibrary LoadDynLibrary, + const char *RuntimePath) { + return std::unique_ptr( + new COFFVCRuntimeBootstrapper(ES, ObjLinkingLayer, + std::move(LoadDynLibrary), RuntimePath)); +} + +COFFVCRuntimeBootstrapper::COFFVCRuntimeBootstrapper( + ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, + LoadDynamicLibrary LoadDynLibrary, const char *RuntimePath) + : ES(ES), ObjLinkingLayer(ObjLinkingLayer), + LoadDynLibrary(std::move(LoadDynLibrary)) { + if (RuntimePath) + this->RuntimePath = RuntimePath; +} + +Error COFFVCRuntimeBootstrapper::loadStaticVCRuntime(JITDylib &JD, + bool DebugVersion) { + StringRef VCLibs[] = {"libvcruntime.lib", "libcmt.lib", "libcpmt.lib"}; + StringRef UCRTLibs[] = {"libucrt.lib"}; + if (auto Err = + lLoadVCRuntime(JD, makeArrayRef(VCLibs), makeArrayRef(UCRTLibs))) + return Err; + + return Error::success(); +} + +Error COFFVCRuntimeBootstrapper::loadDynamicVCRuntime(JITDylib &JD, + bool DebugVersion) { + StringRef VCLibs[] = {"vcruntime.lib", "msvcrt.lib", "msvcprt.lib"}; + StringRef UCRTLibs[] = {"ucrt.lib"}; + return lLoadVCRuntime(JD, makeArrayRef(VCLibs), makeArrayRef(UCRTLibs)); +} + +Error COFFVCRuntimeBootstrapper::lLoadVCRuntime(JITDylib &JD, + 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"; + }); + + std::vector ImportedLibraries; + 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"); + + for (auto &Lib : ImportedLibraries) + if (auto Err = LoadDynLibrary(JD, Lib)) + return Err; + + 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, None, None, None, 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, None, None, None, 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; +} Index: llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp =================================================================== --- llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp +++ llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp @@ -121,6 +121,18 @@ return orc::runAsMain(MainFnAddr.toPtr(), Args); } +Expected +SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) { + using VoidTy = int (*)(); + return orc::runAsVoidFunction(VoidFnAddr.toPtr()); +} + +Expected +SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) { + using IntTy = int (*)(int); + return orc::runAsIntFunction(IntFnAddr.toPtr(), Arg); +} + void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler SendResult, ArrayRef ArgBuffer) { Index: llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp =================================================================== --- llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp +++ llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp @@ -56,6 +56,10 @@ "__llvm_orc_bootstrap_deregister_ehframe_section_wrapper"; const char *RunAsMainWrapperName = "__llvm_orc_bootstrap_run_as_main_wrapper"; +const char *RunAsVoidFunctionWrapperName = + "__llvm_orc_bootstrap_run_as_void_function_wrapper"; +const char *RunAsIntFunctionWrapperName = + "__llvm_orc_bootstrap_run_as_int_function_wrapper"; } // end namespace rt } // end namespace orc Index: llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp =================================================================== --- llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp +++ llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp @@ -54,6 +54,23 @@ return Result; } +Expected SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr) { + int32_t Result = 0; + if (auto Err = callSPSWrapper( + RunAsVoidFunctionAddr, Result, ExecutorAddr(VoidFnAddr))) + return std::move(Err); + return Result; +} + +Expected SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr, + int Arg) { + int32_t Result = 0; + if (auto Err = callSPSWrapper( + RunAsIntFunctionAddr, Result, ExecutorAddr(IntFnAddr), Arg)) + return std::move(Err); + return Result; +} + void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef ArgBuffer) { @@ -312,7 +329,9 @@ if (auto Err = getBootstrapSymbols( {{JDI.JITDispatchContext, ExecutorSessionObjectName}, {JDI.JITDispatchFunction, DispatchFnName}, - {RunAsMainAddr, rt::RunAsMainWrapperName}})) + {RunAsMainAddr, rt::RunAsMainWrapperName}, + {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName}, + {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}})) return Err; if (auto DM = Index: llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp =================================================================== --- llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp +++ llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp @@ -56,6 +56,27 @@ .release(); } +static llvm::orc::shared::CWrapperFunctionResult +runAsVoidFunctionWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction::handle( + ArgData, ArgSize, + [](ExecutorAddr MainAddr) -> int32_t { + return runAsVoidFunction(MainAddr.toPtr()); + }) + .release(); +} + +static llvm::orc::shared::CWrapperFunctionResult +runAsIntFunctionWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction::handle( + ArgData, ArgSize, + [](ExecutorAddr MainAddr, int32_t Arg) -> int32_t { + return runAsIntFunction(MainAddr.toPtr(), + Arg); + }) + .release(); +} + void addTo(StringMap &M) { M[rt::MemoryWriteUInt8sWrapperName] = ExecutorAddr::fromPtr( &writeUIntsWrapper