OSDN Git Service

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