aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSilvio Traversaro <pegua1@gmail.com>2019-02-14 14:57:29 +0100
committerGitHub <noreply@github.com>2019-02-14 14:57:29 +0100
commit278c782a3205dbe49de4233b3bd1e68687a9998b (patch)
tree71d0ea65a3c604982b20445384392fbdbce6d136
parent1530bed62922128ed0c2cdc436a55649ff9423fe (diff)
parent63d7bda42322bb0916e30bc547123a8330a4dcc2 (diff)
downloaddlfcn-win32-278c782a3205dbe49de4233b3bd1e68687a9998b.tar.gz
dlfcn-win32-278c782a3205dbe49de4233b3bd1e68687a9998b.tar.bz2
dlfcn-win32-278c782a3205dbe49de4233b3bd1e68687a9998b.zip
Merge pull request #44 from pali/master
Fix resolving global symbols and implement RTLD_DEFAULT and RTLD_NEXT
-rw-r--r--CMakeLists.txt5
-rw-r--r--Makefile10
-rw-r--r--cmake-test/CMakeLists.txt5
-rw-r--r--dlfcn.c245
-rw-r--r--dlfcn.h4
-rw-r--r--test.c87
-rw-r--r--testdll.c6
-rw-r--r--testdll2.c55
-rw-r--r--testdll3.c38
9 files changed, 335 insertions, 120 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48945b2..07addbb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,11 @@ if (BUILD_TESTS)
63 enable_testing() 63 enable_testing()
64 add_library(testdll SHARED testdll.c) 64 add_library(testdll SHARED testdll.c)
65 set_target_properties(testdll PROPERTIES PREFIX "") 65 set_target_properties(testdll PROPERTIES PREFIX "")
66 add_library(testdll2 SHARED testdll2.c)
67 set_target_properties(testdll2 PROPERTIES PREFIX "")
68 target_link_libraries(testdll2 dl)
69 add_library(testdll3 SHARED testdll3.c)
70 set_target_properties(testdll3 PROPERTIES PREFIX "")
66 add_executable(t_dlfcn test.c) 71 add_executable(t_dlfcn test.c)
67 target_link_libraries(t_dlfcn dl) 72 target_link_libraries(t_dlfcn dl)
68 add_test (NAME t_dlfcn COMMAND t_dlfcn) 73 add_test (NAME t_dlfcn COMMAND t_dlfcn)
diff --git a/Makefile b/Makefile
index c02dce0..efac5af 100644
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,13 @@ test.exe: test.o $(TARGETS)
66testdll.dll: testdll.c 66testdll.dll: testdll.c
67 $(CC) -shared -o $@ $^ 67 $(CC) -shared -o $@ $^
68 68
69test: $(TARGETS) test.exe testdll.dll 69testdll2.dll: testdll2.c $(TARGETS)
70 $(CC) -shared -o $@ $< -L. -ldl $(LIBS)
71
72testdll3.dll: testdll3.c
73 $(CC) -shared -o $@ $^
74
75test: $(TARGETS) test.exe testdll.dll testdll2.dll testdll3.dll
70 $(WINE) test.exe 76 $(WINE) test.exe
71 77
72clean:: 78clean::
@@ -74,7 +80,7 @@ clean::
74 dlfcn.o \ 80 dlfcn.o \
75 libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \ 81 libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \
76 tmptest.c tmptest.dll \ 82 tmptest.c tmptest.dll \
77 test.exe testdll.dll 83 test.exe testdll.dll testdll2.dll testdll3.dll
78 84
79distclean: clean 85distclean: clean
80 rm -f config.mak 86 rm -f config.mak
diff --git a/cmake-test/CMakeLists.txt b/cmake-test/CMakeLists.txt
index 532f2b8..659a79a 100644
--- a/cmake-test/CMakeLists.txt
+++ b/cmake-test/CMakeLists.txt
@@ -8,6 +8,11 @@ find_package(dlfcn-win32 REQUIRED)
8 8
9add_library(testdll SHARED ../testdll.c) 9add_library(testdll SHARED ../testdll.c)
10set_target_properties(testdll PROPERTIES PREFIX "") 10set_target_properties(testdll PROPERTIES PREFIX "")
11add_library(testdll2 SHARED ../testdll2.c)
12set_target_properties(testdll2 PROPERTIES PREFIX "")
13target_link_libraries(testdll2 dlfcn-win32::dl)
14add_library(testdll3 SHARED ../testdll3.c)
15set_target_properties(testdll3 PROPERTIES PREFIX "")
11add_executable(t_dlfcn ../test.c) 16add_executable(t_dlfcn ../test.c)
12target_link_libraries(t_dlfcn dlfcn-win32::dl) 17target_link_libraries(t_dlfcn dlfcn-win32::dl)
13enable_testing() 18enable_testing()
diff --git a/dlfcn.c b/dlfcn.c
index b356558..8d3c793 100644
--- a/dlfcn.c
+++ b/dlfcn.c
@@ -2,6 +2,7 @@
2 * dlfcn-win32 2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla 3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2015 Tiancheng "Timothy" Gu 4 * Copyright (c) 2015 Tiancheng "Timothy" Gu
5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 * 6 *
6 * dlfcn-win32 is free software; you can redistribute it and/or 7 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
@@ -29,6 +30,17 @@
29#include <stdio.h> 30#include <stdio.h>
30#include <stdlib.h> 31#include <stdlib.h>
31 32
33#ifdef _MSC_VER
34/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
35#include <intrin.h>
36#pragma intrinsic(_ReturnAddress)
37#else
38/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
39#ifndef _ReturnAddress
40#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0)))
41#endif
42#endif
43
32#ifdef SHARED 44#ifdef SHARED
33#define DLFCN_WIN32_EXPORTS 45#define DLFCN_WIN32_EXPORTS
34#endif 46#endif
@@ -52,57 +64,48 @@
52 * any kind of thread safety. 64 * any kind of thread safety.
53 */ 65 */
54 66
55typedef struct global_object { 67typedef struct local_object {
56 HMODULE hModule; 68 HMODULE hModule;
57 struct global_object *previous; 69 struct local_object *previous;
58 struct global_object *next; 70 struct local_object *next;
59} global_object; 71} local_object;
60 72
61static global_object first_object; 73static local_object first_object;
62static global_object first_automatic_object;
63static int auto_ref_count = 0;
64 74
65/* These functions implement a double linked list for the global objects. */ 75/* These functions implement a double linked list for the local objects. */
66static global_object *global_search( global_object *start, HMODULE hModule ) 76static local_object *local_search( HMODULE hModule )
67{ 77{
68 global_object *pobject; 78 local_object *pobject;
69 79
70 if( hModule == NULL ) 80 if( hModule == NULL )
71 return NULL; 81 return NULL;
72 82
73 for( pobject = start; pobject; pobject = pobject->next ) 83 for( pobject = &first_object; pobject; pobject = pobject->next )
74 if( pobject->hModule == hModule ) 84 if( pobject->hModule == hModule )
75 return pobject; 85 return pobject;
76 86
77 return NULL; 87 return NULL;
78} 88}
79 89
80static void global_add( global_object *start, HMODULE hModule ) 90static void local_add( HMODULE hModule )
81{ 91{
82 global_object *pobject; 92 local_object *pobject;
83 global_object *nobject; 93 local_object *nobject;
84 94
85 if( hModule == NULL ) 95 if( hModule == NULL )
86 return; 96 return;
87 97
88 pobject = global_search( start, hModule ); 98 pobject = local_search( hModule );
89 99
90 /* Do not add object again if it's already on the list */ 100 /* Do not add object again if it's already on the list */
91 if( pobject ) 101 if( pobject )
92 return; 102 return;
93 103
94 if( start == &first_automatic_object ) 104 for( pobject = &first_object; pobject->next; pobject = pobject->next );
95 {
96 pobject = global_search( &first_object, hModule );
97 if( pobject )
98 return;
99 }
100
101 for( pobject = start; pobject->next; pobject = pobject->next );
102 105
103 nobject = (global_object*) malloc( sizeof( global_object ) ); 106 nobject = (local_object*) malloc( sizeof( local_object ) );
104 107
105 /* Should this be enough to fail global_add, and therefore also fail 108 /* Should this be enough to fail local_add, and therefore also fail
106 * dlopen? 109 * dlopen?
107 */ 110 */
108 if( !nobject ) 111 if( !nobject )
@@ -114,14 +117,14 @@ static void global_add( global_object *start, HMODULE hModule )
114 nobject->hModule = hModule; 117 nobject->hModule = hModule;
115} 118}
116 119
117static void global_rem( global_object *start, HMODULE hModule ) 120static void local_rem( HMODULE hModule )
118{ 121{
119 global_object *pobject; 122 local_object *pobject;
120 123
121 if( hModule == NULL ) 124 if( hModule == NULL )
122 return; 125 return;
123 126
124 pobject = global_search( start, hModule ); 127 pobject = local_search( hModule );
125 128
126 if( !pobject ) 129 if( !pobject )
127 return; 130 return;
@@ -224,10 +227,6 @@ void *dlopen( const char *file, int mode )
224 227
225 if( file == 0 ) 228 if( file == 0 )
226 { 229 {
227 HMODULE hAddtnlMods[1024]; // Already loaded modules
228 HANDLE hCurrentProc = GetCurrentProcess( );
229 DWORD cbNeeded;
230
231 /* POSIX says that if the value of file is 0, a handle on a global 230 /* POSIX says that if the value of file is 0, a handle on a global
232 * symbol object must be provided. That object must be able to access 231 * symbol object must be provided. That object must be able to access
233 * all symbols from the original program file, and any objects loaded 232 * all symbols from the original program file, and any objects loaded
@@ -242,27 +241,13 @@ void *dlopen( const char *file, int mode )
242 241
243 if( !hModule ) 242 if( !hModule )
244 save_err_ptr_str( file ); 243 save_err_ptr_str( file );
245
246
247 /* GetModuleHandle( NULL ) only returns the current program file. So
248 * if we want to get ALL loaded module including those in linked DLLs,
249 * we have to use EnumProcessModules( ).
250 */
251 if( EnumProcessModules( hCurrentProc, hAddtnlMods,
252 sizeof( hAddtnlMods ), &cbNeeded ) != 0 )
253 {
254 DWORD i;
255 for( i = 0; i < cbNeeded / sizeof( HMODULE ); i++ )
256 {
257 global_add( &first_automatic_object, hAddtnlMods[i] );
258 }
259 }
260 auto_ref_count++;
261 } 244 }
262 else 245 else
263 { 246 {
247 HANDLE hCurrentProc;
248 DWORD dwProcModsBefore, dwProcModsAfter;
264 CHAR lpFileName[MAX_PATH]; 249 CHAR lpFileName[MAX_PATH];
265 int i; 250 size_t i;
266 251
267 /* MSDN says backslashes *must* be used instead of forward slashes. */ 252 /* MSDN says backslashes *must* be used instead of forward slashes. */
268 for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ ) 253 for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ )
@@ -276,6 +261,11 @@ void *dlopen( const char *file, int mode )
276 } 261 }
277 lpFileName[i] = '\0'; 262 lpFileName[i] = '\0';
278 263
264 hCurrentProc = GetCurrentProcess( );
265
266 if( EnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
267 dwProcModsBefore = 0;
268
279 /* POSIX says the search path is implementation-defined. 269 /* POSIX says the search path is implementation-defined.
280 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely 270 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
281 * to UNIX's search paths (start with system folders instead of current 271 * to UNIX's search paths (start with system folders instead of current
@@ -284,17 +274,24 @@ void *dlopen( const char *file, int mode )
284 hModule = LoadLibraryEx(lpFileName, NULL, 274 hModule = LoadLibraryEx(lpFileName, NULL,
285 LOAD_WITH_ALTERED_SEARCH_PATH ); 275 LOAD_WITH_ALTERED_SEARCH_PATH );
286 276
287 /* If the object was loaded with RTLD_GLOBAL, add it to list of global 277 if( EnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
288 * objects, so that its symbols may be retrieved even if the handle for 278 dwProcModsAfter = 0;
279
280 /* If the object was loaded with RTLD_LOCAL, add it to list of local
281 * objects, so that its symbols cannot be retrieved even if the handle for
289 * the original program file is passed. POSIX says that if the same 282 * the original program file is passed. POSIX says that if the same
290 * file is specified in multiple invocations, and any of them are 283 * file is specified in multiple invocations, and any of them are
291 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the 284 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
292 * symbols will remain global. 285 * symbols will remain global. If number of loaded modules was not
286 * changed after calling LoadLibraryEx(), it means that library was
287 * already loaded.
293 */ 288 */
294 if( !hModule ) 289 if( !hModule )
295 save_err_str( lpFileName ); 290 save_err_str( lpFileName );
296 else if( (mode & RTLD_GLOBAL) ) 291 else if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
297 global_add( &first_object, hModule ); 292 local_add( hModule );
293 else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
294 local_rem( hModule );
298 } 295 }
299 296
300 /* Return to previous state of the error-mode bit flags. */ 297 /* Return to previous state of the error-mode bit flags. */
@@ -303,21 +300,6 @@ void *dlopen( const char *file, int mode )
303 return (void *) hModule; 300 return (void *) hModule;
304} 301}
305 302
306static void free_auto( )
307{
308 global_object *pobject = first_automatic_object.next;
309 if( pobject )
310 {
311 global_object *next;
312 for ( ; pobject; pobject = next )
313 {
314 next = pobject->next;
315 free( pobject );
316 }
317 first_automatic_object.next = NULL;
318 }
319}
320
321int dlclose( void *handle ) 303int dlclose( void *handle )
322{ 304{
323 HMODULE hModule = (HMODULE) handle; 305 HMODULE hModule = (HMODULE) handle;
@@ -327,22 +309,11 @@ int dlclose( void *handle )
327 309
328 ret = FreeLibrary( hModule ); 310 ret = FreeLibrary( hModule );
329 311
330 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global 312 /* If the object was loaded with RTLD_LOCAL, remove it from list of local
331 * objects. 313 * objects.
332 */ 314 */
333 if( ret ) 315 if( ret )
334 { 316 local_rem( hModule );
335 HMODULE cur = GetModuleHandle( NULL );
336 global_rem( &first_object, hModule );
337 if( hModule == cur )
338 {
339 auto_ref_count--;
340 if( auto_ref_count < 0 )
341 auto_ref_count = 0;
342 if( !auto_ref_count )
343 free_auto( );
344 }
345 }
346 else 317 else
347 save_err_ptr_str( handle ); 318 save_err_ptr_str( handle );
348 319
@@ -352,10 +323,13 @@ int dlclose( void *handle )
352 return (int) ret; 323 return (int) ret;
353} 324}
354 325
326__declspec(noinline) /* Needed for _ReturnAddress() */
355void *dlsym( void *handle, const char *name ) 327void *dlsym( void *handle, const char *name )
356{ 328{
357 FARPROC symbol; 329 FARPROC symbol;
330 HMODULE hCaller;
358 HMODULE hModule; 331 HMODULE hModule;
332 HANDLE hCurrentProc;
359 333
360#ifdef UNICODE 334#ifdef UNICODE
361 wchar_t namew[MAX_PATH]; 335 wchar_t namew[MAX_PATH];
@@ -363,39 +337,88 @@ void *dlsym( void *handle, const char *name )
363#endif 337#endif
364 338
365 current_error = NULL; 339 current_error = NULL;
340 symbol = NULL;
341 hCaller = NULL;
342 hModule = GetModuleHandle( NULL );
343 hCurrentProc = GetCurrentProcess( );
366 344
367 symbol = GetProcAddress( (HMODULE) handle, name ); 345 if( handle == RTLD_DEFAULT )
346 {
347 /* The symbol lookup happens in the normal global scope; that is,
348 * a search for a symbol using this handle would find the same
349 * definition as a direct use of this symbol in the program code.
350 * So use same lookup procedure as when filename is NULL.
351 */
352 handle = hModule;
353 }
354 else if( handle == RTLD_NEXT )
355 {
356 /* Specifies the next object after this one that defines name.
357 * This one refers to the object containing the invocation of dlsym().
358 * The next object is the one found upon the application of a load
359 * order symbol resolution algorithm. To get caller function of dlsym()
360 * use _ReturnAddress() intrinsic. To get HMODULE of caller function
361 * use undocumented hack from https://stackoverflow.com/a/2396380
362 * The HMODULE of a DLL is the same value as the module's base address.
363 */
364 MEMORY_BASIC_INFORMATION info;
365 size_t sLen;
366 sLen = VirtualQueryEx( hCurrentProc, _ReturnAddress(), &info, sizeof( info ) );
367 if( sLen != sizeof( info ) )
368 goto end;
369 hCaller = (HMODULE) info.AllocationBase;
370 if(!hCaller)
371 goto end;
372 }
368 373
369 if( symbol != NULL ) 374 if( handle != RTLD_NEXT )
370 goto end; 375 {
376 symbol = GetProcAddress( (HMODULE) handle, name );
377
378 if( symbol != NULL )
379 goto end;
380 }
371 381
372 /* If the handle for the original program file is passed, also search 382 /* If the handle for the original program file is passed, also search
373 * in all globally loaded objects. 383 * in all globally loaded objects.
374 */ 384 */
375 385
376 hModule = GetModuleHandle( NULL ); 386 if( hModule == handle || handle == RTLD_NEXT )
377
378 if( hModule == handle )
379 { 387 {
380 global_object *pobject; 388 HMODULE *modules;
381 389 DWORD cbNeeded;
382 for( pobject = &first_object; pobject; pobject = pobject->next ) 390 DWORD dwSize;
383 { 391 size_t i;
384 if( pobject->hModule )
385 {
386 symbol = GetProcAddress( pobject->hModule, name );
387 if( symbol != NULL )
388 goto end;
389 }
390 }
391 392
392 for( pobject = &first_automatic_object; pobject; pobject = pobject->next ) 393 /* GetModuleHandle( NULL ) only returns the current program file. So
394 * if we want to get ALL loaded module including those in linked DLLs,
395 * we have to use EnumProcessModules( ).
396 */
397 if( EnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
393 { 398 {
394 if( pobject->hModule ) 399 modules = malloc( dwSize );
400 if( modules )
395 { 401 {
396 symbol = GetProcAddress( pobject->hModule, name ); 402 if( EnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
397 if( symbol != NULL ) 403 {
398 goto end; 404 for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
405 {
406 if( handle == RTLD_NEXT && hCaller )
407 {
408 /* Next modules can be used for RTLD_NEXT */
409 if( hCaller == modules[i] )
410 hCaller = NULL;
411 continue;
412 }
413 if( local_search( modules[i] ) )
414 continue;
415 symbol = GetProcAddress( modules[i], name );
416 if( symbol != NULL )
417 goto end;
418 }
419
420 }
421 free( modules );
399 } 422 }
400 } 423 }
401 } 424 }
@@ -472,18 +495,8 @@ char *dlerror( void )
472BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) 495BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
473{ 496{
474 (void) hinstDLL; 497 (void) hinstDLL;
475 /* 498 (void) fdwReason;
476 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx 499 (void) lpvReserved;
477 *
478 * When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap
479 * memory only if the DLL is being unloaded dynamically (the lpReserved
480 * parameter is NULL).
481 */
482 if( fdwReason == DLL_PROCESS_DETACH && !lpvReserved )
483 {
484 auto_ref_count = 0;
485 free_auto( );
486 }
487 return TRUE; 500 return TRUE;
488} 501}
489#endif 502#endif
diff --git a/dlfcn.h b/dlfcn.h
index 711e431..c0d7777 100644
--- a/dlfcn.h
+++ b/dlfcn.h
@@ -44,8 +44,8 @@ extern "C" {
44 * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. 44 * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
45 */ 45 */
46 46
47#define RTLD_DEFAULT 0 47#define RTLD_DEFAULT ((void *)0)
48#define RTLD_NEXT 0 48#define RTLD_NEXT ((void *)-1)
49 49
50DLFCN_EXPORT void *dlopen ( const char *file, int mode ); 50DLFCN_EXPORT void *dlopen ( const char *file, int mode );
51DLFCN_EXPORT int dlclose(void *handle); 51DLFCN_EXPORT int dlclose(void *handle);
diff --git a/test.c b/test.c
index ba440da..814aca1 100644
--- a/test.c
+++ b/test.c
@@ -2,6 +2,7 @@
2 * dlfcn-win32 2 * dlfcn-win32
3 * Copyright (c) 2007-2009 Ramiro Polla 3 * Copyright (c) 2007-2009 Ramiro Polla
4 * Copyright (c) 2014 Tiancheng "Timothy" Gu 4 * Copyright (c) 2014 Tiancheng "Timothy" Gu
5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 * 6 *
6 * dlfcn-win32 is free software; you can redistribute it and/or 7 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
@@ -25,6 +26,7 @@
25#endif 26#endif
26#include <stdio.h> 27#include <stdio.h>
27#include <string.h> 28#include <string.h>
29#include <windows.h>
28#include "dlfcn.h" 30#include "dlfcn.h"
29 31
30/* If these dlclose's fails, we don't care as the handles are going to be 32/* If these dlclose's fails, we don't care as the handles are going to be
@@ -71,12 +73,16 @@
71int main() 73int main()
72{ 74{
73 void *global; 75 void *global;
76 void *library2;
74 void *library; 77 void *library;
75 char *error; 78 char *error;
76 int (*function)( void ); 79 int (*function)( void );
80 int (*function2_from_library2)( void );
77 size_t (*fwrite_local) ( const void *, size_t, size_t, FILE * ); 81 size_t (*fwrite_local) ( const void *, size_t, size_t, FILE * );
82 size_t (*fputs_default) ( const char *, FILE * );
78 int (*nonexistentfunction)( void ); 83 int (*nonexistentfunction)( void );
79 int ret; 84 int ret;
85 HMODULE library3;
80 86
81#ifdef _DEBUG 87#ifdef _DEBUG
82 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); 88 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
@@ -87,6 +93,16 @@ int main()
87 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); 93 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
88#endif 94#endif
89 95
96 library2 = dlopen( "testdll2.dll", RTLD_GLOBAL );
97 if( !library2 )
98 {
99 error = dlerror( );
100 printf( "ERROR\tCould not open library2 globally: %s\n", error ? error : "" );
101 RETURN_ERROR;
102 }
103 else
104 printf( "SUCCESS\tOpened library2 globally: %p\n", library2 );
105
90 library = dlopen( "testdll.dll", RTLD_GLOBAL ); 106 library = dlopen( "testdll.dll", RTLD_GLOBAL );
91 if( !library ) 107 if( !library )
92 { 108 {
@@ -124,6 +140,22 @@ int main()
124 fwrite_local(hello_world,sizeof(char),strlen(hello_world),stderr); 140 fwrite_local(hello_world,sizeof(char),strlen(hello_world),stderr);
125 fflush(stderr); 141 fflush(stderr);
126 142
143 fputs_default = dlsym(RTLD_DEFAULT, "fputs");
144 if (!fputs_default)
145 {
146 error = dlerror();
147 printf("ERROR\tCould not get symbol from default handle: %s\n",
148 error ? error : "");
149 CLOSE_LIB;
150 CLOSE_GLOBAL;
151 RETURN_ERROR;
152 }
153 else
154 printf("SUCCESS\tGot symbol from default handle: %p\n", fputs_default);
155 char * hello_world_fputs = "Hello world from default fputs!\n";
156 fputs_default(hello_world_fputs, stderr);
157 fflush(stderr);
158
127 function = dlsym( library, "function" ); 159 function = dlsym( library, "function" );
128 if( !function ) 160 if( !function )
129 { 161 {
@@ -139,6 +171,27 @@ int main()
139 171
140 RUNFUNC; 172 RUNFUNC;
141 173
174 function2_from_library2 = dlsym( library2, "function2" );
175 if( !function2_from_library2 )
176 {
177 error = dlerror( );
178 printf( "ERROR\tCould not get symbol from library2 handle: %s\n",
179 error ? error : "" );
180 CLOSE_LIB;
181 CLOSE_GLOBAL;
182 RETURN_ERROR;
183 }
184 else
185 printf( "SUCCESS\tGot symbol from library2 handle: %p\n", function2_from_library2 );
186
187 ret = function2_from_library2 ();
188 if( ret != 2 )
189 {
190 CLOSE_LIB;
191 CLOSE_GLOBAL;
192 RETURN_ERROR;
193 }
194
142 nonexistentfunction = dlsym( library, "nonexistentfunction" ); 195 nonexistentfunction = dlsym( library, "nonexistentfunction" );
143 if( nonexistentfunction ) 196 if( nonexistentfunction )
144 { 197 {
@@ -194,6 +247,16 @@ int main()
194 else 247 else
195 printf( "SUCCESS\tClosed library.\n" ); 248 printf( "SUCCESS\tClosed library.\n" );
196 249
250 ret = dlclose( library2 );
251 if( ret )
252 {
253 error = dlerror( );
254 printf( "ERROR\tCould not close library2: %s\n", error ? error : "" );
255 RETURN_ERROR;
256 }
257 else
258 printf( "SUCCESS\tClosed library2.\n" );
259
197 library = dlopen( "testdll.dll", RTLD_LOCAL ); 260 library = dlopen( "testdll.dll", RTLD_LOCAL );
198 if( !library ) 261 if( !library )
199 { 262 {
@@ -335,6 +398,15 @@ int main()
335 printf("SUCCESS\tGot symbol from global handle: %p\n", function); 398 printf("SUCCESS\tGot symbol from global handle: %p\n", function);
336 399
337 400
401 library3 = LoadLibraryA("testdll3.dll");
402 if (!library3)
403 {
404 printf( "ERROR\tCould not open library3 via WINAPI\n" );
405 RETURN_ERROR;
406 }
407 else
408 printf( "SUCCESS\tOpened library3 via WINAPI: %p\n", library3 );
409
338 ret = dlclose( library ); 410 ret = dlclose( library );
339 if( ret ) 411 if( ret )
340 { 412 {
@@ -346,6 +418,21 @@ int main()
346 else 418 else
347 printf( "SUCCESS\tClosed library.\n" ); 419 printf( "SUCCESS\tClosed library.\n" );
348 420
421 function = dlsym(global, "function3");
422 if (!function)
423 {
424 error = dlerror();
425 printf("ERROR\tCould not get symbol from global handle: %s\n",
426 error ? error : "");
427 CLOSE_LIB;
428 CLOSE_GLOBAL;
429 RETURN_ERROR;
430 }
431 else
432 printf("SUCCESS\tGot symbol from global handle: %p\n", function);
433
434 RUNFUNC;
435
349 ret = dlclose( global ); 436 ret = dlclose( global );
350 if( ret ) 437 if( ret )
351 { 438 {
diff --git a/testdll.c b/testdll.c
index ff99f87..3df2234 100644
--- a/testdll.c
+++ b/testdll.c
@@ -30,6 +30,12 @@
30#define EXPORT 30#define EXPORT
31#endif 31#endif
32 32
33EXPORT int function2( void )
34{
35 printf( "Hello, world! from original library\n" );
36 return 0;
37}
38
33EXPORT int function( void ) 39EXPORT int function( void )
34{ 40{
35 printf( "Hello, world!\n" ); 41 printf( "Hello, world!\n" );
diff --git a/testdll2.c b/testdll2.c
new file mode 100644
index 0000000..910c820
--- /dev/null
+++ b/testdll2.c
@@ -0,0 +1,55 @@
1/*
2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 *
6 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * dlfcn-win32 is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with dlfcn-win32; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#ifdef _DEBUG
22#define _CRTDBG_MAP_ALLOC
23#include <stdlib.h>
24#include <crtdbg.h>
25#endif
26#include <stdio.h>
27
28#include "dlfcn.h"
29
30#if defined(_WIN32)
31#define EXPORT __declspec(dllexport)
32#else
33#define EXPORT
34#endif
35
36EXPORT int function2( void )
37{
38 char *error;
39 int (*function2_orig)(void);
40 printf( "Hello, world! from wrapper library\n" );
41 function2_orig = dlsym(RTLD_NEXT, "function2");
42 if (!function2_orig)
43 {
44 error = dlerror( );
45 printf( "ERROR\tCould not get symbol from RTLD_NEXT handle: %s\n",
46 error ? error : "" );
47 return 1;
48 }
49 if (function2_orig() != 0)
50 {
51 printf( "ERROR\tOriginal function from RTLD_NEXT handle did not return correct value\n" );
52 return 1;
53 }
54 return 2;
55}
diff --git a/testdll3.c b/testdll3.c
new file mode 100644
index 0000000..3906e48
--- /dev/null
+++ b/testdll3.c
@@ -0,0 +1,38 @@
1/*
2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 *
6 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * dlfcn-win32 is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with dlfcn-win32; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#ifdef _DEBUG
22#define _CRTDBG_MAP_ALLOC
23#include <stdlib.h>
24#include <crtdbg.h>
25#endif
26#include <stdio.h>
27
28#if defined(_WIN32)
29#define EXPORT __declspec(dllexport)
30#else
31#define EXPORT
32#endif
33
34EXPORT int function3( void )
35{
36 printf( "Hello, world!\n" );
37 return 0;
38}