LLVM 20.0.0git
DynamicLibrary.inc
Go to the documentation of this file.
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
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
25 for (void *Handle : llvm::reverse(Handles))
26 FreeLibrary(HMODULE(Handle));
27
28 // 'Process' should not be released on Windows.
29 assert((!Process || Process == this) && "Bad Handle");
30 // llvm_shutdown called, Return to default
31 DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
32}
33
34void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
35 // Create the instance and return it to be the *Process* handle
36 // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
37 if (!File)
38 return &getGlobals().OpenedHandles;
39
40 SmallVector<wchar_t, MAX_PATH> FileUnicode;
41 if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
42 SetLastError(ec.value());
43 MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
44 return &DynamicLibrary::Invalid;
45 }
46
47 HMODULE Handle = LoadLibraryW(FileUnicode.data());
48 if (Handle == NULL) {
49 MakeErrMsg(Err, std::string(File) + ": Can't open");
50 return &DynamicLibrary::Invalid;
51 }
52
53 return reinterpret_cast<void *>(Handle);
54}
55
56static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
57 DynamicLibrary::HandleSet &Inst = getGlobals().OpenedHandles;
58 return Handle == &Inst ? &Inst : nullptr;
59}
60
61void DynamicLibrary::HandleSet::DLClose(void *Handle) {
62 if (HandleSet *HS = IsOpenedHandlesInstance(Handle))
63 HS->Process = nullptr; // Just drop the *Process* handle.
64 else
65 FreeLibrary((HMODULE)Handle);
66}
67
68static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
69 // EnumProcessModules will fail on Windows 64 while some versions of
70 // MingW-32 don't have EnumProcessModulesEx.
71 if (
72#ifdef _WIN64
73 !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)
74#else
75 !EnumProcessModules(H, Data, Bytes, &Bytes)
76#endif
77 ) {
78 std::string Err;
79 if (MakeErrMsg(&Err, "EnumProcessModules failure"))
80 llvm::errs() << Err << "\n";
81 return false;
82 }
83 return true;
84}
85
86void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
87 HandleSet *HS = IsOpenedHandlesInstance(Handle);
88 if (!HS)
89 return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
90
91 // Could have done a dlclose on the *Process* handle
92 if (!HS->Process)
93 return nullptr;
94
95 // Trials indicate EnumProcessModulesEx is consistantly faster than using
96 // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
97 //
98 // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
99 // |=========|=============|========================================
100 // | 37 | 0.0000585 * | 0.0003031 | 0.0000152
101 // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683
102 // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610
103 //
104 // * Not including the load time of Dbghelp.dll (~.005 sec)
105 //
106 // There's still a case to somehow cache the result of EnumProcessModulesEx
107 // across invocations, but the complication of doing that properly...
108 // Possibly using LdrRegisterDllNotification to invalidate the cache?
109
110 DWORD Bytes = 0;
111 HMODULE Self = HMODULE(GetCurrentProcess());
112 if (!GetProcessModules(Self, Bytes))
113 return nullptr;
114
115 // Get the most recent list in case any modules added/removed between calls
116 // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
117 // MSDN is pretty clear that if the module list changes during the call to
118 // EnumProcessModulesEx the results should not be used.
119 std::vector<HMODULE> Handles;
120 do {
121 assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
122 "Should have at least one module and be aligned");
123 Handles.resize(Bytes / sizeof(HMODULE));
124 if (!GetProcessModules(Self, Bytes, Handles.data()))
125 return nullptr;
126 } while (Bytes != (Handles.size() * sizeof(HMODULE)));
127
128 // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
129 if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
130 return (void *)uintptr_t(Ptr);
131
132 if (Handles.size() > 1) {
133 // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
134 // Doing that here is causing real problems for the JIT where msvc.dll
135 // and ucrt.dll can define the same symbols. The runtime linker will choose
136 // symbols from ucrt.dll first, but iterating NOT in reverse here would
137 // mean that the msvc.dll versions would be returned.
138
139 for (auto I = Handles.rbegin(), E = Handles.rend() - 1; I != E; ++I) {
140 if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
141 return (void *)uintptr_t(Ptr);
142 }
143 }
144 return nullptr;
145}
146
147// Stack probing routines are in the support library (e.g. libgcc), but we don't
148// have dynamic linking on windows. Provide a hook.
149#define EXPLICIT_SYMBOL(SYM) \
150 extern "C" { \
151 extern void *SYM; \
152 }
153#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
154
155#ifdef _M_IX86
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.
160
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); }
165#endif
166
167#include "explicit_symbols.inc"
168
169#undef EXPLICIT_SYMBOL
170#undef EXPLICIT_SYMBOL2
171#undef INLINE_DEF_SYMBOL1
172#undef INLINE_DEF_SYMBOL2
173
174static void *DoSearch(const char *SymbolName) {
175
176#define EXPLICIT_SYMBOL(SYM) \
177 if (!strcmp(SymbolName, #SYM)) \
178 return (void *)&SYM;
179#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \
180 if (!strcmp(SymbolName, #SYMFROM)) \
181 return (void *)&SYMTO;
182
183#ifdef _M_IX86
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)
188#endif
189
190 {
191#include "explicit_symbols.inc"
192 }
193
194#undef EXPLICIT_SYMBOL
195#undef EXPLICIT_SYMBOL2
196#undef INLINE_DEF_SYMBOL1
197#undef INLINE_DEF_SYMBOL2
198
199 return nullptr;
200}
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define I(x, y, z)
Definition: MD5.cpp:58
#define H(x, y, z)
Definition: MD5.cpp:57
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix, int errnum=-1)
This function builds an error message into ErrMsg using the prefix string and the Unix error number g...
Definition: Unix.h:59
static void * DLOpen(const char *Filename, std::string *Err)
static void * DLSym(void *Handle, const char *Symbol)
static void DLClose(void *Handle)
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.