//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides the Win32 specific implementation of DynamicLibrary. // //===----------------------------------------------------------------------===// #include "WindowsSupport.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code. //===----------------------------------------------------------------------===// DynamicLibrary::HandleSet::~HandleSet() { for (void *Handle : llvm::reverse(Handles)) FreeLibrary(HMODULE(Handle)); // 'Process' should not be released on Windows. assert((!Process || Process==this) && "Bad Handle"); // llvm_shutdown called, Return to default DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; } void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { // Create the instance and return it to be the *Process* handle // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) if (!File) return &(*OpenedHandles); SmallVector FileUnicode; if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { SetLastError(ec.value()); MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); return &DynamicLibrary::Invalid; } HMODULE Handle = LoadLibraryW(FileUnicode.data()); if (Handle == NULL) { MakeErrMsg(Err, std::string(File) + ": Can't open"); return &DynamicLibrary::Invalid; } return reinterpret_cast(Handle); } static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { if (!OpenedHandles.isConstructed()) return nullptr; DynamicLibrary::HandleSet &Inst = *OpenedHandles; return Handle == &Inst ? &Inst : nullptr; } void DynamicLibrary::HandleSet::DLClose(void *Handle) { if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) HS->Process = nullptr; // Just drop the *Process* handle. else FreeLibrary((HMODULE)Handle); } static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { // EnumProcessModules will fail on Windows 64 while some versions of // MingW-32 don't have EnumProcessModulesEx. if ( #ifdef _WIN64 !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) #else !EnumProcessModules(H, Data, Bytes, &Bytes) #endif ) { std::string Err; if (MakeErrMsg(&Err, "EnumProcessModules failure")) llvm::errs() << Err << "\n"; return false; } return true; } void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { HandleSet* HS = IsOpenedHandlesInstance(Handle); if (!HS) return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); // Could have done a dlclose on the *Process* handle if (!HS->Process) return nullptr; // Trials indicate EnumProcessModulesEx is consistantly faster than using // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. // // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx // |=========|=============|======================================== // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 // // * Not including the load time of Dbghelp.dll (~.005 sec) // // There's still a case to somehow cache the result of EnumProcessModulesEx // across invocations, but the complication of doing that properly... // Possibly using LdrRegisterDllNotification to invalidate the cache? DWORD Bytes = 0; HMODULE Self = HMODULE(GetCurrentProcess()); if (!GetProcessModules(Self, Bytes)) return nullptr; // Get the most recent list in case any modules added/removed between calls // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. // MSDN is pretty clear that if the module list changes during the call to // EnumProcessModulesEx the results should not be used. std::vector Handles; do { assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && "Should have at least one module and be aligned"); Handles.resize(Bytes / sizeof(HMODULE)); if (!GetProcessModules(Self, Bytes, Handles.data())) return nullptr; } while (Bytes != (Handles.size() * sizeof(HMODULE))); // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) return (void *) uintptr_t(Ptr); if (Handles.size() > 1) { // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. // Doing that here is causing real problems for the JIT where msvc.dll // and ucrt.dll can define the same symbols. The runtime linker will choose // symbols from ucrt.dll first, but iterating NOT in reverse here would // mean that the msvc.dll versions would be returned. for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) return (void *) uintptr_t(Ptr); } } return nullptr; } // Stack probing routines are in the support library (e.g. libgcc), but we don't // have dynamic linking on windows. Provide a hook. #define EXPLICIT_SYMBOL(SYM) \ extern "C" { extern void *SYM; } #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) #ifdef _M_IX86 // Win32 on x86 implements certain single-precision math functions as macros. // These functions are not exported by the DLL, but will still be needed // for symbol-resolution by the JIT loader. Therefore, this Support libray // provides helper functions with the same implementation. #define INLINE_DEF_SYMBOL1(TYP, SYM) \ extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); } #define INLINE_DEF_SYMBOL2(TYP, SYM) \ extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); } #endif #include "explicit_symbols.inc" #undef EXPLICIT_SYMBOL #undef EXPLICIT_SYMBOL2 #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 static void *DoSearch(const char *SymbolName) { #define EXPLICIT_SYMBOL(SYM) \ if (!strcmp(SymbolName, #SYM)) \ return (void *)&SYM; #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ if (!strcmp(SymbolName, #SYMFROM)) \ return (void *)&SYMTO; #ifdef _M_IX86 #define INLINE_DEF_SYMBOL1(TYP, SYM) \ if (!strcmp(SymbolName, #SYM)) \ return (void *)&inline_##SYM; #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) #endif { #include "explicit_symbols.inc" } #undef EXPLICIT_SYMBOL #undef EXPLICIT_SYMBOL2 #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 return nullptr; }