ntdll: Move the loading of .so dlls to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-06-23 19:39:12 +02:00
parent 99649d7892
commit 31538a79a9
9 changed files with 313 additions and 349 deletions

View file

@ -24,12 +24,6 @@
#include <assert.h>
#include <stdarg.h>
#ifdef HAVE_LINK_H
# include <link.h>
#endif
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@ -42,7 +36,6 @@
#include "delayloadhandler.h"
#include "wine/exception.h"
#include "wine/library.h"
#include "wine/debug.h"
#include "wine/list.h"
#include "wine/server.h"
@ -133,25 +126,11 @@ typedef struct _wine_modref
{
LDR_DATA_TABLE_ENTRY ldr;
struct file_id id;
void *so_handle;
int alloc_deps;
int nDeps;
struct _wine_modref **deps;
} WINE_MODREF;
/* info about the current builtin dll load */
/* used to keep track of things across the register_dll constructor call */
struct builtin_load_info
{
const WCHAR *load_path;
const UNICODE_STRING *filename;
NTSTATUS status;
WINE_MODREF *wm;
};
static struct builtin_load_info default_load_info;
static struct builtin_load_info *builtin_load_info = &default_load_info;
static UINT tls_module_count; /* number of modules with TLS directory */
static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
LIST_ENTRY tls_links = { &tls_links, &tls_links };
@ -581,28 +560,6 @@ static WINE_MODREF *find_fileid_module( const struct file_id *id )
}
/**********************************************************************
* find_so_module
*
* Find a module from its so file handle.
* The loader_section must be locked while calling this function
*/
static WINE_MODREF *find_so_module( void *handle )
{
LIST_ENTRY *mark, *entry;
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 );
WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
if (wm->so_handle == handle) return wm;
}
return NULL;
}
/*************************************************************************
* grow_module_deps
*/
@ -1323,85 +1280,6 @@ static void call_tls_callbacks( HMODULE module, UINT reason )
}
}
#ifdef __FreeBSD__
/* The PT_LOAD segments are sorted in increasing order, and the first
* starts at the beginning of the ELF file. By parsing the file, we can
* find that first PT_LOAD segment, from which we can find the base
* address it wanted, and knowing mapbase where the binary was actually
* loaded, use them to work out the relocbase offset. */
static BOOL get_relocbase(caddr_t mapbase, caddr_t *relocbase)
{
Elf_Half i;
#ifdef _WIN64
const Elf64_Ehdr *elf_header = (Elf64_Ehdr*) mapbase;
#else
const Elf32_Ehdr *elf_header = (Elf32_Ehdr*) mapbase;
#endif
const Elf_Phdr *prog_header = (const Elf_Phdr *)(mapbase + elf_header->e_phoff);
for (i = 0; i < elf_header->e_phnum; i++)
{
if (prog_header->p_type == PT_LOAD)
{
caddr_t desired_base = (caddr_t)((prog_header->p_vaddr / prog_header->p_align) * prog_header->p_align);
*relocbase = (caddr_t) (mapbase - desired_base);
return TRUE;
}
prog_header++;
}
return FALSE;
}
#endif
/*************************************************************************
* call_constructors
*/
static void call_constructors( WINE_MODREF *wm )
{
#ifdef HAVE_DLINFO
struct link_map *map;
void (*init_func)(int, char **, char **) = NULL;
void (**init_array)(int, char **, char **) = NULL;
ULONG_PTR i, init_arraysz = 0;
int argc;
char **argv, **envp;
#ifdef _WIN64
const Elf64_Dyn *dyn;
#else
const Elf32_Dyn *dyn;
#endif
if (dlinfo( wm->so_handle, RTLD_DI_LINKMAP, &map ) == -1) return;
for (dyn = map->l_ld; dyn->d_tag; dyn++)
{
caddr_t relocbase = (caddr_t)map->l_addr;
#ifdef __FreeBSD__
/* On older FreeBSD versions, l_addr was the absolute load address, now it's the relocation offset. */
if (!dlsym(RTLD_DEFAULT, "_rtld_version_laddr_offset"))
if (!get_relocbase(map->l_addr, &relocbase)) return;
#endif
switch (dyn->d_tag)
{
case 0x60009990: init_array = (void *)(relocbase + dyn->d_un.d_val); break;
case 0x60009991: init_arraysz = dyn->d_un.d_val; break;
case 0x60009992: init_func = (void *)(relocbase + dyn->d_un.d_val); break;
}
}
TRACE( "%s: got init_func %p init_array %p %lu\n", debugstr_us( &wm->ldr.BaseDllName ),
init_func, init_array, init_arraysz );
unix_funcs->get_main_args( &argc, &argv, &envp );
if (init_func) init_func( argc, argv, envp );
if (init_array)
for (i = 0; i < init_arraysz / sizeof(*init_array); i++) init_array[i]( argc, argv, envp );
#endif
}
/*************************************************************************
* MODULE_InitDLL
*/
@ -1417,7 +1295,8 @@ static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved
if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, reason );
if (wm->so_handle && reason == DLL_PROCESS_ATTACH) call_constructors( wm );
if (wm->ldr.Flags & LDR_WINE_INTERNAL && reason == DLL_PROCESS_ATTACH)
unix_funcs->init_builtin_dll( wm->ldr.DllBase );
if (!entry) return STATUS_SUCCESS;
if (TRACE_ON(relay))
@ -2070,30 +1949,13 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name,
static NTSTATUS build_so_dll_module( const WCHAR *load_path, const UNICODE_STRING *nt_name,
void *module, DWORD flags, WINE_MODREF **pwm )
{
NTSTATUS status;
pe_image_info_t image_info = { 0 };
image_info.image_flags = IMAGE_FLAGS_WineBuiltin;
unix_funcs->virtual_create_builtin_view( module );
return build_module( load_path, nt_name, &module, &image_info, NULL, flags, pwm );
}
/***********************************************************************
* load_builtin_callback
*
* Load a library in memory; callback function for wine_dll_register
*/
static void load_builtin_callback( void *module, const char *filename )
{
if (!module)
{
ERR("could not map image for %s\n", debugstr_us(builtin_load_info->filename) );
builtin_load_info->status = STATUS_NO_MEMORY;
return;
}
builtin_load_info->status = build_so_dll_module( builtin_load_info->load_path,
builtin_load_info->filename, module,
0, &builtin_load_info->wm );
status = build_module( load_path, nt_name, &module, &image_info, NULL, flags, pwm );
if (status && module) unix_funcs->unload_builtin_dll( module );
return status;
}
@ -2481,7 +2343,7 @@ static inline char *prepend( char *buffer, const char *str, size_t len )
* open_builtin_file
*/
static NTSTATUS open_builtin_file( char *name, WINE_MODREF **pwm, void **module,
pe_image_info_t *image_info, struct file_id *id, char **so_name )
pe_image_info_t *image_info, struct file_id *id )
{
ANSI_STRING strA;
UNICODE_STRING nt_name;
@ -2513,11 +2375,20 @@ static NTSTATUS open_builtin_file( char *name, WINE_MODREF **pwm, void **module,
{
if (check_library_arch( fd ))
{
if ((*so_name = RtlAllocateHeap( GetProcessHeap(), 0, strlen(name) + 1 )))
strcpy( *so_name, name );
NtUnmapViewOfSection( NtCurrentProcess(), *module );
*module = NULL;
status = STATUS_SUCCESS;
if (!unix_funcs->load_builtin_dll( name, module ))
{
memset( id, 0, sizeof(*id) );
memset( image_info, 0, sizeof(*image_info) );
image_info->image_flags = IMAGE_FLAGS_WineBuiltin;
status = STATUS_SUCCESS;
}
else
{
ERR( "failed to load .so lib %s\n", debugstr_a(name) );
status = STATUS_PROCEDURE_NOT_FOUND;
}
}
else status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
close( fd );
@ -2530,7 +2401,7 @@ static NTSTATUS open_builtin_file( char *name, WINE_MODREF **pwm, void **module,
* find_builtin_dll
*/
static NTSTATUS find_builtin_dll( const WCHAR *name, WINE_MODREF **pwm, void **module,
pe_image_info_t *image_info, struct file_id *id, char **so_name )
pe_image_info_t *image_info, struct file_id *id )
{
unsigned int i, pos, len, namelen, maxlen = 0;
char *ptr, *file;
@ -2567,7 +2438,7 @@ static NTSTATUS find_builtin_dll( const WCHAR *name, WINE_MODREF **pwm, void **m
ptr = prepend( ptr, ptr, namelen );
ptr = prepend( ptr, "/dlls", sizeof("/dlls") - 1 );
ptr = prepend( ptr, build_dir, strlen(build_dir) );
status = open_builtin_file( ptr, pwm, module, image_info, id, so_name );
status = open_builtin_file( ptr, pwm, module, image_info, id );
if (status != STATUS_DLL_NOT_FOUND) goto done;
/* now as a program */
@ -2578,7 +2449,7 @@ static NTSTATUS find_builtin_dll( const WCHAR *name, WINE_MODREF **pwm, void **m
ptr = prepend( ptr, ptr, namelen );
ptr = prepend( ptr, "/programs", sizeof("/programs") - 1 );
ptr = prepend( ptr, build_dir, strlen(build_dir) );
status = open_builtin_file( ptr, pwm, module, image_info, id, so_name );
status = open_builtin_file( ptr, pwm, module, image_info, id );
if (status != STATUS_DLL_NOT_FOUND) goto done;
}
@ -2586,7 +2457,7 @@ static NTSTATUS find_builtin_dll( const WCHAR *name, WINE_MODREF **pwm, void **m
{
file[pos + len + 1] = 0;
ptr = prepend( file + pos, dll_paths[i], strlen(dll_paths[i]) );
status = open_builtin_file( ptr, pwm, module, image_info, id, so_name );
status = open_builtin_file( ptr, pwm, module, image_info, id );
if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
else if (status != STATUS_DLL_NOT_FOUND) goto done;
}
@ -2604,108 +2475,33 @@ done:
* load_so_dll
*/
static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
const char *so_name, DWORD flags, WINE_MODREF** pwm )
DWORD flags, WINE_MODREF **pwm )
{
static const WCHAR soW[] = {'.','s','o',0};
DWORD len;
void *handle;
const IMAGE_NT_HEADERS *nt;
struct builtin_load_info info, *prev_info;
ANSI_STRING unix_name;
void *module;
NTSTATUS status;
WINE_MODREF *wm;
UNICODE_STRING win_name = *nt_name;
unix_name.Buffer = NULL;
info.load_path = load_path;
info.filename = &win_name;
info.status = STATUS_SUCCESS;
info.wm = NULL;
if (!so_name)
TRACE( "trying %s as so lib\n", debugstr_us(&win_name) );
if (unix_funcs->load_so_dll( &win_name, &module ))
{
if (wine_nt_to_unix_file_name( nt_name, &unix_name, FILE_OPEN, FALSE ))
return STATUS_DLL_NOT_FOUND;
/* remove .so extension from Windows name */
len = nt_name->Length / sizeof(WCHAR);
if (len > 3 && !wcsicmp( nt_name->Buffer + len - 3, soW )) win_name.Length -= 3 * sizeof(WCHAR);
WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
return STATUS_INVALID_IMAGE_FORMAT;
}
TRACE( "loading %s from so lib %s\n", debugstr_us(&win_name),
debugstr_a( so_name ? so_name : unix_name.Buffer ));
prev_info = builtin_load_info;
builtin_load_info = &info;
handle = dlopen( so_name ? so_name : unix_name.Buffer, RTLD_NOW );
builtin_load_info = prev_info;
RtlFreeHeap( GetProcessHeap(), 0, unix_name.Buffer );
if (!handle)
if ((wm = get_modref( module ))) /* already loaded */
{
if (so_name)
{
ERR("failed to load .so lib %s: %s\n", debugstr_a(so_name), dlerror() );
info.status = STATUS_PROCEDURE_NOT_FOUND;
}
else
{
WARN( "failed to load .so lib %s: %s\n", debugstr_us(nt_name), dlerror() );
info.status = STATUS_INVALID_IMAGE_FORMAT;
}
}
if (info.status != STATUS_SUCCESS) goto failed;
if (!info.wm && (nt = dlsym( handle, "__wine_spec_nt_header" )))
{
HMODULE module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
if ((info.wm = get_modref( module ))) /* already loaded */
{
TRACE( "Found %s at %p for builtin %s\n",
debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.DllBase,
debugstr_us(nt_name) );
if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
dlclose( handle );
}
else
{
if ((info.status = unix_funcs->map_so_dll( nt, module ))) goto failed;
if ((info.status = build_so_dll_module( load_path, &win_name, module, flags, &info.wm )))
goto failed;
TRACE_(loaddll)( "Loaded %s at %p: builtin\n",
debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.DllBase );
info.wm->ldr.LoadCount = 1;
info.wm->so_handle = handle;
}
}
else if (!info.wm)
{
/* The constructor wasn't called, this means the .so is already
* loaded under a different name. Try to find the wm for it. */
if (!(info.wm = find_so_module( handle )))
{
info.status = STATUS_INVALID_IMAGE_FORMAT;
goto failed;
}
TRACE( "Found %s at %p for builtin %s\n",
debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.DllBase,
debugstr_us(nt_name) );
if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
dlclose( handle ); /* release the libdl refcount */
debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
}
else
{
TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.DllBase );
info.wm->ldr.LoadCount = 1;
info.wm->so_handle = handle;
if ((status = build_so_dll_module( load_path, &win_name, module, flags, &wm ))) return status;
TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
}
*pwm = info.wm;
*pwm = wm;
return STATUS_SUCCESS;
failed:
if (handle) dlclose( handle );
return info.status;
}
@ -2720,7 +2516,6 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_na
void *module = NULL;
pe_image_info_t image_info;
struct file_id id;
char *so_name;
/* Fix the name in case we have a full path and extension */
name = nt_name->Buffer;
@ -2731,7 +2526,7 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_na
if (!module_ptr) module_ptr = &module;
status = find_builtin_dll( name, pwm, module_ptr, &image_info, &id, &so_name );
status = find_builtin_dll( name, pwm, module_ptr, &image_info, &id );
if (status) return status;
if (*pwm)
@ -2743,14 +2538,9 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_na
return STATUS_SUCCESS;
}
if (*module_ptr)
{
TRACE( "loading %s from PE builtin %s\n", debugstr_w(name), debugstr_us(nt_name) );
return load_native_dll( load_path, nt_name, module_ptr, &image_info, &id, flags, pwm );
}
status = load_so_dll( load_path, nt_name, so_name, flags, pwm );
RtlFreeHeap( GetProcessHeap(), 0, so_name );
TRACE( "loading %s from %s\n", debugstr_w(name), debugstr_us(nt_name) );
status = build_module( load_path, nt_name, module_ptr, &image_info, &id, flags, pwm );
if (status && *module_ptr) unix_funcs->unload_builtin_dll( *module_ptr );
return status;
}
@ -3030,7 +2820,7 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
case LO_BUILTIN:
case LO_BUILTIN_NATIVE:
case LO_DEFAULT:
if (!load_so_dll( load_path, &nt_name, NULL, flags, pwm )) nts = STATUS_SUCCESS;
if (!load_so_dll( load_path, &nt_name, flags, pwm )) nts = STATUS_SUCCESS;
break;
default:
nts = STATUS_DLL_NOT_FOUND;
@ -3628,7 +3418,7 @@ static void free_modref( WINE_MODREF *wm )
free_tls_slot( &wm->ldr );
RtlReleaseActivationContext( wm->ldr.ActivationContext );
if (wm->so_handle) dlclose( wm->so_handle );
unix_funcs->unload_builtin_dll( wm->ldr.DllBase );
NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
if (cached_modref == wm) cached_modref = NULL;
RtlFreeUnicodeString( &wm->ldr.FullDllName );
@ -3845,7 +3635,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknow
attach_implicitly_loaded_dlls( context );
unix_funcs->virtual_release_address_space();
if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
if (wm->so_handle) call_constructors( wm );
if (wm->ldr.Flags & LDR_WINE_INTERNAL) unix_funcs->init_builtin_dll( wm->ldr.DllBase );
if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
}
else
@ -4351,8 +4141,6 @@ void __wine_process_init(void)
status = build_so_dll_module( params->DllPath.Buffer, &nt_name, ntdll_module, 0, &wm );
assert( !status );
wine_dll_set_callback( load_builtin_callback );
RtlInitUnicodeString( &nt_name, kernel32W );
if ((status = load_builtin_dll( params->DllPath.Buffer, &nt_name, NULL, 0, &wm )) != STATUS_SUCCESS)
{

View file

@ -74,10 +74,6 @@ extern void init_user_process_params( SIZE_T data_size ) DECLSPEC_HIDDEN;
extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN;
extern NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) DECLSPEC_HIDDEN;
extern int __wine_main_argc;
extern char **__wine_main_argv;
extern WCHAR **__wine_main_wargv;
/* server support */
extern const char *build_dir DECLSPEC_HIDDEN;
extern const char *data_dir DECLSPEC_HIDDEN;
@ -107,9 +103,6 @@ extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN;
extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN;
extern void init_directories(void) DECLSPEC_HIDDEN;
/* virtual memory */
extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN;
/* locale */

