From 31538a79a90653afb8bc7744506989c8811a800d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 23 Jun 2020 19:39:12 +0200 Subject: [PATCH] ntdll: Move the loading of .so dlls to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/ntdll/loader.c | 300 +++++---------------------------- dlls/ntdll/ntdll_misc.h | 7 - dlls/ntdll/unix/env.c | 19 +-- dlls/ntdll/unix/loader.c | 275 +++++++++++++++++++++++++++--- dlls/ntdll/unix/thread.c | 1 + dlls/ntdll/unix/unix_private.h | 7 +- dlls/ntdll/unix/virtual.c | 9 +- dlls/ntdll/unixlib.h | 11 +- dlls/ntdll/virtual.c | 33 ---- 9 files changed, 313 insertions(+), 349 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 1a2eb658db0..866814951b6 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -24,12 +24,6 @@ #include #include -#ifdef HAVE_LINK_H -# include -#endif -#ifdef HAVE_SYS_MMAN_H -# include -#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) { diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index f433e02aeb6..e2276f1ead5 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -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 */ diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index de03bb566d3..c03dfe64565 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -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 * diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 51ff7f950e8..608bc513d2c 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -30,6 +30,9 @@ #include #include #include +#ifdef HAVE_LINK_H +# include +#endif #ifdef HAVE_PWD_H # include #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; diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 2e2e5a3882d..d6c9c2de1e3 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -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 ); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index e0bc5a9603e..beef6358623 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -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; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 6166507871c..f142d2948dd 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -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; } diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 311d99f482d..7a891a38040 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -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 ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 9556761840b..2572fa01f41 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -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.@)