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