View file

@ -67,9 +67,9 @@ extern WCHAR **__wine_main_wargv;
USHORT *uctable = NULL, *lctable = NULL;
static int main_argc;
static char **main_argv;
static char **main_envp;
int main_argc = 0;
char **main_argv = NULL;
char **main_envp = NULL;
static WCHAR **main_wargv;
static CPTABLEINFO unix_table;
@ -802,19 +802,6 @@ void init_environment( int argc, char *argv[], char *envp[] )
}
/*************************************************************************
* get_main_args
*
* Return the initial arguments.
*/
void CDECL get_main_args( int *argc, char **argv[], char **envp[] )
{
*argc = main_argc;
*argv = main_argv;
*envp = main_envp;
}
/*************************************************************************
* get_initial_environment
*

View file

@ -30,6 +30,9 @@
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#ifdef HAVE_LINK_H
# include <link.h>
#endif
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
@ -82,10 +85,11 @@
#include "winnls.h"
#include "winternl.h"
#include "unix_private.h"
#include "wine/list.h"
#include "wine/library.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
WINE_DEFAULT_DEBUG_CHANNEL(module);
extern IMAGE_NT_HEADERS __wine_spec_nt_header;
@ -121,6 +125,26 @@ static SIZE_T dll_path_maxlen;
const char *data_dir = NULL;
const char *build_dir = NULL;
const char *config_dir = NULL;
HMODULE ntdll_module = NULL;
struct builtin_module
{
struct list entry;
void *handle;
void *module;
};
static struct list builtin_modules = LIST_INIT( builtin_modules );
static NTSTATUS add_builtin_module( void *module, void *handle )
{
struct builtin_module *builtin;
if (!(builtin = malloc( sizeof(*builtin) ))) return STATUS_NO_MEMORY;
builtin->handle = handle;
builtin->module = module;
list_add_tail( &builtin_modules, &builtin->entry );
return STATUS_SUCCESS;
}
static inline void *get_rva( const IMAGE_NT_HEADERS *nt, ULONG_PTR addr )
{
@ -569,7 +593,7 @@ void start_server( BOOL debug )
*
* Map a builtin dll in memory and fixup RVAs.
*/
static NTSTATUS CDECL map_so_dll( const IMAGE_NT_HEADERS *nt_descr, HMODULE module )
static NTSTATUS map_so_dll( const IMAGE_NT_HEADERS *nt_descr, HMODULE module )
{
static const char builtin_signature[32] = "Wine builtin DLL";
IMAGE_DATA_DIRECTORY *dir;
@ -762,7 +786,7 @@ static ULONG_PTR find_pe_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *e
return find_named_export( module, exports, (char *)name->Name );
}
static void fixup_ntdll_imports( const IMAGE_NT_HEADERS *nt, HMODULE ntdll_module )
static void fixup_ntdll_imports( const IMAGE_NT_HEADERS *nt )
{
const IMAGE_EXPORT_DIRECTORY *ntdll_exports = get_export_dir( ntdll_module );
const IMAGE_IMPORT_DESCRIPTOR *descr;
@ -813,29 +837,224 @@ static void fixup_ntdll_imports( const IMAGE_NT_HEADERS *nt, HMODULE ntdll_modul
#undef GET_FUNC
}
static void *callback_module;
/***********************************************************************
* load_builtin_callback
*
* Load a library in memory; callback function for wine_dll_register
*/
static void load_builtin_callback( void *module, const char *filename )
{
callback_module = module;
}
/***********************************************************************
* dlopen_dll
*/
static NTSTATUS dlopen_dll( const char *so_name, void **ret_module )
{
struct builtin_module *builtin;
void *module, *handle;
const IMAGE_NT_HEADERS *nt;
callback_module = (void *)1;
handle = dlopen( so_name, RTLD_NOW );
if (!handle)
{
WARN( "failed to load .so lib %s: %s\n", debugstr_a(so_name), dlerror() );
return STATUS_INVALID_IMAGE_FORMAT;
}
if (callback_module != (void *)1) /* callback was called */
{
if (!callback_module) return STATUS_NO_MEMORY;
WARN( "got old-style builtin library %s, constructors won't work\n", debugstr_a(so_name) );
module = callback_module;
LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
if (builtin->module == module) goto already_loaded;
}
else if ((nt = dlsym( handle, "__wine_spec_nt_header" )))
{
module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
if (builtin->module == module) goto already_loaded;
if (map_so_dll( nt, module ))
{
dlclose( handle );
return STATUS_NO_MEMORY;
}
}
else /* already loaded .so */
{
WARN( "%s already loaded?\n", debugstr_a(so_name));
LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
if (builtin->handle == handle) goto already_loaded;
return STATUS_INVALID_IMAGE_FORMAT;
}
if (add_builtin_module( module, handle ))
{
dlclose( handle );
return STATUS_NO_MEMORY;
}
virtual_create_builtin_view( module );
*ret_module = module;
return STATUS_SUCCESS;
already_loaded:
*ret_module = builtin->module;
dlclose( handle );
return STATUS_SUCCESS;
}
/***********************************************************************
* load_so_dll
*/
static NTSTATUS CDECL load_so_dll( UNICODE_STRING *nt_name, void **module )
{
static const WCHAR soW[] = {'.','s','o',0};
ANSI_STRING unix_name;
NTSTATUS status;
DWORD len;
if (nt_to_unix_file_name( nt_name, &unix_name, FILE_OPEN, FALSE )) return STATUS_DLL_NOT_FOUND;
/* remove .so extension from Windows name */
len = nt_name->Length / sizeof(WCHAR);
if (len > 3 && !wcsicmp( nt_name->Buffer + len - 3, soW )) nt_name->Length -= 3 * sizeof(WCHAR);
status = dlopen_dll( unix_name.Buffer, module );
RtlFreeAnsiString( &unix_name );
return status;
}
/***********************************************************************
* load_builtin_dll
*/
static NTSTATUS CDECL load_builtin_dll( const char *so_name, void **module )
{
return dlopen_dll( so_name, module );
}
/***********************************************************************
* unload_builtin_dll
*/
static NTSTATUS CDECL unload_builtin_dll( void *module )
{
struct builtin_module *builtin;
LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
{
if (builtin->module != module) continue;
list_remove( &builtin->entry );
if (builtin->handle) dlclose( builtin->handle );
free( builtin );
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
#ifdef __FreeBSD__
/* The PT_LOAD segments are sorted in increasing order, and the first
* starts at the beginning of the ELF file. By parsing the file, we can
* find that first PT_LOAD segment, from which we can find the base
* address it wanted, and knowing mapbase where the binary was actually
* loaded, use them to work out the relocbase offset. */
static BOOL get_relocbase(caddr_t mapbase, caddr_t *relocbase)
{
Elf_Half i;
#ifdef _WIN64
const Elf64_Ehdr *elf_header = (Elf64_Ehdr*) mapbase;
#else
const Elf32_Ehdr *elf_header = (Elf32_Ehdr*) mapbase;
#endif
const Elf_Phdr *prog_header = (const Elf_Phdr *)(mapbase + elf_header->e_phoff);
for (i = 0; i < elf_header->e_phnum; i++)
{
if (prog_header->p_type == PT_LOAD)
{
caddr_t desired_base = (caddr_t)((prog_header->p_vaddr / prog_header->p_align) * prog_header->p_align);
*relocbase = (caddr_t) (mapbase - desired_base);
return TRUE;
}
prog_header++;
}
return FALSE;
}
#endif
/*************************************************************************
* init_builtin_dll
*/
static void CDECL init_builtin_dll( void *module )
{
#ifdef HAVE_DLINFO
struct builtin_module *builtin;
struct link_map *map;
void (*init_func)(int, char **, char **) = NULL;
void (**init_array)(int, char **, char **) = NULL;
ULONG_PTR i, init_arraysz = 0;
#ifdef _WIN64
const Elf64_Dyn *dyn;
#else
const Elf32_Dyn *dyn;
#endif
LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
{
if (builtin->module != module) continue;
if (!builtin->handle) break;
if (!dlinfo( builtin->handle, RTLD_DI_LINKMAP, &map )) goto found;
break;
}
return;
found:
for (dyn = map->l_ld; dyn->d_tag; dyn++)
{
caddr_t relocbase = (caddr_t)map->l_addr;
#ifdef __FreeBSD__
/* On older FreeBSD versions, l_addr was the absolute load address, now it's the relocation offset. */
if (!dlsym(RTLD_DEFAULT, "_rtld_version_laddr_offset"))
if (!get_relocbase(map->l_addr, &relocbase)) return;
#endif
switch (dyn->d_tag)
{
case 0x60009990: init_array = (void *)(relocbase + dyn->d_un.d_val); break;
case 0x60009991: init_arraysz = dyn->d_un.d_val; break;
case 0x60009992: init_func = (void *)(relocbase + dyn->d_un.d_val); break;
}
}
TRACE( "%p: got init_func %p init_array %p %lu\n", module, init_func, init_array, init_arraysz );
if (init_func) init_func( main_argc, main_argv, main_envp );
if (init_array)
for (i = 0; i < init_arraysz / sizeof(*init_array); i++)
init_array[i]( main_argc, main_argv, main_envp );
#endif
}
/***********************************************************************
* load_ntdll
*/
static HMODULE load_ntdll(void)
{
const IMAGE_NT_HEADERS *nt;
HMODULE module;
Dl_info info;
char *name;
void *handle;
void *module;
char *name = build_path( dll_dir, "ntdll.dll.so" );
NTSTATUS status = dlopen_dll( name, &module );
name = build_path( dll_dir, "ntdll.dll.so" );
if (!dladdr( load_ntdll, &info )) fatal_error( "cannot get path to ntdll.so\n" );
name = malloc( strlen(info.dli_fname) + 5 );
strcpy( name, info.dli_fname );
strcpy( name + strlen(info.dli_fname) - 3, ".dll.so" );
if (!(handle = dlopen( name, RTLD_NOW ))) fatal_error( "failed to load %s: %s\n", name, dlerror() );
if (!(nt = dlsym( handle, "__wine_spec_nt_header" )))
fatal_error( "NT header not found in %s (too old?)\n", name );
dll_dir = realpath_dirname( name );
if (status) fatal_error( "failed to load %s error %x\n", name, status );
free( name );
module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
map_so_dll( nt, module );
return module;
}
@ -1000,7 +1219,6 @@ static struct unix_funcs unix_funcs =
fast_RtlSleepConditionVariableSRW,
fast_RtlSleepConditionVariableCS,
fast_RtlWakeConditionVariable,
get_main_args,
get_initial_environment,
get_initial_directory,
get_paths,
@ -1010,10 +1228,8 @@ static struct unix_funcs unix_funcs =
get_version,
get_build_id,
get_host_version,
map_so_dll,
virtual_map_section,
virtual_get_system_info,
virtual_create_builtin_view,
virtual_alloc_thread_stack,
virtual_locked_recvmsg,
virtual_release_address_space,
@ -1031,6 +1247,10 @@ static struct unix_funcs unix_funcs =
nt_to_unix_file_name,
unix_to_nt_file_name,
set_show_dot_files,
load_so_dll,
load_builtin_dll,
unload_builtin_dll,
init_builtin_dll,
__wine_dbg_get_channel_flags,
__wine_dbg_strdup,
__wine_dbg_output,
@ -1266,8 +1486,6 @@ static void check_command_line( int argc, char *argv[] )
*/
void __wine_main( int argc, char *argv[], char *envp[] )
{
HMODULE module;
init_paths( argc, argv, envp );
if (!getenv( "WINELOADERNOEXEC" )) /* first time around */
@ -1294,10 +1512,11 @@ void __wine_main( int argc, char *argv[], char *envp[] )
virtual_init();
module = load_ntdll();
fixup_ntdll_imports( &__wine_spec_nt_header, module );
ntdll_module = load_ntdll();
fixup_ntdll_imports( &__wine_spec_nt_header );
init_environment( argc, argv, envp );
wine_dll_set_callback( load_builtin_callback );
#ifdef __APPLE__
apple_main_thread();
@ -1329,9 +1548,11 @@ NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, const void *ptr_in, void
#endif
init_paths( __wine_main_argc, __wine_main_argv, envp );
ntdll_module = module;
map_so_dll( nt, module );
fixup_ntdll_imports( &__wine_spec_nt_header, module );
fixup_ntdll_imports( &__wine_spec_nt_header );
init_environment( __wine_main_argc, __wine_main_argv, envp );
wine_dll_set_callback( load_builtin_callback );
*(struct unix_funcs **)ptr_out = &unix_funcs;
wine_mmap_enum_reserved_areas( add_area, NULL, 0 );
return STATUS_SUCCESS;

View file

@ -104,6 +104,7 @@ TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZ
server_init_process();
info_size = server_init_thread( teb->Peb, suspend );
virtual_map_user_shared_data();
virtual_create_builtin_view( ntdll_module );
init_files();
NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 );

View file

@ -95,7 +95,6 @@ void CDECL mmap_remove_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg), void *arg,
int top_down ) DECLSPEC_HIDDEN;
extern void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN;
extern void CDECL get_initial_directory( UNICODE_STRING *dir ) DECLSPEC_HIDDEN;
extern void CDECL get_unix_codepage( CPTABLEINFO *table ) DECLSPEC_HIDDEN;
@ -104,7 +103,6 @@ extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsig
const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type,
ULONG protect, pe_image_info_t *image_info ) DECLSPEC_HIDDEN;
extern void CDECL virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL virtual_create_builtin_view( void *module ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN;
extern ssize_t CDECL virtual_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) DECLSPEC_HIDDEN;
extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN;
@ -132,8 +130,12 @@ extern void CDECL set_show_dot_files( BOOL enable ) DECLSPEC_HIDDEN;
extern const char *data_dir DECLSPEC_HIDDEN;
extern const char *build_dir DECLSPEC_HIDDEN;
extern const char *config_dir DECLSPEC_HIDDEN;
extern HMODULE ntdll_module DECLSPEC_HIDDEN;
extern USHORT *uctable DECLSPEC_HIDDEN;
extern USHORT *lctable DECLSPEC_HIDDEN;
extern int main_argc DECLSPEC_HIDDEN;
extern char **main_argv DECLSPEC_HIDDEN;
extern char **main_envp DECLSPEC_HIDDEN;
extern unsigned int server_cpus DECLSPEC_HIDDEN;
extern BOOL is_wow64 DECLSPEC_HIDDEN;
extern HANDLE keyed_event DECLSPEC_HIDDEN;
@ -181,6 +183,7 @@ extern NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct o
extern void virtual_init(void) DECLSPEC_HIDDEN;
extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_create_builtin_view( void *module ) DECLSPEC_HIDDEN;
extern TEB *virtual_alloc_first_teb(void) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb ) DECLSPEC_HIDDEN;
extern void virtual_free_teb( TEB *teb ) DECLSPEC_HIDDEN;

