aboutsummaryrefslogtreecommitdiff
path: root/dlfcn.c
diff options
context:
space:
mode:
authorPali Rohár <pali.rohar@gmail.com>2019-01-29 22:57:04 +0100
committerPali Rohár <pali.rohar@gmail.com>2019-02-14 09:25:21 +0100
commit63d7bda42322bb0916e30bc547123a8330a4dcc2 (patch)
tree71d0ea65a3c604982b20445384392fbdbce6d136 /dlfcn.c
parent29c46a54ffa31513be1a2cdcd9e8a55938d6e549 (diff)
downloaddlfcn-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.c65
1 files changed, 59 insertions, 6 deletions
diff --git a/dlfcn.c b/dlfcn.c
index 1e706f0..8d3c793 100644
--- a/dlfcn.c
+++ b/dlfcn.c
@@ -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() */
315void *dlsym( void *handle, const char *name ) 327void *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 );