2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: dll/ntdll/ldr/startup.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
10 /* INCLUDES *****************************************************************/
15 #include <win32k/callback.h>
17 VOID
RtlInitializeHeapManager(VOID
);
18 VOID
LdrpInitLoader(VOID
);
19 VOID NTAPI
RtlpInitDeferedCriticalSection(VOID
);
20 NTSTATUS
LdrpAttachThread(VOID
);
21 VOID
RtlpInitializeVectoredExceptionHandling(VOID
);
22 extern PTEB LdrpTopLevelDllBeingLoadedTeb
;
24 /* GLOBALS *******************************************************************/
26 PLDR_DATA_TABLE_ENTRY ExeModule
;
27 static RTL_CRITICAL_SECTION PebLock
;
28 static RTL_CRITICAL_SECTION LoaderLock
;
29 static RTL_BITMAP TlsBitMap
;
30 static RTL_BITMAP TlsExpansionBitMap
;
31 static volatile BOOLEAN LdrpInitialized
= FALSE
;
32 static LONG LdrpInitLock
= 0;
34 #define VALUE_BUFFER_SIZE 256
36 /* FUNCTIONS *****************************************************************/
40 ReadCompatibilitySetting(HANDLE Key
,
42 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
,
45 UNICODE_STRING ValueName
;
49 RtlInitUnicodeString(&ValueName
, Value
);
50 Status
= NtQueryValueKey(Key
,
52 KeyValuePartialInformation
,
57 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_DWORD
))
59 RtlFreeUnicodeString(&ValueName
);
63 RtlCopyMemory(Buffer
, &ValueInfo
->Data
[0], sizeof(DWORD
));
64 RtlFreeUnicodeString(&ValueName
);
70 LoadImageFileExecutionOptions(PPEB Peb
)
72 NTSTATUS Status
= STATUS_SUCCESS
;
74 UNICODE_STRING ValueString
;
75 UNICODE_STRING ImageName
;
76 UNICODE_STRING ImagePathName
;
77 WCHAR ValueBuffer
[64];
80 if (Peb
->ProcessParameters
&&
81 Peb
->ProcessParameters
->ImagePathName
.Length
> 0)
83 DPRINT("%wZ\n", &Peb
->ProcessParameters
->ImagePathName
);
85 ImagePathName
= Peb
->ProcessParameters
->ImagePathName
;
86 ImageName
.Buffer
= ImagePathName
.Buffer
+ ImagePathName
.Length
/ sizeof(WCHAR
);
89 while (ImagePathName
.Buffer
< ImageName
.Buffer
)
92 if (*ImageName
.Buffer
== L
'\\')
99 ImageName
.Length
= ImagePathName
.Length
-
100 (ImageName
.Buffer
- ImagePathName
.Buffer
) * sizeof(WCHAR
);
101 ImageName
.MaximumLength
= ImageName
.Length
+
102 ImagePathName
.MaximumLength
- ImagePathName
.Length
;
104 DPRINT("%wZ\n", &ImageName
);
107 Status
= LdrQueryImageFileExecutionOptions(&ImageName
,
113 if (NT_SUCCESS(Status
))
115 ValueString
.Buffer
= ValueBuffer
;
116 ValueString
.Length
= ValueSize
- sizeof(WCHAR
);
117 ValueString
.MaximumLength
= sizeof(ValueBuffer
);
118 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, &Value
);
119 if (NT_SUCCESS(Status
))
121 Peb
->NtGlobalFlag
|= Value
;
122 DPRINT("GlobalFlag: Key='%S', Value=0x%lx\n", ValueBuffer
, Value
);
134 LoadCompatibilitySettings(PPEB Peb
)
137 HANDLE UserKey
= NULL
;
140 OBJECT_ATTRIBUTES ObjectAttributes
;
141 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(
142 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
143 UNICODE_STRING ValueName
;
144 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
145 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
147 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
148 SPMajorVersion
, SPMinorVersion
= 0;
150 if (Peb
->ProcessParameters
&&
151 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
153 Status
= RtlOpenCurrentUser(KEY_READ
, &UserKey
);
154 if (!NT_SUCCESS(Status
))
159 InitializeObjectAttributes(&ObjectAttributes
,
161 OBJ_CASE_INSENSITIVE
,
165 Status
= NtOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
167 if (!NT_SUCCESS(Status
))
174 /* query version name for application */
175 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
) ValueBuffer
;
176 Status
= NtQueryValueKey(KeyHandle
,
177 &Peb
->ProcessParameters
->ImagePathName
,
178 KeyValuePartialInformation
,
183 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
191 ValueName
.Length
= ValueInfo
->DataLength
;
192 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
193 ValueName
.Buffer
= (PWSTR
) ValueInfo
->Data
;
195 /* load version info */
196 InitializeObjectAttributes(&ObjectAttributes
,
198 OBJ_CASE_INSENSITIVE
,
202 Status
= NtOpenKey(&SubKeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
204 if (!NT_SUCCESS(Status
))
212 DPRINT("Loading version information for: %wZ\n", &ValueName
);
214 /* read settings from registry */
215 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
217 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
219 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
221 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
224 /* now assign the settings */
225 Peb
->OSMajorVersion
= (ULONG
) MajorVersion
;
226 Peb
->OSMinorVersion
= (ULONG
) MinorVersion
;
227 Peb
->OSBuildNumber
= (USHORT
) BuildNumber
;
228 Peb
->OSPlatformId
= (ULONG
) PlatformId
;
230 /* optional service pack version numbers */
231 if (ReadCompatibilitySetting(SubKeyHandle
,
235 ReadCompatibilitySetting(SubKeyHandle
,
240 Peb
->OSCSDVersion
= ((SPMajorVersion
& 0xFF) << 8) |
241 (SPMinorVersion
& 0xFF);
246 NtClose(SubKeyHandle
);
258 LdrpInit2(PCONTEXT Context
,
259 PVOID SystemArgument1
,
260 PVOID SystemArgument2
)
262 PIMAGE_NT_HEADERS NTHeaders
;
264 PIMAGE_DOS_HEADER PEDosHeader
;
266 PPEB Peb
= NtCurrentPeb();
267 PLDR_DATA_TABLE_ENTRY NtModule
; // ntdll
268 NLSTABLEINFO NlsTable
;
269 WCHAR FullNtDllPath
[MAX_PATH
];
270 SYSTEM_BASIC_INFORMATION SystemInformation
;
272 PVOID BaseAddress
= SystemArgument1
;
274 DPRINT("LdrpInit()\n");
275 DPRINT("Peb %p\n", Peb
);
276 ImageBase
= Peb
->ImageBaseAddress
;
277 DPRINT("ImageBase %p\n", ImageBase
);
279 if (ImageBase
<= (PVOID
) 0x1000)
281 DPRINT("ImageBase is null\n");
282 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
285 /* If MZ header exists */
286 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
287 DPRINT("PEDosHeader %p\n", PEDosHeader
);
289 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
290 PEDosHeader
->e_lfanew
== 0L ||
291 *(PULONG
)((PUCHAR
)ImageBase
+ PEDosHeader
->e_lfanew
) != IMAGE_NT_SIGNATURE
)
293 DPRINT1("Image has bad header\n");
294 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
297 /* normalize process parameters */
298 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
300 /* Initialize NLS data */
301 RtlInitNlsTables(Peb
->AnsiCodePageData
,
302 Peb
->OemCodePageData
,
303 Peb
->UnicodeCaseTableData
,
305 RtlResetRtlTranslations(&NlsTable
);
307 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
309 /* Get number of processors */
311 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
313 sizeof(SYSTEM_BASIC_INFORMATION
),
316 if (!NT_SUCCESS(Status
))
318 ZwTerminateProcess(NtCurrentProcess(), Status
);
321 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
323 /* Initialize Critical Section Data */
324 RtlpInitDeferedCriticalSection();
326 /* create process heap */
327 RtlInitializeHeapManager();
328 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
330 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
331 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
334 if (Peb
->ProcessHeap
== 0)
336 DPRINT1("Failed to create process heap\n");
337 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
340 /* initialized vectored exception handling */
341 RtlpInitializeVectoredExceptionHandling();
343 /* initalize peb lock support */
344 RtlInitializeCriticalSection(&PebLock
);
345 Peb
->FastPebLock
= &PebLock
;
346 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
347 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
349 /* initialize tls bitmaps */
350 RtlInitializeBitMap(&TlsBitMap
, Peb
->TlsBitmapBits
, TLS_MINIMUM_AVAILABLE
);
351 RtlInitializeBitMap(&TlsExpansionBitMap
, Peb
->TlsExpansionBitmapBits
, TLS_EXPANSION_SLOTS
);
353 Peb
->TlsBitmap
= &TlsBitMap
;
354 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
355 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
357 /* Initialize table of callbacks for the kernel. */
358 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
361 (USER32_CALLBACK_MAXIMUM
+ 1));
362 if (Peb
->KernelCallbackTable
== NULL
)
364 DPRINT1("Failed to create callback table\n");
365 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
368 /* initalize loader lock */
369 RtlInitializeCriticalSection(&LoaderLock
);
370 Peb
->LoaderLock
= &LoaderLock
;
372 /* create loader information */
373 Peb
->Ldr
= (PPEB_LDR_DATA
) RtlAllocateHeap(Peb
->ProcessHeap
,
375 sizeof(PEB_LDR_DATA
));
376 if (Peb
->Ldr
== NULL
)
378 DPRINT1("Failed to create loader data\n");
379 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
382 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
383 Peb
->Ldr
->Initialized
= FALSE
;
384 Peb
->Ldr
->SsHandle
= NULL
;
385 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
386 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
387 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
389 /* Load compatibility settings */
390 LoadCompatibilitySettings(Peb
);
392 /* Load execution options */
393 LoadImageFileExecutionOptions(Peb
);
395 /* build full ntdll path */
396 wcscpy(FullNtDllPath
, SharedUserData
->NtSystemRoot
);
397 wcscat(FullNtDllPath
, L
"\\system32\\ntdll.dll");
399 /* add entry for ntdll */
400 NtModule
= (PLDR_DATA_TABLE_ENTRY
)
401 RtlAllocateHeap(Peb
->ProcessHeap
,
403 sizeof(LDR_DATA_TABLE_ENTRY
));
404 if (NtModule
== NULL
)
406 DPRINT1("Failed to create loader module entry (NTDLL)\n");
407 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
409 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
411 NtModule
->DllBase
= BaseAddress
;
412 NtModule
->EntryPoint
= 0; /* no entry point */
413 RtlCreateUnicodeString(&NtModule
->FullDllName
, FullNtDllPath
);
414 RtlCreateUnicodeString(&NtModule
->BaseDllName
, L
"ntdll.dll");
415 NtModule
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
417 NtModule
->LoadCount
= -1; /* don't unload */
418 NtModule
->TlsIndex
= -1;
419 NtModule
->SectionPointer
= NULL
;
420 NtModule
->CheckSum
= 0;
422 NTHeaders
= RtlImageNtHeader(NtModule
->DllBase
);
423 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
424 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
426 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
427 &NtModule
->InLoadOrderLinks
);
428 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
429 &NtModule
->InInitializationOrderModuleList
);
431 /* add entry for executable (becomes first list entry) */
432 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)
433 RtlAllocateHeap(Peb
->ProcessHeap
,
435 sizeof(LDR_DATA_TABLE_ENTRY
));
436 if (ExeModule
== NULL
)
438 DPRINT1("Failed to create loader module infomation\n");
439 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
442 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
444 if ((Peb
->ProcessParameters
== NULL
) ||
445 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
447 DPRINT1("Failed to access the process parameter block\n");
448 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
451 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
452 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
453 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
454 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
456 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule
->BaseDllName
, &ExeModule
->FullDllName
);
458 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
459 ExeModule
->LoadCount
= -1; /* don't unload */
460 ExeModule
->TlsIndex
= -1;
461 ExeModule
->SectionPointer
= NULL
;
462 ExeModule
->CheckSum
= 0;
464 NTHeaders
= RtlImageNtHeader(ExeModule
->DllBase
);
465 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
466 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
468 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
470 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
471 &ExeModule
->InLoadOrderLinks
);
475 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
476 ExeModule
->EntryPoint
= EntryPoint
;
478 /* all required dlls are loaded now */
479 Peb
->Ldr
->Initialized
= TRUE
;
481 /* Check before returning that we can run the image safely. */
482 if (EntryPoint
== NULL
)
484 DPRINT1("Failed to initialize image\n");
485 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
488 /* Break into debugger */
489 if (Peb
->BeingDebugged
)
495 LdrpInit(PCONTEXT Context
,
496 PVOID SystemArgument1
,
497 PVOID SystemArgument2
)
499 if (!LdrpInitialized
)
501 if (!_InterlockedExchange(&LdrpInitLock
, 1))
503 LdrpInit2(Context
, SystemArgument1
, SystemArgument2
);
504 LdrpInitialized
= TRUE
;
508 LARGE_INTEGER Interval
= {{-200000, -1}};
512 NtDelayExecution(FALSE
, &Interval
);
514 while (!LdrpInitialized
);
518 /* attach the thread */
519 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
521 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);