View file

@ -2498,11 +2498,12 @@ void CDECL virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info )
/***********************************************************************
* virtual_create_builtin_view
*/
NTSTATUS CDECL virtual_create_builtin_view( void *module )
NTSTATUS virtual_create_builtin_view( void *module )
{
NTSTATUS status;
sigset_t sigset;
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
IMAGE_DOS_HEADER *dos = module;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
SIZE_T size = nt->OptionalHeader.SizeOfImage;
IMAGE_SECTION_HEADER *sec;
struct file_view *view;
@ -2511,7 +2512,7 @@ NTSTATUS CDECL virtual_create_builtin_view( void *module )
size = ROUND_SIZE( module, size );
base = ROUND_ADDR( module, page_mask );
server_enter_uninterrupted_section( &csVirtual, &sigset );
if (use_locks) server_enter_uninterrupted_section( &csVirtual, &sigset );
status = create_view( &view, base, size, SEC_IMAGE | SEC_FILE | VPROT_SYSTEM |
VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC );
if (!status)
@ -2533,7 +2534,7 @@ NTSTATUS CDECL virtual_create_builtin_view( void *module )
}
VIRTUAL_DEBUG_DUMP_VIEW( view );
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
if (use_locks) server_leave_uninterrupted_section( &csVirtual, &sigset );
return status;
}

