1 //===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides the Win32 specific implementation of DynamicLibrary.
12 //===----------------------------------------------------------------------===//
14 #include "WindowsSupport.h"
15 #include "llvm/Support/raw_ostream.h"
19 //===----------------------------------------------------------------------===//
20 //=== WARNING: Implementation here must contain only Win32 specific code
21 //=== and must not be UNIX code.
22 //===----------------------------------------------------------------------===//
25 DynamicLibrary::HandleSet::~HandleSet() {
26 for (void *Handle : Handles)
27 FreeLibrary(HMODULE(Handle));
29 // 'Process' should not be released on Windows.
30 assert((!Process || Process==this) && "Bad Handle");
33 void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
34 // Create the instance and return it to be the *Process* handle
35 // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
37 return &(*OpenedHandles);
39 SmallVector<wchar_t, MAX_PATH> FileUnicode;
40 if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
41 SetLastError(ec.value());
42 MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
43 return &DynamicLibrary::Invalid;
46 HMODULE Handle = LoadLibraryW(FileUnicode.data());
48 MakeErrMsg(Err, std::string(File) + ": Can't open");
49 return &DynamicLibrary::Invalid;
52 return reinterpret_cast<void*>(Handle);
55 static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
56 if (!OpenedHandles.isConstructed())
58 DynamicLibrary::HandleSet &Inst = *OpenedHandles;
59 return Handle == &Inst ? &Inst : nullptr;
62 void DynamicLibrary::HandleSet::DLClose(void *Handle) {
63 if (HandleSet* HS = IsOpenedHandlesInstance(Handle))
64 HS->Process = nullptr; // Just drop the *Process* handle.
66 FreeLibrary((HMODULE)Handle);
69 static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
70 // EnumProcessModules will fail on Windows 64 while some versions of
71 // MingW-32 don't have EnumProcessModulesEx.
74 !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)
76 !EnumProcessModules(H, Data, Bytes, &Bytes)
80 if (MakeErrMsg(&Err, "EnumProcessModules failure"))
81 llvm::errs() << Err << "\n";
87 void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
88 HandleSet* HS = IsOpenedHandlesInstance(Handle);
90 return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
92 // Could have done a dlclose on the *Process* handle
96 // Trials indicate EnumProcessModulesEx is consistantly faster than using
97 // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
99 // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
100 // |=========|=============|========================================
101 // | 37 | 0.0000585 * | 0.0003031 | 0.0000152
102 // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683
103 // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610
105 // * Not including the load time of Dbghelp.dll (~.005 sec)
107 // There's still a case to somehow cache the result of EnumProcessModulesEx
108 // across invocations, but the complication of doing that properly...
109 // Possibly using LdrRegisterDllNotification to invalidate the cache?
112 HMODULE Self = HMODULE(GetCurrentProcess());
113 if (!GetProcessModules(Self, Bytes))
116 // Get the most recent list in case any modules added/removed between calls
117 // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
118 // MSDN is pretty clear that if the module list changes during the call to
119 // EnumProcessModulesEx the results should not be used.
120 std::vector<HMODULE> Handles;
122 assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
123 "Should have at least one module and be aligned");
124 Handles.resize(Bytes / sizeof(HMODULE));
125 if (!GetProcessModules(Self, Bytes, Handles.data()))
127 } while (Bytes != (Handles.size() * sizeof(HMODULE)));
129 // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
130 if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
131 return (void *) uintptr_t(Ptr);
133 if (Handles.size() > 1) {
134 // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
135 // Doing that here is causing real problems for the JIT where msvc.dll
136 // and ucrt.dll can define the same symbols. The runtime linker will choose
137 // symbols from ucrt.dll first, but iterating NOT in reverse here would
138 // mean that the msvc.dll versions would be returned.
140 for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) {
141 if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
142 return (void *) uintptr_t(Ptr);
149 // Stack probing routines are in the support library (e.g. libgcc), but we don't
150 // have dynamic linking on windows. Provide a hook.
151 #define EXPLICIT_SYMBOL(SYM) \
152 extern "C" { extern void *SYM; }
153 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
156 // Win32 on x86 implements certain single-precision math functions as macros.
157 // These functions are not exported by the DLL, but will still be needed
158 // for symbol-resolution by the JIT loader. Therefore, this Support libray
159 // provides helper functions with the same implementation.
161 #define INLINE_DEF_SYMBOL1(TYP, SYM) \
162 extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); }
163 #define INLINE_DEF_SYMBOL2(TYP, SYM) \
164 extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); }
167 #include "explicit_symbols.inc"
169 #undef EXPLICIT_SYMBOL
170 #undef EXPLICIT_SYMBOL2
171 #undef INLINE_DEF_SYMBOL1
172 #undef INLINE_DEF_SYMBOL2
174 static void *DoSearch(const char *SymbolName) {
176 #define EXPLICIT_SYMBOL(SYM) \
177 if (!strcmp(SymbolName, #SYM)) \
179 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \
180 if (!strcmp(SymbolName, #SYMFROM)) \
181 return (void *)&SYMTO;
184 #define INLINE_DEF_SYMBOL1(TYP, SYM) \
185 if (!strcmp(SymbolName, #SYM)) \
186 return (void *)&inline_##SYM;
187 #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
191 #include "explicit_symbols.inc"
194 #undef EXPLICIT_SYMBOL
195 #undef EXPLICIT_SYMBOL2
196 #undef INLINE_DEF_SYMBOL1
197 #undef INLINE_DEF_SYMBOL2