1447762daSMichael J. Spencer//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// 2447762daSMichael J. Spencer// 32946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6447762daSMichael J. Spencer// 7447762daSMichael J. Spencer//===----------------------------------------------------------------------===// 8447762daSMichael J. Spencer// 9447762daSMichael J. Spencer// This file provides the Win32 specific implementation of DynamicLibrary. 10447762daSMichael J. Spencer// 11447762daSMichael J. Spencer//===----------------------------------------------------------------------===// 12447762daSMichael J. Spencer 13*01f9abbbSHans Wennborg#include "llvm/Support/Windows/WindowsSupport.h" 14b44d7a0dSZachary Turner#include "llvm/Support/ConvertUTF.h" 15c1db8cf9SFrederich Munch#include "llvm/Support/raw_ostream.h" 16447762daSMichael J. Spencer 17c1db8cf9SFrederich Munch#include <psapi.h> 18b8c236a6SFrederich Munch 19447762daSMichael J. Spencer//===----------------------------------------------------------------------===// 20447762daSMichael J. Spencer//=== WARNING: Implementation here must contain only Win32 specific code 21447762daSMichael J. Spencer//=== and must not be UNIX code. 22447762daSMichael J. Spencer//===----------------------------------------------------------------------===// 23447762daSMichael J. Spencer 24447762daSMichael J. Spencer 25c1db8cf9SFrederich MunchDynamicLibrary::HandleSet::~HandleSet() { 26ad125800SFrederich Munch for (void *Handle : llvm::reverse(Handles)) 27c1db8cf9SFrederich Munch FreeLibrary(HMODULE(Handle)); 28c1db8cf9SFrederich Munch 29c1db8cf9SFrederich Munch // 'Process' should not be released on Windows. 30c1db8cf9SFrederich Munch assert((!Process || Process==this) && "Bad Handle"); 315fdd2cbaSFrederich Munch // llvm_shutdown called, Return to default 325fdd2cbaSFrederich Munch DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; 33bebb27b0SLeny Kholodov} 34bebb27b0SLeny Kholodov 35c1db8cf9SFrederich Munchvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { 36c1db8cf9SFrederich Munch // Create the instance and return it to be the *Process* handle 37c1db8cf9SFrederich Munch // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) 38c1db8cf9SFrederich Munch if (!File) 39c1db8cf9SFrederich Munch return &(*OpenedHandles); 40447762daSMichael J. Spencer 41c1db8cf9SFrederich Munch SmallVector<wchar_t, MAX_PATH> FileUnicode; 42c1db8cf9SFrederich Munch if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { 4361eae2e3SDavid Majnemer SetLastError(ec.value()); 44c1db8cf9SFrederich Munch MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); 45c1db8cf9SFrederich Munch return &DynamicLibrary::Invalid; 4661eae2e3SDavid Majnemer } 4761eae2e3SDavid Majnemer 48c1db8cf9SFrederich Munch HMODULE Handle = LoadLibraryW(FileUnicode.data()); 49c1db8cf9SFrederich Munch if (Handle == NULL) { 50c1db8cf9SFrederich Munch MakeErrMsg(Err, std::string(File) + ": Can't open"); 51c1db8cf9SFrederich Munch return &DynamicLibrary::Invalid; 52a19917daSJordy Rose } 53a19917daSJordy Rose 54c1db8cf9SFrederich Munch return reinterpret_cast<void*>(Handle); 55447762daSMichael J. Spencer} 56447762daSMichael J. Spencer 57c1db8cf9SFrederich Munchstatic DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { 58c1db8cf9SFrederich Munch if (!OpenedHandles.isConstructed()) 59c1db8cf9SFrederich Munch return nullptr; 60c1db8cf9SFrederich Munch DynamicLibrary::HandleSet &Inst = *OpenedHandles; 61c1db8cf9SFrederich Munch return Handle == &Inst ? &Inst : nullptr; 627f1c255dSVassil Vassilev} 637f1c255dSVassil Vassilev 64c1db8cf9SFrederich Munchvoid DynamicLibrary::HandleSet::DLClose(void *Handle) { 65c1db8cf9SFrederich Munch if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) 66c1db8cf9SFrederich Munch HS->Process = nullptr; // Just drop the *Process* handle. 67c1db8cf9SFrederich Munch else 68c1db8cf9SFrederich Munch FreeLibrary((HMODULE)Handle); 697f1c255dSVassil Vassilev} 707f1c255dSVassil Vassilev 71c1db8cf9SFrederich Munchstatic bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { 72c1db8cf9SFrederich Munch // EnumProcessModules will fail on Windows 64 while some versions of 73c1db8cf9SFrederich Munch // MingW-32 don't have EnumProcessModulesEx. 74c1db8cf9SFrederich Munch if ( 75c1db8cf9SFrederich Munch#ifdef _WIN64 76c1db8cf9SFrederich Munch !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) 77c1db8cf9SFrederich Munch#else 78c1db8cf9SFrederich Munch !EnumProcessModules(H, Data, Bytes, &Bytes) 79c1db8cf9SFrederich Munch#endif 80c1db8cf9SFrederich Munch ) { 81c1db8cf9SFrederich Munch std::string Err; 82c1db8cf9SFrederich Munch if (MakeErrMsg(&Err, "EnumProcessModules failure")) 83c1db8cf9SFrederich Munch llvm::errs() << Err << "\n"; 84c1db8cf9SFrederich Munch return false; 85c1db8cf9SFrederich Munch } 86c1db8cf9SFrederich Munch return true; 87c1db8cf9SFrederich Munch} 88c1db8cf9SFrederich Munch 89c1db8cf9SFrederich Munchvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { 90c1db8cf9SFrederich Munch HandleSet* HS = IsOpenedHandlesInstance(Handle); 91c1db8cf9SFrederich Munch if (!HS) 92c1db8cf9SFrederich Munch return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); 93c1db8cf9SFrederich Munch 94c1db8cf9SFrederich Munch // Could have done a dlclose on the *Process* handle 95c1db8cf9SFrederich Munch if (!HS->Process) 96c1db8cf9SFrederich Munch return nullptr; 97c1db8cf9SFrederich Munch 98c1db8cf9SFrederich Munch // Trials indicate EnumProcessModulesEx is consistantly faster than using 99c1db8cf9SFrederich Munch // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. 100c1db8cf9SFrederich Munch // 101c1db8cf9SFrederich Munch // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx 102c1db8cf9SFrederich Munch // |=========|=============|======================================== 103c1db8cf9SFrederich Munch // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 104c1db8cf9SFrederich Munch // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 105c1db8cf9SFrederich Munch // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 106c1db8cf9SFrederich Munch // 107c1db8cf9SFrederich Munch // * Not including the load time of Dbghelp.dll (~.005 sec) 108c1db8cf9SFrederich Munch // 109c1db8cf9SFrederich Munch // There's still a case to somehow cache the result of EnumProcessModulesEx 110c1db8cf9SFrederich Munch // across invocations, but the complication of doing that properly... 111c1db8cf9SFrederich Munch // Possibly using LdrRegisterDllNotification to invalidate the cache? 112c1db8cf9SFrederich Munch 113c1db8cf9SFrederich Munch DWORD Bytes = 0; 114c1db8cf9SFrederich Munch HMODULE Self = HMODULE(GetCurrentProcess()); 115c1db8cf9SFrederich Munch if (!GetProcessModules(Self, Bytes)) 116c1db8cf9SFrederich Munch return nullptr; 117c1db8cf9SFrederich Munch 118c1db8cf9SFrederich Munch // Get the most recent list in case any modules added/removed between calls 119c1db8cf9SFrederich Munch // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. 120c1db8cf9SFrederich Munch // MSDN is pretty clear that if the module list changes during the call to 121c1db8cf9SFrederich Munch // EnumProcessModulesEx the results should not be used. 122c1db8cf9SFrederich Munch std::vector<HMODULE> Handles; 123c1db8cf9SFrederich Munch do { 124c1db8cf9SFrederich Munch assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && 125c1db8cf9SFrederich Munch "Should have at least one module and be aligned"); 126c1db8cf9SFrederich Munch Handles.resize(Bytes / sizeof(HMODULE)); 127c1db8cf9SFrederich Munch if (!GetProcessModules(Self, Bytes, Handles.data())) 128c1db8cf9SFrederich Munch return nullptr; 129c1db8cf9SFrederich Munch } while (Bytes != (Handles.size() * sizeof(HMODULE))); 130c1db8cf9SFrederich Munch 131c1db8cf9SFrederich Munch // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. 132c1db8cf9SFrederich Munch if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) 133c1db8cf9SFrederich Munch return (void *) uintptr_t(Ptr); 134c1db8cf9SFrederich Munch 135c1db8cf9SFrederich Munch if (Handles.size() > 1) { 136c1db8cf9SFrederich Munch // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. 137c1db8cf9SFrederich Munch // Doing that here is causing real problems for the JIT where msvc.dll 138c1db8cf9SFrederich Munch // and ucrt.dll can define the same symbols. The runtime linker will choose 139c1db8cf9SFrederich Munch // symbols from ucrt.dll first, but iterating NOT in reverse here would 140c1db8cf9SFrederich Munch // mean that the msvc.dll versions would be returned. 141c1db8cf9SFrederich Munch 142c1db8cf9SFrederich Munch for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { 143c1db8cf9SFrederich Munch if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) 144c1db8cf9SFrederich Munch return (void *) uintptr_t(Ptr); 145c1db8cf9SFrederich Munch } 146c1db8cf9SFrederich Munch } 147c1db8cf9SFrederich Munch return nullptr; 148c1db8cf9SFrederich Munch} 149c1db8cf9SFrederich Munch 150c1db8cf9SFrederich Munch 151447762daSMichael J. Spencer// Stack probing routines are in the support library (e.g. libgcc), but we don't 152447762daSMichael J. Spencer// have dynamic linking on windows. Provide a hook. 153447762daSMichael J. Spencer#define EXPLICIT_SYMBOL(SYM) \ 154447762daSMichael J. Spencer extern "C" { extern void *SYM; } 15503a541f5SNAKAMURA Takumi#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) 156447762daSMichael J. Spencer 1579aeb0479SReid Kleckner#ifdef _M_IX86 1589aeb0479SReid Kleckner// Win32 on x86 implements certain single-precision math functions as macros. 1599aeb0479SReid Kleckner// These functions are not exported by the DLL, but will still be needed 1609aeb0479SReid Kleckner// for symbol-resolution by the JIT loader. Therefore, this Support libray 1619aeb0479SReid Kleckner// provides helper functions with the same implementation. 1629aeb0479SReid Kleckner 1639aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL1(TYP, SYM) \ 1649aeb0479SReid Kleckner extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); } 1659aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL2(TYP, SYM) \ 1669aeb0479SReid Kleckner extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); } 1679aeb0479SReid Kleckner#endif 1689aeb0479SReid Kleckner 16903a541f5SNAKAMURA Takumi#include "explicit_symbols.inc" 17003a541f5SNAKAMURA Takumi 17103a541f5SNAKAMURA Takumi#undef EXPLICIT_SYMBOL 17203a541f5SNAKAMURA Takumi#undef EXPLICIT_SYMBOL2 1739aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL1 1749aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL2 175447762daSMichael J. Spencer 176c1db8cf9SFrederich Munchstatic void *DoSearch(const char *SymbolName) { 177447762daSMichael J. Spencer 17803a541f5SNAKAMURA Takumi#define EXPLICIT_SYMBOL(SYM) \ 179c1db8cf9SFrederich Munch if (!strcmp(SymbolName, #SYM)) \ 1809aeb0479SReid Kleckner return (void *)&SYM; 18103a541f5SNAKAMURA Takumi#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ 182c1db8cf9SFrederich Munch if (!strcmp(SymbolName, #SYMFROM)) \ 1839aeb0479SReid Kleckner return (void *)&SYMTO; 1849aeb0479SReid Kleckner 1859aeb0479SReid Kleckner#ifdef _M_IX86 1869aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL1(TYP, SYM) \ 187c1db8cf9SFrederich Munch if (!strcmp(SymbolName, #SYM)) \ 1889aeb0479SReid Kleckner return (void *)&inline_##SYM; 1899aeb0479SReid Kleckner#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) 1909aeb0479SReid Kleckner#endif 191447762daSMichael J. Spencer 192447762daSMichael J. Spencer { 19303a541f5SNAKAMURA Takumi#include "explicit_symbols.inc" 19403a541f5SNAKAMURA Takumi } 19503a541f5SNAKAMURA Takumi 196447762daSMichael J. Spencer#undef EXPLICIT_SYMBOL 197447762daSMichael J. Spencer#undef EXPLICIT_SYMBOL2 1989aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL1 1999aeb0479SReid Kleckner#undef INLINE_DEF_SYMBOL2 200447762daSMichael J. Spencer 201c1db8cf9SFrederich Munch return nullptr; 202447762daSMichael J. Spencer} 203