View file

@ -28,7 +28,7 @@ struct ldt_copy;
struct msghdr;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 57
#define NTDLL_UNIXLIB_VERSION 58
struct unix_funcs
{
@ -277,7 +277,6 @@ struct unix_funcs
NTSTATUS (CDECL *fast_RtlWakeConditionVariable)( RTL_CONDITION_VARIABLE *variable, int count );
/* environment functions */
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
NTSTATUS (CDECL *get_initial_environment)( WCHAR **wargv[], WCHAR *env, SIZE_T *size );
void (CDECL *get_initial_directory)( UNICODE_STRING *dir );
void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir );
@ -289,12 +288,10 @@ struct unix_funcs
void (CDECL *get_host_version)( const char **sysname, const char **release );
/* virtual memory functions */
NTSTATUS (CDECL *map_so_dll)( const IMAGE_NT_HEADERS *nt_descr, HMODULE module );
NTSTATUS (CDECL *virtual_map_section)( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size,
const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type,
ULONG protect, pe_image_info_t *image_info );
void (CDECL *virtual_get_system_info)( SYSTEM_BASIC_INFORMATION *info );
NTSTATUS (CDECL *virtual_create_builtin_view)( void *module );
NTSTATUS (CDECL *virtual_alloc_thread_stack)( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size );
ssize_t (CDECL *virtual_locked_recvmsg)( int fd, struct msghdr *hdr, int flags );
void (CDECL *virtual_release_address_space)(void);
@ -323,6 +320,12 @@ struct unix_funcs
NTSTATUS (CDECL *unix_to_nt_file_name)( const ANSI_STRING *name, UNICODE_STRING *nt );
void (CDECL *set_show_dot_files)( BOOL enable );
/* loader functions */
NTSTATUS (CDECL *load_so_dll)( UNICODE_STRING *nt_name, void **module );
NTSTATUS (CDECL *load_builtin_dll)( const char *so_name, void **module );
NTSTATUS (CDECL *unload_builtin_dll)( void *module );
void (CDECL *init_builtin_dll)( void *module );
/* debugging functions */
unsigned char (CDECL *dbg_get_channel_flags)( struct __wine_debug_channel *channel );
const char * (CDECL *dbg_strdup)( const char *str );

