Moved the final process init and dependency loading to

dlls/ntdll/loader.c, (ab)using the LdrInitializeThunk entry point.
This commit is contained in:
Alexandre Julliard 2003-10-06 21:18:51 +00:00
parent 5dc5bf5d8a
commit 632676b17e
6 changed files with 106 additions and 106 deletions

View File

@ -45,7 +45,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(process); WINE_DEFAULT_DEBUG_CHANNEL(process);
WINE_DECLARE_DEBUG_CHANNEL(server); WINE_DECLARE_DEBUG_CHANNEL(server);
WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DECLARE_DEBUG_CHANNEL(relay);
WINE_DECLARE_DEBUG_CHANNEL(snoop);
/* Win32 process database */ /* Win32 process database */
typedef struct _PDB 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 */ /* dlls/ntdll/env.c */
extern BOOL build_command_line( char **argv ); extern BOOL build_command_line( char **argv );
extern void RELAY_InitDebugLists(void);
extern void SHELL_LoadRegistry(void); extern void SHELL_LoadRegistry(void);
extern void VERSION_Init( const WCHAR *appname ); extern void VERSION_Init( const WCHAR *appname );
extern void MODULE_InitLoadPath(void); 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. * 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; IMAGE_NT_HEADERS *nt;
HANDLE mapping; HANDLE mapping;
@ -339,6 +337,7 @@ static HMODULE load_pe_exe( HANDLE file )
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
LARGE_INTEGER size; LARGE_INTEGER size;
DWORD len = 0; DWORD len = 0;
UINT drive_type;
attr.Length = sizeof(attr); attr.Length = sizeof(attr);
attr.RootDirectory = 0; attr.RootDirectory = 0;
@ -364,10 +363,19 @@ static HMODULE load_pe_exe( HANDLE file )
if (nt->OptionalHeader.AddressOfEntryPoint) if (nt->OptionalHeader.AddressOfEntryPoint)
{ {
if (!RtlImageRvaToSection( nt, module, 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", "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; return module;
} }
@ -610,8 +618,6 @@ static BOOL process_init( char *argv[] )
} }
SERVER_END_REQ; SERVER_END_REQ;
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY_InitDebugLists();
return TRUE; return TRUE;
} }
@ -625,65 +631,7 @@ static void start_process( void *arg )
{ {
__TRY __TRY
{ {
LPTHREAD_START_ROUTINE entry; LdrInitializeThunk( main_exe_file, 0, 0, 0 );
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() );
} }
__EXCEPT(UnhandledExceptionFilter) __EXCEPT(UnhandledExceptionFilter)
{ {
@ -753,7 +701,7 @@ void __wine_process_init( int argc, char *argv[] )
{ {
case BINARY_PE_EXE: case BINARY_PE_EXE:
TRACE( "starting Win32 binary %s\n", debugstr_w(main_exe_name) ); 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) ); MESSAGE( "wine: could not load %s as Win32 binary\n", debugstr_w(main_exe_name) );
ExitProcess(1); ExitProcess(1);
case BINARY_PE_DLL: case BINARY_PE_DLL:

View File

@ -66,12 +66,12 @@ static const char * const reason_names[] =
static const WCHAR dllW[] = {'.','d','l','l',0}; static const WCHAR dllW[] = {'.','d','l','l',0};
/* internal representation of 32bit modules. per process. */ /* internal representation of 32bit modules. per process. */
struct _wine_modref typedef struct _wine_modref
{ {
LDR_MODULE ldr; LDR_MODULE ldr;
int nDeps; int nDeps;
struct _wine_modref **deps; struct _wine_modref **deps;
}; } WINE_MODREF;
static UINT tls_module_count; /* number of modules with TLS directory */ static UINT tls_module_count; /* number of modules with TLS directory */
static UINT tls_total_size; /* total size of TLS storage */ 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 * Send the process attach notification to all DLLs the given module
* depends on (recursively). This is somewhat complicated due to the fact that * 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 * list after the attach notification has returned. This implies that the
* detach notifications are called in the reverse of the sequence the attach * detach notifications are called in the reverse of the sequence the attach
* notifications *returned*. * 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; NTSTATUS status = STATUS_SUCCESS;
int i; 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 */ /* prevent infinite recursion in case of cyclical dependencies */
if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS ) if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
|| ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) ) || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
goto done; return status;
TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved ); 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++ ) for ( i = 0; i < wm->nDeps; i++ )
{ {
if (!wm->deps[i]) continue; 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 */ /* Call DLL entry point */
@ -762,20 +746,17 @@ NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS; wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved ); TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
done:
RtlLeaveCriticalSection( &loader_section );
return status; return status;
} }
/************************************************************************* /*************************************************************************
* MODULE_DllProcessDetach * process_detach
* *
* Send DLL process detach notifications. See the comment about calling * 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. * 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; PLIST_ENTRY mark, entry;
PLDR_MODULE mod; 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)) 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) if (nts != STATUS_SUCCESS)
{ {
WARN("Attach failed for module %s\n", debugstr_w(libname->Buffer)); 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) void WINAPI LdrShutdownProcess(void)
{ {
TRACE("()\n"); 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 */ /* Call process detach notifications */
if ( free_lib_count <= 1 ) if ( free_lib_count <= 1 )
{ {
MODULE_DllProcessDetach( FALSE, NULL ); process_detach( FALSE, NULL );
MODULE_FlushModrefs(); 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.@) * RtlImageDirectoryEntryToData (NTDLL.@)
*/ */

View File

@ -41,7 +41,7 @@
@ stdcall LdrFindResource_U(long ptr long ptr) @ stdcall LdrFindResource_U(long ptr long ptr)
@ stdcall LdrGetDllHandle(long long ptr ptr) @ stdcall LdrGetDllHandle(long long ptr ptr)
@ stdcall LdrGetProcedureAddress(ptr ptr long ptr) @ stdcall LdrGetProcedureAddress(ptr ptr long ptr)
@ stub LdrInitializeThunk @ stdcall LdrInitializeThunk(long long long long)
@ stdcall LdrLoadDll(wstr long ptr ptr) @ stdcall LdrLoadDll(wstr long ptr ptr)
@ stdcall LdrLockLoaderLock(long ptr ptr) @ stdcall LdrLockLoaderLock(long ptr ptr)
@ stub LdrProcessRelocationBlock @ stub LdrProcessRelocationBlock

View File

@ -40,6 +40,7 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl
const LARGE_INTEGER *timeout ); const LARGE_INTEGER *timeout );
/* module handling */ /* module handling */
extern void RELAY_InitDebugLists(void);
extern FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports, extern FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, FARPROC proc, const WCHAR *user ); DWORD exp_size, FARPROC proc, const WCHAR *user );
extern FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size, extern FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,

