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:
Alexandre Julliard 2020-09-21 13:41:28 +02:00
parent 6d7037c9ff
commit a014f413d6
7 changed files with 224 additions and 11 deletions

View File

@ -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.@)
*/

View File

@ -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

View File

@ -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;
}

View File

@ -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 );

View File

@ -14,4 +14,5 @@ C_SRCS = \
exe_wmain.c \
register.c \
setjmp.c \
stub.c
stub.c \
unix_lib.c

55
dlls/winecrt0/unix_lib.c Normal file
View File

@ -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 */

View File

@ -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