View file

@ -201,39 +201,6 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
}
/******************************************************************************
* virtual_fill_image_information
*
* Helper for NtQuerySection.
*/
void virtual_fill_image_information( const pe_image_info_t *pe_info, SECTION_IMAGE_INFORMATION *info )
{
info->TransferAddress = wine_server_get_ptr( pe_info->entry_point );
info->ZeroBits = pe_info->zerobits;
info->MaximumStackSize = pe_info->stack_size;
info->CommittedStackSize = pe_info->stack_commit;
info->SubSystemType = pe_info->subsystem;
info->SubsystemVersionLow = pe_info->subsystem_low;
info->SubsystemVersionHigh = pe_info->subsystem_high;
info->GpValue = pe_info->gp;
info->ImageCharacteristics = pe_info->image_charact;
info->DllCharacteristics = pe_info->dll_charact;
info->Machine = pe_info->machine;
info->ImageContainsCode = pe_info->contains_code;
info->u.ImageFlags = pe_info->image_flags & ~(IMAGE_FLAGS_WineBuiltin|IMAGE_FLAGS_WineFakeDll);
info->LoaderFlags = pe_info->loader_flags;
info->ImageFileSize = pe_info->file_size;
info->CheckSum = pe_info->checksum;
#ifndef _WIN64 /* don't return 64-bit values to 32-bit processes */
if (pe_info->machine == IMAGE_FILE_MACHINE_AMD64 || pe_info->machine == IMAGE_FILE_MACHINE_ARM64)
{
info->TransferAddress = (void *)0x81231234; /* sic */
info->MaximumStackSize = 0x100000;
info->CommittedStackSize = 0x10000;
}
#endif
}
/******************************************************************************
* NtQuerySection (NTDLL.@)
* ZwQuerySection (NTDLL.@)