ntdll: Add support for loading a Unix helper library from builtin dlls.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
6d7037c9ff
commit
a014f413d6
|
@ -128,6 +128,7 @@ typedef struct _wine_modref
|
|||
{
|
||||
LDR_DATA_TABLE_ENTRY ldr;
|
||||
struct file_id id;
|
||||
void *unix_entry;
|
||||
int alloc_deps;
|
||||
int nDeps;
|
||||
struct _wine_modref **deps;
|
||||
|
@ -2356,7 +2357,7 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_na
|
|||
{
|
||||
const WCHAR *name, *p;
|
||||
NTSTATUS status;
|
||||
void *module = NULL;
|
||||
void *module = NULL, *unix_entry = NULL;
|
||||
SECTION_IMAGE_INFORMATION image_info;
|
||||
|
||||
/* Fix the name in case we have a full path and extension */
|
||||
|
@ -2368,7 +2369,7 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_na
|
|||
|
||||
if (!module_ptr) module_ptr = &module;
|
||||
|
||||
status = unix_funcs->load_builtin_dll( name, module_ptr, &image_info );
|
||||
status = unix_funcs->load_builtin_dll( name, module_ptr, &unix_entry, &image_info );
|
||||
if (status) return status;
|
||||
|
||||
if ((*pwm = get_modref( *module_ptr ))) /* already loaded */
|
||||
|
@ -2383,7 +2384,8 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_na
|
|||
|
||||
TRACE( "loading %s from %s\n", debugstr_w(name), debugstr_us(nt_name) );
|
||||
status = build_module( load_path, nt_name, module_ptr, &image_info, NULL, flags, pwm );
|
||||
if (status && *module_ptr) unix_funcs->unload_builtin_dll( *module_ptr );
|
||||
if (!status) (*pwm)->unix_entry = unix_entry;
|
||||
else if (*module_ptr) unix_funcs->unload_builtin_dll( *module_ptr );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -2755,6 +2757,29 @@ done:
|
|||
return nts;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* __wine_init_unix_lib
|
||||
*/
|
||||
NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
NTSTATUS ret = STATUS_DLL_NOT_FOUND;
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
if ((wm = get_modref( module )))
|
||||
{
|
||||
NTSTATUS (CDECL *init_func)( HMODULE, DWORD, const void *, void * ) = wm->unix_entry;
|
||||
if (init_func) ret = init_func( module, reason, ptr_in, ptr_out );
|
||||
}
|
||||
else ret = STATUS_INVALID_HANDLE;
|
||||
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* LdrLoadDll (NTDLL.@)
|
||||
*/
|
||||
|
|
|
@ -1597,7 +1597,10 @@
|
|||
@ cdecl -syscall wine_server_release_fd(long long)
|
||||
@ cdecl -syscall wine_server_send_fd(long)
|
||||
@ cdecl -syscall __wine_make_process_system()
|
||||
|
||||
# Unix interface
|
||||
@ cdecl __wine_set_unix_funcs(long ptr)
|
||||
@ cdecl __wine_init_unix_lib(long long ptr ptr)
|
||||
@ extern __wine_syscall_dispatcher
|
||||
@ extern -arch=i386 __wine_ldt_copy
|
||||
|
||||
|
|
|
@ -123,6 +123,8 @@ const char *build_dir = NULL;
|
|||
const char *config_dir = NULL;
|
||||
const char **dll_paths = NULL;
|
||||
const char *user_name = NULL;
|
||||
static HMODULE ntdll_module;
|
||||
static const IMAGE_EXPORT_DIRECTORY *ntdll_exports;
|
||||
|
||||
struct file_id
|
||||
{
|
||||
|
@ -136,6 +138,7 @@ struct builtin_module
|
|||
struct file_id id;
|
||||
void *handle;
|
||||
void *module;
|
||||
void *unix_module;
|
||||
};
|
||||
|
||||
static struct list builtin_modules = LIST_INIT( builtin_modules );
|
||||
|
@ -146,6 +149,7 @@ static NTSTATUS add_builtin_module( void *module, void *handle, const struct sta
|
|||
if (!(builtin = malloc( sizeof(*builtin) ))) return STATUS_NO_MEMORY;
|
||||
builtin->handle = handle;
|
||||
builtin->module = module;
|
||||
builtin->unix_module = NULL;
|
||||
if (st)
|
||||
{
|
||||
builtin->id.dev = st->st_dev;
|
||||
|
@ -782,11 +786,76 @@ static ULONG_PTR find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ULONG_PTR find_pe_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
|
||||
const IMAGE_IMPORT_BY_NAME *name )
|
||||
{
|
||||
const WORD *ordinals = (const WORD *)((BYTE *)module + exports->AddressOfNameOrdinals);
|
||||
const DWORD *names = (const DWORD *)((BYTE *)module + exports->AddressOfNames);
|
||||
|
||||
if (name->Hint < exports->NumberOfNames)
|
||||
{
|
||||
char *ename = (char *)module + names[name->Hint];
|
||||
if (!strcmp( ename, (char *)name->Name ))
|
||||
return find_ordinal_export( module, exports, ordinals[name->Hint] );
|
||||
}
|
||||
return find_named_export( module, exports, (char *)name->Name );
|
||||
}
|
||||
|
||||
static inline void *get_rva( void *module, ULONG_PTR addr )
|
||||
{
|
||||
return (BYTE *)module + addr;
|
||||
}
|
||||
|
||||
static NTSTATUS fixup_ntdll_imports( const char *name, HMODULE module )
|
||||
{
|
||||
const IMAGE_NT_HEADERS *nt;
|
||||
const IMAGE_IMPORT_DESCRIPTOR *descr;
|
||||
const IMAGE_THUNK_DATA *import_list;
|
||||
IMAGE_THUNK_DATA *thunk_list;
|
||||
|
||||
nt = get_rva( module, ((IMAGE_DOS_HEADER *)module)->e_lfanew );
|
||||
descr = get_rva( module, nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].VirtualAddress );
|
||||
for (; descr->Name && descr->FirstThunk; descr++)
|
||||
{
|
||||
thunk_list = get_rva( module, descr->FirstThunk );
|
||||
|
||||
/* ntdll must be the only import */
|
||||
if (strcmp( get_rva( module, descr->Name ), "ntdll.dll" ))
|
||||
{
|
||||
ERR( "module %s is importing %s\n", debugstr_a(name), (char *)get_rva( module, descr->Name ));
|
||||
return STATUS_PROCEDURE_NOT_FOUND;
|
||||
}
|
||||
if (descr->u.OriginalFirstThunk)
|
||||
import_list = get_rva( module, descr->u.OriginalFirstThunk );
|
||||
else
|
||||
import_list = thunk_list;
|
||||
|
||||
while (import_list->u1.Ordinal)
|
||||
{
|
||||
if (IMAGE_SNAP_BY_ORDINAL( import_list->u1.Ordinal ))
|
||||
{
|
||||
int ordinal = IMAGE_ORDINAL( import_list->u1.Ordinal ) - ntdll_exports->Base;
|
||||
thunk_list->u1.Function = find_ordinal_export( ntdll_module, ntdll_exports, ordinal );
|
||||
if (!thunk_list->u1.Function) ERR( "%s: ntdll.%u not found\n", debugstr_a(name), ordinal );
|
||||
}
|
||||
else /* import by name */
|
||||
{
|
||||
IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, import_list->u1.AddressOfData );
|
||||
thunk_list->u1.Function = find_pe_export( ntdll_module, ntdll_exports, pe_name );
|
||||
if (!thunk_list->u1.Function) ERR( "%s: ntdll.%s not found\n", debugstr_a(name), pe_name->Name );
|
||||
}
|
||||
import_list++;
|
||||
thunk_list++;
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void load_ntdll_functions( HMODULE module )
|
||||
{
|
||||
const IMAGE_EXPORT_DIRECTORY *ntdll_exports = get_export_dir( module );
|
||||
void **ptr;
|
||||
|
||||
ntdll_exports = get_export_dir( module );
|
||||
assert( ntdll_exports );
|
||||
|
||||
#define GET_FUNC(name) \
|
||||
|
@ -926,6 +995,55 @@ already_loaded:
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* dlopen_unix_dll
|
||||
*/
|
||||
static NTSTATUS dlopen_unix_dll( void *module, const char *name, void **unix_entry )
|
||||
{
|
||||
struct builtin_module *builtin;
|
||||
void *unix_module, *handle, *entry;
|
||||
const IMAGE_NT_HEADERS *nt;
|
||||
NTSTATUS status = STATUS_INVALID_IMAGE_FORMAT;
|
||||
|
||||
handle = dlopen( name, RTLD_NOW );
|
||||
if (!handle) return STATUS_DLL_NOT_FOUND;
|
||||
if (!(nt = dlsym( handle, "__wine_spec_nt_header" ))) goto done;
|
||||
if (!(entry = dlsym( handle, "__wine_init_unix_lib" ))) goto done;
|
||||
|
||||
unix_module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
|
||||
LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
|
||||
{
|
||||
if (builtin->module == module)
|
||||
{
|
||||
if (builtin->unix_module == unix_module) /* already loaded */
|
||||
{
|
||||
status = STATUS_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
if (builtin->unix_module)
|
||||
{
|
||||
ERR( "module %p already has a Unix module that's not %s\n", module, debugstr_a(name) );
|
||||
goto done;
|
||||
}
|
||||
if ((status = map_so_dll( nt, unix_module ))) goto done;
|
||||
if ((status = fixup_ntdll_imports( name, unix_module ))) goto done;
|
||||
builtin->unix_module = handle;
|
||||
*unix_entry = entry;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (builtin->unix_module == unix_module)
|
||||
{
|
||||
ERR( "%s already loaded for module %p\n", debugstr_a(name), module );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ERR( "builtin module not found for %s\n", debugstr_a(name) );
|
||||
done:
|
||||
dlclose( handle );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_so_dll
|
||||
*/
|
||||
|
@ -1136,11 +1254,11 @@ static NTSTATUS open_builtin_file( char *name, void **module, SECTION_IMAGE_INFO
|
|||
/***********************************************************************
|
||||
* load_builtin_dll
|
||||
*/
|
||||
static NTSTATUS CDECL load_builtin_dll( const WCHAR *name, void **module,
|
||||
static NTSTATUS CDECL load_builtin_dll( const WCHAR *name, void **module, void **unix_entry,
|
||||
SECTION_IMAGE_INFORMATION *image_info )
|
||||
{
|
||||
unsigned int i, pos, len, namelen, maxlen = 0;
|
||||
char *ptr, *file;
|
||||
char *ptr = NULL, *file, *ext = NULL;
|
||||
NTSTATUS status = STATUS_DLL_NOT_FOUND;
|
||||
BOOL found_image = FALSE;
|
||||
|
||||
|
@ -1157,6 +1275,7 @@ static NTSTATUS CDECL load_builtin_dll( const WCHAR *name, void **module,
|
|||
if (name[i] > 127) goto done;
|
||||
file[pos + i] = (char)name[i];
|
||||
if (file[pos + i] >= 'A' && file[pos + i] <= 'Z') file[pos + i] += 'a' - 'A';
|
||||
else if (file[pos + i] == '.') ext = file + pos + i;
|
||||
}
|
||||
file[--pos] = '/';
|
||||
|
||||
|
@ -1166,7 +1285,7 @@ static NTSTATUS CDECL load_builtin_dll( const WCHAR *name, void **module,
|
|||
ptr = file + pos;
|
||||
namelen = len + 1;
|
||||
file[pos + len + 1] = 0;
|
||||
if (namelen > 4 && !memcmp( ptr + namelen - 4, ".dll", 4 )) namelen -= 4;
|
||||
if (ext && !strcmp( ext, ".dll" )) namelen -= 4;
|
||||
ptr = prepend( ptr, ptr, namelen );
|
||||
ptr = prepend( ptr, "/dlls", sizeof("/dlls") - 1 );
|
||||
ptr = prepend( ptr, build_dir, strlen(build_dir) );
|
||||
|
@ -1177,7 +1296,7 @@ static NTSTATUS CDECL load_builtin_dll( const WCHAR *name, void **module,
|
|||
ptr = file + pos;
|
||||
namelen = len + 1;
|
||||
file[pos + len + 1] = 0;
|
||||
if (namelen > 4 && !memcmp( ptr + namelen - 4, ".exe", 4 )) namelen -= 4;
|
||||
if (ext && !strcmp( ext, ".exe" )) namelen -= 4;
|
||||
ptr = prepend( ptr, ptr, namelen );
|
||||
ptr = prepend( ptr, "/programs", sizeof("/programs") - 1 );
|
||||
ptr = prepend( ptr, build_dir, strlen(build_dir) );
|
||||
|
@ -1198,6 +1317,11 @@ static NTSTATUS CDECL load_builtin_dll( const WCHAR *name, void **module,
|
|||
WARN( "cannot find builtin library for %s\n", debugstr_w(name) );
|
||||
|
||||
done:
|
||||
if (!status && ext)
|
||||
{
|
||||
strcpy( ext, ".so" );
|
||||
dlopen_unix_dll( *module, ptr, unix_entry );
|
||||
}
|
||||
free( file );
|
||||
return status;
|
||||
}
|
||||
|
@ -1215,6 +1339,7 @@ static NTSTATUS CDECL unload_builtin_dll( void *module )
|
|||
if (builtin->module != module) continue;
|
||||
list_remove( &builtin->entry );
|
||||
if (builtin->handle) dlclose( builtin->handle );
|
||||
if (builtin->unix_module) dlclose( builtin->unix_module );
|
||||
free( builtin );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -1334,6 +1459,7 @@ static void load_ntdll(void)
|
|||
if (status) fatal_error( "failed to load %s error %x\n", name, status );
|
||||
free( name );
|
||||
load_ntdll_functions( module );
|
||||
ntdll_module = module;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
struct _DISPATCHER_CONTEXT;
|
||||
|
||||
/* increment this when you change the function table */
|
||||
#define NTDLL_UNIXLIB_VERSION 104
|
||||
#define NTDLL_UNIXLIB_VERSION 105
|
||||
|
||||
struct unix_funcs
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ struct unix_funcs
|
|||
|
||||
/* loader functions */
|
||||
NTSTATUS (CDECL *load_so_dll)( UNICODE_STRING *nt_name, void **module );
|
||||
NTSTATUS (CDECL *load_builtin_dll)( const WCHAR *name, void **module,
|
||||
NTSTATUS (CDECL *load_builtin_dll)( const WCHAR *name, void **module, void **unix_entry,
|
||||
SECTION_IMAGE_INFORMATION *image_info );
|
||||
NTSTATUS (CDECL *unload_builtin_dll)( void *module );
|
||||
void (CDECL *init_builtin_dll)( void *module );
|
||||
|
|
|
@ -14,4 +14,5 @@ C_SRCS = \
|
|||
exe_wmain.c \
|
||||
register.c \
|
||||
setjmp.c \
|
||||
stub.c
|
||||
stub.c \
|
||||
unix_lib.c
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Support for the Unix part of builtin dlls
|
||||
*
|
||||
* Copyright 2019 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
|
||||
static NTSTATUS (__cdecl *p__wine_init_unix_lib)( HMODULE, DWORD, const void *, void * );
|
||||
|
||||
static void load_func( void **func, const char *name, void *def )
|
||||
{
|
||||
if (!*func)
|
||||
{
|
||||
HMODULE module = GetModuleHandleA( "ntdll.dll" );
|
||||
void *proc = GetProcAddress( module, name );
|
||||
InterlockedExchangePointer( func, proc ? proc : def );
|
||||
}
|
||||
}
|
||||
#define LOAD_FUNC(name) load_func( (void **)&p ## name, #name, fallback ## name )
|
||||
|
||||
static NTSTATUS __cdecl fallback__wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
|
||||
{
|
||||
return STATUS_DLL_NOT_FOUND;
|
||||
}
|
||||
|
||||
NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
|
||||
{
|
||||
LOAD_FUNC( __wine_init_unix_lib );
|
||||
return p__wine_init_unix_lib( module, reason, ptr_in, ptr_out );
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
|
@ -3756,6 +3756,9 @@ static inline PLIST_ENTRY RemoveTailList(PLIST_ENTRY le)
|
|||
|
||||
#ifdef __WINESRC__
|
||||
|
||||
/* Wine internal functions */
|
||||
extern NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out );
|
||||
|
||||
/* The thread information for 16-bit threads */
|
||||
/* NtCurrentTeb()->SubSystemTib points to this */
|
||||
typedef struct
|
||||
|
|
Loading…
Reference in New Issue