LLVM  6.0.0svn
DynamicLibrary.inc
Go to the documentation of this file.
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"
16 
17 #include <psapi.h>
18 
19 //===----------------------------------------------------------------------===//
20 //=== WARNING: Implementation here must contain only Win32 specific code
21 //=== and must not be UNIX code.
22 //===----------------------------------------------------------------------===//
23 
24 
26  for (void *Handle : llvm::reverse(Handles))
27  FreeLibrary(HMODULE(Handle));
28 
29  // 'Process' should not be released on Windows.
30  assert((!Process || Process==this) && "Bad Handle");
31  // llvm_shutdown called, Return to default
32  DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
33 }
34 
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);
40 
41  SmallVector<wchar_t, MAX_PATH> FileUnicode;
42  if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
43  SetLastError(ec.value());
44  MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
46  }
47 
48  HMODULE Handle = LoadLibraryW(FileUnicode.data());
49  if (Handle == NULL) {
50  MakeErrMsg(Err, std::string(File) + ": Can't open");
52  }
53 
54  return reinterpret_cast<void*>(Handle);
55 }
56 
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;
62 }
63 
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 
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.
153 #define EXPLICIT_SYMBOL(SYM) \
154  extern "C" { extern void *SYM; }
155 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
156 
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 
169 #include "explicit_symbols.inc"
170 
171 #undef EXPLICIT_SYMBOL
172 #undef EXPLICIT_SYMBOL2
173 #undef INLINE_DEF_SYMBOL1
174 #undef INLINE_DEF_SYMBOL2
175 
176 static void *DoSearch(const char *SymbolName) {
177 
178 #define EXPLICIT_SYMBOL(SYM) \
179  if (!strcmp(SymbolName, #SYM)) \
180  return (void *)&SYM;
181 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \
182  if (!strcmp(SymbolName, #SYMFROM)) \
183  return (void *)&SYMTO;
184 
185 #ifdef _M_IX86
186 #define INLINE_DEF_SYMBOL1(TYP, SYM) \
187  if (!strcmp(SymbolName, #SYM)) \
188  return (void *)&inline_##SYM;
189 #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
190 #endif
191 
192  {
193 #include "explicit_symbols.inc"
194  }
195 
196 #undef EXPLICIT_SYMBOL
197 #undef EXPLICIT_SYMBOL2
198 #undef INLINE_DEF_SYMBOL1
199 #undef INLINE_DEF_SYMBOL2
200 
201  return nullptr;
202 }
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
static void * DLSym(void *Handle, const char *Symbol)
static void * DLOpen(const char *Filename, std::string *Err)
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
Definition: STLExtras.h:248
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define H(x, y, z)
Definition: MD5.cpp:57
std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl< wchar_t > &utf16)
bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix)
static void DLClose(void *Handle)
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())