• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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