12754fe60SDimitry Andric//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// 22754fe60SDimitry Andric// 32754fe60SDimitry Andric// The LLVM Compiler Infrastructure 42754fe60SDimitry Andric// 52754fe60SDimitry Andric// This file is distributed under the University of Illinois Open Source 62754fe60SDimitry Andric// License. See LICENSE.TXT for details. 72754fe60SDimitry Andric// 82754fe60SDimitry Andric//===----------------------------------------------------------------------===// 92754fe60SDimitry Andric// 102754fe60SDimitry Andric// This file provides the Win32 specific implementation of DynamicLibrary. 112754fe60SDimitry Andric// 122754fe60SDimitry Andric//===----------------------------------------------------------------------===// 132754fe60SDimitry Andric 1491bc56edSDimitry Andric#include "WindowsSupport.h" 15*4ba319b5SDimitry Andric#include "llvm/Support/ConvertUTF.h" 16f37b6182SDimitry Andric#include "llvm/Support/raw_ostream.h" 172754fe60SDimitry Andric 18f37b6182SDimitry Andric#include <psapi.h> 192754fe60SDimitry Andric 202754fe60SDimitry Andric//===----------------------------------------------------------------------===// 212754fe60SDimitry Andric//=== WARNING: Implementation here must contain only Win32 specific code 222754fe60SDimitry Andric//=== and must not be UNIX code. 232754fe60SDimitry Andric//===----------------------------------------------------------------------===// 242754fe60SDimitry Andric 252754fe60SDimitry Andric 26f37b6182SDimitry AndricDynamicLibrary::HandleSet::~HandleSet() { 27db17bf38SDimitry Andric for (void *Handle : llvm::reverse(Handles)) 28f37b6182SDimitry Andric FreeLibrary(HMODULE(Handle)); 29f37b6182SDimitry Andric 30f37b6182SDimitry Andric // 'Process' should not be released on Windows. 31f37b6182SDimitry Andric assert((!Process || Process==this) && "Bad Handle"); 32c4394386SDimitry Andric // llvm_shutdown called, Return to default 33c4394386SDimitry Andric DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; 343dac3a9bSDimitry Andric} 353dac3a9bSDimitry Andric 36f37b6182SDimitry Andricvoid *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { 37f37b6182SDimitry Andric // Create the instance and return it to be the *Process* handle 38f37b6182SDimitry Andric // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) 39f37b6182SDimitry Andric if (!File) 40f37b6182SDimitry Andric return &(*OpenedHandles); 412754fe60SDimitry Andric 42f37b6182SDimitry Andric SmallVector<wchar_t, MAX_PATH> FileUnicode; 43f37b6182SDimitry Andric if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { 44f785676fSDimitry Andric SetLastError(ec.value()); 45f37b6182SDimitry Andric MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); 46f37b6182SDimitry Andric return &DynamicLibrary::Invalid; 47f785676fSDimitry Andric } 48f785676fSDimitry Andric 49f37b6182SDimitry Andric HMODULE Handle = LoadLibraryW(FileUnicode.data()); 50f37b6182SDimitry Andric if (Handle == NULL) { 51f37b6182SDimitry Andric MakeErrMsg(Err, std::string(File) + ": Can't open"); 52f37b6182SDimitry Andric return &DynamicLibrary::Invalid; 536122f3e6SDimitry Andric } 546122f3e6SDimitry Andric 55f37b6182SDimitry Andric return reinterpret_cast<void*>(Handle); 562754fe60SDimitry Andric} 572754fe60SDimitry Andric 58f37b6182SDimitry Andricstatic DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { 59f37b6182SDimitry Andric if (!OpenedHandles.isConstructed()) 60f37b6182SDimitry Andric return nullptr; 61f37b6182SDimitry Andric DynamicLibrary::HandleSet &Inst = *OpenedHandles; 62f37b6182SDimitry Andric return Handle == &Inst ? &Inst : nullptr; 637a7e6055SDimitry Andric} 647a7e6055SDimitry Andric 65f37b6182SDimitry Andricvoid DynamicLibrary::HandleSet::DLClose(void *Handle) { 66f37b6182SDimitry Andric if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) 67f37b6182SDimitry Andric HS->Process = nullptr; // Just drop the *Process* handle. 68f37b6182SDimitry Andric else 69f37b6182SDimitry Andric FreeLibrary((HMODULE)Handle); 707a7e6055SDimitry Andric} 717a7e6055SDimitry Andric 72f37b6182SDimitry Andricstatic bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { 73f37b6182SDimitry Andric // EnumProcessModules will fail on Windows 64 while some versions of 74f37b6182SDimitry Andric // MingW-32 don't have EnumProcessModulesEx. 75f37b6182SDimitry Andric if ( 76f37b6182SDimitry Andric#ifdef _WIN64 77f37b6182SDimitry Andric !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) 78f37b6182SDimitry Andric#else 79f37b6182SDimitry Andric !EnumProcessModules(H, Data, Bytes, &Bytes) 80f37b6182SDimitry Andric#endif 81f37b6182SDimitry Andric ) { 82f37b6182SDimitry Andric std::string Err; 83f37b6182SDimitry Andric if (MakeErrMsg(&Err, "EnumProcessModules failure")) 84f37b6182SDimitry Andric llvm::errs() << Err << "\n"; 85f37b6182SDimitry Andric return false; 86f37b6182SDimitry Andric } 87f37b6182SDimitry Andric return true; 88f37b6182SDimitry Andric} 89f37b6182SDimitry Andric 90f37b6182SDimitry Andricvoid *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { 91f37b6182SDimitry Andric HandleSet* HS = IsOpenedHandlesInstance(Handle); 92f37b6182SDimitry Andric if (!HS) 93f37b6182SDimitry Andric return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); 94f37b6182SDimitry Andric 95f37b6182SDimitry Andric // Could have done a dlclose on the *Process* handle 96f37b6182SDimitry Andric if (!HS->Process) 97f37b6182SDimitry Andric return nullptr; 98f37b6182SDimitry Andric 99f37b6182SDimitry Andric // Trials indicate EnumProcessModulesEx is consistantly faster than using 100f37b6182SDimitry Andric // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. 101f37b6182SDimitry Andric // 102f37b6182SDimitry Andric // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx 103f37b6182SDimitry Andric // |=========|=============|======================================== 104f37b6182SDimitry Andric // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 105f37b6182SDimitry Andric // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 106f37b6182SDimitry Andric // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 107f37b6182SDimitry Andric // 108f37b6182SDimitry Andric // * Not including the load time of Dbghelp.dll (~.005 sec) 109f37b6182SDimitry Andric // 110f37b6182SDimitry Andric // There's still a case to somehow cache the result of EnumProcessModulesEx 111f37b6182SDimitry Andric // across invocations, but the complication of doing that properly... 112f37b6182SDimitry Andric // Possibly using LdrRegisterDllNotification to invalidate the cache? 113f37b6182SDimitry Andric 114f37b6182SDimitry Andric DWORD Bytes = 0; 115f37b6182SDimitry Andric HMODULE Self = HMODULE(GetCurrentProcess()); 116f37b6182SDimitry Andric if (!GetProcessModules(Self, Bytes)) 117f37b6182SDimitry Andric return nullptr; 118f37b6182SDimitry Andric 119f37b6182SDimitry Andric // Get the most recent list in case any modules added/removed between calls 120f37b6182SDimitry Andric // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. 121f37b6182SDimitry Andric // MSDN is pretty clear that if the module list changes during the call to 122f37b6182SDimitry Andric // EnumProcessModulesEx the results should not be used. 123f37b6182SDimitry Andric std::vector<HMODULE> Handles; 124f37b6182SDimitry Andric do { 125f37b6182SDimitry Andric assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && 126f37b6182SDimitry Andric "Should have at least one module and be aligned"); 127f37b6182SDimitry Andric Handles.resize(Bytes / sizeof(HMODULE)); 128f37b6182SDimitry Andric if (!GetProcessModules(Self, Bytes, Handles.data())) 129f37b6182SDimitry Andric return nullptr; 130f37b6182SDimitry Andric } while (Bytes != (Handles.size() * sizeof(HMODULE))); 131f37b6182SDimitry Andric 132f37b6182SDimitry Andric // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. 133f37b6182SDimitry Andric if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) 134f37b6182SDimitry Andric return (void *) uintptr_t(Ptr); 135f37b6182SDimitry Andric 136f37b6182SDimitry Andric if (Handles.size() > 1) { 137f37b6182SDimitry Andric // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. 138f37b6182SDimitry Andric // Doing that here is causing real problems for the JIT where msvc.dll 139f37b6182SDimitry Andric // and ucrt.dll can define the same symbols. The runtime linker will choose 140f37b6182SDimitry Andric // symbols from ucrt.dll first, but iterating NOT in reverse here would 141f37b6182SDimitry Andric // mean that the msvc.dll versions would be returned. 142f37b6182SDimitry Andric 143f37b6182SDimitry Andric for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { 144f37b6182SDimitry Andric if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) 145f37b6182SDimitry Andric return (void *) uintptr_t(Ptr); 146f37b6182SDimitry Andric } 147f37b6182SDimitry Andric } 148f37b6182SDimitry Andric return nullptr; 149f37b6182SDimitry Andric} 150f37b6182SDimitry Andric 151f37b6182SDimitry Andric 1522754fe60SDimitry Andric// Stack probing routines are in the support library (e.g. libgcc), but we don't 1532754fe60SDimitry Andric// have dynamic linking on windows. Provide a hook. 1542754fe60SDimitry Andric#define EXPLICIT_SYMBOL(SYM) \ 1552754fe60SDimitry Andric extern "C" { extern void *SYM; } 1562754fe60SDimitry Andric#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) 1572754fe60SDimitry Andric 15839d628a0SDimitry Andric#ifdef _M_IX86 15939d628a0SDimitry Andric// Win32 on x86 implements certain single-precision math functions as macros. 16039d628a0SDimitry Andric// These functions are not exported by the DLL, but will still be needed 16139d628a0SDimitry Andric// for symbol-resolution by the JIT loader. Therefore, this Support libray 16239d628a0SDimitry Andric// provides helper functions with the same implementation. 16339d628a0SDimitry Andric 16439d628a0SDimitry Andric#define INLINE_DEF_SYMBOL1(TYP, SYM) \ 16539d628a0SDimitry Andric extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); } 16639d628a0SDimitry Andric#define INLINE_DEF_SYMBOL2(TYP, SYM) \ 16739d628a0SDimitry Andric extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); } 16839d628a0SDimitry Andric#endif 16939d628a0SDimitry Andric 1702754fe60SDimitry Andric#include "explicit_symbols.inc" 1712754fe60SDimitry Andric 1722754fe60SDimitry Andric#undef EXPLICIT_SYMBOL 1732754fe60SDimitry Andric#undef EXPLICIT_SYMBOL2 17439d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL1 17539d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL2 1762754fe60SDimitry Andric 177f37b6182SDimitry Andricstatic void *DoSearch(const char *SymbolName) { 1782754fe60SDimitry Andric 1792754fe60SDimitry Andric#define EXPLICIT_SYMBOL(SYM) \ 180f37b6182SDimitry Andric if (!strcmp(SymbolName, #SYM)) \ 18139d628a0SDimitry Andric return (void *)&SYM; 1822754fe60SDimitry Andric#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ 183f37b6182SDimitry Andric if (!strcmp(SymbolName, #SYMFROM)) \ 18439d628a0SDimitry Andric return (void *)&SYMTO; 18539d628a0SDimitry Andric 18639d628a0SDimitry Andric#ifdef _M_IX86 18739d628a0SDimitry Andric#define INLINE_DEF_SYMBOL1(TYP, SYM) \ 188f37b6182SDimitry Andric if (!strcmp(SymbolName, #SYM)) \ 18939d628a0SDimitry Andric return (void *)&inline_##SYM; 19039d628a0SDimitry Andric#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) 19139d628a0SDimitry Andric#endif 1922754fe60SDimitry Andric 1932754fe60SDimitry Andric { 1942754fe60SDimitry Andric#include "explicit_symbols.inc" 1952754fe60SDimitry Andric } 1962754fe60SDimitry Andric 1972754fe60SDimitry Andric#undef EXPLICIT_SYMBOL 1982754fe60SDimitry Andric#undef EXPLICIT_SYMBOL2 19939d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL1 20039d628a0SDimitry Andric#undef INLINE_DEF_SYMBOL2 2012754fe60SDimitry Andric 202f37b6182SDimitry Andric return nullptr; 2032754fe60SDimitry Andric} 204