aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRalf Habacker <ralf.habacker@freenet.de>2020-08-25 23:34:19 +0200
committerRalf Habacker <ralf.habacker@freenet.de>2020-09-14 12:26:07 +0200
commitf0ac8495872ee078f18bd349e3db6883ed4106e2 (patch)
tree0f9b609aa80b924f6b391e1c4b687c0f73eaa7b9 /src
parent5ead6f2d2c515d3d85c31fffebea55168c1bc1b4 (diff)
downloaddlfcn-win32-f0ac8495872ee078f18bd349e3db6883ed4106e2.tar.gz
dlfcn-win32-f0ac8495872ee078f18bd349e3db6883ed4106e2.tar.bz2
dlfcn-win32-f0ac8495872ee078f18bd349e3db6883ed4106e2.zip
Move cmake targets into sub directories
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt43
-rw-r--r--src/dlfcn.c478
-rw-r--r--src/dlfcn.h78
3 files changed, 599 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..d5296b1
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,43 @@
1set(headers dlfcn.h)
2set(sources dlfcn.c)
3
4if (BUILD_SHARED_LIBS)
5 add_definitions(-DSHARED)
6endif (BUILD_SHARED_LIBS)
7
8add_library(dl ${sources})
9
10# Correctly export the location of installed includes in the target
11target_include_directories(dl INTERFACE $<INSTALL_INTERFACE:include>)
12
13install (TARGETS dl EXPORT dlfcn-win32-targets
14 RUNTIME DESTINATION bin
15 LIBRARY DESTINATION lib${LIB_SUFFIX}
16 ARCHIVE DESTINATION lib${LIB_SUFFIX})
17
18install (FILES ${headers} DESTINATION include)
19
20# Export the targets (build tree)
21export(EXPORT dlfcn-win32-targets
22 FILE "${CMAKE_BINARY_DIR}/dlfcn-win32-targets.cmake"
23 NAMESPACE dlfcn-win32::
24)
25
26# Write the CMake config file
27set(CMAKE_CONF_INSTALL_DIR share/dlfcn-win32)
28set(INCLUDE_INSTALL_DIR include)
29include(CMakePackageConfigHelpers)
30configure_package_config_file(../dlfcn-win32-config.cmake.in ${CMAKE_BINARY_DIR}/dlfcn-win32-config.cmake
31 INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
32 PATH_VARS INCLUDE_INSTALL_DIR
33 NO_CHECK_REQUIRED_COMPONENTS_MACRO)
34
35# Install the targets (install)
36install(EXPORT dlfcn-win32-targets
37 FILE dlfcn-win32-targets.cmake
38 NAMESPACE dlfcn-win32::
39 DESTINATION ${CMAKE_CONF_INSTALL_DIR})
40
41# Install the CMake config file
42install(FILES ${CMAKE_BINARY_DIR}/dlfcn-win32-config.cmake
43 DESTINATION ${CMAKE_CONF_INSTALL_DIR})
diff --git a/src/dlfcn.c b/src/dlfcn.c
new file mode 100644
index 0000000..532af91
--- /dev/null
+++ b/src/dlfcn.c
@@ -0,0 +1,478 @@
1/*
2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2015 Tiancheng "Timothy" Gu
5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26#ifndef _WIN32_WINNT
27#define _WIN32_WINNT 0x0501
28#endif
29#ifdef _DEBUG
30#define _CRTDBG_MAP_ALLOC
31#include <stdlib.h>
32#include <crtdbg.h>
33#endif
34#include <windows.h>
35#include <stdio.h>
36#include <stdlib.h>
37
38#ifdef _MSC_VER
39/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
40#pragma intrinsic(_ReturnAddress)
41#else
42/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
43#ifndef _ReturnAddress
44#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0)))
45#endif
46#endif
47
48#ifdef SHARED
49#define DLFCN_WIN32_EXPORTS
50#endif
51#include "dlfcn.h"
52
53/* Note:
54 * MSDN says these functions are not thread-safe. We make no efforts to have
55 * any kind of thread safety.
56 */
57
58typedef struct local_object {
59 HMODULE hModule;
60 struct local_object *previous;
61 struct local_object *next;
62} local_object;
63
64static local_object first_object;
65
66/* These functions implement a double linked list for the local objects. */
67static local_object *local_search( HMODULE hModule )
68{
69 local_object *pobject;
70
71 if( hModule == NULL )
72 return NULL;
73
74 for( pobject = &first_object; pobject; pobject = pobject->next )
75 if( pobject->hModule == hModule )
76 return pobject;
77
78 return NULL;
79}
80
81static BOOL local_add( HMODULE hModule )
82{
83 local_object *pobject;
84 local_object *nobject;
85
86 if( hModule == NULL )
87 return TRUE;
88
89 pobject = local_search( hModule );
90
91 /* Do not add object again if it's already on the list */
92 if( pobject )
93 return TRUE;
94
95 for( pobject = &first_object; pobject->next; pobject = pobject->next );
96
97 nobject = (local_object*) malloc( sizeof( local_object ) );
98
99 if( !nobject )
100 {
101 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
102 return FALSE;
103 }
104
105 pobject->next = nobject;
106 nobject->next = NULL;
107 nobject->previous = pobject;
108 nobject->hModule = hModule;
109
110 return TRUE;
111}
112
113static void local_rem( HMODULE hModule )
114{
115 local_object *pobject;
116
117 if( hModule == NULL )
118 return;
119
120 pobject = local_search( hModule );
121
122 if( !pobject )
123 return;
124
125 if( pobject->next )
126 pobject->next->previous = pobject->previous;
127 if( pobject->previous )
128 pobject->previous->next = pobject->next;
129
130 free( pobject );
131}
132
133/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
134 * static buffer.
135 * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
136 * the limit.
137 */
138static char error_buffer[65535];
139static BOOL error_occurred;
140
141static void save_err_str( const char *str )
142{
143 DWORD dwMessageId;
144 DWORD ret;
145 size_t pos, len;
146
147 dwMessageId = GetLastError( );
148
149 if( dwMessageId == 0 )
150 return;
151
152 len = strlen( str );
153 if( len > sizeof( error_buffer ) - 5 )
154 len = sizeof( error_buffer ) - 5;
155
156 /* Format error message to:
157 * "<argument to function that failed>": <Windows localized error message>
158 */
159 pos = 0;
160 error_buffer[pos++] = '"';
161 memcpy( error_buffer+pos, str, len );
162 pos += len;
163 error_buffer[pos++] = '"';
164 error_buffer[pos++] = ':';
165 error_buffer[pos++] = ' ';
166
167 ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
168 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
169 error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL );
170 pos += ret;
171
172 /* When FormatMessageA() fails it returns zero and does not touch buffer
173 * so add trailing null byte */
174 if( ret == 0 )
175 error_buffer[pos] = '\0';
176
177 if( pos > 1 )
178 {
179 /* POSIX says the string must not have trailing <newline> */
180 if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
181 error_buffer[pos-2] = '\0';
182 }
183
184 error_occurred = TRUE;
185}
186
187static void save_err_ptr_str( const void *ptr )
188{
189 char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */
190
191#ifdef _MSC_VER
192/* Supress warning C4996: 'sprintf': This function or variable may be unsafe */
193#pragma warning( suppress: 4996 )
194#endif
195 sprintf( ptr_buf, "0x%p", ptr );
196
197 save_err_str( ptr_buf );
198}
199
200/* Load Psapi.dll at runtime, this avoids linking caveat */
201static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
202{
203 static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD);
204 HMODULE psapi;
205
206 if( !EnumProcessModulesPtr )
207 {
208 psapi = LoadLibraryA( "Psapi.dll" );
209 if( psapi )
210 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" );
211 if( !EnumProcessModulesPtr )
212 return 0;
213 }
214
215 return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
216}
217
218void *dlopen( const char *file, int mode )
219{
220 HMODULE hModule;
221 UINT uMode;
222
223 error_occurred = FALSE;
224
225 /* Do not let Windows display the critical-error-handler message box */
226 uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
227
228 if( file == 0 )
229 {
230 /* POSIX says that if the value of file is 0, a handle on a global
231 * symbol object must be provided. That object must be able to access
232 * all symbols from the original program file, and any objects loaded
233 * with the RTLD_GLOBAL flag.
234 * The return value from GetModuleHandle( ) allows us to retrieve
235 * symbols only from the original program file. EnumProcessModules() is
236 * used to access symbols from other libraries. For objects loaded
237 * with the RTLD_LOCAL flag, we create our own list later on. They are
238 * excluded from EnumProcessModules() iteration.
239 */
240 hModule = GetModuleHandle( NULL );
241
242 if( !hModule )
243 save_err_str( "(null)" );
244 }
245 else
246 {
247 HANDLE hCurrentProc;
248 DWORD dwProcModsBefore, dwProcModsAfter;
249 char lpFileName[MAX_PATH];
250 size_t i, len;
251
252 len = strlen( file );
253
254 if( len >= sizeof( lpFileName ) )
255 {
256 SetLastError( ERROR_FILENAME_EXCED_RANGE );
257 save_err_str( file );
258 hModule = NULL;
259 }
260 else
261 {
262 /* MSDN says backslashes *must* be used instead of forward slashes. */
263 for( i = 0; i < len; i++ )
264 {
265 if( file[i] == '/' )
266 lpFileName[i] = '\\';
267 else
268 lpFileName[i] = file[i];
269 }
270 lpFileName[len] = '\0';
271
272 hCurrentProc = GetCurrentProcess( );
273
274 if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
275 dwProcModsBefore = 0;
276
277 /* POSIX says the search path is implementation-defined.
278 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
279 * to UNIX's search paths (start with system folders instead of current
280 * folder).
281 */
282 hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
283
284 if( !hModule )
285 {
286 save_err_str( lpFileName );
287 }
288 else
289 {
290 if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
291 dwProcModsAfter = 0;
292
293 /* If the object was loaded with RTLD_LOCAL, add it to list of local
294 * objects, so that its symbols cannot be retrieved even if the handle for
295 * the original program file is passed. POSIX says that if the same
296 * file is specified in multiple invocations, and any of them are
297 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
298 * symbols will remain global. If number of loaded modules was not
299 * changed after calling LoadLibraryEx(), it means that library was
300 * already loaded.
301 */
302 if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
303 {
304 if( !local_add( hModule ) )
305 {
306 save_err_str( lpFileName );
307 FreeLibrary( hModule );
308 hModule = NULL;
309 }
310 }
311 else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
312 {
313 local_rem( hModule );
314 }
315 }
316 }
317 }
318
319 /* Return to previous state of the error-mode bit flags. */
320 SetErrorMode( uMode );
321
322 return (void *) hModule;
323}
324
325int dlclose( void *handle )
326{
327 HMODULE hModule = (HMODULE) handle;
328 BOOL ret;
329
330 error_occurred = FALSE;
331
332 ret = FreeLibrary( hModule );
333
334 /* If the object was loaded with RTLD_LOCAL, remove it from list of local
335 * objects.
336 */
337 if( ret )
338 local_rem( hModule );
339 else
340 save_err_ptr_str( handle );
341
342 /* dlclose's return value in inverted in relation to FreeLibrary's. */
343 ret = !ret;
344
345 return (int) ret;
346}
347
348__declspec(noinline) /* Needed for _ReturnAddress() */
349void *dlsym( void *handle, const char *name )
350{
351 FARPROC symbol;
352 HMODULE hCaller;
353 HMODULE hModule;
354 HANDLE hCurrentProc;
355
356 error_occurred = FALSE;
357
358 symbol = NULL;
359 hCaller = NULL;
360 hModule = GetModuleHandle( NULL );
361 hCurrentProc = GetCurrentProcess( );
362
363 if( handle == RTLD_DEFAULT )
364 {
365 /* The symbol lookup happens in the normal global scope; that is,
366 * a search for a symbol using this handle would find the same
367 * definition as a direct use of this symbol in the program code.
368 * So use same lookup procedure as when filename is NULL.
369 */
370 handle = hModule;
371 }
372 else if( handle == RTLD_NEXT )
373 {
374 /* Specifies the next object after this one that defines name.
375 * This one refers to the object containing the invocation of dlsym().
376 * The next object is the one found upon the application of a load
377 * order symbol resolution algorithm. To get caller function of dlsym()
378 * use _ReturnAddress() intrinsic. To get HMODULE of caller function
379 * use standard GetModuleHandleExA() function.
380 */
381 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) )
382 goto end;
383 }
384
385 if( handle != RTLD_NEXT )
386 {
387 symbol = GetProcAddress( (HMODULE) handle, name );
388
389 if( symbol != NULL )
390 goto end;
391 }
392
393 /* If the handle for the original program file is passed, also search
394 * in all globally loaded objects.
395 */
396
397 if( hModule == handle || handle == RTLD_NEXT )
398 {
399 HMODULE *modules;
400 DWORD cbNeeded;
401 DWORD dwSize;
402 size_t i;
403
404 /* GetModuleHandle( NULL ) only returns the current program file. So
405 * if we want to get ALL loaded module including those in linked DLLs,
406 * we have to use EnumProcessModules( ).
407 */
408 if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
409 {
410 modules = malloc( dwSize );
411 if( modules )
412 {
413 if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
414 {
415 for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
416 {
417 if( handle == RTLD_NEXT && hCaller )
418 {
419 /* Next modules can be used for RTLD_NEXT */
420 if( hCaller == modules[i] )
421 hCaller = NULL;
422 continue;
423 }
424 if( local_search( modules[i] ) )
425 continue;
426 symbol = GetProcAddress( modules[i], name );
427 if( symbol != NULL )
428 {
429 free( modules );
430 goto end;
431 }
432 }
433
434 }
435 free( modules );
436 }
437 else
438 {
439 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
440 goto end;
441 }
442 }
443 }
444
445end:
446 if( symbol == NULL )
447 {
448 if( GetLastError() == 0 )
449 SetLastError( ERROR_PROC_NOT_FOUND );
450 save_err_str( name );
451 }
452
453 return *(void **) (&symbol);
454}
455
456char *dlerror( void )
457{
458 /* If this is the second consecutive call to dlerror, return NULL */
459 if( !error_occurred )
460 return NULL;
461
462 /* POSIX says that invoking dlerror( ) a second time, immediately following
463 * a prior invocation, shall result in NULL being returned.
464 */
465 error_occurred = FALSE;
466
467 return error_buffer;
468}
469
470#ifdef SHARED
471BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
472{
473 (void) hinstDLL;
474 (void) fdwReason;
475 (void) lpvReserved;
476 return TRUE;
477}
478#endif
diff --git a/src/dlfcn.h b/src/dlfcn.h
new file mode 100644
index 0000000..9ddbba3
--- /dev/null
+++ b/src/dlfcn.h
@@ -0,0 +1,78 @@
1/*
2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef DLFCN_H
25#define DLFCN_H
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31#if defined(DLFCN_WIN32_EXPORTS)
32# define DLFCN_EXPORT __declspec(dllexport)
33#else
34# define DLFCN_EXPORT
35#endif
36
37/* Relocations are performed when the object is loaded. */
38#define RTLD_NOW 0
39
40/* Relocations are performed at an implementation-defined time.
41 * Windows API does not support lazy symbol resolving (when first reference
42 * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW.
43 */
44#define RTLD_LAZY RTLD_NOW
45
46/* All symbols are available for relocation processing of other modules. */
47#define RTLD_GLOBAL (1 << 1)
48
49/* All symbols are not made available for relocation processing by other modules. */
50#define RTLD_LOCAL (1 << 2)
51
52/* These two were added in The Open Group Base Specifications Issue 6.
53 * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
54 */
55
56/* The symbol lookup happens in the normal global scope. */
57#define RTLD_DEFAULT ((void *)0)
58
59/* Specifies the next object after this one that defines name. */
60#define RTLD_NEXT ((void *)-1)
61
62/* Open a symbol table handle. */
63DLFCN_EXPORT void *dlopen(const char *file, int mode);
64
65/* Close a symbol table handle. */
66DLFCN_EXPORT int dlclose(void *handle);
67
68/* Get the address of a symbol from a symbol table handle. */
69DLFCN_EXPORT void *dlsym(void *handle, const char *name);
70
71/* Get diagnostic information. */
72DLFCN_EXPORT char *dlerror(void);
73
74#ifdef __cplusplus
75}
76#endif
77
78#endif /* DLFCN_H */