aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile34
-rw-r--r--libs/dlfcn-win32/dlfcn.cc820
-rw-r--r--libs/dlfcn-win32/dlfcn.h94
3 files changed, 942 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index b7071f53c..78526d5ef 100644
--- a/Makefile
+++ b/Makefile
@@ -56,6 +56,9 @@ PROGRAM_PREFIX :=
OS := $(shell uname -s)
PREFIX ?= /usr/local
INSTALL_SUDO :=
+ifneq ($(filter MINGW%,$(OS)),)
+OS := MINGW
+endif
ifneq ($(wildcard Makefile.conf),)
include Makefile.conf
@@ -91,6 +94,13 @@ CXXSTD ?= c++11
CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include
LDLIBS := $(LDLIBS) -lstdc++ -lm
PLUGIN_LDFLAGS :=
+PLUGIN_LDLIBS :=
+EXE_LDFLAGS :=
+ifeq ($(OS), MINGW)
+EXE_LDFLAGS := -Wl,--export-all-symbols -Wl,--out-implib,libyosys_exe.a
+PLUGIN_LDFLAGS += -L"$(LIBDIR)"
+PLUGIN_LDLIBS := -lyosys_exe
+endif
PKG_CONFIG ?= pkg-config
SED ?= sed
@@ -436,8 +446,11 @@ endif
ifeq ($(ENABLE_PLUGINS),1)
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS
+ifeq ($(OS), MINGW)
+CXXFLAGS += -Ilibs/dlfcn-win32
+endif
LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi)
-ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD))
+ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD MINGW))
LDLIBS += -ldl
endif
endif
@@ -646,6 +659,11 @@ OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kern
ifeq ($(ENABLE_ZLIB),1)
OBJS += kernel/fstdata.o
endif
+ifeq ($(ENABLE_PLUGINS),1)
+ifeq ($(OS), MINGW)
+OBJS += libs/dlfcn-win32/dlfcn.o
+endif
+endif
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"'
@@ -724,7 +742,7 @@ yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS))
endif
$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
- $(P) $(LD) -o $(PROGRAM_PREFIX)yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
+ $(P) $(LD) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
ifeq ($(OS), Darwin)
@@ -767,8 +785,8 @@ LDLIBS_NOVERIFIC = $(LDLIBS)
endif
$(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in
- $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC)))#;' \
- -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC))#;' \
+ $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -Ilibs/dlfcn-win32,,$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC))))#;' \
+ -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC) $(PLUGIN_LDLIBS))#;' \
-e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config
$(Q) chmod +x $(PROGRAM_PREFIX)yosys-config
@@ -916,6 +934,12 @@ ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) cp misc/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/
endif
endif
+ifeq ($(ENABLE_PLUGINS),1)
+ifeq ($(OS), MINGW)
+ $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
+ $(INSTALL_SUDO) cp libyosys_exe.a $(DESTDIR)$(LIBDIR)/
+endif
+endif
uninstall:
$(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR)/,$(notdir $(TARGETS)))
@@ -1040,12 +1064,10 @@ config-mxe: clean
config-msys2-32: clean
echo 'CONFIG := msys2-32' > Makefile.conf
- echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
config-msys2-64: clean
echo 'CONFIG := msys2-64' > Makefile.conf
- echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
config-cygwin: clean
diff --git a/libs/dlfcn-win32/dlfcn.cc b/libs/dlfcn-win32/dlfcn.cc
new file mode 100644
index 000000000..03ed34dba
--- /dev/null
+++ b/libs/dlfcn-win32/dlfcn.cc
@@ -0,0 +1,820 @@
+/*
+ * dlfcn-win32
+ * Copyright (c) 2007 Ramiro Polla
+ * Copyright (c) 2015 Tiancheng "Timothy" Gu
+ * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (c) 2020 Ralf Habacker <ralf.habacker@freenet.de>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Older versions do not have this type */
+#if _WIN32_WINNT < 0x0500
+typedef ULONG ULONG_PTR;
+#endif
+
+/* Older SDK versions do not have these macros */
+#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4
+#endif
+#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
+#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2
+#endif
+
+#ifdef _MSC_VER
+/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
+#pragma intrinsic( _ReturnAddress )
+#else
+/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
+#ifndef _ReturnAddress
+#define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) )
+#endif
+#endif
+
+#ifdef DLFCN_WIN32_SHARED
+#define DLFCN_WIN32_EXPORTS
+#endif
+#include "dlfcn.h"
+
+#if defined( _MSC_VER ) && _MSC_VER >= 1300
+/* https://docs.microsoft.com/en-us/cpp/cpp/noinline */
+#define DLFCN_NOINLINE __declspec( noinline )
+#elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) )
+/* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */
+#define DLFCN_NOINLINE __attribute__(( noinline ))
+#else
+#define DLFCN_NOINLINE
+#endif
+
+/* Note:
+ * MSDN says these functions are not thread-safe. We make no efforts to have
+ * any kind of thread safety.
+ */
+
+typedef struct local_object {
+ HMODULE hModule;
+ struct local_object *previous;
+ struct local_object *next;
+} local_object;
+
+static local_object first_object;
+
+/* These functions implement a double linked list for the local objects. */
+static local_object *local_search( HMODULE hModule )
+{
+ local_object *pobject;
+
+ if( hModule == NULL )
+ return NULL;
+
+ for( pobject = &first_object; pobject; pobject = pobject->next )
+ if( pobject->hModule == hModule )
+ return pobject;
+
+ return NULL;
+}
+
+static BOOL local_add( HMODULE hModule )
+{
+ local_object *pobject;
+ local_object *nobject;
+
+ if( hModule == NULL )
+ return TRUE;
+
+ pobject = local_search( hModule );
+
+ /* Do not add object again if it's already on the list */
+ if( pobject != NULL )
+ return TRUE;
+
+ for( pobject = &first_object; pobject->next; pobject = pobject->next );
+
+ nobject = (local_object *) malloc( sizeof( local_object ) );
+
+ if( !nobject )
+ return FALSE;
+
+ pobject->next = nobject;
+ nobject->next = NULL;
+ nobject->previous = pobject;
+ nobject->hModule = hModule;
+
+ return TRUE;
+}
+
+static void local_rem( HMODULE hModule )
+{
+ local_object *pobject;
+
+ if( hModule == NULL )
+ return;
+
+ pobject = local_search( hModule );
+
+ if( pobject == NULL )
+ return;
+
+ if( pobject->next )
+ pobject->next->previous = pobject->previous;
+ if( pobject->previous )
+ pobject->previous->next = pobject->next;
+
+ free( pobject );
+}
+
+/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
+ * static buffer.
+ * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
+ * the limit.
+ */
+static char error_buffer[65535];
+static BOOL error_occurred;
+
+static void save_err_str( const char *str, DWORD dwMessageId )
+{
+ DWORD ret;
+ size_t pos, len;
+
+ len = strlen( str );
+ if( len > sizeof( error_buffer ) - 5 )
+ len = sizeof( error_buffer ) - 5;
+
+ /* Format error message to:
+ * "<argument to function that failed>": <Windows localized error message>
+ */
+ pos = 0;
+ error_buffer[pos++] = '"';
+ memcpy( error_buffer + pos, str, len );
+ pos += len;
+ error_buffer[pos++] = '"';
+ error_buffer[pos++] = ':';
+ error_buffer[pos++] = ' ';
+
+ ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
+ MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
+ error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL );
+ pos += ret;
+
+ /* When FormatMessageA() fails it returns zero and does not touch buffer
+ * so add trailing null byte */
+ if( ret == 0 )
+ error_buffer[pos] = '\0';
+
+ if( pos > 1 )
+ {
+ /* POSIX says the string must not have trailing <newline> */
+ if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
+ error_buffer[pos-2] = '\0';
+ }
+
+ error_occurred = TRUE;
+}
+
+static void save_err_ptr_str( const void *ptr, DWORD dwMessageId )
+{
+ char ptr_buf[2 + 2 * sizeof( ptr ) + 1];
+ char num;
+ size_t i;
+
+ ptr_buf[0] = '0';
+ ptr_buf[1] = 'x';
+
+ for( i = 0; i < 2 * sizeof( ptr ); i++ )
+ {
+ num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF );
+ ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) );
+ }
+
+ ptr_buf[2 + 2 * sizeof( ptr )] = 0;
+
+ save_err_str( ptr_buf, dwMessageId );
+}
+
+static UINT MySetErrorMode( UINT uMode )
+{
+ static BOOL (WINAPI *SetThreadErrorModePtr)(DWORD, DWORD *) = NULL;
+ static BOOL failed = FALSE;
+ HMODULE kernel32;
+ DWORD oldMode;
+
+ if( !failed && SetThreadErrorModePtr == NULL )
+ {
+ kernel32 = GetModuleHandleA( "Kernel32.dll" );
+ if( kernel32 != NULL )
+ SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (LPVOID) GetProcAddress( kernel32, "SetThreadErrorMode" );
+ if( SetThreadErrorModePtr == NULL )
+ failed = TRUE;
+ }
+
+ if( !failed )
+ {
+ if( !SetThreadErrorModePtr( uMode, &oldMode ) )
+ return 0;
+ else
+ return oldMode;
+ }
+ else
+ {
+ return SetErrorMode( uMode );
+ }
+}
+
+static HMODULE MyGetModuleHandleFromAddress( const void *addr )
+{
+ static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL;
+ static BOOL failed = FALSE;
+ HMODULE kernel32;
+ HMODULE hModule;
+ MEMORY_BASIC_INFORMATION info;
+ SIZE_T sLen;
+
+ if( !failed && GetModuleHandleExAPtr == NULL )
+ {
+ kernel32 = GetModuleHandleA( "Kernel32.dll" );
+ if( kernel32 != NULL )
+ GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (LPVOID) GetProcAddress( kernel32, "GetModuleHandleExA" );
+ if( GetModuleHandleExAPtr == NULL )
+ failed = TRUE;
+ }
+
+ if( !failed )
+ {
+ /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */
+ if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)addr, &hModule ) )
+ return NULL;
+ }
+ else
+ {
+ /* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380
+ * The HMODULE of a DLL is the same value as the module's base address.
+ */
+ sLen = VirtualQuery( addr, &info, sizeof( info ) );
+ if( sLen != sizeof( info ) )
+ return NULL;
+ hModule = (HMODULE) info.AllocationBase;
+ }
+
+ return hModule;
+}
+
+/* Load Psapi.dll at runtime, this avoids linking caveat */
+static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
+{
+ static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
+ static BOOL failed = FALSE;
+ UINT uMode;
+ HMODULE psapi;
+
+ if( failed )
+ return FALSE;
+
+ if( EnumProcessModulesPtr == NULL )
+ {
+ /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */
+ psapi = GetModuleHandleA( "Kernel32.dll" );
+ if( psapi != NULL )
+ EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "K32EnumProcessModules" );
+
+ /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */
+ if( EnumProcessModulesPtr == NULL )
+ {
+ /* Do not let Windows display the critical-error-handler message box */
+ uMode = MySetErrorMode( SEM_FAILCRITICALERRORS );
+ psapi = LoadLibraryA( "Psapi.dll" );
+ if( psapi != NULL )
+ {
+ EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" );
+ if( EnumProcessModulesPtr == NULL )
+ FreeLibrary( psapi );
+ }
+ MySetErrorMode( uMode );
+ }
+
+ if( EnumProcessModulesPtr == NULL )
+ {
+ failed = TRUE;
+ return FALSE;
+ }
+ }
+
+ return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
+}
+
+DLFCN_EXPORT
+void *dlopen( const char *file, int mode )
+{
+ HMODULE hModule;
+ UINT uMode;
+
+ error_occurred = FALSE;
+
+ /* Do not let Windows display the critical-error-handler message box */
+ uMode = MySetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if( file == NULL )
+ {
+ /* POSIX says that if the value of file is NULL, a handle on a global
+ * symbol object must be provided. That object must be able to access
+ * all symbols from the original program file, and any objects loaded
+ * with the RTLD_GLOBAL flag.
+ * The return value from GetModuleHandle( ) allows us to retrieve
+ * symbols only from the original program file. EnumProcessModules() is
+ * used to access symbols from other libraries. For objects loaded
+ * with the RTLD_LOCAL flag, we create our own list later on. They are
+ * excluded from EnumProcessModules() iteration.
+ */
+ hModule = GetModuleHandle( NULL );
+
+ if( !hModule )
+ save_err_str( "(null)", GetLastError( ) );
+ }
+ else
+ {
+ HANDLE hCurrentProc;
+ DWORD dwProcModsBefore, dwProcModsAfter;
+ char lpFileName[MAX_PATH];
+ size_t i, len;
+
+ len = strlen( file );
+
+ if( len >= sizeof( lpFileName ) )
+ {
+ save_err_str( file, ERROR_FILENAME_EXCED_RANGE );
+ hModule = NULL;
+ }
+ else
+ {
+ /* MSDN says backslashes *must* be used instead of forward slashes. */
+ for( i = 0; i < len; i++ )
+ {
+ if( file[i] == '/' )
+ lpFileName[i] = '\\';
+ else
+ lpFileName[i] = file[i];
+ }
+ lpFileName[len] = '\0';
+
+ hCurrentProc = GetCurrentProcess( );
+
+ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
+ dwProcModsBefore = 0;
+
+ /* POSIX says the search path is implementation-defined.
+ * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
+ * to UNIX's search paths (start with system folders instead of current
+ * folder).
+ */
+ hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
+
+ if( !hModule )
+ {
+ save_err_str( lpFileName, GetLastError( ) );
+ }
+ else
+ {
+ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
+ dwProcModsAfter = 0;
+
+ /* If the object was loaded with RTLD_LOCAL, add it to list of local
+ * objects, so that its symbols cannot be retrieved even if the handle for
+ * the original program file is passed. POSIX says that if the same
+ * file is specified in multiple invocations, and any of them are
+ * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
+ * symbols will remain global. If number of loaded modules was not
+ * changed after calling LoadLibraryEx(), it means that library was
+ * already loaded.
+ */
+ if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
+ {
+ if( !local_add( hModule ) )
+ {
+ save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY );
+ FreeLibrary( hModule );
+ hModule = NULL;
+ }
+ }
+ else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
+ {
+ local_rem( hModule );
+ }
+ }
+ }
+ }
+
+ /* Return to previous state of the error-mode bit flags. */
+ MySetErrorMode( uMode );
+
+ return (void *) hModule;
+}
+
+DLFCN_EXPORT
+int dlclose( void *handle )
+{
+ HMODULE hModule = (HMODULE) handle;
+ BOOL ret;
+
+ error_occurred = FALSE;
+
+ ret = FreeLibrary( hModule );
+
+ /* If the object was loaded with RTLD_LOCAL, remove it from list of local
+ * objects.
+ */
+ if( ret )
+ local_rem( hModule );
+ else
+ save_err_ptr_str( handle, GetLastError( ) );
+
+ /* dlclose's return value in inverted in relation to FreeLibrary's. */
+ ret = !ret;
+
+ return (int) ret;
+}
+
+DLFCN_NOINLINE /* Needed for _ReturnAddress() */
+DLFCN_EXPORT
+void *dlsym( void *handle, const char *name )
+{
+ FARPROC symbol;
+ HMODULE hCaller;
+ HMODULE hModule;
+ DWORD dwMessageId;
+
+ error_occurred = FALSE;
+
+ symbol = NULL;
+ hCaller = NULL;
+ hModule = GetModuleHandle( NULL );
+ dwMessageId = 0;
+
+ if( handle == RTLD_DEFAULT )
+ {
+ /* The symbol lookup happens in the normal global scope; that is,
+ * a search for a symbol using this handle would find the same
+ * definition as a direct use of this symbol in the program code.
+ * So use same lookup procedure as when filename is NULL.
+ */
+ handle = hModule;
+ }
+ else if( handle == RTLD_NEXT )
+ {
+ /* Specifies the next object after this one that defines name.
+ * This one refers to the object containing the invocation of dlsym().
+ * The next object is the one found upon the application of a load
+ * order symbol resolution algorithm. To get caller function of dlsym()
+ * use _ReturnAddress() intrinsic. To get HMODULE of caller function
+ * use MyGetModuleHandleFromAddress() which calls either standard
+ * GetModuleHandleExA() function or hack via VirtualQuery().
+ */
+ hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) );
+
+ if( hCaller == NULL )
+ {
+ dwMessageId = ERROR_INVALID_PARAMETER;
+ goto end;
+ }
+ }
+
+ if( handle != RTLD_NEXT )
+ {
+ symbol = GetProcAddress( (HMODULE) handle, name );
+
+ if( symbol != NULL )
+ goto end;
+ }
+
+ /* If the handle for the original program file is passed, also search
+ * in all globally loaded objects.
+ */
+
+ if( hModule == handle || handle == RTLD_NEXT )
+ {
+ HANDLE hCurrentProc;
+ HMODULE *modules;
+ DWORD cbNeeded;
+ DWORD dwSize;
+ size_t i;
+
+ hCurrentProc = GetCurrentProcess( );
+
+ /* GetModuleHandle( NULL ) only returns the current program file. So
+ * if we want to get ALL loaded module including those in linked DLLs,
+ * we have to use EnumProcessModules( ).
+ */
+ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
+ {
+ modules = (HMODULE *)malloc( dwSize );
+ if( modules )
+ {
+ if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
+ {
+ for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
+ {
+ if( handle == RTLD_NEXT && hCaller )
+ {
+ /* Next modules can be used for RTLD_NEXT */
+ if( hCaller == modules[i] )
+ hCaller = NULL;
+ continue;
+ }
+ if( local_search( modules[i] ) )
+ continue;
+ symbol = GetProcAddress( modules[i], name );
+ if( symbol != NULL )
+ {
+ free( modules );
+ goto end;
+ }
+ }
+
+ }
+ free( modules );
+ }
+ else
+ {
+ dwMessageId = ERROR_NOT_ENOUGH_MEMORY;
+ goto end;
+ }
+ }
+ }
+
+end:
+ if( symbol == NULL )
+ {
+ if( !dwMessageId )
+ dwMessageId = ERROR_PROC_NOT_FOUND;
+ save_err_str( name, dwMessageId );
+ }
+
+ return *(void **) (&symbol);
+}
+
+DLFCN_EXPORT
+char *dlerror( void )
+{
+ /* If this is the second consecutive call to dlerror, return NULL */
+ if( !error_occurred )
+ return NULL;
+
+ /* POSIX says that invoking dlerror( ) a second time, immediately following
+ * a prior invocation, shall result in NULL being returned.
+ */
+ error_occurred = FALSE;
+
+ return error_buffer;
+}
+
+/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
+ * for details */
+
+/* Get specific image section */
+static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size )
+{
+ IMAGE_DOS_HEADER *dosHeader;
+ IMAGE_NT_HEADERS *ntHeaders;
+ IMAGE_OPTIONAL_HEADER *optionalHeader;
+
+ dosHeader = (IMAGE_DOS_HEADER *) module;
+
+ if( dosHeader->e_magic != IMAGE_DOS_SIGNATURE )
+ return FALSE;
+
+ ntHeaders = (IMAGE_NT_HEADERS *) ( (BYTE *) dosHeader + dosHeader->e_lfanew );
+
+ if( ntHeaders->Signature != IMAGE_NT_SIGNATURE )
+ return FALSE;
+
+ optionalHeader = &ntHeaders->OptionalHeader;
+
+ if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC )
+ return FALSE;
+
+ if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
+ return FALSE;
+
+ if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 )
+ return FALSE;
+
+ if( size != NULL )
+ *size = optionalHeader->DataDirectory[index].Size;
+
+ *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress );
+
+ return TRUE;
+}
+
+/* Return symbol name for a given address from export table */
+static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, const void *addr, void **func_address )
+{
+ DWORD i;
+ void *candidateAddr = NULL;
+ int candidateIndex = -1;
+ BYTE *base = (BYTE *) module;
+ DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions);
+ DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames);
+ USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals);
+
+ for( i = 0; i < ied->NumberOfFunctions; i++ )
+ {
+ if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) )
+ continue;
+
+ candidateAddr = (void *) ( base + functionAddressesOffsets[i] );
+ candidateIndex = i;
+ }
+
+ if( candidateIndex == -1 )
+ return NULL;
+
+ *func_address = candidateAddr;
+
+ for( i = 0; i < ied->NumberOfNames; i++ )
+ {
+ if( functionNameOrdinalsIndexes[i] == candidateIndex )
+ return (const char *) ( base + functionNamesOffsets[i] );
+ }
+
+ return NULL;
+}
+
+static BOOL is_valid_address( const void *addr )
+{
+ MEMORY_BASIC_INFORMATION info;
+ SIZE_T result;
+
+ if( addr == NULL )
+ return FALSE;
+
+ /* check valid pointer */
+ result = VirtualQuery( addr, &info, sizeof( info ) );
+
+ if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS )
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Return state if address points to an import thunk
+ *
+ * An import thunk is setup with a 'jmp' instruction followed by an
+ * absolute address (32bit) or relative offset (64bit) pointing into
+ * the import address table (iat), which is partially maintained by
+ * the runtime linker.
+ */
+static BOOL is_import_thunk( const void *addr )
+{
+ return *(short *) addr == 0x25ff ? TRUE : FALSE;
+}
+
+/* Return adress from the import address table (iat),
+ * if the original address points to a thunk table entry.
+ */
+static void *get_address_from_import_address_table( void *iat, DWORD iat_size, const void *addr )
+{
+ BYTE *thkp = (BYTE *) addr;
+ /* Get offset from thunk table (after instruction 0xff 0x25)
+ * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00
+ */
+ ULONG offset = *(ULONG *)( thkp + 2 );
+#ifdef _WIN64
+ /* On 64 bit the offset is relative
+ * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery>
+ * And can be also negative (MSVC in WDK)
+ * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060
+ * So cast to signed LONG type
+ */
+ BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset );
+#else
+ /* On 32 bit the offset is absolute
+ * 4019b4: ff 25 90 71 40 00 jmp *0x40719
+ */
+ BYTE *ptr = (BYTE *) offset;
+#endif
+
+ if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size )
+ return NULL;
+
+ return *(void **) ptr;
+}
+
+/* Holds module filename */
+static char module_filename[2*MAX_PATH];
+
+static BOOL fill_info( const void *addr, Dl_info *info )
+{
+ HMODULE hModule;
+ DWORD dwSize;
+ IMAGE_EXPORT_DIRECTORY *ied;
+ void *funcAddress = NULL;
+
+ /* Get module of the specified address */
+ hModule = MyGetModuleHandleFromAddress( addr );
+
+ if( hModule == NULL )
+ return FALSE;
+
+ dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) );
+
+ if( dwSize == 0 || dwSize == sizeof( module_filename ) )
+ return FALSE;
+
+ info->dli_fname = module_filename;
+ info->dli_fbase = (void *) hModule;
+
+ /* Find function name and function address in module's export table */
+ if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) )
+ info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress );
+ else
+ info->dli_sname = NULL;
+
+ info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : (void *) addr;
+
+ return TRUE;
+}
+
+DLFCN_EXPORT
+int dladdr( const void *addr, Dl_info *info )
+{
+ if( info == NULL )
+ return 0;
+
+ if( !is_valid_address( addr ) )
+ return 0;
+
+ if( is_import_thunk( addr ) )
+ {
+ void *iat;
+ DWORD iatSize;
+ HMODULE hModule;
+
+ /* Get module of the import thunk address */
+ hModule = MyGetModuleHandleFromAddress( addr );
+
+ if( hModule == NULL )
+ return 0;
+
+ if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) )
+ {
+ /* Fallback for cases where the iat is not defined,
+ * for example i586-mingw32msvc-gcc */
+ IMAGE_IMPORT_DESCRIPTOR *iid;
+ DWORD iidSize;
+
+ if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) )
+ return 0;
+
+ if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 )
+ return 0;
+
+ iat = (void *)( (BYTE *) hModule + iid->FirstThunk );
+ /* We assume that in this case iid and iat's are in linear order */
+ iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid );
+ }
+
+ addr = get_address_from_import_address_table( iat, iatSize, addr );
+
+ if( !is_valid_address( addr ) )
+ return 0;
+ }
+
+ if( !fill_info( addr, info ) )
+ return 0;
+
+ return 1;
+}
+
+#ifdef DLFCN_WIN32_SHARED
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
+{
+ (void) hinstDLL;
+ (void) fdwReason;
+ (void) lpvReserved;
+ return TRUE;
+}
+#endif
diff --git a/libs/dlfcn-win32/dlfcn.h b/libs/dlfcn-win32/dlfcn.h
new file mode 100644
index 000000000..bf5c7d4d1
--- /dev/null
+++ b/libs/dlfcn-win32/dlfcn.h
@@ -0,0 +1,94 @@
+/*
+ * dlfcn-win32
+ * Copyright (c) 2007 Ramiro Polla
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef DLFCN_H
+#define DLFCN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(DLFCN_WIN32_SHARED)
+#if defined(DLFCN_WIN32_EXPORTS)
+# define DLFCN_EXPORT __declspec(dllexport)
+#else
+# define DLFCN_EXPORT __declspec(dllimport)
+#endif
+#else
+# define DLFCN_EXPORT
+#endif
+
+/* Relocations are performed when the object is loaded. */
+#define RTLD_NOW 0
+
+/* Relocations are performed at an implementation-defined time.
+ * Windows API does not support lazy symbol resolving (when first reference
+ * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW.
+ */
+#define RTLD_LAZY RTLD_NOW
+
+/* All symbols are available for relocation processing of other modules. */
+#define RTLD_GLOBAL (1 << 1)
+
+/* All symbols are not made available for relocation processing by other modules. */
+#define RTLD_LOCAL (1 << 2)
+
+/* These two were added in The Open Group Base Specifications Issue 6.
+ * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
+ */
+
+/* The symbol lookup happens in the normal global scope. */
+#define RTLD_DEFAULT ((void *)0)
+
+/* Specifies the next object after this one that defines name. */
+#define RTLD_NEXT ((void *)-1)
+
+/* Structure filled in by dladdr() */
+typedef struct dl_info
+{
+ const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */
+ void *dli_fbase; /* Load address of that object */
+ const char *dli_sname; /* Name of nearest lower symbol */
+ void *dli_saddr; /* Exact value of nearest symbol */
+} Dl_info;
+
+/* Open a symbol table handle. */
+DLFCN_EXPORT void *dlopen(const char *file, int mode);
+
+/* Close a symbol table handle. */
+DLFCN_EXPORT int dlclose(void *handle);
+
+/* Get the address of a symbol from a symbol table handle. */
+DLFCN_EXPORT void *dlsym(void *handle, const char *name);
+
+/* Get diagnostic information. */
+DLFCN_EXPORT char *dlerror(void);
+
+/* Translate address to symbolic information (no POSIX standard) */
+DLFCN_EXPORT int dladdr(const void *addr, Dl_info *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DLFCN_H */