View File

@ -128,9 +128,6 @@ typedef struct
#include <poppack.h> #include <poppack.h>
struct _wine_modref;
typedef struct _wine_modref WINE_MODREF;
/* Resource types */ /* Resource types */
#define NE_SEG_TABLE(pModule) \ #define NE_SEG_TABLE(pModule) \
@ -165,7 +162,6 @@ enum binary_type
}; };
/* module.c */ /* module.c */
extern NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved ); extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name ); extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name );

View File

@ -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 LdrFindResource_U(HMODULE,const LDR_RESOURCE_INFO*,ULONG,const IMAGE_RESOURCE_DATA_ENTRY**);
NTSTATUS WINAPI LdrGetDllHandle(ULONG, ULONG, const UNICODE_STRING*, HMODULE*); NTSTATUS WINAPI LdrGetDllHandle(ULONG, ULONG, const UNICODE_STRING*, HMODULE*);
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, const ANSI_STRING*, ULONG, void**); 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*); NTSTATUS WINAPI LdrLoadDll(LPCWSTR, DWORD, const UNICODE_STRING*, HMODULE*);
void WINAPI LdrShutdownProcess(void); void WINAPI LdrShutdownProcess(void);
void WINAPI LdrShutdownThread(void); void WINAPI LdrShutdownThread(void);