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