diff options
Diffstat (limited to 'dlfcn.c')
-rw-r--r-- | dlfcn.c | 142 |
1 files changed, 115 insertions, 27 deletions
@@ -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 | ||
42 | static global_object first_object; | 44 | static global_object first_object; |
45 | static global_object first_automatic_object; | ||
46 | static 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. */ |
45 | static global_object *global_search( HMODULE hModule ) | 49 | static 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 | ||
59 | static void global_add( HMODULE hModule ) | 63 | static 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 | ||
89 | static void global_rem( HMODULE hModule ) | 100 | static 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 | ||
278 | static 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 | |||
245 | int dlclose( void *handle ) | 293 | int 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 ) | |||
268 | void *dlsym( void *handle, const char *name ) | 327 | void *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 | ||
370 | end: | ||
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 | ||
390 | BOOL 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 | ||