aboutsummaryrefslogtreecommitdiff
path: root/dlfcn.c
diff options
context:
space:
mode:
Diffstat (limited to 'dlfcn.c')
-rw-r--r--dlfcn.c142
1 files changed, 115 insertions, 27 deletions
diff --git a/dlfcn.c b/dlfcn.c
index add1f4f..324fafc 100644
--- a/dlfcn.c
+++ b/dlfcn.c
@@ -22,7 +22,9 @@
22#include <stdlib.h> 22#include <stdlib.h>
23#include <crtdbg.h> 23#include <crtdbg.h>
24#endif 24#endif
25#define PSAPI_VERSION 1
25#include <windows.h> 26#include <windows.h>
27#include <psapi.h>
26#include <stdio.h> 28#include <stdio.h>
27 29
28#define DLFCN_WIN32_EXPORTS 30#define DLFCN_WIN32_EXPORTS
@@ -40,23 +42,25 @@ typedef struct global_object {
40} global_object; 42} global_object;
41 43
42static global_object first_object; 44static global_object first_object;
45static global_object first_automatic_object;
46static int auto_ref_count = 0;
43 47
44/* These functions implement a double linked list for the global objects. */ 48/* These functions implement a double linked list for the global objects. */
45static global_object *global_search( HMODULE hModule ) 49static global_object *global_search( global_object *start, HMODULE hModule )
46{ 50{
47 global_object *pobject; 51 global_object *pobject;
48 52
49 if( hModule == NULL ) 53 if( hModule == NULL )
50 return NULL; 54 return NULL;
51 55
52 for( pobject = &first_object; pobject ; pobject = pobject->next ) 56 for( pobject = start; pobject; pobject = pobject->next )
53 if( pobject->hModule == hModule ) 57 if( pobject->hModule == hModule )
54 return pobject; 58 return pobject;
55 59
56 return NULL; 60 return NULL;
57} 61}
58 62
59static void global_add( HMODULE hModule ) 63static void global_add( global_object *start, HMODULE hModule )
60{ 64{
61 global_object *pobject; 65 global_object *pobject;
62 global_object *nobject; 66 global_object *nobject;
@@ -64,15 +68,22 @@ static void global_add( HMODULE hModule )
64 if( hModule == NULL ) 68 if( hModule == NULL )
65 return; 69 return;
66 70
67 pobject = global_search( hModule ); 71 pobject = global_search( start, hModule );
68 72
69 /* Do not add object again if it's already on the list */ 73 /* Do not add object again if it's already on the list */
70 if( pobject ) 74 if( pobject )
71 return; 75 return;
72 76
73 for( pobject = &first_object; pobject->next ; pobject = pobject->next ); 77 if( start == &first_automatic_object )
78 {
79 pobject = global_search( &first_object, hModule );
80 if( pobject )
81 return;
82 }
83
84 for( pobject = start; pobject->next; pobject = pobject->next );
74 85
75 nobject = malloc( sizeof(global_object) ); 86 nobject = malloc( sizeof( global_object ) );
76 87
77 /* Should this be enough to fail global_add, and therefore also fail 88 /* Should this be enough to fail global_add, and therefore also fail
78 * dlopen? 89 * dlopen?
@@ -86,14 +97,14 @@ static void global_add( HMODULE hModule )
86 nobject->hModule = hModule; 97 nobject->hModule = hModule;
87} 98}
88 99
89static void global_rem( HMODULE hModule ) 100static void global_rem( global_object *start, HMODULE hModule )
90{ 101{
91 global_object *pobject; 102 global_object *pobject;
92 103
93 if( hModule == NULL ) 104 if( hModule == NULL )
94 return; 105 return;
95 106
96 pobject = global_search( hModule ); 107 pobject = global_search( start, hModule );
97 108
98 if( !pobject ) 109 if( !pobject )
99 return; 110 return;
@@ -185,18 +196,40 @@ void *dlopen( const char *file, int mode )
185 196
186 if( file == 0 ) 197 if( file == 0 )
187 { 198 {
199 HMODULE hAddtnlMods[1024]; // Already loaded modules
200 HANDLE hCurrentProc = GetCurrentProcess( );
201 DWORD cbNeeded;
202
188 /* POSIX says that if the value of file is 0, a handle on a global 203 /* POSIX says that if the value of file is 0, a handle on a global
189 * symbol object must be provided. That object must be able to access 204 * symbol object must be provided. That object must be able to access
190 * all symbols from the original program file, and any objects loaded 205 * all symbols from the original program file, and any objects loaded
191 * with the RTLD_GLOBAL flag. 206 * with the RTLD_GLOBAL flag.
192 * The return value from GetModuleHandle( ) allows us to retrieve 207 * The return value from GetModuleHandle( ) allows us to retrieve
193 * symbols only from the original program file. For objects loaded with 208 * symbols only from the original program file. For objects loaded with
194 * the RTLD_GLOBAL flag, we create our own list later on. 209 * the RTLD_GLOBAL flag, we create our own list later on. For objects
210 * outside of the program file but already loaded (e.g. linked DLLs)
211 * they are added below.
195 */ 212 */
196 hModule = GetModuleHandle( NULL ); 213 hModule = GetModuleHandle( NULL );
197 214
198 if( !hModule ) 215 if( !hModule )
199 save_err_ptr_str( file ); 216 save_err_ptr_str( file );
217
218
219 /* GetModuleHandle( NULL ) only returns the current program file. So
220 * if we want to get ALL loaded module including those in linked DLLs,
221 * we have to use EnumProcessModules( ).
222 */
223 if( EnumProcessModules( hCurrentProc, hAddtnlMods,
224 sizeof( hAddtnlMods ), &cbNeeded ) != 0 )
225 {
226 DWORD i;
227 for( i = 0; i < cbNeeded / sizeof( HMODULE ); i++ )
228 {
229 global_add( &first_automatic_object, hAddtnlMods[i] );
230 }
231 }
232 auto_ref_count++;
200 } 233 }
201 else 234 else
202 { 235 {
@@ -233,7 +266,7 @@ void *dlopen( const char *file, int mode )
233 if( !hModule ) 266 if( !hModule )
234 save_err_str( lpFileName ); 267 save_err_str( lpFileName );
235 else if( (mode & RTLD_GLOBAL) ) 268 else if( (mode & RTLD_GLOBAL) )
236 global_add( hModule ); 269 global_add( &first_object, hModule );
237 } 270 }
238 271
239 /* Return to previous state of the error-mode bit flags. */ 272 /* Return to previous state of the error-mode bit flags. */
@@ -242,6 +275,21 @@ void *dlopen( const char *file, int mode )
242 return (void *) hModule; 275 return (void *) hModule;
243} 276}
244 277
278static void free_auto( )
279{
280 global_object *pobject = first_automatic_object.next;
281 if( pobject )
282 {
283 global_object *next;
284 for ( ; pobject; pobject = next )
285 {
286 next = pobject->next;
287 free( pobject );
288 }
289 first_automatic_object.next = NULL;
290 }
291}
292
245int dlclose( void *handle ) 293int dlclose( void *handle )
246{ 294{
247 HMODULE hModule = (HMODULE) handle; 295 HMODULE hModule = (HMODULE) handle;
@@ -255,7 +303,18 @@ int dlclose( void *handle )
255 * objects. 303 * objects.
256 */ 304 */
257 if( ret ) 305 if( ret )
258 global_rem( hModule ); 306 {
307 HMODULE cur = GetModuleHandle( NULL );
308 global_rem( &first_object, hModule );
309 if( hModule == cur )
310 {
311 auto_ref_count--;
312 if( auto_ref_count < 0 )
313 auto_ref_count = 0;
314 if( !auto_ref_count )
315 free_auto( );
316 }
317 }
259 else 318 else
260 save_err_ptr_str( handle ); 319 save_err_ptr_str( handle );
261 320
@@ -268,37 +327,47 @@ int dlclose( void *handle )
268void *dlsym( void *handle, const char *name ) 327void *dlsym( void *handle, const char *name )
269{ 328{
270 FARPROC symbol; 329 FARPROC symbol;
330 HMODULE hModule;
271 331
272 current_error = NULL; 332 current_error = NULL;
273 333
274 symbol = GetProcAddress( handle, name ); 334 symbol = GetProcAddress( handle, name );
275 335
276 if( symbol == NULL ) 336 if( symbol != NULL )
277 { 337 goto end;
278 HMODULE hModule;
279 338
280 /* If the handle for the original program file is passed, also search 339 /* If the handle for the original program file is passed, also search
281 * in all globally loaded objects. 340 * in all globally loaded objects.
282 */ 341 */
283 342
284 hModule = GetModuleHandle( NULL ); 343 hModule = GetModuleHandle( NULL );
285 344
286 if( hModule == handle ) 345 if( hModule == handle )
346 {
347 global_object *pobject;
348
349 for( pobject = &first_object; pobject; pobject = pobject->next )
287 { 350 {
288 global_object *pobject; 351 if( pobject->hModule )
352 {
353 symbol = GetProcAddress( pobject->hModule, name );
354 if( symbol != NULL )
355 goto end;
356 }
357 }
289 358
290 for( pobject = &first_object; pobject ; pobject = pobject->next ) 359 for( pobject = &first_automatic_object; pobject; pobject = pobject->next )
360 {
361 if( pobject->hModule )
291 { 362 {
292 if( pobject->hModule ) 363 symbol = GetProcAddress( pobject->hModule, name );
293 { 364 if( symbol != NULL )
294 symbol = GetProcAddress( pobject->hModule, name ); 365 goto end;
295 if( symbol != NULL )
296 break;
297 }
298 } 366 }
299 } 367 }
300 } 368 }
301 369
370end:
302 if( symbol == NULL ) 371 if( symbol == NULL )
303 save_err_str( name ); 372 save_err_str( name );
304 373
@@ -316,3 +385,22 @@ char *dlerror( void )
316 385
317 return error_pointer; 386 return error_pointer;
318} 387}
388
389#ifdef SHARED
390BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
391{
392 /*
393 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
394 *
395 * When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap
396 * memory only if the DLL is being unloaded dynamically (the lpReserved
397 * parameter is NULL).
398 */
399 if( fdwReason == DLL_PROCESS_DETACH && !lpvReserved )
400 {
401 auto_ref_count = 0;
402 free_auto( );
403 }
404 return TRUE;
405}
406#endif