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_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:

View File

@ -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 */
@ -757,25 +741,22 @@ NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
&wm->ldr.InInitializationOrderModuleList);
/* Remove recursion flag */
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.@)
*/

View File

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

View File

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

View File

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

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