aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSilvio Traversaro <silvio@traversaro.it>2021-02-24 09:54:51 +0100
committerGitHub <noreply@github.com>2021-02-24 09:54:51 +0100
commit522c301ec366e9b42205ae21617780d37cc0e9f0 (patch)
treebe6641139c2a09b59eb66bf92645be9d6b18241d
parent3ec513f9d9fec0cf52aa7e2f2050112499cac581 (diff)
parent9e40646cf3a7d0817b2298f915399a128fcb4d27 (diff)
downloaddlfcn-win32-1.3.0.tar.gz
dlfcn-win32-1.3.0.tar.bz2
dlfcn-win32-1.3.0.zip
Merge pull request #95 from pali/masterv1.3.0
Various fixes
-rw-r--r--src/dlfcn.c186
-rw-r--r--tests/test.c8
2 files changed, 140 insertions, 54 deletions
diff --git a/src/dlfcn.c b/src/dlfcn.c
index abbd58d..86f24df 100644
--- a/src/dlfcn.c
+++ b/src/dlfcn.c
@@ -24,9 +24,6 @@
24 * THE SOFTWARE. 24 * THE SOFTWARE.
25 */ 25 */
26 26
27#ifndef _WIN32_WINNT
28#define _WIN32_WINNT 0x0501
29#endif
30#ifdef _DEBUG 27#ifdef _DEBUG
31#define _CRTDBG_MAP_ALLOC 28#define _CRTDBG_MAP_ALLOC
32#include <stdlib.h> 29#include <stdlib.h>
@@ -36,13 +33,26 @@
36#include <stdio.h> 33#include <stdio.h>
37#include <stdlib.h> 34#include <stdlib.h>
38 35
36/* Older versions do not have this type */
37#if _WIN32_WINNT < 0x0500
38typedef ULONG ULONG_PTR;
39#endif
40
41/* Older SDK versions do not have these macros */
42#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
43#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4
44#endif
45#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
46#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2
47#endif
48
39#ifdef _MSC_VER 49#ifdef _MSC_VER
40/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ 50/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
41#pragma intrinsic(_ReturnAddress) 51#pragma intrinsic( _ReturnAddress )
42#else 52#else
43/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */ 53/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
44#ifndef _ReturnAddress 54#ifndef _ReturnAddress
45#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0))) 55#define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) )
46#endif 56#endif
47#endif 57#endif
48 58
@@ -51,6 +61,16 @@
51#endif 61#endif
52#include "dlfcn.h" 62#include "dlfcn.h"
53 63
64#if defined( _MSC_VER ) && _MSC_VER >= 1300
65/* https://docs.microsoft.com/en-us/cpp/cpp/noinline */
66#define DLFCN_NOINLINE __declspec( noinline )
67#elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) )
68/* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */
69#define DLFCN_NOINLINE __attribute__(( noinline ))
70#else
71#define DLFCN_NOINLINE
72#endif
73
54/* Note: 74/* Note:
55 * MSDN says these functions are not thread-safe. We make no efforts to have 75 * MSDN says these functions are not thread-safe. We make no efforts to have
56 * any kind of thread safety. 76 * any kind of thread safety.
@@ -90,18 +110,15 @@ static BOOL local_add( HMODULE hModule )
90 pobject = local_search( hModule ); 110 pobject = local_search( hModule );
91 111
92 /* Do not add object again if it's already on the list */ 112 /* Do not add object again if it's already on the list */
93 if( pobject ) 113 if( pobject != NULL )
94 return TRUE; 114 return TRUE;
95 115
96 for( pobject = &first_object; pobject->next; pobject = pobject->next ); 116 for( pobject = &first_object; pobject->next; pobject = pobject->next );
97 117
98 nobject = (local_object*) malloc( sizeof( local_object ) ); 118 nobject = (local_object *) malloc( sizeof( local_object ) );
99 119
100 if( !nobject ) 120 if( !nobject )
101 {
102 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
103 return FALSE; 121 return FALSE;
104 }
105 122
106 pobject->next = nobject; 123 pobject->next = nobject;
107 nobject->next = NULL; 124 nobject->next = NULL;
@@ -120,7 +137,7 @@ static void local_rem( HMODULE hModule )
120 137
121 pobject = local_search( hModule ); 138 pobject = local_search( hModule );
122 139
123 if( !pobject ) 140 if( pobject == NULL )
124 return; 141 return;
125 142
126 if( pobject->next ) 143 if( pobject->next )
@@ -139,17 +156,11 @@ static void local_rem( HMODULE hModule )
139static char error_buffer[65535]; 156static char error_buffer[65535];
140static BOOL error_occurred; 157static BOOL error_occurred;
141 158
142static void save_err_str( const char *str ) 159static void save_err_str( const char *str, DWORD dwMessageId )
143{ 160{
144 DWORD dwMessageId;
145 DWORD ret; 161 DWORD ret;
146 size_t pos, len; 162 size_t pos, len;
147 163
148 dwMessageId = GetLastError( );
149
150 if( dwMessageId == 0 )
151 return;
152
153 len = strlen( str ); 164 len = strlen( str );
154 if( len > sizeof( error_buffer ) - 5 ) 165 if( len > sizeof( error_buffer ) - 5 )
155 len = sizeof( error_buffer ) - 5; 166 len = sizeof( error_buffer ) - 5;
@@ -159,7 +170,7 @@ static void save_err_str( const char *str )
159 */ 170 */
160 pos = 0; 171 pos = 0;
161 error_buffer[pos++] = '"'; 172 error_buffer[pos++] = '"';
162 memcpy( error_buffer+pos, str, len ); 173 memcpy( error_buffer + pos, str, len );
163 pos += len; 174 pos += len;
164 error_buffer[pos++] = '"'; 175 error_buffer[pos++] = '"';
165 error_buffer[pos++] = ':'; 176 error_buffer[pos++] = ':';
@@ -167,7 +178,7 @@ static void save_err_str( const char *str )
167 178
168 ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId, 179 ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
169 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), 180 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
170 error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL ); 181 error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL );
171 pos += ret; 182 pos += ret;
172 183
173 /* When FormatMessageA() fails it returns zero and does not touch buffer 184 /* When FormatMessageA() fails it returns zero and does not touch buffer
@@ -185,7 +196,7 @@ static void save_err_str( const char *str )
185 error_occurred = TRUE; 196 error_occurred = TRUE;
186} 197}
187 198
188static void save_err_ptr_str( const void *ptr ) 199static void save_err_ptr_str( const void *ptr, DWORD dwMessageId )
189{ 200{
190 char ptr_buf[2 + 2 * sizeof( ptr ) + 1]; 201 char ptr_buf[2 + 2 * sizeof( ptr ) + 1];
191 char num; 202 char num;
@@ -196,28 +207,91 @@ static void save_err_ptr_str( const void *ptr )
196 207
197 for( i = 0; i < 2 * sizeof( ptr ); i++ ) 208 for( i = 0; i < 2 * sizeof( ptr ); i++ )
198 { 209 {
199 num = ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF; 210 num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF );
200 ptr_buf[2+i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); 211 ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) );
201 } 212 }
202 213
203 ptr_buf[2 + 2 * sizeof( ptr )] = 0; 214 ptr_buf[2 + 2 * sizeof( ptr )] = 0;
204 215
205 save_err_str( ptr_buf ); 216 save_err_str( ptr_buf, dwMessageId );
217}
218
219static HMODULE MyGetModuleHandleFromAddress( void *addr )
220{
221 static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL;
222 static BOOL failed = FALSE;
223 HMODULE kernel32;
224 HMODULE hModule;
225 MEMORY_BASIC_INFORMATION info;
226 SIZE_T sLen;
227
228 if( !failed && GetModuleHandleExAPtr == NULL )
229 {
230 kernel32 = GetModuleHandleA( "Kernel32.dll" );
231 if( kernel32 != NULL )
232 GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) GetProcAddress( kernel32, "GetModuleHandleExA" );
233 if( GetModuleHandleExAPtr == NULL )
234 failed = TRUE;
235 }
236
237 if( !failed )
238 {
239 /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */
240 if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) addr, &hModule ) )
241 return NULL;
242 }
243 else
244 {
245 /* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380
246 * The HMODULE of a DLL is the same value as the module's base address.
247 */
248 sLen = VirtualQuery( addr, &info, sizeof( info ) );
249 if( sLen != sizeof( info ) )
250 return NULL;
251 hModule = (HMODULE) info.AllocationBase;
252 }
253
254 return hModule;
206} 255}
207 256
208/* Load Psapi.dll at runtime, this avoids linking caveat */ 257/* Load Psapi.dll at runtime, this avoids linking caveat */
209static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) 258static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
210{ 259{
211 static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD); 260 static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
261 static BOOL failed = FALSE;
262 UINT uMode;
212 HMODULE psapi; 263 HMODULE psapi;
213 264
214 if( !EnumProcessModulesPtr ) 265 if( failed )
266 return FALSE;
267
268 if( EnumProcessModulesPtr == NULL )
215 { 269 {
216 psapi = LoadLibraryA( "Psapi.dll" ); 270 /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */
217 if( psapi ) 271 psapi = GetModuleHandleA( "Kernel32.dll" );
218 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" ); 272 if( psapi != NULL )
219 if( !EnumProcessModulesPtr ) 273 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "K32EnumProcessModules" );
220 return 0; 274
275 /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */
276 if( EnumProcessModulesPtr == NULL )
277 {
278 /* Do not let Windows display the critical-error-handler message box */
279 uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
280 psapi = LoadLibraryA( "Psapi.dll" );
281 if( psapi != NULL )
282 {
283 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" );
284 if( EnumProcessModulesPtr == NULL )
285 FreeLibrary( psapi );
286 }
287 SetErrorMode( uMode );
288 }
289
290 if( EnumProcessModulesPtr == NULL )
291 {
292 failed = TRUE;
293 return FALSE;
294 }
221 } 295 }
222 296
223 return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); 297 return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
@@ -234,9 +308,9 @@ void *dlopen( const char *file, int mode )
234 /* Do not let Windows display the critical-error-handler message box */ 308 /* Do not let Windows display the critical-error-handler message box */
235 uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); 309 uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
236 310
237 if( file == 0 ) 311 if( file == NULL )
238 { 312 {
239 /* POSIX says that if the value of file is 0, a handle on a global 313 /* POSIX says that if the value of file is NULL, a handle on a global
240 * symbol object must be provided. That object must be able to access 314 * symbol object must be provided. That object must be able to access
241 * all symbols from the original program file, and any objects loaded 315 * all symbols from the original program file, and any objects loaded
242 * with the RTLD_GLOBAL flag. 316 * with the RTLD_GLOBAL flag.
@@ -249,7 +323,7 @@ void *dlopen( const char *file, int mode )
249 hModule = GetModuleHandle( NULL ); 323 hModule = GetModuleHandle( NULL );
250 324
251 if( !hModule ) 325 if( !hModule )
252 save_err_str( "(null)" ); 326 save_err_str( "(null)", GetLastError( ) );
253 } 327 }
254 else 328 else
255 { 329 {
@@ -262,8 +336,7 @@ void *dlopen( const char *file, int mode )
262 336
263 if( len >= sizeof( lpFileName ) ) 337 if( len >= sizeof( lpFileName ) )
264 { 338 {
265 SetLastError( ERROR_FILENAME_EXCED_RANGE ); 339 save_err_str( file, ERROR_FILENAME_EXCED_RANGE );
266 save_err_str( file );
267 hModule = NULL; 340 hModule = NULL;
268 } 341 }
269 else 342 else
@@ -292,7 +365,7 @@ void *dlopen( const char *file, int mode )
292 365
293 if( !hModule ) 366 if( !hModule )
294 { 367 {
295 save_err_str( lpFileName ); 368 save_err_str( lpFileName, GetLastError( ) );
296 } 369 }
297 else 370 else
298 { 371 {
@@ -312,7 +385,7 @@ void *dlopen( const char *file, int mode )
312 { 385 {
313 if( !local_add( hModule ) ) 386 if( !local_add( hModule ) )
314 { 387 {
315 save_err_str( lpFileName ); 388 save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY );
316 FreeLibrary( hModule ); 389 FreeLibrary( hModule );
317 hModule = NULL; 390 hModule = NULL;
318 } 391 }
@@ -347,7 +420,7 @@ int dlclose( void *handle )
347 if( ret ) 420 if( ret )
348 local_rem( hModule ); 421 local_rem( hModule );
349 else 422 else
350 save_err_ptr_str( handle ); 423 save_err_ptr_str( handle, GetLastError( ) );
351 424
352 /* dlclose's return value in inverted in relation to FreeLibrary's. */ 425 /* dlclose's return value in inverted in relation to FreeLibrary's. */
353 ret = !ret; 426 ret = !ret;
@@ -355,21 +428,21 @@ int dlclose( void *handle )
355 return (int) ret; 428 return (int) ret;
356} 429}
357 430
358__declspec(noinline) /* Needed for _ReturnAddress() */ 431DLFCN_NOINLINE /* Needed for _ReturnAddress() */
359DLFCN_EXPORT 432DLFCN_EXPORT
360void *dlsym( void *handle, const char *name ) 433void *dlsym( void *handle, const char *name )
361{ 434{
362 FARPROC symbol; 435 FARPROC symbol;
363 HMODULE hCaller; 436 HMODULE hCaller;
364 HMODULE hModule; 437 HMODULE hModule;
365 HANDLE hCurrentProc; 438 DWORD dwMessageId;
366 439
367 error_occurred = FALSE; 440 error_occurred = FALSE;
368 441
369 symbol = NULL; 442 symbol = NULL;
370 hCaller = NULL; 443 hCaller = NULL;
371 hModule = GetModuleHandle( NULL ); 444 hModule = GetModuleHandle( NULL );
372 hCurrentProc = GetCurrentProcess( ); 445 dwMessageId = 0;
373 446
374 if( handle == RTLD_DEFAULT ) 447 if( handle == RTLD_DEFAULT )
375 { 448 {
@@ -387,10 +460,16 @@ void *dlsym( void *handle, const char *name )
387 * The next object is the one found upon the application of a load 460 * The next object is the one found upon the application of a load
388 * order symbol resolution algorithm. To get caller function of dlsym() 461 * order symbol resolution algorithm. To get caller function of dlsym()
389 * use _ReturnAddress() intrinsic. To get HMODULE of caller function 462 * use _ReturnAddress() intrinsic. To get HMODULE of caller function
390 * use standard GetModuleHandleExA() function. 463 * use MyGetModuleHandleFromAddress() which calls either standard
464 * GetModuleHandleExA() function or hack via VirtualQuery().
391 */ 465 */
392 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) ) 466 hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) );
467
468 if( hCaller == NULL )
469 {
470 dwMessageId = ERROR_INVALID_PARAMETER;
393 goto end; 471 goto end;
472 }
394 } 473 }
395 474
396 if( handle != RTLD_NEXT ) 475 if( handle != RTLD_NEXT )
@@ -407,11 +486,14 @@ void *dlsym( void *handle, const char *name )
407 486
408 if( hModule == handle || handle == RTLD_NEXT ) 487 if( hModule == handle || handle == RTLD_NEXT )
409 { 488 {
489 HANDLE hCurrentProc;
410 HMODULE *modules; 490 HMODULE *modules;
411 DWORD cbNeeded; 491 DWORD cbNeeded;
412 DWORD dwSize; 492 DWORD dwSize;
413 size_t i; 493 size_t i;
414 494
495 hCurrentProc = GetCurrentProcess( );
496
415 /* GetModuleHandle( NULL ) only returns the current program file. So 497 /* GetModuleHandle( NULL ) only returns the current program file. So
416 * if we want to get ALL loaded module including those in linked DLLs, 498 * if we want to get ALL loaded module including those in linked DLLs,
417 * we have to use EnumProcessModules( ). 499 * we have to use EnumProcessModules( ).
@@ -447,7 +529,7 @@ void *dlsym( void *handle, const char *name )
447 } 529 }
448 else 530 else
449 { 531 {
450 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 532 dwMessageId = ERROR_NOT_ENOUGH_MEMORY;
451 goto end; 533 goto end;
452 } 534 }
453 } 535 }
@@ -456,9 +538,9 @@ void *dlsym( void *handle, const char *name )
456end: 538end:
457 if( symbol == NULL ) 539 if( symbol == NULL )
458 { 540 {
459 if( GetLastError() == 0 ) 541 if( !dwMessageId )
460 SetLastError( ERROR_PROC_NOT_FOUND ); 542 dwMessageId = ERROR_PROC_NOT_FOUND;
461 save_err_str( name ); 543 save_err_str( name, dwMessageId );
462 } 544 }
463 545
464 return *(void **) (&symbol); 546 return *(void **) (&symbol);
@@ -617,7 +699,9 @@ static BOOL fill_info( void *addr, Dl_info *info )
617 void *funcAddress = NULL; 699 void *funcAddress = NULL;
618 700
619 /* Get module of the specified address */ 701 /* Get module of the specified address */
620 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) 702 hModule = MyGetModuleHandleFromAddress( addr );
703
704 if( hModule == NULL )
621 return FALSE; 705 return FALSE;
622 706
623 dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) ); 707 dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) );
@@ -655,7 +739,9 @@ int dladdr( void *addr, Dl_info *info )
655 HMODULE hModule; 739 HMODULE hModule;
656 740
657 /* Get module of the import thunk address */ 741 /* Get module of the import thunk address */
658 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) 742 hModule = MyGetModuleHandleFromAddress( addr );
743
744 if( hModule == NULL )
659 return 0; 745 return 0;
660 746
661 if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) 747 if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) )
diff --git a/tests/test.c b/tests/test.c
index 132ede6..1d0d437 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -342,7 +342,7 @@ int main()
342 *(void **) (&fwrite_local) = dlsym( global, "fwrite" ); 342 *(void **) (&fwrite_local) = dlsym( global, "fwrite" );
343 if (!fwrite_local) 343 if (!fwrite_local)
344 { 344 {
345 error = dlerror(); 345 error = dlerror( );
346 printf("ERROR\tCould not get symbol from global handle: %s\n", 346 printf("ERROR\tCould not get symbol from global handle: %s\n",
347 error ? error : ""); 347 error ? error : "");
348 CLOSE_LIB; 348 CLOSE_LIB;
@@ -360,7 +360,7 @@ int main()
360 *(void **) (&fputs_default) = dlsym( RTLD_DEFAULT, "fputs" ); 360 *(void **) (&fputs_default) = dlsym( RTLD_DEFAULT, "fputs" );
361 if (!fputs_default) 361 if (!fputs_default)
362 { 362 {
363 error = dlerror(); 363 error = dlerror( );
364 printf("ERROR\tCould not get symbol from default handle: %s\n", 364 printf("ERROR\tCould not get symbol from default handle: %s\n",
365 error ? error : ""); 365 error ? error : "");
366 CLOSE_LIB; 366 CLOSE_LIB;
@@ -623,7 +623,7 @@ int main()
623 *(void **) (&function) = dlsym( global, "fwrite" ); 623 *(void **) (&function) = dlsym( global, "fwrite" );
624 if (!function) 624 if (!function)
625 { 625 {
626 error = dlerror(); 626 error = dlerror( );
627 printf("ERROR\tCould not get symbol from global handle: %s\n", 627 printf("ERROR\tCould not get symbol from global handle: %s\n",
628 error ? error : ""); 628 error ? error : "");
629 CLOSE_LIB; 629 CLOSE_LIB;
@@ -659,7 +659,7 @@ int main()
659 *(void **) (&function) = dlsym( global, "function3" ); 659 *(void **) (&function) = dlsym( global, "function3" );
660 if (!function) 660 if (!function)
661 { 661 {
662 error = dlerror(); 662 error = dlerror( );
663 printf("ERROR\tCould not get symbol from global handle: %s\n", 663 printf("ERROR\tCould not get symbol from global handle: %s\n",
664 error ? error : ""); 664 error ? error : "");
665 CLOSE_LIB; 665 CLOSE_LIB;