201 lines · plain
1//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the Win32 specific implementation of DynamicLibrary.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Support/ConvertUTF.h"14#include "llvm/Support/Windows/WindowsSupport.h"15#include "llvm/Support/raw_ostream.h"16 17#include <psapi.h>18 19//===----------------------------------------------------------------------===//20//=== WARNING: Implementation here must contain only Win32 specific code21//=== and must not be UNIX code.22//===----------------------------------------------------------------------===//23 24DynamicLibrary::HandleSet::~HandleSet() {25 for (void *Handle : llvm::reverse(Handles))26 FreeLibrary(HMODULE(Handle));27 28 // 'Process' should not be released on Windows.29 assert((Process == &Invalid || Process == this) && "Bad Handle");30 // llvm_shutdown called, Return to default31 DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;32}33 34void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {35 // Create the instance and return it to be the *Process* handle36 // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)37 if (!File)38 return &getGlobals().OpenedHandles;39 40 SmallVector<wchar_t, MAX_PATH> FileUnicode;41 if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {42 SetLastError(ec.value());43 MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");44 return &DynamicLibrary::Invalid;45 }46 47 HMODULE Handle = LoadLibraryW(FileUnicode.data());48 if (Handle == NULL) {49 MakeErrMsg(Err, std::string(File) + ": Can't open");50 return &DynamicLibrary::Invalid;51 }52 53 return reinterpret_cast<void *>(Handle);54}55 56static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {57 DynamicLibrary::HandleSet &Inst = getGlobals().OpenedHandles;58 return Handle == &Inst ? &Inst : nullptr;59}60 61void DynamicLibrary::HandleSet::DLClose(void *Handle) {62 if (HandleSet *HS = IsOpenedHandlesInstance(Handle))63 HS->Process = &Invalid; // Just drop the *Process* handle.64 else65 FreeLibrary((HMODULE)Handle);66}67 68static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {69 // EnumProcessModules will fail on Windows 64 while some versions of70 // MingW-32 don't have EnumProcessModulesEx.71 if (72#ifdef _WIN6473 !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)74#else75 !EnumProcessModules(H, Data, Bytes, &Bytes)76#endif77 ) {78 std::string Err;79 if (MakeErrMsg(&Err, "EnumProcessModules failure"))80 llvm::errs() << Err << "\n";81 return false;82 }83 return true;84}85 86void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {87 HandleSet *HS = IsOpenedHandlesInstance(Handle);88 if (!HS)89 return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));90 91 // Could have done a dlclose on the *Process* handle92 if (HS->Process == &Invalid)93 return nullptr;94 95 // Trials indicate EnumProcessModulesEx is consistantly faster than using96 // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.97 //98 // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx99 // |=========|=============|========================================100 // | 37 | 0.0000585 * | 0.0003031 | 0.0000152101 // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683102 // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610103 //104 // * Not including the load time of Dbghelp.dll (~.005 sec)105 //106 // There's still a case to somehow cache the result of EnumProcessModulesEx107 // across invocations, but the complication of doing that properly...108 // Possibly using LdrRegisterDllNotification to invalidate the cache?109 110 DWORD Bytes = 0;111 HMODULE Self = HMODULE(GetCurrentProcess());112 if (!GetProcessModules(Self, Bytes))113 return nullptr;114 115 // Get the most recent list in case any modules added/removed between calls116 // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.117 // MSDN is pretty clear that if the module list changes during the call to118 // EnumProcessModulesEx the results should not be used.119 std::vector<HMODULE> Handles;120 do {121 assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&122 "Should have at least one module and be aligned");123 Handles.resize(Bytes / sizeof(HMODULE));124 if (!GetProcessModules(Self, Bytes, Handles.data()))125 return nullptr;126 } while (Bytes != (Handles.size() * sizeof(HMODULE)));127 128 // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.129 if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))130 return (void *)uintptr_t(Ptr);131 132 if (Handles.size() > 1) {133 // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.134 // Doing that here is causing real problems for the JIT where msvc.dll135 // and ucrt.dll can define the same symbols. The runtime linker will choose136 // symbols from ucrt.dll first, but iterating NOT in reverse here would137 // mean that the msvc.dll versions would be returned.138 139 for (auto I = Handles.rbegin(), E = Handles.rend() - 1; I != E; ++I) {140 if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))141 return (void *)uintptr_t(Ptr);142 }143 }144 return nullptr;145}146 147// Stack probing routines are in the support library (e.g. libgcc), but we don't148// have dynamic linking on windows. Provide a hook.149#define EXPLICIT_SYMBOL(SYM) \150 extern "C" { \151 extern void *SYM; \152 }153#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)154 155#ifdef _M_IX86156// Win32 on x86 implements certain single-precision math functions as macros.157// These functions are not exported by the DLL, but will still be needed158// for symbol-resolution by the JIT loader. Therefore, this Support libray159// provides helper functions with the same implementation.160 161#define INLINE_DEF_SYMBOL1(TYP, SYM) \162 extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); }163#define INLINE_DEF_SYMBOL2(TYP, SYM) \164 extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); }165#endif166 167#include "explicit_symbols.inc"168 169#undef EXPLICIT_SYMBOL170#undef EXPLICIT_SYMBOL2171#undef INLINE_DEF_SYMBOL1172#undef INLINE_DEF_SYMBOL2173 174static void *DoSearch(const char *SymbolName) {175 176#define EXPLICIT_SYMBOL(SYM) \177 if (!strcmp(SymbolName, #SYM)) \178 return (void *)&SYM;179#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \180 if (!strcmp(SymbolName, #SYMFROM)) \181 return (void *)&SYMTO;182 183#ifdef _M_IX86184#define INLINE_DEF_SYMBOL1(TYP, SYM) \185 if (!strcmp(SymbolName, #SYM)) \186 return (void *)&inline_##SYM;187#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)188#endif189 190 {191#include "explicit_symbols.inc"192 }193 194#undef EXPLICIT_SYMBOL195#undef EXPLICIT_SYMBOL2196#undef INLINE_DEF_SYMBOL1197#undef INLINE_DEF_SYMBOL2198 199 return nullptr;200}201