aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSilvio Traversaro <silvio@traversaro.it>2025-05-03 12:27:40 +0200
committerGitHub <noreply@github.com>2025-05-03 12:27:40 +0200
commit8bfddb5aa345ce10ba98e925acbc7bfb53639679 (patch)
tree43c768ea57ebe87edb35aeb7f71e7a90efc7bc92
parent3b52e651f385df00045dd8966407fd9de57fc94b (diff)
parent7989e4dc4fa1dc31b4c353c72b092209a773c78f (diff)
downloaddlfcn-win32-master.tar.gz
dlfcn-win32-master.tar.bz2
dlfcn-win32-master.zip
Merge pull request #118 from dlfcn-win32/variousimprovements2025HEADmaster
Remove use of CRT, fix gcc compilation in C++ mode, fix missing includes and fix warnings
-rw-r--r--src/dlfcn.c132
-rw-r--r--tests/CMakeLists.txt2
-rw-r--r--tests/test-dladdr.c9
-rw-r--r--tests/test.c1
4 files changed, 91 insertions, 53 deletions
diff --git a/src/dlfcn.c b/src/dlfcn.c
index cb9f9bb..1830b20 100644
--- a/src/dlfcn.c
+++ b/src/dlfcn.c
@@ -26,12 +26,10 @@
26 26
27#ifdef _DEBUG 27#ifdef _DEBUG
28#define _CRTDBG_MAP_ALLOC 28#define _CRTDBG_MAP_ALLOC
29#include <stdlib.h> 29#include <stdlib.h> /* malloc() and free() */
30#include <crtdbg.h> 30#include <crtdbg.h>
31#endif 31#endif
32#include <windows.h> 32#include <windows.h>
33#include <stdio.h>
34#include <stdlib.h>
35 33
36/* Older versions do not have this type */ 34/* Older versions do not have this type */
37#if _WIN32_WINNT < 0x0500 35#if _WIN32_WINNT < 0x0500
@@ -61,7 +59,12 @@ typedef ULONG ULONG_PTR;
61 59
62#ifdef _MSC_VER 60#ifdef _MSC_VER
63#if _MSC_VER >= 1000 61#if _MSC_VER >= 1000
64/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ 62/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress
63 * When compiling in C++ mode, it is required to have C declaration for _ReturnAddress.
64 */
65#ifdef __cplusplus
66extern "C" void *_ReturnAddress(void);
67#endif
65#pragma intrinsic( _ReturnAddress ) 68#pragma intrinsic( _ReturnAddress )
66#else 69#else
67/* On older version read return address from the value on stack pointer + 4 of 70/* On older version read return address from the value on stack pointer + 4 of
@@ -70,7 +73,11 @@ typedef ULONG ULONG_PTR;
70 * EBP register optimization. Read value of EBP + 4 via inline assembly. And 73 * EBP register optimization. Read value of EBP + 4 via inline assembly. And
71 * because inline assembly does not have a return value, put it into naked 74 * because inline assembly does not have a return value, put it into naked
72 * function which does not have prologue and epilogue and preserve registers. 75 * function which does not have prologue and epilogue and preserve registers.
76 * When compiling in C++ mode, it is required to have C declaration for _alloca.
73 */ 77 */
78#ifdef __cplusplus
79extern "C" void *__cdecl _alloca(size_t);
80#endif
74__declspec( naked ) static void *_ReturnAddress( void ) { __asm mov eax, [ebp+4] __asm ret } 81__declspec( naked ) static void *_ReturnAddress( void ) { __asm mov eax, [ebp+4] __asm ret }
75#define _ReturnAddress( ) ( _alloca(1), _ReturnAddress( ) ) 82#define _ReturnAddress( ) ( _alloca(1), _ReturnAddress( ) )
76#endif 83#endif
@@ -96,6 +103,24 @@ __declspec( naked ) static void *_ReturnAddress( void ) { __asm mov eax, [ebp+4]
96#define DLFCN_NOINLINE 103#define DLFCN_NOINLINE
97#endif 104#endif
98 105
106static void *MyAlloc( size_t size )
107{
108#ifdef _DEBUG
109 return malloc( size );
110#else
111 return LocalAlloc( LPTR, size );
112#endif
113}
114
115static void MyFree( void *ptr )
116{
117#ifdef _DEBUG
118 free( ptr );
119#else
120 LocalFree( ptr );
121#endif
122}
123
99/* Note: 124/* Note:
100 * MSDN says these functions are not thread-safe. We make no efforts to have 125 * MSDN says these functions are not thread-safe. We make no efforts to have
101 * any kind of thread safety. 126 * any kind of thread safety.
@@ -140,7 +165,7 @@ static BOOL local_add( HMODULE hModule )
140 165
141 for( pobject = &first_object; pobject->next; pobject = pobject->next ); 166 for( pobject = &first_object; pobject->next; pobject = pobject->next );
142 167
143 nobject = (local_object *) malloc( sizeof( local_object ) ); 168 nobject = (local_object *) MyAlloc( sizeof( local_object ) );
144 169
145 if( !nobject ) 170 if( !nobject )
146 return FALSE; 171 return FALSE;
@@ -170,7 +195,7 @@ static void local_rem( HMODULE hModule )
170 if( pobject->previous ) 195 if( pobject->previous )
171 pobject->previous->next = pobject->next; 196 pobject->previous->next = pobject->next;
172 197
173 free( pobject ); 198 MyFree( pobject );
174} 199}
175 200
176/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one 201/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
@@ -184,19 +209,15 @@ static BOOL error_occurred;
184static void save_err_str( const char *str, DWORD dwMessageId ) 209static void save_err_str( const char *str, DWORD dwMessageId )
185{ 210{
186 DWORD ret; 211 DWORD ret;
187 size_t pos, len; 212 size_t pos, i;
188
189 len = strlen( str );
190 if( len > sizeof( error_buffer ) - 5 )
191 len = sizeof( error_buffer ) - 5;
192 213
193 /* Format error message to: 214 /* Format error message to:
194 * "<argument to function that failed>": <Windows localized error message> 215 * "<argument to function that failed>": <Windows localized error message>
195 */ 216 */
196 pos = 0; 217 pos = 0;
197 error_buffer[pos++] = '"'; 218 error_buffer[pos++] = '"';
198 memcpy( error_buffer + pos, str, len ); 219 for( i = 0; i < sizeof( error_buffer ) - 5 && str[i] != '\0'; i++ )
199 pos += len; 220 error_buffer[pos++] = str[i];
200 error_buffer[pos++] = '"'; 221 error_buffer[pos++] = '"';
201 error_buffer[pos++] = ':'; 222 error_buffer[pos++] = ':';
202 error_buffer[pos++] = ' '; 223 error_buffer[pos++] = ' ';
@@ -233,7 +254,7 @@ static void save_err_ptr_str( const void *ptr, DWORD dwMessageId )
233 for( i = 0; i < 2 * sizeof( ptr ); i++ ) 254 for( i = 0; i < 2 * sizeof( ptr ); i++ )
234 { 255 {
235 num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF ); 256 num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF );
236 ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); 257 ptr_buf[2 + i] = (char) ( num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ) );
237 } 258 }
238 259
239 ptr_buf[2 + 2 * sizeof( ptr )] = 0; 260 ptr_buf[2 + 2 * sizeof( ptr )] = 0;
@@ -252,7 +273,7 @@ static UINT MySetErrorMode( UINT uMode )
252 { 273 {
253 kernel32 = GetModuleHandleA( "Kernel32.dll" ); 274 kernel32 = GetModuleHandleA( "Kernel32.dll" );
254 if( kernel32 != NULL ) 275 if( kernel32 != NULL )
255 SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (LPVOID) GetProcAddress( kernel32, "SetThreadErrorMode" ); 276 SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (void(*)(void)) GetProcAddress( kernel32, "SetThreadErrorMode" );
256 if( SetThreadErrorModePtr == NULL ) 277 if( SetThreadErrorModePtr == NULL )
257 failed = TRUE; 278 failed = TRUE;
258 } 279 }
@@ -283,7 +304,7 @@ static HMODULE MyGetModuleHandleFromAddress( const void *addr )
283 { 304 {
284 kernel32 = GetModuleHandleA( "Kernel32.dll" ); 305 kernel32 = GetModuleHandleA( "Kernel32.dll" );
285 if( kernel32 != NULL ) 306 if( kernel32 != NULL )
286 GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (LPVOID) GetProcAddress( kernel32, "GetModuleHandleExA" ); 307 GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (void(*)(void)) GetProcAddress( kernel32, "GetModuleHandleExA" );
287 if( GetModuleHandleExAPtr == NULL ) 308 if( GetModuleHandleExAPtr == NULL )
288 failed = TRUE; 309 failed = TRUE;
289 } 310 }
@@ -291,7 +312,7 @@ static HMODULE MyGetModuleHandleFromAddress( const void *addr )
291 if( !failed ) 312 if( !failed )
292 { 313 {
293 /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */ 314 /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */
294 if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) ) 315 if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) addr, &hModule ) )
295 return NULL; 316 return NULL;
296 } 317 }
297 else 318 else
@@ -314,6 +335,7 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb,
314 static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL; 335 static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
315 static BOOL failed = FALSE; 336 static BOOL failed = FALSE;
316 UINT uMode; 337 UINT uMode;
338 HMODULE kernel32;
317 HMODULE psapi; 339 HMODULE psapi;
318 340
319 if( failed ) 341 if( failed )
@@ -322,9 +344,9 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb,
322 if( EnumProcessModulesPtr == NULL ) 344 if( EnumProcessModulesPtr == NULL )
323 { 345 {
324 /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */ 346 /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */
325 psapi = GetModuleHandleA( "Kernel32.dll" ); 347 kernel32 = GetModuleHandleA( "Kernel32.dll" );
326 if( psapi != NULL ) 348 if( kernel32 != NULL )
327 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "K32EnumProcessModules" ); 349 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (void(*)(void)) GetProcAddress( kernel32, "K32EnumProcessModules" );
328 350
329 /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ 351 /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */
330 if( EnumProcessModulesPtr == NULL ) 352 if( EnumProcessModulesPtr == NULL )
@@ -332,13 +354,13 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb,
332 /* Do not let Windows display the critical-error-handler message box */ 354 /* Do not let Windows display the critical-error-handler message box */
333 uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); 355 uMode = MySetErrorMode( SEM_FAILCRITICALERRORS );
334 psapi = LoadLibraryA( "Psapi.dll" ); 356 psapi = LoadLibraryA( "Psapi.dll" );
357 MySetErrorMode( uMode );
335 if( psapi != NULL ) 358 if( psapi != NULL )
336 { 359 {
337 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" ); 360 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (void(*)(void)) GetProcAddress( psapi, "EnumProcessModules" );
338 if( EnumProcessModulesPtr == NULL ) 361 if( EnumProcessModulesPtr == NULL )
339 FreeLibrary( psapi ); 362 FreeLibrary( psapi );
340 } 363 }
341 MySetErrorMode( uMode );
342 } 364 }
343 365
344 if( EnumProcessModulesPtr == NULL ) 366 if( EnumProcessModulesPtr == NULL )
@@ -368,13 +390,13 @@ void *dlopen( const char *file, int mode )
368 * symbol object must be provided. That object must be able to access 390 * symbol object must be provided. That object must be able to access
369 * all symbols from the original program file, and any objects loaded 391 * all symbols from the original program file, and any objects loaded
370 * with the RTLD_GLOBAL flag. 392 * with the RTLD_GLOBAL flag.
371 * The return value from GetModuleHandle( ) allows us to retrieve 393 * The return value from GetModuleHandleA( ) allows us to retrieve
372 * symbols only from the original program file. EnumProcessModules() is 394 * symbols only from the original program file. EnumProcessModules() is
373 * used to access symbols from other libraries. For objects loaded 395 * used to access symbols from other libraries. For objects loaded
374 * with the RTLD_LOCAL flag, we create our own list later on. They are 396 * with the RTLD_LOCAL flag, we create our own list later on. They are
375 * excluded from EnumProcessModules() iteration. 397 * excluded from EnumProcessModules() iteration.
376 */ 398 */
377 hModule = GetModuleHandle( NULL ); 399 hModule = GetModuleHandleA( NULL );
378 400
379 if( !hModule ) 401 if( !hModule )
380 save_err_str( "(null)", GetLastError( ) ); 402 save_err_str( "(null)", GetLastError( ) );
@@ -386,7 +408,11 @@ void *dlopen( const char *file, int mode )
386 char lpFileName[MAX_PATH]; 408 char lpFileName[MAX_PATH];
387 size_t i, len; 409 size_t i, len;
388 410
389 len = strlen( file ); 411 for( len = 0; ; len++ )
412 {
413 if( file[len] == '\0' )
414 break;
415 }
390 416
391 if( len >= sizeof( lpFileName ) ) 417 if( len >= sizeof( lpFileName ) )
392 { 418 {
@@ -466,6 +492,10 @@ int dlclose( void *handle )
466 492
467 error_occurred = FALSE; 493 error_occurred = FALSE;
468 494
495 /* dlopen(NULL, ...) does not call LoadLibrary(), so do not call FreeLibrary(). */
496 if( hModule == GetModuleHandleA( NULL ) )
497 return 0;
498
469 ret = FreeLibrary( hModule ); 499 ret = FreeLibrary( hModule );
470 500
471 /* If the object was loaded with RTLD_LOCAL, remove it from list of local 501 /* If the object was loaded with RTLD_LOCAL, remove it from list of local
@@ -495,7 +525,7 @@ void *dlsym( void *handle, const char *name )
495 525
496 symbol = NULL; 526 symbol = NULL;
497 hCaller = NULL; 527 hCaller = NULL;
498 hModule = GetModuleHandle( NULL ); 528 hModule = GetModuleHandleA( NULL );
499 dwMessageId = 0; 529 dwMessageId = 0;
500 530
501 if( handle == RTLD_DEFAULT ) 531 if( handle == RTLD_DEFAULT )
@@ -548,13 +578,13 @@ void *dlsym( void *handle, const char *name )
548 578
549 hCurrentProc = GetCurrentProcess( ); 579 hCurrentProc = GetCurrentProcess( );
550 580
551 /* GetModuleHandle( NULL ) only returns the current program file. So 581 /* GetModuleHandleA( NULL ) only returns the current program file. So
552 * if we want to get ALL loaded module including those in linked DLLs, 582 * if we want to get ALL loaded module including those in linked DLLs,
553 * we have to use EnumProcessModules( ). 583 * we have to use EnumProcessModules( ).
554 */ 584 */
555 if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) 585 if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
556 { 586 {
557 modules = malloc( dwSize ); 587 modules = (HMODULE *) MyAlloc( dwSize );
558 if( modules ) 588 if( modules )
559 { 589 {
560 if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) 590 if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
@@ -573,13 +603,13 @@ void *dlsym( void *handle, const char *name )
573 symbol = GetProcAddress( modules[i], name ); 603 symbol = GetProcAddress( modules[i], name );
574 if( symbol != NULL ) 604 if( symbol != NULL )
575 { 605 {
576 free( modules ); 606 MyFree( modules );
577 goto end; 607 goto end;
578 } 608 }
579 } 609 }
580 610
581 } 611 }
582 free( modules ); 612 MyFree( modules );
583 } 613 }
584 else 614 else
585 { 615 {
@@ -640,7 +670,7 @@ static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *siz
640 if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) 670 if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC )
641 return FALSE; 671 return FALSE;
642 672
643 if( index < 0 || index >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES || index >= optionalHeader->NumberOfRvaAndSizes ) 673 if( index < 0 || index >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES || (DWORD)index >= optionalHeader->NumberOfRvaAndSizes )
644 return FALSE; 674 return FALSE;
645 675
646 if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 ) 676 if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 )
@@ -699,18 +729,18 @@ static BOOL is_valid_address( const void *addr )
699 /* check valid pointer */ 729 /* check valid pointer */
700 result = VirtualQuery( addr, &info, sizeof( info ) ); 730 result = VirtualQuery( addr, &info, sizeof( info ) );
701 731
702 if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS ) 732 if( result != sizeof( info ) || info.AllocationBase == NULL || info.State == MEM_FREE || info.State == MEM_RESERVE || info.Protect == 0 || info.Protect == PAGE_NOACCESS )
703 return FALSE; 733 return FALSE;
704 734
705 return TRUE; 735 return TRUE;
706} 736}
707 737
708#if defined(_M_ARM64) || defined(__aarch64__) 738#if defined(_M_ARM64) || defined(__aarch64__)
709static INT64 sign_extend(UINT64 value, UINT bits) 739static INT64 sign_extend( UINT64 value, UINT bits )
710{ 740{
711 const UINT left = 64 - bits; 741 const UINT left = 64 - bits;
712 const INT64 m1 = -1; 742 const INT64 m1 = -1;
713 const INT64 wide = (INT64) (value << left); 743 const INT64 wide = (INT64) ( value << left );
714 const INT64 sign = ( wide < 0 ) ? ( m1 << left ) : 0; 744 const INT64 sign = ( wide < 0 ) ? ( m1 << left ) : 0;
715 745
716 return value | sign; 746 return value | sign;
@@ -742,16 +772,18 @@ static INT64 sign_extend(UINT64 value, UINT bits)
742static BOOL is_import_thunk( const void *addr ) 772static BOOL is_import_thunk( const void *addr )
743{ 773{
744#if defined(_M_ARM64) || defined(__aarch64__) 774#if defined(_M_ARM64) || defined(__aarch64__)
745 ULONG opCode1 = * (ULONG *) ( (BYTE *) addr ); 775 ULONG opCode1 = *(ULONG *) ( (BYTE *) addr );
746 ULONG opCode2 = * (ULONG *) ( (BYTE *) addr + 4 ); 776 ULONG opCode2 = *(ULONG *) ( (BYTE *) addr + 4 );
747 ULONG opCode3 = * (ULONG *) ( (BYTE *) addr + 8 ); 777 ULONG opCode3 = *(ULONG *) ( (BYTE *) addr + 8 );
748 778
749 return (opCode1 & 0x9f00001f) == 0x90000010 /* adrp x16, [page_offset] */ 779 return ( opCode1 & 0x9f00001f ) == 0x90000010 /* adrp x16, [page_offset] */
750 && (opCode2 & 0xffe003ff) == 0xf9400210 /* ldr x16, [x16, offset] */ 780 && ( opCode2 & 0xffe003ff ) == 0xf9400210 /* ldr x16, [x16, offset] */
751 && opCode3 == 0xd61f0200 /* br x16 */ 781 && opCode3 == 0xd61f0200 /* br x16 */
752 ? TRUE : FALSE; 782 ? TRUE : FALSE;
783#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
784 return *(USHORT *) addr == 0x25ff ? TRUE : FALSE;
753#else 785#else
754 return *(short *) addr == 0x25ff ? TRUE : FALSE; 786 return FALSE;
755#endif 787#endif
756} 788}
757 789
@@ -768,24 +800,24 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c
768 * 0x7ff772ae78c4 <+25764>: ldr x16, [x16, #0xdc0] 800 * 0x7ff772ae78c4 <+25764>: ldr x16, [x16, #0xdc0]
769 * 0x7ff772ae78c8 <+25768>: br x16 801 * 0x7ff772ae78c8 <+25768>: br x16
770 */ 802 */
771 ULONG opCode1 = * (ULONG *) ( (BYTE *) addr ); 803 ULONG opCode1 = *(ULONG *) ( (BYTE *) addr );
772 ULONG opCode2 = * (ULONG *) ( (BYTE *) addr + 4 ); 804 ULONG opCode2 = *(ULONG *) ( (BYTE *) addr + 4 );
773 805
774 /* Extract the offset from adrp instruction */ 806 /* Extract the offset from adrp instruction */
775 UINT64 pageLow2 = (opCode1 >> 29) & 3; 807 UINT64 pageLow2 = ( opCode1 >> 29 ) & 3;
776 UINT64 pageHigh19 = (opCode1 >> 5) & ~(~0ull << 19); 808 UINT64 pageHigh19 = ( opCode1 >> 5 ) & ~( ~0ull << 19 );
777 INT64 page = sign_extend((pageHigh19 << 2) | pageLow2, 21) << 12; 809 INT64 page = sign_extend( ( pageHigh19 << 2 ) | pageLow2, 21 ) << 12;
778 810
779 /* Extract the offset from ldr instruction */ 811 /* Extract the offset from ldr instruction */
780 UINT64 offset = ((opCode2 >> 10) & ~(~0ull << 12)) << 3; 812 UINT64 offset = ( ( opCode2 >> 10 ) & ~( ~0ull << 12 ) ) << 3;
781 813
782 /* Calculate the final address */ 814 /* Calculate the final address */
783 BYTE *ptr = (BYTE *) ( (ULONG64) thkp & ~0xfffull ) + page + offset; 815 BYTE *ptr = (BYTE *) ( (ULONG64) thkp & ~0xfffull ) + page + offset;
784#else 816#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
785 /* Get offset from thunk table (after instruction 0xff 0x25) 817 /* Get offset from thunk table (after instruction 0xff 0x25)
786 * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 818 * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00
787 */ 819 */
788 ULONG offset = *(ULONG *)( thkp + 2 ); 820 ULONG offset = *(ULONG *) ( thkp + 2 );
789#if defined(_M_AMD64) || defined(__x86_64__) 821#if defined(_M_AMD64) || defined(__x86_64__)
790 /* On 64 bit the offset is relative 822 /* On 64 bit the offset is relative
791 * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery> 823 * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery>
@@ -793,13 +825,15 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c
793 * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060 825 * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060
794 * So cast to signed LONG type 826 * So cast to signed LONG type
795 */ 827 */
796 BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset ); 828 BYTE *ptr = (BYTE *) ( thkp + 6 + (LONG) offset );
797#else 829#else
798 /* On 32 bit the offset is absolute 830 /* On 32 bit the offset is absolute
799 * 4019b4: ff 25 90 71 40 00 jmp *0x40719 831 * 4019b4: ff 25 90 71 40 00 jmp *0x40719
800 */ 832 */
801 BYTE *ptr = (BYTE *) offset; 833 BYTE *ptr = (BYTE *) offset;
802#endif 834#endif
835#else
836 return NULL;
803#endif 837#endif
804 838
805 if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size ) 839 if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size )
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index cd321f2..1fe7387 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -31,6 +31,4 @@ if(WIN32 AND NOT BUILD_SHARED_LIBS)
31 endif() 31 endif()
32endif() 32endif()
33 33
34install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin)
35
36add_test(NAME test-dladdr COMMAND test-dladdr WORKING_DIRECTORY $<TARGET_FILE_DIR:test-dladdr>) 34add_test(NAME test-dladdr COMMAND test-dladdr WORKING_DIRECTORY $<TARGET_FILE_DIR:test-dladdr>)
diff --git a/tests/test-dladdr.c b/tests/test-dladdr.c
index 5568f23..aa815b0 100644
--- a/tests/test-dladdr.c
+++ b/tests/test-dladdr.c
@@ -140,6 +140,7 @@ __declspec(dllexport)
140#endif 140#endif
141int main(int argc, char **argv) 141int main(int argc, char **argv)
142{ 142{
143#ifdef _WIN32
143#if defined(_M_ARM64) || defined(__aarch64__) 144#if defined(_M_ARM64) || defined(__aarch64__)
144 /* points to non reachable address */ 145 /* points to non reachable address */
145 unsigned char zero_thunk_address[12] = { 0x10, 0x00, 0x00, 0x90, 0x10, 0x02, 0x40, 0xF9, 0x00, 0x02, 0x1F, 0xD6 }; 146 unsigned char zero_thunk_address[12] = { 0x10, 0x00, 0x00, 0x90, 0x10, 0x02, 0x40, 0xF9, 0x00, 0x02, 0x1F, 0xD6 };
@@ -147,13 +148,16 @@ int main(int argc, char **argv)
147 unsigned char invalid_thunk_address[12] = { 0x10, 0x00, 0x00, 0xb0, 0x10, 0x06, 0x47, 0xF9, 0x00, 0x02, 0x1F, 0xD6 }; 148 unsigned char invalid_thunk_address[12] = { 0x10, 0x00, 0x00, 0xb0, 0x10, 0x06, 0x47, 0xF9, 0x00, 0x02, 0x1F, 0xD6 };
148 /* no import thunk */ 149 /* no import thunk */
149 unsigned char no_import_thunk[12] = { 0x11, 0x00, 0x00, 0xb0, 0x31, 0x06, 0x47, 0xF9, 0x20, 0x02, 0x1F, 0xD6 }; 150 unsigned char no_import_thunk[12] = { 0x11, 0x00, 0x00, 0xb0, 0x31, 0x06, 0x47, 0xF9, 0x20, 0x02, 0x1F, 0xD6 };
150#else 151#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
151 /* points to non reachable address */ 152 /* points to non reachable address */
152 unsigned char zero_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; 153 unsigned char zero_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 };
153 /* points to executable base */ 154 /* points to executable base */
154 unsigned char invalid_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x40, 0x00 }; 155 unsigned char invalid_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x40, 0x00 };
155 /* no import thunk */ 156 /* no import thunk */
156 unsigned char no_import_thunk[6] = { 0xFF, 0x26, 0x00, 0x00, 0x40, 0x00 }; 157 unsigned char no_import_thunk[6] = { 0xFF, 0x26, 0x00, 0x00, 0x40, 0x00 };
158#else
159#error "thunk test cases are not defined for this architecture"
160#endif
157#endif 161#endif
158 int result = 0; 162 int result = 0;
159 UNUSED(argv); 163 UNUSED(argv);
@@ -169,11 +173,12 @@ int main(int argc, char **argv)
169 result |= check_dladdr( "function from executable", (void*)main, "main", Pass ); 173 result |= check_dladdr( "function from executable", (void*)main, "main", Pass );
170 result |= check_dladdr( "static function from executable", (void*)print_dl_info, "print_dl_info", Fail ); 174 result |= check_dladdr( "static function from executable", (void*)print_dl_info, "print_dl_info", Fail );
171 result |= check_dladdr( "address with positive offset", ((char*)atoi)+1, "atoi", PassWithDifferentAddress ); 175 result |= check_dladdr( "address with positive offset", ((char*)atoi)+1, "atoi", PassWithDifferentAddress );
176
177#ifdef _WIN32
172 result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo ); 178 result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo );
173 result |= check_dladdr( "invalid address from import thunk", invalid_thunk_address, "", NoInfo ); 179 result |= check_dladdr( "invalid address from import thunk", invalid_thunk_address, "", NoInfo );
174 result |= check_dladdr( "no import thunk", no_import_thunk, "", NoInfo ); 180 result |= check_dladdr( "no import thunk", no_import_thunk, "", NoInfo );
175 181
176#ifdef _WIN32
177 result |= check_dladdr( "last entry in iat", (void*)VirtualQuery, "VirtualQuery", PassWithDifferentAddress ); 182 result |= check_dladdr( "last entry in iat", (void*)VirtualQuery, "VirtualQuery", PassWithDifferentAddress );
178 183
179 result |= check_dladdr ( "address through import thunk", (void*)GetModuleHandleA, "GetModuleHandleA", PassWithDifferentAddress ); 184 result |= check_dladdr ( "address through import thunk", (void*)GetModuleHandleA, "GetModuleHandleA", PassWithDifferentAddress );
diff --git a/tests/test.c b/tests/test.c
index 1d0d437..4fa7089 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -36,6 +36,7 @@
36#include <io.h> 36#include <io.h>
37#include <fcntl.h> 37#include <fcntl.h>
38#include <direct.h> 38#include <direct.h>
39#include <errno.h>
39#include "dlfcn.h" 40#include "dlfcn.h"
40 41
41/* If these dlclose's fails, we don't care as the handles are going to be 42/* If these dlclose's fails, we don't care as the handles are going to be