diff options
| author | Ralf Habacker <ralf.habacker@freenet.de> | 2020-08-25 23:34:19 +0200 |
|---|---|---|
| committer | Ralf Habacker <ralf.habacker@freenet.de> | 2020-09-14 12:26:07 +0200 |
| commit | f0ac8495872ee078f18bd349e3db6883ed4106e2 (patch) | |
| tree | 0f9b609aa80b924f6b391e1c4b687c0f73eaa7b9 /src | |
| parent | 5ead6f2d2c515d3d85c31fffebea55168c1bc1b4 (diff) | |
| download | dlfcn-win32-f0ac8495872ee078f18bd349e3db6883ed4106e2.tar.gz dlfcn-win32-f0ac8495872ee078f18bd349e3db6883ed4106e2.tar.bz2 dlfcn-win32-f0ac8495872ee078f18bd349e3db6883ed4106e2.zip | |
Move cmake targets into sub directories
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 43 | ||||
| -rw-r--r-- | src/dlfcn.c | 478 | ||||
| -rw-r--r-- | src/dlfcn.h | 78 |
3 files changed, 599 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..d5296b1 --- /dev/null +++ b/src/CMakeLists.txt | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | set(headers dlfcn.h) | ||
| 2 | set(sources dlfcn.c) | ||
| 3 | |||
| 4 | if (BUILD_SHARED_LIBS) | ||
| 5 | add_definitions(-DSHARED) | ||
| 6 | endif (BUILD_SHARED_LIBS) | ||
| 7 | |||
| 8 | add_library(dl ${sources}) | ||
| 9 | |||
| 10 | # Correctly export the location of installed includes in the target | ||
| 11 | target_include_directories(dl INTERFACE $<INSTALL_INTERFACE:include>) | ||
| 12 | |||
| 13 | install (TARGETS dl EXPORT dlfcn-win32-targets | ||
| 14 | RUNTIME DESTINATION bin | ||
| 15 | LIBRARY DESTINATION lib${LIB_SUFFIX} | ||
| 16 | ARCHIVE DESTINATION lib${LIB_SUFFIX}) | ||
| 17 | |||
| 18 | install (FILES ${headers} DESTINATION include) | ||
| 19 | |||
| 20 | # Export the targets (build tree) | ||
| 21 | export(EXPORT dlfcn-win32-targets | ||
| 22 | FILE "${CMAKE_BINARY_DIR}/dlfcn-win32-targets.cmake" | ||
| 23 | NAMESPACE dlfcn-win32:: | ||
| 24 | ) | ||
| 25 | |||
| 26 | # Write the CMake config file | ||
| 27 | set(CMAKE_CONF_INSTALL_DIR share/dlfcn-win32) | ||
| 28 | set(INCLUDE_INSTALL_DIR include) | ||
| 29 | include(CMakePackageConfigHelpers) | ||
| 30 | configure_package_config_file(../dlfcn-win32-config.cmake.in ${CMAKE_BINARY_DIR}/dlfcn-win32-config.cmake | ||
| 31 | INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR} | ||
| 32 | PATH_VARS INCLUDE_INSTALL_DIR | ||
| 33 | NO_CHECK_REQUIRED_COMPONENTS_MACRO) | ||
| 34 | |||
| 35 | # Install the targets (install) | ||
| 36 | install(EXPORT dlfcn-win32-targets | ||
| 37 | FILE dlfcn-win32-targets.cmake | ||
| 38 | NAMESPACE dlfcn-win32:: | ||
| 39 | DESTINATION ${CMAKE_CONF_INSTALL_DIR}) | ||
| 40 | |||
| 41 | # Install the CMake config file | ||
| 42 | install(FILES ${CMAKE_BINARY_DIR}/dlfcn-win32-config.cmake | ||
| 43 | DESTINATION ${CMAKE_CONF_INSTALL_DIR}) | ||
diff --git a/src/dlfcn.c b/src/dlfcn.c new file mode 100644 index 0000000..532af91 --- /dev/null +++ b/src/dlfcn.c | |||
| @@ -0,0 +1,478 @@ | |||
| 1 | /* | ||
| 2 | * dlfcn-win32 | ||
| 3 | * Copyright (c) 2007 Ramiro Polla | ||
| 4 | * Copyright (c) 2015 Tiancheng "Timothy" Gu | ||
| 5 | * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com> | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 8 | * of this software and associated documentation files (the "Software"), to deal | ||
| 9 | * in the Software without restriction, including without limitation the rights | ||
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 11 | * copies of the Software, and to permit persons to whom the Software is | ||
| 12 | * furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 23 | * THE SOFTWARE. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #ifndef _WIN32_WINNT | ||
| 27 | #define _WIN32_WINNT 0x0501 | ||
| 28 | #endif | ||
| 29 | #ifdef _DEBUG | ||
| 30 | #define _CRTDBG_MAP_ALLOC | ||
| 31 | #include <stdlib.h> | ||
| 32 | #include <crtdbg.h> | ||
| 33 | #endif | ||
| 34 | #include <windows.h> | ||
| 35 | #include <stdio.h> | ||
| 36 | #include <stdlib.h> | ||
| 37 | |||
| 38 | #ifdef _MSC_VER | ||
| 39 | /* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ | ||
| 40 | #pragma intrinsic(_ReturnAddress) | ||
| 41 | #else | ||
| 42 | /* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */ | ||
| 43 | #ifndef _ReturnAddress | ||
| 44 | #define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0))) | ||
| 45 | #endif | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #ifdef SHARED | ||
| 49 | #define DLFCN_WIN32_EXPORTS | ||
| 50 | #endif | ||
| 51 | #include "dlfcn.h" | ||
| 52 | |||
| 53 | /* Note: | ||
| 54 | * MSDN says these functions are not thread-safe. We make no efforts to have | ||
| 55 | * any kind of thread safety. | ||
| 56 | */ | ||
| 57 | |||
| 58 | typedef struct local_object { | ||
| 59 | HMODULE hModule; | ||
| 60 | struct local_object *previous; | ||
| 61 | struct local_object *next; | ||
| 62 | } local_object; | ||
| 63 | |||
| 64 | static local_object first_object; | ||
| 65 | |||
| 66 | /* These functions implement a double linked list for the local objects. */ | ||
| 67 | static local_object *local_search( HMODULE hModule ) | ||
| 68 | { | ||
| 69 | local_object *pobject; | ||
| 70 | |||
| 71 | if( hModule == NULL ) | ||
| 72 | return NULL; | ||
| 73 | |||
| 74 | for( pobject = &first_object; pobject; pobject = pobject->next ) | ||
| 75 | if( pobject->hModule == hModule ) | ||
| 76 | return pobject; | ||
| 77 | |||
| 78 | return NULL; | ||
| 79 | } | ||
| 80 | |||
| 81 | static BOOL local_add( HMODULE hModule ) | ||
| 82 | { | ||
| 83 | local_object *pobject; | ||
| 84 | local_object *nobject; | ||
| 85 | |||
| 86 | if( hModule == NULL ) | ||
| 87 | return TRUE; | ||
| 88 | |||
| 89 | pobject = local_search( hModule ); | ||
| 90 | |||
| 91 | /* Do not add object again if it's already on the list */ | ||
| 92 | if( pobject ) | ||
| 93 | return TRUE; | ||
| 94 | |||
| 95 | for( pobject = &first_object; pobject->next; pobject = pobject->next ); | ||
| 96 | |||
| 97 | nobject = (local_object*) malloc( sizeof( local_object ) ); | ||
| 98 | |||
| 99 | if( !nobject ) | ||
| 100 | { | ||
| 101 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); | ||
| 102 | return FALSE; | ||
| 103 | } | ||
| 104 | |||
| 105 | pobject->next = nobject; | ||
| 106 | nobject->next = NULL; | ||
| 107 | nobject->previous = pobject; | ||
| 108 | nobject->hModule = hModule; | ||
| 109 | |||
| 110 | return TRUE; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void local_rem( HMODULE hModule ) | ||
| 114 | { | ||
| 115 | local_object *pobject; | ||
| 116 | |||
| 117 | if( hModule == NULL ) | ||
| 118 | return; | ||
| 119 | |||
| 120 | pobject = local_search( hModule ); | ||
| 121 | |||
| 122 | if( !pobject ) | ||
| 123 | return; | ||
| 124 | |||
| 125 | if( pobject->next ) | ||
| 126 | pobject->next->previous = pobject->previous; | ||
| 127 | if( pobject->previous ) | ||
| 128 | pobject->previous->next = pobject->next; | ||
| 129 | |||
| 130 | free( pobject ); | ||
| 131 | } | ||
| 132 | |||
| 133 | /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one | ||
| 134 | * static buffer. | ||
| 135 | * MSDN says the buffer cannot be larger than 64K bytes, so we set it to | ||
| 136 | * the limit. | ||
| 137 | */ | ||
| 138 | static char error_buffer[65535]; | ||
| 139 | static BOOL error_occurred; | ||
| 140 | |||
| 141 | static void save_err_str( const char *str ) | ||
| 142 | { | ||
| 143 | DWORD dwMessageId; | ||
| 144 | DWORD ret; | ||
| 145 | size_t pos, len; | ||
| 146 | |||
| 147 | dwMessageId = GetLastError( ); | ||
| 148 | |||
| 149 | if( dwMessageId == 0 ) | ||
| 150 | return; | ||
| 151 | |||
| 152 | len = strlen( str ); | ||
| 153 | if( len > sizeof( error_buffer ) - 5 ) | ||
| 154 | len = sizeof( error_buffer ) - 5; | ||
| 155 | |||
| 156 | /* Format error message to: | ||
| 157 | * "<argument to function that failed>": <Windows localized error message> | ||
| 158 | */ | ||
| 159 | pos = 0; | ||
| 160 | error_buffer[pos++] = '"'; | ||
| 161 | memcpy( error_buffer+pos, str, len ); | ||
| 162 | pos += len; | ||
| 163 | error_buffer[pos++] = '"'; | ||
| 164 | error_buffer[pos++] = ':'; | ||
| 165 | error_buffer[pos++] = ' '; | ||
| 166 | |||
| 167 | ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId, | ||
| 168 | MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), | ||
| 169 | error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL ); | ||
| 170 | pos += ret; | ||
| 171 | |||
| 172 | /* When FormatMessageA() fails it returns zero and does not touch buffer | ||
| 173 | * so add trailing null byte */ | ||
| 174 | if( ret == 0 ) | ||
| 175 | error_buffer[pos] = '\0'; | ||
| 176 | |||
| 177 | if( pos > 1 ) | ||
| 178 | { | ||
| 179 | /* POSIX says the string must not have trailing <newline> */ | ||
| 180 | if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) | ||
| 181 | error_buffer[pos-2] = '\0'; | ||
| 182 | } | ||
| 183 | |||
| 184 | error_occurred = TRUE; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void save_err_ptr_str( const void *ptr ) | ||
| 188 | { | ||
| 189 | char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */ | ||
| 190 | |||
| 191 | #ifdef _MSC_VER | ||
| 192 | /* Supress warning C4996: 'sprintf': This function or variable may be unsafe */ | ||
| 193 | #pragma warning( suppress: 4996 ) | ||
| 194 | #endif | ||
| 195 | sprintf( ptr_buf, "0x%p", ptr ); | ||
| 196 | |||
| 197 | save_err_str( ptr_buf ); | ||
| 198 | } | ||
| 199 | |||
| 200 | /* Load Psapi.dll at runtime, this avoids linking caveat */ | ||
| 201 | static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) | ||
| 202 | { | ||
| 203 | static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD); | ||
| 204 | HMODULE psapi; | ||
| 205 | |||
| 206 | if( !EnumProcessModulesPtr ) | ||
| 207 | { | ||
| 208 | psapi = LoadLibraryA( "Psapi.dll" ); | ||
| 209 | if( psapi ) | ||
| 210 | EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" ); | ||
| 211 | if( !EnumProcessModulesPtr ) | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); | ||
| 216 | } | ||
| 217 | |||
| 218 | void *dlopen( const char *file, int mode ) | ||
| 219 | { | ||
| 220 | HMODULE hModule; | ||
| 221 | UINT uMode; | ||
| 222 | |||
| 223 | error_occurred = FALSE; | ||
| 224 | |||
| 225 | /* Do not let Windows display the critical-error-handler message box */ | ||
| 226 | uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); | ||
| 227 | |||
| 228 | if( file == 0 ) | ||
| 229 | { | ||
| 230 | /* POSIX says that if the value of file is 0, a handle on a global | ||
| 231 | * symbol object must be provided. That object must be able to access | ||
| 232 | * all symbols from the original program file, and any objects loaded | ||
| 233 | * with the RTLD_GLOBAL flag. | ||
| 234 | * The return value from GetModuleHandle( ) allows us to retrieve | ||
| 235 | * symbols only from the original program file. EnumProcessModules() is | ||
| 236 | * used to access symbols from other libraries. For objects loaded | ||
| 237 | * with the RTLD_LOCAL flag, we create our own list later on. They are | ||
| 238 | * excluded from EnumProcessModules() iteration. | ||
| 239 | */ | ||
| 240 | hModule = GetModuleHandle( NULL ); | ||
| 241 | |||
| 242 | if( !hModule ) | ||
| 243 | save_err_str( "(null)" ); | ||
| 244 | } | ||
| 245 | else | ||
| 246 | { | ||
| 247 | HANDLE hCurrentProc; | ||
| 248 | DWORD dwProcModsBefore, dwProcModsAfter; | ||
| 249 | char lpFileName[MAX_PATH]; | ||
| 250 | size_t i, len; | ||
| 251 | |||
| 252 | len = strlen( file ); | ||
| 253 | |||
| 254 | if( len >= sizeof( lpFileName ) ) | ||
| 255 | { | ||
| 256 | SetLastError( ERROR_FILENAME_EXCED_RANGE ); | ||
| 257 | save_err_str( file ); | ||
| 258 | hModule = NULL; | ||
| 259 | } | ||
| 260 | else | ||
| 261 | { | ||
| 262 | /* MSDN says backslashes *must* be used instead of forward slashes. */ | ||
| 263 | for( i = 0; i < len; i++ ) | ||
| 264 | { | ||
| 265 | if( file[i] == '/' ) | ||
| 266 | lpFileName[i] = '\\'; | ||
| 267 | else | ||
| 268 | lpFileName[i] = file[i]; | ||
| 269 | } | ||
| 270 | lpFileName[len] = '\0'; | ||
| 271 | |||
| 272 | hCurrentProc = GetCurrentProcess( ); | ||
| 273 | |||
| 274 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 ) | ||
| 275 | dwProcModsBefore = 0; | ||
| 276 | |||
| 277 | /* POSIX says the search path is implementation-defined. | ||
| 278 | * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely | ||
| 279 | * to UNIX's search paths (start with system folders instead of current | ||
| 280 | * folder). | ||
| 281 | */ | ||
| 282 | hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); | ||
| 283 | |||
| 284 | if( !hModule ) | ||
| 285 | { | ||
| 286 | save_err_str( lpFileName ); | ||
| 287 | } | ||
| 288 | else | ||
| 289 | { | ||
| 290 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) | ||
| 291 | dwProcModsAfter = 0; | ||
| 292 | |||
| 293 | /* If the object was loaded with RTLD_LOCAL, add it to list of local | ||
| 294 | * objects, so that its symbols cannot be retrieved even if the handle for | ||
| 295 | * the original program file is passed. POSIX says that if the same | ||
| 296 | * file is specified in multiple invocations, and any of them are | ||
| 297 | * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the | ||
| 298 | * symbols will remain global. If number of loaded modules was not | ||
| 299 | * changed after calling LoadLibraryEx(), it means that library was | ||
| 300 | * already loaded. | ||
| 301 | */ | ||
| 302 | if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter ) | ||
| 303 | { | ||
| 304 | if( !local_add( hModule ) ) | ||
| 305 | { | ||
| 306 | save_err_str( lpFileName ); | ||
| 307 | FreeLibrary( hModule ); | ||
| 308 | hModule = NULL; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter ) | ||
| 312 | { | ||
| 313 | local_rem( hModule ); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | /* Return to previous state of the error-mode bit flags. */ | ||
| 320 | SetErrorMode( uMode ); | ||
| 321 | |||
| 322 | return (void *) hModule; | ||
| 323 | } | ||
| 324 | |||
| 325 | int dlclose( void *handle ) | ||
| 326 | { | ||
| 327 | HMODULE hModule = (HMODULE) handle; | ||
| 328 | BOOL ret; | ||
| 329 | |||
| 330 | error_occurred = FALSE; | ||
| 331 | |||
| 332 | ret = FreeLibrary( hModule ); | ||
| 333 | |||
| 334 | /* If the object was loaded with RTLD_LOCAL, remove it from list of local | ||
| 335 | * objects. | ||
| 336 | */ | ||
| 337 | if( ret ) | ||
| 338 | local_rem( hModule ); | ||
| 339 | else | ||
| 340 | save_err_ptr_str( handle ); | ||
| 341 | |||
| 342 | /* dlclose's return value in inverted in relation to FreeLibrary's. */ | ||
| 343 | ret = !ret; | ||
| 344 | |||
| 345 | return (int) ret; | ||
| 346 | } | ||
| 347 | |||
| 348 | __declspec(noinline) /* Needed for _ReturnAddress() */ | ||
| 349 | void *dlsym( void *handle, const char *name ) | ||
| 350 | { | ||
| 351 | FARPROC symbol; | ||
| 352 | HMODULE hCaller; | ||
| 353 | HMODULE hModule; | ||
| 354 | HANDLE hCurrentProc; | ||
| 355 | |||
| 356 | error_occurred = FALSE; | ||
| 357 | |||
| 358 | symbol = NULL; | ||
| 359 | hCaller = NULL; | ||
| 360 | hModule = GetModuleHandle( NULL ); | ||
| 361 | hCurrentProc = GetCurrentProcess( ); | ||
| 362 | |||
| 363 | if( handle == RTLD_DEFAULT ) | ||
| 364 | { | ||
| 365 | /* The symbol lookup happens in the normal global scope; that is, | ||
| 366 | * a search for a symbol using this handle would find the same | ||
| 367 | * definition as a direct use of this symbol in the program code. | ||
| 368 | * So use same lookup procedure as when filename is NULL. | ||
| 369 | */ | ||
| 370 | handle = hModule; | ||
| 371 | } | ||
| 372 | else if( handle == RTLD_NEXT ) | ||
| 373 | { | ||
| 374 | /* Specifies the next object after this one that defines name. | ||
| 375 | * This one refers to the object containing the invocation of dlsym(). | ||
| 376 | * The next object is the one found upon the application of a load | ||
| 377 | * order symbol resolution algorithm. To get caller function of dlsym() | ||
| 378 | * use _ReturnAddress() intrinsic. To get HMODULE of caller function | ||
| 379 | * use standard GetModuleHandleExA() function. | ||
| 380 | */ | ||
| 381 | if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) ) | ||
| 382 | goto end; | ||
| 383 | } | ||
| 384 | |||
| 385 | if( handle != RTLD_NEXT ) | ||
| 386 | { | ||
| 387 | symbol = GetProcAddress( (HMODULE) handle, name ); | ||
| 388 | |||
| 389 | if( symbol != NULL ) | ||
| 390 | goto end; | ||
| 391 | } | ||
| 392 | |||
| 393 | /* If the handle for the original program file is passed, also search | ||
| 394 | * in all globally loaded objects. | ||
| 395 | */ | ||
| 396 | |||
| 397 | if( hModule == handle || handle == RTLD_NEXT ) | ||
| 398 | { | ||
| 399 | HMODULE *modules; | ||
| 400 | DWORD cbNeeded; | ||
| 401 | DWORD dwSize; | ||
| 402 | size_t i; | ||
| 403 | |||
| 404 | /* GetModuleHandle( NULL ) only returns the current program file. So | ||
| 405 | * if we want to get ALL loaded module including those in linked DLLs, | ||
| 406 | * we have to use EnumProcessModules( ). | ||
| 407 | */ | ||
| 408 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) | ||
| 409 | { | ||
| 410 | modules = malloc( dwSize ); | ||
| 411 | if( modules ) | ||
| 412 | { | ||
| 413 | if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) | ||
| 414 | { | ||
| 415 | for( i = 0; i < dwSize / sizeof( HMODULE ); i++ ) | ||
| 416 | { | ||
| 417 | if( handle == RTLD_NEXT && hCaller ) | ||
| 418 | { | ||
| 419 | /* Next modules can be used for RTLD_NEXT */ | ||
| 420 | if( hCaller == modules[i] ) | ||
| 421 | hCaller = NULL; | ||
| 422 | continue; | ||
| 423 | } | ||
| 424 | if( local_search( modules[i] ) ) | ||
| 425 | continue; | ||
| 426 | symbol = GetProcAddress( modules[i], name ); | ||
| 427 | if( symbol != NULL ) | ||
| 428 | { | ||
| 429 | free( modules ); | ||
| 430 | goto end; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | } | ||
| 435 | free( modules ); | ||
| 436 | } | ||
| 437 | else | ||
| 438 | { | ||
| 439 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); | ||
| 440 | goto end; | ||
| 441 | } | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | end: | ||
| 446 | if( symbol == NULL ) | ||
| 447 | { | ||
| 448 | if( GetLastError() == 0 ) | ||
| 449 | SetLastError( ERROR_PROC_NOT_FOUND ); | ||
| 450 | save_err_str( name ); | ||
| 451 | } | ||
| 452 | |||
| 453 | return *(void **) (&symbol); | ||
| 454 | } | ||
| 455 | |||
| 456 | char *dlerror( void ) | ||
| 457 | { | ||
| 458 | /* If this is the second consecutive call to dlerror, return NULL */ | ||
| 459 | if( !error_occurred ) | ||
| 460 | return NULL; | ||
| 461 | |||
| 462 | /* POSIX says that invoking dlerror( ) a second time, immediately following | ||
| 463 | * a prior invocation, shall result in NULL being returned. | ||
| 464 | */ | ||
| 465 | error_occurred = FALSE; | ||
| 466 | |||
| 467 | return error_buffer; | ||
| 468 | } | ||
| 469 | |||
| 470 | #ifdef SHARED | ||
| 471 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) | ||
| 472 | { | ||
| 473 | (void) hinstDLL; | ||
| 474 | (void) fdwReason; | ||
| 475 | (void) lpvReserved; | ||
| 476 | return TRUE; | ||
| 477 | } | ||
| 478 | #endif | ||
diff --git a/src/dlfcn.h b/src/dlfcn.h new file mode 100644 index 0000000..9ddbba3 --- /dev/null +++ b/src/dlfcn.h | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 2 | * dlfcn-win32 | ||
| 3 | * Copyright (c) 2007 Ramiro Polla | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | * of this software and associated documentation files (the "Software"), to deal | ||
| 7 | * in the Software without restriction, including without limitation the rights | ||
| 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | * copies of the Software, and to permit persons to whom the Software is | ||
| 10 | * furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice shall be included in | ||
| 13 | * all copies or substantial portions of the Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 21 | * THE SOFTWARE. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #ifndef DLFCN_H | ||
| 25 | #define DLFCN_H | ||
| 26 | |||
| 27 | #ifdef __cplusplus | ||
| 28 | extern "C" { | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if defined(DLFCN_WIN32_EXPORTS) | ||
| 32 | # define DLFCN_EXPORT __declspec(dllexport) | ||
| 33 | #else | ||
| 34 | # define DLFCN_EXPORT | ||
| 35 | #endif | ||
| 36 | |||
| 37 | /* Relocations are performed when the object is loaded. */ | ||
| 38 | #define RTLD_NOW 0 | ||
| 39 | |||
| 40 | /* Relocations are performed at an implementation-defined time. | ||
| 41 | * Windows API does not support lazy symbol resolving (when first reference | ||
| 42 | * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW. | ||
| 43 | */ | ||
| 44 | #define RTLD_LAZY RTLD_NOW | ||
| 45 | |||
| 46 | /* All symbols are available for relocation processing of other modules. */ | ||
| 47 | #define RTLD_GLOBAL (1 << 1) | ||
| 48 | |||
| 49 | /* All symbols are not made available for relocation processing by other modules. */ | ||
| 50 | #define RTLD_LOCAL (1 << 2) | ||
| 51 | |||
| 52 | /* These two were added in The Open Group Base Specifications Issue 6. | ||
| 53 | * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. | ||
| 54 | */ | ||
| 55 | |||
| 56 | /* The symbol lookup happens in the normal global scope. */ | ||
| 57 | #define RTLD_DEFAULT ((void *)0) | ||
| 58 | |||
| 59 | /* Specifies the next object after this one that defines name. */ | ||
| 60 | #define RTLD_NEXT ((void *)-1) | ||
| 61 | |||
| 62 | /* Open a symbol table handle. */ | ||
| 63 | DLFCN_EXPORT void *dlopen(const char *file, int mode); | ||
| 64 | |||
| 65 | /* Close a symbol table handle. */ | ||
| 66 | DLFCN_EXPORT int dlclose(void *handle); | ||
| 67 | |||
| 68 | /* Get the address of a symbol from a symbol table handle. */ | ||
| 69 | DLFCN_EXPORT void *dlsym(void *handle, const char *name); | ||
| 70 | |||
| 71 | /* Get diagnostic information. */ | ||
| 72 | DLFCN_EXPORT char *dlerror(void); | ||
| 73 | |||
| 74 | #ifdef __cplusplus | ||
| 75 | } | ||
| 76 | #endif | ||
| 77 | |||
| 78 | #endif /* DLFCN_H */ | ||
