3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
11 /* INCLUDES *****************************************************************/
16 #include <win32k/callback.h>
18 VOID
RtlInitializeHeapManager (VOID
);
19 VOID
LdrpInitLoader(VOID
);
21 /* GLOBALS *******************************************************************/
24 extern unsigned int _image_base__
;
26 static RTL_CRITICAL_SECTION PebLock
;
27 static RTL_CRITICAL_SECTION LoaderLock
;
28 static RTL_BITMAP TlsBitMap
;
29 PLDR_DATA_TABLE_ENTRY ExeModule
;
31 NTSTATUS
LdrpAttachThread (VOID
);
33 VOID
RtlpInitializeVectoredExceptionHandling(VOID
);
36 #define VALUE_BUFFER_SIZE 256
39 ReadCompatibilitySetting(HANDLE Key
, LPWSTR Value
, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
, DWORD
*Buffer
)
41 UNICODE_STRING ValueName
;
45 RtlInitUnicodeString(&ValueName
, Value
);
46 Status
= NtQueryValueKey(Key
,
48 KeyValuePartialInformation
,
53 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_DWORD
))
55 RtlFreeUnicodeString(&ValueName
);
58 RtlCopyMemory(Buffer
, &ValueInfo
->Data
[0], sizeof(DWORD
));
59 RtlFreeUnicodeString(&ValueName
);
64 LoadImageFileExecutionOptions(PPEB Peb
)
66 NTSTATUS Status
= STATUS_SUCCESS
;
68 UNICODE_STRING ValueString
;
69 UNICODE_STRING ImageName
;
70 UNICODE_STRING ImagePathName
;
71 WCHAR ValueBuffer
[64];
74 if (Peb
->ProcessParameters
&&
75 Peb
->ProcessParameters
->ImagePathName
.Length
> 0)
77 DPRINT("%wZ\n", &Peb
->ProcessParameters
->ImagePathName
);
79 ImagePathName
= Peb
->ProcessParameters
->ImagePathName
;
80 ImageName
.Buffer
= ImagePathName
.Buffer
+ ImagePathName
.Length
/ sizeof(WCHAR
);
82 while (ImagePathName
.Buffer
< ImageName
.Buffer
)
85 if (*ImageName
.Buffer
== L
'\\')
91 ImageName
.Length
= ImagePathName
.Length
- (ImageName
.Buffer
- ImagePathName
.Buffer
) * sizeof(WCHAR
);
92 ImageName
.MaximumLength
= ImageName
.Length
+ ImagePathName
.MaximumLength
- ImagePathName
.Length
;
94 DPRINT("%wZ\n", &ImageName
);
97 Status
= LdrQueryImageFileExecutionOptions (&ImageName
,
103 if (NT_SUCCESS(Status
))
105 ValueString
.Buffer
= ValueBuffer
;
106 ValueString
.Length
= ValueSize
- sizeof(WCHAR
);
107 ValueString
.MaximumLength
= sizeof(ValueBuffer
);
108 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, &Value
);
109 if (NT_SUCCESS(Status
))
111 Peb
->NtGlobalFlag
|= Value
;
112 DPRINT("GlobalFlag: Key='%S', Value=%08x\n", ValueBuffer
, Value
);
126 LoadCompatibilitySettings(PPEB Peb
)
129 HANDLE UserKey
= NULL
;
132 OBJECT_ATTRIBUTES ObjectAttributes
;
133 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(
134 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
135 UNICODE_STRING ValueName
;
136 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
137 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
139 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
140 SPMajorVersion
, SPMinorVersion
= 0;
142 if(Peb
->ProcessParameters
&&
143 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
145 Status
= RtlOpenCurrentUser(KEY_READ
,
147 if (!NT_SUCCESS(Status
))
152 InitializeObjectAttributes(&ObjectAttributes
,
154 OBJ_CASE_INSENSITIVE
,
158 Status
= NtOpenKey(&KeyHandle
,
162 if (!NT_SUCCESS(Status
))
164 if (UserKey
) NtClose(UserKey
);
168 /* query version name for application */
169 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
170 Status
= NtQueryValueKey(KeyHandle
,
171 &Peb
->ProcessParameters
->ImagePathName
,
172 KeyValuePartialInformation
,
177 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
180 if (UserKey
) NtClose(UserKey
);
184 ValueName
.Length
= ValueInfo
->DataLength
;
185 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
186 ValueName
.Buffer
= (PWSTR
)ValueInfo
->Data
;
188 /* load version info */
189 InitializeObjectAttributes(&ObjectAttributes
,
191 OBJ_CASE_INSENSITIVE
,
195 Status
= NtOpenKey(&SubKeyHandle
,
199 if (!NT_SUCCESS(Status
))
202 if (UserKey
) NtClose(UserKey
);
206 DPRINT("Loading version information for: %wZ\n", &ValueName
);
208 /* read settings from registry */
209 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
211 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
213 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
215 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
218 /* now assign the settings */
219 Peb
->OSMajorVersion
= (ULONG
)MajorVersion
;
220 Peb
->OSMinorVersion
= (ULONG
)MinorVersion
;
221 Peb
->OSBuildNumber
= (USHORT
)BuildNumber
;
222 Peb
->OSPlatformId
= (ULONG
)PlatformId
;
224 /* optional service pack version numbers */
225 if(ReadCompatibilitySetting(SubKeyHandle
, L
"SPMajorVersion", ValueInfo
, &SPMajorVersion
) &&
226 ReadCompatibilitySetting(SubKeyHandle
, L
"SPMinorVersion", ValueInfo
, &SPMinorVersion
))
227 Peb
->OSCSDVersion
= ((SPMajorVersion
& 0xFF) << 8) | (SPMinorVersion
& 0xFF);
231 NtClose(SubKeyHandle
);
233 if (UserKey
) NtClose(UserKey
);
239 /* FUNCTIONS *****************************************************************/
242 __true_LdrInitializeThunk (ULONG Unknown1
,
247 PIMAGE_NT_HEADERS NTHeaders
;
249 PIMAGE_DOS_HEADER PEDosHeader
;
252 PLDR_DATA_TABLE_ENTRY NtModule
; // ntdll
253 NLSTABLEINFO NlsTable
;
254 WCHAR FullNtDllPath
[MAX_PATH
];
255 SYSTEM_BASIC_INFORMATION SystemInformation
;
258 DPRINT("LdrInitializeThunk()\n");
259 if (NtCurrentPeb()->Ldr
== NULL
|| NtCurrentPeb()->Ldr
->Initialized
== FALSE
)
261 Peb
= (PPEB
)(PEB_BASE
);
262 DPRINT("Peb %x\n", Peb
);
263 ImageBase
= Peb
->ImageBaseAddress
;
264 DPRINT("ImageBase %x\n", ImageBase
);
265 if (ImageBase
<= (PVOID
)0x1000)
267 DPRINT("ImageBase is null\n");
268 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
271 /* If MZ header exists */
272 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
273 DPRINT("PEDosHeader %x\n", PEDosHeader
);
275 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
276 PEDosHeader
->e_lfanew
== 0L ||
277 *(PULONG
)((PUCHAR
)ImageBase
+ PEDosHeader
->e_lfanew
) != IMAGE_NT_SIGNATURE
)
279 DPRINT1("Image has bad header\n");
280 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
283 /* normalize process parameters */
284 RtlNormalizeProcessParams (Peb
->ProcessParameters
);
286 /* Initialize NLS data */
287 RtlInitNlsTables (Peb
->AnsiCodePageData
,
288 Peb
->OemCodePageData
,
289 Peb
->UnicodeCaseTableData
,
291 RtlResetRtlTranslations (&NlsTable
);
293 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
295 /* Get number of processors */
296 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
298 sizeof(SYSTEM_BASIC_INFORMATION
),
300 if (!NT_SUCCESS(Status
))
302 ZwTerminateProcess(NtCurrentProcess(), Status
);
305 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
307 /* Initialize Critical Section Data */
308 RtlpInitDeferedCriticalSection();
310 /* create process heap */
311 RtlInitializeHeapManager();
312 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
314 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
315 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
318 if (Peb
->ProcessHeap
== 0)
320 DPRINT1("Failed to create process heap\n");
321 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
324 /* initialized vectored exception handling */
325 RtlpInitializeVectoredExceptionHandling();
327 /* initalize peb lock support */
328 RtlInitializeCriticalSection (&PebLock
);
329 Peb
->FastPebLock
= &PebLock
;
330 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
331 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
333 /* initialize tls bitmap */
334 RtlInitializeBitMap (&TlsBitMap
,
336 TLS_MINIMUM_AVAILABLE
);
337 Peb
->TlsBitmap
= &TlsBitMap
;
338 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
340 /* Initialize table of callbacks for the kernel. */
341 Peb
->KernelCallbackTable
=
342 RtlAllocateHeap(RtlGetProcessHeap(),
344 sizeof(PVOID
) * (USER32_CALLBACK_MAXIMUM
+ 1));
346 /* initalize loader lock */
347 RtlInitializeCriticalSection (&LoaderLock
);
348 Peb
->LoaderLock
= &LoaderLock
;
350 /* create loader information */
351 Peb
->Ldr
= (PPEB_LDR_DATA
)RtlAllocateHeap (Peb
->ProcessHeap
,
353 sizeof(PEB_LDR_DATA
));
354 if (Peb
->Ldr
== NULL
)
356 DPRINT1("Failed to create loader data\n");
357 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
359 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
360 Peb
->Ldr
->Initialized
= FALSE
;
361 Peb
->Ldr
->SsHandle
= NULL
;
362 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
363 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
364 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
366 /* Load compatibility settings */
367 LoadCompatibilitySettings(Peb
);
369 /* Load execution options */
370 LoadImageFileExecutionOptions(Peb
);
372 /* build full ntdll path */
373 wcscpy (FullNtDllPath
, SharedUserData
->NtSystemRoot
);
374 wcscat (FullNtDllPath
, L
"\\system32\\ntdll.dll");
376 /* add entry for ntdll */
377 NtModule
= (PLDR_DATA_TABLE_ENTRY
)RtlAllocateHeap (Peb
->ProcessHeap
,
379 sizeof(LDR_DATA_TABLE_ENTRY
));
380 if (NtModule
== NULL
)
382 DPRINT1("Failed to create loader module entry (NTDLL)\n");
383 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
385 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
387 NtModule
->DllBase
= (PVOID
)&_image_base__
;
388 NtModule
->EntryPoint
= 0; /* no entry point */
389 RtlCreateUnicodeString (&NtModule
->FullDllName
,
391 RtlCreateUnicodeString (&NtModule
->BaseDllName
,
393 NtModule
->Flags
= LDRP_IMAGE_DLL
|LDRP_ENTRY_PROCESSED
;
395 NtModule
->LoadCount
= -1; /* don't unload */
396 NtModule
->TlsIndex
= -1;
397 NtModule
->SectionPointer
= NULL
;
398 NtModule
->CheckSum
= 0;
400 NTHeaders
= RtlImageNtHeader (NtModule
->DllBase
);
401 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
402 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
404 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
405 &NtModule
->InLoadOrderModuleList
);
406 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
407 &NtModule
->InInitializationOrderModuleList
);
409 #if defined(DBG) || defined(KDBG)
411 LdrpLoadUserModuleSymbols(NtModule
);
413 #endif /* DBG || KDBG */
415 /* add entry for executable (becomes first list entry) */
416 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)RtlAllocateHeap (Peb
->ProcessHeap
,
418 sizeof(LDR_DATA_TABLE_ENTRY
));
419 if (ExeModule
== NULL
)
421 DPRINT1("Failed to create loader module infomation\n");
422 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
424 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
426 if ((Peb
->ProcessParameters
== NULL
) ||
427 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
429 DPRINT1("Failed to access the process parameter block\n");
430 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
433 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
434 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
435 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
436 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
438 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
439 &ExeModule
->BaseDllName
,
440 &ExeModule
->FullDllName
);
442 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
443 ExeModule
->LoadCount
= -1; /* don't unload */
444 ExeModule
->TlsIndex
= -1;
445 ExeModule
->SectionPointer
= NULL
;
446 ExeModule
->CheckSum
= 0;
448 NTHeaders
= RtlImageNtHeader (ExeModule
->DllBase
);
449 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
450 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
452 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
453 &ExeModule
->InLoadOrderModuleList
);
457 #if defined(DBG) || defined(KDBG)
459 LdrpLoadUserModuleSymbols(ExeModule
);
461 #endif /* DBG || KDBG */
463 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
464 ExeModule
->EntryPoint
= EntryPoint
;
466 /* all required dlls are loaded now */
467 Peb
->Ldr
->Initialized
= TRUE
;
469 /* Check before returning that we can run the image safely. */
470 if (EntryPoint
== NULL
)
472 DPRINT1("Failed to initialize image\n");
473 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
476 /* attach the thread */
477 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
479 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);