Moved the final process init and dependency loading to
dlls/ntdll/loader.c, (ab)using the LdrInitializeThunk entry point.
This commit is contained in:
parent
5dc5bf5d8a
commit
632676b17e
|
@ -45,7 +45,6 @@
|
|||
WINE_DEFAULT_DEBUG_CHANNEL(process);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(server);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(snoop);
|
||||
|
||||
/* Win32 process database */
|
||||
typedef struct _PDB
|
||||
|
@ -125,7 +124,6 @@ static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0};
|
|||
/* dlls/ntdll/env.c */
|
||||
extern BOOL build_command_line( char **argv );
|
||||
|
||||
extern void RELAY_InitDebugLists(void);
|
||||
extern void SHELL_LoadRegistry(void);
|
||||
extern void VERSION_Init( const WCHAR *appname );
|
||||
extern void MODULE_InitLoadPath(void);
|
||||
|
@ -331,7 +329,7 @@ static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, int buflen, HANDLE
|
|||
*
|
||||
* Load a PE format EXE file.
|
||||
*/
|
||||
static HMODULE load_pe_exe( HANDLE file )
|
||||
static HMODULE load_pe_exe( const WCHAR *name, HANDLE file )
|
||||
{
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
HANDLE mapping;
|
||||
|
@ -339,6 +337,7 @@ static HMODULE load_pe_exe( HANDLE file )
|
|||
OBJECT_ATTRIBUTES attr;
|
||||
LARGE_INTEGER size;
|
||||
DWORD len = 0;
|
||||
UINT drive_type;
|
||||
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = 0;
|
||||
|
@ -364,10 +363,19 @@ static HMODULE load_pe_exe( HANDLE file )
|
|||
if (nt->OptionalHeader.AddressOfEntryPoint)
|
||||
{
|
||||
if (!RtlImageRvaToSection( nt, module, nt->OptionalHeader.AddressOfEntryPoint ))
|
||||
MESSAGE("VIRUS WARNING: PE module has an invalid entrypoint (0x%08lx) "
|
||||
MESSAGE("VIRUS WARNING: PE module %s has an invalid entrypoint (0x%08lx) "
|
||||
"outside all sections (possibly infected by Tchernobyl/SpaceFiller virus)!\n",
|
||||
nt->OptionalHeader.AddressOfEntryPoint );
|
||||
debugstr_w(name), nt->OptionalHeader.AddressOfEntryPoint );
|
||||
}
|
||||
|
||||
drive_type = GetDriveTypeW( name );
|
||||
/* don't keep the file handle open on removable media */
|
||||
if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM)
|
||||
{
|
||||
CloseHandle( main_exe_file );
|
||||
main_exe_file = 0;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
|
@ -610,8 +618,6 @@ static BOOL process_init( char *argv[] )
|
|||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY_InitDebugLists();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -625,65 +631,7 @@ static void start_process( void *arg )
|
|||
{
|
||||
__TRY
|
||||
{
|
||||
LPTHREAD_START_ROUTINE entry;
|
||||
HANDLE main_file = main_exe_file;
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
PEB *peb = NtCurrentTeb()->Peb;
|
||||
UNICODE_STRING *main_exe_name = &peb->ProcessParameters->ImagePathName;
|
||||
|
||||
if (main_file)
|
||||
{
|
||||
UINT drive_type = GetDriveTypeW( main_exe_name->Buffer );
|
||||
/* don't keep the file handle open on removable media */
|
||||
if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM) main_file = 0;
|
||||
}
|
||||
|
||||
/* Retrieve entry point address */
|
||||
nt = RtlImageNtHeader( peb->ImageBaseAddress );
|
||||
entry = (LPTHREAD_START_ROUTINE)((char*)peb->ImageBaseAddress +
|
||||
nt->OptionalHeader.AddressOfEntryPoint);
|
||||
|
||||
/* Install signal handlers; this cannot be done before, since we cannot
|
||||
* send exceptions to the debugger before the create process event that
|
||||
* is sent by REQ_INIT_PROCESS_DONE.
|
||||
* We do need the handlers in place by the time the request is over, so
|
||||
* we set them up here. If we segfault between here and the server call
|
||||
* something is very wrong... */
|
||||
if (!SIGNAL_Init()) goto error;
|
||||
|
||||
/* Signal the parent process to continue */
|
||||
SERVER_START_REQ( init_process_done )
|
||||
{
|
||||
req->module = peb->ImageBaseAddress;
|
||||
req->module_size = nt->OptionalHeader.SizeOfImage;
|
||||
req->entry = entry;
|
||||
/* API requires a double indirection */
|
||||
req->name = &main_exe_name->Buffer;
|
||||
req->exe_file = main_file;
|
||||
req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI);
|
||||
wine_server_add_data( req, main_exe_name->Buffer, main_exe_name->Length );
|
||||
wine_server_call( req );
|
||||
peb->BeingDebugged = reply->debugged;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
/* create the main modref and load dependencies */
|
||||
if (main_exe_file) CloseHandle( main_exe_file ); /* we no longer need it */
|
||||
if (MODULE_DllProcessAttach( NULL, (LPVOID)1 ) != STATUS_SUCCESS)
|
||||
{
|
||||
ERR( "Main exe initialization failed\n" );
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
DPRINTF( "%04lx:Starting process %s (entryproc=%p)\n",
|
||||
GetCurrentThreadId(), debugstr_w(main_exe_name->Buffer), entry );
|
||||
if (peb->BeingDebugged) DbgBreakPoint();
|
||||
SetLastError(0); /* clear error code */
|
||||
ExitThread( entry( NtCurrentTeb()->Peb ) );
|
||||
|
||||
error:
|
||||
ExitProcess( GetLastError() );
|
||||
LdrInitializeThunk( main_exe_file, 0, 0, 0 );
|
||||
}
|
||||
__EXCEPT(UnhandledExceptionFilter)
|
||||
{
|
||||
|
@ -753,7 +701,7 @@ void __wine_process_init( int argc, char *argv[] )
|
|||
{
|
||||
case BINARY_PE_EXE:
|
||||
TRACE( "starting Win32 binary %s\n", debugstr_w(main_exe_name) );
|
||||
if ((current_process.module = load_pe_exe( main_exe_file ))) goto found;
|
||||
if ((current_process.module = load_pe_exe( main_exe_name, main_exe_file ))) goto found;
|
||||
MESSAGE( "wine: could not load %s as Win32 binary\n", debugstr_w(main_exe_name) );
|
||||
ExitProcess(1);
|
||||
case BINARY_PE_DLL:
|
||||
|
|
|
@ -66,12 +66,12 @@ static const char * const reason_names[] =
|
|||
static const WCHAR dllW[] = {'.','d','l','l',0};
|
||||
|
||||
/* internal representation of 32bit modules. per process. */
|
||||
struct _wine_modref
|
||||
typedef struct _wine_modref
|
||||
{
|
||||
LDR_MODULE ldr;
|
||||
int nDeps;
|
||||
struct _wine_modref **deps;
|
||||
};
|
||||
} WINE_MODREF;
|
||||
|
||||
static UINT tls_module_count; /* number of modules with TLS directory */
|
||||
static UINT tls_total_size; /* total size of TLS storage */
|
||||
|
@ -675,7 +675,7 @@ static BOOL MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
|
|||
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllProcessAttach
|
||||
* process_attach
|
||||
*
|
||||
* Send the process attach notification to all DLLs the given module
|
||||
* depends on (recursively). This is somewhat complicated due to the fact that
|
||||
|
@ -702,34 +702,18 @@ static BOOL MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
|
|||
* list after the attach notification has returned. This implies that the
|
||||
* detach notifications are called in the reverse of the sequence the attach
|
||||
* notifications *returned*.
|
||||
*
|
||||
* The loader_section must be locked while calling this function.
|
||||
*/
|
||||
NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
|
||||
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
int i;
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
if (!wm)
|
||||
{
|
||||
/* allocate the modref for the main exe */
|
||||
if (!(wm = alloc_module( NtCurrentTeb()->Peb->ImageBaseAddress,
|
||||
NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer )))
|
||||
{
|
||||
status = STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
wm->ldr.LoadCount = -1; /* can't unload main exe */
|
||||
if ((status = fixup_imports( wm )) != STATUS_SUCCESS) goto done;
|
||||
if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done;
|
||||
if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
|
||||
}
|
||||
assert( wm );
|
||||
|
||||
/* prevent infinite recursion in case of cyclical dependencies */
|
||||
if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
|
||||
|| ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
|
||||
goto done;
|
||||
return status;
|
||||
|
||||
TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
|
||||
|
||||
|
@ -740,7 +724,7 @@ NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
|
|||
for ( i = 0; i < wm->nDeps; i++ )
|
||||
{
|
||||
if (!wm->deps[i]) continue;
|
||||
if ((status = MODULE_DllProcessAttach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
|
||||
if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
|
||||
}
|
||||
|
||||
/* Call DLL entry point */
|
||||
|
@ -762,20 +746,17 @@ NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
|
|||
wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
|
||||
|
||||
TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
|
||||
|
||||
done:
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllProcessDetach
|
||||
* process_detach
|
||||
*
|
||||
* Send DLL process detach notifications. See the comment about calling
|
||||
* sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
|
||||
* sequence at process_attach. Unless the bForceDetach flag
|
||||
* is set, only DLLs with zero refcount are notified.
|
||||
*/
|
||||
static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
|
||||
static void process_detach( BOOL bForceDetach, LPVOID lpReserved )
|
||||
{
|
||||
PLIST_ENTRY mark, entry;
|
||||
PLDR_MODULE mod;
|
||||
|
@ -1393,7 +1374,7 @@ NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags,
|
|||
|
||||
if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
|
||||
{
|
||||
nts = MODULE_DllProcessAttach( wm, NULL );
|
||||
nts = process_attach( wm, NULL );
|
||||
if (nts != STATUS_SUCCESS)
|
||||
{
|
||||
WARN("Attach failed for module %s\n", debugstr_w(libname->Buffer));
|
||||
|
@ -1466,7 +1447,7 @@ NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi,
|
|||
void WINAPI LdrShutdownProcess(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
|
||||
process_detach( TRUE, (LPVOID)1 );
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -1614,7 +1595,7 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
|
|||
/* Call process detach notifications */
|
||||
if ( free_lib_count <= 1 )
|
||||
{
|
||||
MODULE_DllProcessDetach( FALSE, NULL );
|
||||
process_detach( FALSE, NULL );
|
||||
MODULE_FlushModrefs();
|
||||
}
|
||||
|
||||
|
@ -1658,6 +1639,79 @@ PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* LdrInitializeThunk (NTDLL.@)
|
||||
*
|
||||
* FIXME: the arguments are not correct, main_file is a Wine invention.
|
||||
*/
|
||||
void WINAPI LdrInitializeThunk( HANDLE main_file, ULONG unknown2, ULONG unknown3, ULONG unknown4 )
|
||||
{
|
||||
NTSTATUS status;
|
||||
WINE_MODREF *wm;
|
||||
LPTHREAD_START_ROUTINE entry;
|
||||
PEB *peb = NtCurrentTeb()->Peb;
|
||||
UNICODE_STRING *main_exe_name = &peb->ProcessParameters->ImagePathName;
|
||||
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress );
|
||||
|
||||
/* allocate the modref for the main exe */
|
||||
if (!(wm = alloc_module( peb->ImageBaseAddress, main_exe_name->Buffer )))
|
||||
{
|
||||
status = STATUS_NO_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
wm->ldr.LoadCount = -1; /* can't unload main exe */
|
||||
entry = wm->ldr.EntryPoint;
|
||||
|
||||
/* Install signal handlers; this cannot be done before, since we cannot
|
||||
* send exceptions to the debugger before the create process event that
|
||||
* is sent by REQ_INIT_PROCESS_DONE.
|
||||
* We do need the handlers in place by the time the request is over, so
|
||||
* we set them up here. If we segfault between here and the server call
|
||||
* something is very wrong... */
|
||||
if (!SIGNAL_Init()) exit(1);
|
||||
|
||||
/* Signal the parent process to continue */
|
||||
SERVER_START_REQ( init_process_done )
|
||||
{
|
||||
req->module = peb->ImageBaseAddress;
|
||||
req->module_size = wm->ldr.SizeOfImage;
|
||||
req->entry = entry;
|
||||
/* API requires a double indirection */
|
||||
req->name = &main_exe_name->Buffer;
|
||||
req->exe_file = main_file;
|
||||
req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI);
|
||||
wine_server_add_data( req, main_exe_name->Buffer, main_exe_name->Length );
|
||||
wine_server_call( req );
|
||||
peb->BeingDebugged = reply->debugged;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (main_file) NtClose( main_file ); /* we no longer need it */
|
||||
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY_InitDebugLists();
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
if ((status = fixup_imports( wm )) != STATUS_SUCCESS) goto error;
|
||||
if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
|
||||
if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
|
||||
if ((status = process_attach( wm, (LPVOID)1 )) != STATUS_SUCCESS) goto error;
|
||||
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
DPRINTF( "%04lx:Starting process %s (entryproc=%p)\n", GetCurrentThreadId(),
|
||||
debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), entry );
|
||||
|
||||
NtCurrentTeb()->last_error = 0; /* clear error code */
|
||||
if (peb->BeingDebugged) DbgBreakPoint();
|
||||
NtTerminateProcess( GetCurrentProcess(), entry( peb ) );
|
||||
|
||||
error:
|
||||
ERR( "Main exe initialization failed, status %lx\n", status );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* RtlImageDirectoryEntryToData (NTDLL.@)
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
@ stdcall LdrFindResource_U(long ptr long ptr)
|
||||
@ stdcall LdrGetDllHandle(long long ptr ptr)
|
||||
@ stdcall LdrGetProcedureAddress(ptr ptr long ptr)
|
||||
@ stub LdrInitializeThunk
|
||||
@ stdcall LdrInitializeThunk(long long long long)
|
||||
@ stdcall LdrLoadDll(wstr long ptr ptr)
|
||||
@ stdcall LdrLockLoaderLock(long ptr ptr)
|
||||
@ stub LdrProcessRelocationBlock
|
||||
|
|
|
@ -40,6 +40,7 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl
|
|||
const LARGE_INTEGER *timeout );
|
||||
|
||||
/* module handling */
|
||||
extern void RELAY_InitDebugLists(void);
|
||||
extern FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
|
||||
DWORD exp_size, FARPROC proc, const WCHAR *user );
|
||||
extern FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
|
||||
|
|
|
@ -128,9 +128,6 @@ typedef struct
|
|||
|
||||
#include <poppack.h>
|
||||
|
||||
struct _wine_modref;
|
||||
typedef struct _wine_modref WINE_MODREF;
|
||||
|
||||
/* Resource types */
|
||||
|
||||
#define NE_SEG_TABLE(pModule) \
|
||||
|
@ -165,7 +162,6 @@ enum binary_type
|
|||
};
|
||||
|
||||
/* module.c */
|
||||
extern NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
|
||||
extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );
|
||||
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
|
||||
extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name );
|
||||
|
|
|
@ -954,6 +954,7 @@ NTSTATUS WINAPI LdrFindResourceDirectory_U(HMODULE,const LDR_RESOURCE_INFO*,ULO
|
|||
NTSTATUS WINAPI LdrFindResource_U(HMODULE,const LDR_RESOURCE_INFO*,ULONG,const IMAGE_RESOURCE_DATA_ENTRY**);
|
||||
NTSTATUS WINAPI LdrGetDllHandle(ULONG, ULONG, const UNICODE_STRING*, HMODULE*);
|
||||
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, const ANSI_STRING*, ULONG, void**);
|
||||
void WINAPI LdrInitializeThunk(HANDLE,ULONG,ULONG,ULONG);
|
||||
NTSTATUS WINAPI LdrLoadDll(LPCWSTR, DWORD, const UNICODE_STRING*, HMODULE*);
|
||||
void WINAPI LdrShutdownProcess(void);
|
||||
void WINAPI LdrShutdownThread(void);
|
||||
|
|
Loading…
Reference in New Issue