diff options
author | Pali Rohár <pali.rohar@gmail.com> | 2019-01-29 22:57:04 +0100 |
---|---|---|
committer | Pali Rohár <pali.rohar@gmail.com> | 2019-02-14 09:25:21 +0100 |
commit | 63d7bda42322bb0916e30bc547123a8330a4dcc2 (patch) | |
tree | 71d0ea65a3c604982b20445384392fbdbce6d136 /dlfcn.c | |
parent | 29c46a54ffa31513be1a2cdcd9e8a55938d6e549 (diff) | |
download | dlfcn-win32-63d7bda42322bb0916e30bc547123a8330a4dcc2.tar.gz dlfcn-win32-63d7bda42322bb0916e30bc547123a8330a4dcc2.tar.bz2 dlfcn-win32-63d7bda42322bb0916e30bc547123a8330a4dcc2.zip |
Implement support for dlsym() with RTLD_DEFAULT and RTLD_NEXT
dlsym() with RTLD_DEFAULT handle behaves in same way like with global handle
returned by dlopen() with NULL file name.
dlsym() with RTLD_NEXT handle search for next loaded module which provides
specified symbol. "Next" means module which in EnumProcessModules() result
after the module which called dlsym().
To get caller function of dlsym() use _ReturnAddress() intrinsic. To get
module where is caller function use the fact that HMODULE is the same value
as the module's base address.
When compiling under gcc, defines _ReturnAddress() macro via gcc's builtin
as it does not provide MSC's specific _ReturnAddress() intrinsic.
Added tests demonstrate that both RTLD_DEFAULT and RTLD_NEXT are working as
expected.
Diffstat (limited to 'dlfcn.c')
-rw-r--r-- | dlfcn.c | 65 |
1 files changed, 59 insertions, 6 deletions
@@ -30,6 +30,17 @@ | |||
30 | #include <stdio.h> | 30 | #include <stdio.h> |
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | 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 | |||
33 | #ifdef SHARED | 44 | #ifdef SHARED |
34 | #define DLFCN_WIN32_EXPORTS | 45 | #define DLFCN_WIN32_EXPORTS |
35 | #endif | 46 | #endif |
@@ -312,9 +323,11 @@ int dlclose( void *handle ) | |||
312 | return (int) ret; | 323 | return (int) ret; |
313 | } | 324 | } |
314 | 325 | ||
326 | __declspec(noinline) /* Needed for _ReturnAddress() */ | ||
315 | void *dlsym( void *handle, const char *name ) | 327 | void *dlsym( void *handle, const char *name ) |
316 | { | 328 | { |
317 | FARPROC symbol; | 329 | FARPROC symbol; |
330 | HMODULE hCaller; | ||
318 | HMODULE hModule; | 331 | HMODULE hModule; |
319 | HANDLE hCurrentProc; | 332 | HANDLE hCurrentProc; |
320 | 333 | ||
@@ -324,20 +337,53 @@ void *dlsym( void *handle, const char *name ) | |||
324 | #endif | 337 | #endif |
325 | 338 | ||
326 | current_error = NULL; | 339 | current_error = NULL; |
340 | symbol = NULL; | ||
341 | hCaller = NULL; | ||
342 | hModule = GetModuleHandle( NULL ); | ||
327 | hCurrentProc = GetCurrentProcess( ); | 343 | hCurrentProc = GetCurrentProcess( ); |
328 | 344 | ||
329 | 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 | } | ||
373 | |||
374 | if( handle != RTLD_NEXT ) | ||
375 | { | ||
376 | symbol = GetProcAddress( (HMODULE) handle, name ); | ||
330 | 377 | ||
331 | if( symbol != NULL ) | 378 | if( symbol != NULL ) |
332 | goto end; | 379 | goto end; |
380 | } | ||
333 | 381 | ||
334 | /* 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 |
335 | * in all globally loaded objects. | 383 | * in all globally loaded objects. |
336 | */ | 384 | */ |
337 | 385 | ||
338 | hModule = GetModuleHandle( NULL ); | 386 | if( hModule == handle || handle == RTLD_NEXT ) |
339 | |||
340 | if( hModule == handle ) | ||
341 | { | 387 | { |
342 | HMODULE *modules; | 388 | HMODULE *modules; |
343 | DWORD cbNeeded; | 389 | DWORD cbNeeded; |
@@ -357,6 +403,13 @@ void *dlsym( void *handle, const char *name ) | |||
357 | { | 403 | { |
358 | for( i = 0; i < dwSize / sizeof( HMODULE ); i++ ) | 404 | for( i = 0; i < dwSize / sizeof( HMODULE ); i++ ) |
359 | { | 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 | } | ||
360 | if( local_search( modules[i] ) ) | 413 | if( local_search( modules[i] ) ) |
361 | continue; | 414 | continue; |
362 | symbol = GetProcAddress( modules[i], name ); | 415 | symbol = GetProcAddress( modules[i], name ); |