Many distributions provide MinGW-compiled system DLLs which are currently bundled with Wine. Unfortunately, while MinGW pkg-config can be used to detect the linking path, there is no standardized runtime path, and many distributions in fact use different paths.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Makefile.in | 1 + configure.ac | 3 +++ dlls/ntdll/Makefile.in | 1 + dlls/ntdll/loader.c | 10 ++++++++-- dlls/ntdll/unix/env.c | 1 + dlls/ntdll/unix/loader.c | 3 +++ dlls/ntdll/unix/unix_private.h | 1 + 7 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/Makefile.in b/Makefile.in index 42f161e3af9..c4b0fbda616 100644 --- a/Makefile.in +++ b/Makefile.in @@ -32,6 +32,7 @@ nlsdir = ${datadir}/wine/nls dlldir = ${libdir}/wine srcdir = @srcdir@ host_cpu = @host_cpu@ +system_dlldir = @system_dlldir@ SHELL = /bin/sh CC = @CC@ CXX = @CXX@ diff --git a/configure.ac b/configure.ac index 39c8e3a2a4d..4ecc3cce05f 100644 --- a/configure.ac +++ b/configure.ac @@ -103,6 +103,7 @@ AC_ARG_WITH(xshm, AS_HELP_STRING([--without-xshm],[do not use XShm (shared AC_ARG_WITH(xxf86vm, AS_HELP_STRING([--without-xxf86vm],[do not use XFree video mode extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_xf86vmode_h=no; ac_cv_header_X11_extensions_xf86vmproto_h=no; fi])
+AC_ARG_WITH(system-dlldir, AS_HELP_STRING([--with-system-dlldir=DIR],[load external PE dependencies from directory DIR])) AC_ARG_WITH(wine-tools,AS_HELP_STRING([--with-wine-tools=DIR],[use Wine tools from directory DIR])) AC_ARG_WITH(wine64, AS_HELP_STRING([--with-wine64=DIR],[use the 64-bit Wine in DIR for a Wow64 build]))
@@ -256,6 +257,8 @@ then TARGETFLAGS="-b $host_alias $TARGETFLAGS" fi
+AC_SUBST(system_dlldir,"$with_system_dlldir") + dnl Check for flex AC_CHECK_PROGS(FLEX,flex,none) if test "$FLEX" = "none" diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index d3be1fad0bc..bce141bc14b 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -72,5 +72,6 @@ EXTRA_OBJS = unix/version.o
unix_loader_EXTRADEFS = \ -DBINDIR="${bindir}" \ + -DSYSTEMDLLDIR="${system_dlldir}" \ -DDLL_TO_BINDIR="`${MAKEDEP} -R ${dlldir} ${bindir}`" \ -DBIN_TO_DATADIR="`${MAKEDEP} -R ${bindir} ${datadir}/wine`" diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 255d5afef79..a9578ae86bf 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -95,6 +95,7 @@ static int free_lib_count; /* recursion depth of LdrUnloadDll calls */ static ULONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */ static ULONG dll_safe_mode = 1; /* dll search mode */ static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */ +static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */ static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */ static WCHAR *default_load_path; /* default dll search path */
@@ -2981,12 +2982,15 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC struct file_id id; HANDLE mapping = 0; SECTION_IMAGE_INFORMATION image_info; - NTSTATUS nts; + NTSTATUS nts = STATUS_DLL_NOT_FOUND; ULONG64 prev;
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id ); + if (system_dll_path.Buffer) + nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id ); + if (nts) + nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
if (*pwm) /* found already loaded module */ { @@ -3997,6 +4001,8 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR load_global_options(); version_init();
+ get_env_var( L"WINESYSTEMDLLDIR", 0, &system_dll_path ); + wm = build_main_module(); wm->ldr.LoadCount = -1;
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 24f4fa5a588..f9e6e625cbb 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -1296,6 +1296,7 @@ static void add_dynamic_environment( WCHAR **env, SIZE_T *pos, SIZE_T *size ) add_path_var( env, pos, size, "WINEHOMEDIR", home_dir ); add_path_var( env, pos, size, "WINEBUILDDIR", build_dir ); add_path_var( env, pos, size, "WINECONFIGDIR", config_dir ); + add_path_var( env, pos, size, "WINESYSTEMDLLDIR", system_dll_path ); for (i = 0; dll_paths[i]; i++) { sprintf( str, "WINEDLLDIR%u", i ); diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index ea7f18602da..04e3dedc615 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -387,6 +387,7 @@ const char *data_dir = NULL; const char *build_dir = NULL; const char *config_dir = NULL; const char **dll_paths = NULL; +const char *system_dll_path = NULL; const char *user_name = NULL; SECTION_IMAGE_INFORMATION main_image_info = { NULL }; static HMODULE ntdll_module; @@ -618,6 +619,8 @@ static void init_paths( char *argv[] ) data_dir = build_path( bin_dir, BIN_TO_DATADIR ); }
+ if (strlen(SYSTEMDLLDIR)) system_dll_path = SYSTEMDLLDIR; + set_dll_path(); set_home_dir(); set_config_dir(); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 6b8835bcba0..15a3da9ce8e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -127,6 +127,7 @@ extern const char *build_dir DECLSPEC_HIDDEN; extern const char *config_dir DECLSPEC_HIDDEN; extern const char *user_name DECLSPEC_HIDDEN; extern const char **dll_paths DECLSPEC_HIDDEN; +extern const char *system_dll_path DECLSPEC_HIDDEN; extern PEB *peb DECLSPEC_HIDDEN; extern USHORT *uctable DECLSPEC_HIDDEN; extern USHORT *lctable DECLSPEC_HIDDEN;
That is, load Wine system dependencies only when they are imported from Wine builtins or other system dependencies, and do not match a Wine system dependency by its base name when looking for already-loaded modules.
The reasoning is that it is possible for an application to ship, and expect to use, a newer version of a MinGW-compiled library, or one with custom patches, or possibly an unrelated library with the same name. We don't want to offer Wine's system dependencies in place of the application's, or vice versa.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- v5: Only set the system flag if the module was actually loaded from a system path.
dlls/ntdll/loader.c | 56 +++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index a9578ae86bf..3ddfeb43ff7 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -135,6 +135,7 @@ typedef struct _wine_modref LDR_DATA_TABLE_ENTRY ldr; struct file_id id; ULONG CheckSum; + BOOL system; } WINE_MODREF;
static UINT tls_module_count; /* number of modules with TLS directory */ @@ -186,7 +187,7 @@ static WINE_MODREF *last_failed_modref; static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext, - DWORD flags, WINE_MODREF** pwm ); + DWORD flags, WINE_MODREF **pwm, BOOL system ); static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved ); static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size, DWORD ordinal, LPCWSTR load_path ); @@ -505,21 +506,22 @@ static WINE_MODREF *get_modref( HMODULE hmod ) * Find a module from its base name. * The loader_section must be locked while calling this function */ -static WINE_MODREF *find_basename_module( LPCWSTR name ) +static WINE_MODREF *find_basename_module( const WCHAR *name, BOOL system ) { PLIST_ENTRY mark, entry; UNICODE_STRING name_str;
RtlInitUnicodeString( &name_str, name );
- if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE )) + if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ) + && system == cached_modref->system) return cached_modref;
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; for (entry = mark->Flink; entry != mark; entry = entry->Flink) { - LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE )) + WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks); + if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && system == mod->system) { cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); return cached_modref; @@ -714,6 +716,8 @@ static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context, */ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path ) { + WINE_MODREF *imp = get_modref( module ); + BOOL system = imp->system || (imp->ldr.Flags & LDR_WINE_INTERNAL); const IMAGE_EXPORT_DIRECTORY *exports; DWORD exp_size; WINE_MODREF *wm; @@ -733,10 +737,10 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS if (!wcschr( mod_name, '.' )) memcpy( mod_name + (end - forward), L".dll", sizeof(L".dll") );
- if (!(wm = find_basename_module( mod_name ))) + if (!(wm = find_basename_module( mod_name, system ))) { TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward ); - if (load_dll( load_path, mod_name, L".dll", 0, &wm ) == STATUS_SUCCESS && + if (load_dll( load_path, mod_name, L".dll", 0, &wm, system ) == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) { if (!imports_fixup_done && current_modref) @@ -903,6 +907,7 @@ void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name ) */ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm ) { + BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL); NTSTATUS status; WINE_MODREF *wmImp; HMODULE imp_mod; @@ -936,7 +941,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP { ascii_to_unicode( buffer, name, len ); buffer[len] = 0; - status = load_dll( load_path, buffer, L".dll", 0, &wmImp ); + status = load_dll( load_path, buffer, L".dll", 0, &wmImp, system ); } else /* need to allocate a larger buffer */ { @@ -944,7 +949,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP if (!ptr) return FALSE; ascii_to_unicode( ptr, name, len ); ptr[len] = 0; - status = load_dll( load_path, ptr, L".dll", 0, &wmImp ); + status = load_dll( load_path, ptr, L".dll", 0, &wmImp, system ); RtlFreeHeap( GetProcessHeap(), 0, ptr ); }
@@ -1216,7 +1221,7 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void * prev = current_modref; current_modref = wm; assert( !wm->ldr.DdagNode->Dependencies.Tail ); - if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp )) + if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp, FALSE )) && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL )) status = STATUS_NO_MEMORY; current_modref = prev; @@ -2902,7 +2907,7 @@ done: */ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext, UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping, - SECTION_IMAGE_INFORMATION *image_info, struct file_id *id ) + SECTION_IMAGE_INFORMATION *image_info, struct file_id *id, BOOL system ) { WCHAR *ext, *dllname; NTSTATUS status; @@ -2943,7 +2948,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, con else { if (status != STATUS_SXS_KEY_NOT_FOUND) goto done; - if ((*pwm = find_basename_module( libname )) != NULL) + if ((*pwm = find_basename_module( libname, system )) != NULL) { status = STATUS_SUCCESS; goto done; @@ -2976,7 +2981,7 @@ done: * The loader_section must be locked while calling this function. */ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext, - DWORD flags, WINE_MODREF** pwm ) + DWORD flags, WINE_MODREF **pwm, BOOL system ) { UNICODE_STRING nt_name; struct file_id id; @@ -2987,10 +2992,13 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- if (system_dll_path.Buffer) - nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id ); + if (system && system_dll_path.Buffer) + nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id, TRUE ); if (nts) - nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id ); + { + nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id, FALSE ); + system = FALSE; + }
if (*pwm) /* found already loaded module */ { @@ -3027,6 +3035,14 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC break; }
+ /* mark the DLL as system only if it was loaded from a system path and is + * not builtin. note that builtins can appear to be loaded from a system + * path during prefix bootstrap */ + if (!((*pwm)->ldr.Flags & LDR_WINE_INTERNAL)) + (*pwm)->system = system; + + if ((*pwm)->system) FIXME( "%s is a system dependency\n", debugstr_us(&nt_name)); + if (NtCurrentTeb64()) NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev; else @@ -3084,7 +3100,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
RtlEnterCriticalSection( &loader_section );
- nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm ); + nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm, FALSE );
if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) { @@ -3159,7 +3175,7 @@ NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_ch
RtlEnterCriticalSection( &loader_section );
- status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id ); + status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id, FALSE );
if (wm) *base = wm->ldr.DllBase; else @@ -3860,7 +3876,7 @@ static void init_wow64( CONTEXT *context ) NTSTATUS status; static const WCHAR wow64_path[] = L"C:\windows\system32\wow64.dll";
- if ((status = load_dll( NULL, wow64_path, NULL, 0, &wm ))) + if ((status = load_dll( NULL, wow64_path, NULL, 0, &wm, FALSE ))) { ERR( "could not load %s, status %x\n", debugstr_w(wow64_path), status ); NtTerminateProcess( GetCurrentProcess(), status ); @@ -4010,7 +4026,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
- if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32 )) != STATUS_SUCCESS) + if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32, FALSE )) != STATUS_SUCCESS) { MESSAGE( "wine: could not load kernel32.dll, status %x\n", status ); NtTerminateProcess( GetCurrentProcess(), status );