DynamicLibrary.inc 7.4 KB

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