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 ImageName
;
75 UNICODE_STRING ImagePathName
;
77 extern ULONG RtlpDphGlobalFlags
, RtlpPageHeapSizeRangeStart
, RtlpPageHeapSizeRangeEnd
;
78 extern ULONG RtlpPageHeapDllRangeStart
, RtlpPageHeapDllRangeEnd
;
79 extern WCHAR RtlpDphTargetDlls
[512];
80 extern BOOLEAN RtlpPageHeapEnabled
;
82 if (Peb
->ProcessParameters
&&
83 Peb
->ProcessParameters
->ImagePathName
.Length
> 0)
85 DPRINT("%wZ\n", &Peb
->ProcessParameters
->ImagePathName
);
87 ImagePathName
= Peb
->ProcessParameters
->ImagePathName
;
88 ImageName
.Buffer
= ImagePathName
.Buffer
+ ImagePathName
.Length
/ sizeof(WCHAR
);
91 while (ImagePathName
.Buffer
< ImageName
.Buffer
)
94 if (*ImageName
.Buffer
== L
'\\')
101 ImageName
.Length
= ImagePathName
.Length
-
102 (ImageName
.Buffer
- ImagePathName
.Buffer
) * sizeof(WCHAR
);
103 ImageName
.MaximumLength
= ImageName
.Length
+
104 ImagePathName
.MaximumLength
- ImagePathName
.Length
;
106 DPRINT("%wZ\n", &ImageName
);
109 Status
= LdrQueryImageFileExecutionOptions(&ImageName
,
115 if (NT_SUCCESS(Status
))
117 Peb
->NtGlobalFlag
= Value
;
118 DPRINT("GlobalFlag: Value=0x%lx\n", Value
);
122 /* Add debugging flags if there is no GlobalFlags override */
123 if (Peb
->BeingDebugged
)
125 Peb
->NtGlobalFlag
|= FLG_HEAP_VALIDATE_PARAMETERS
|
126 FLG_HEAP_ENABLE_FREE_CHECK
|
127 FLG_HEAP_ENABLE_TAIL_CHECK
;
131 /* Handle the case when page heap is enabled */
132 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
134 /* Disable all heap debugging flags so that no heap call goes via page heap branch */
135 Peb
->NtGlobalFlag
&= ~(FLG_HEAP_VALIDATE_PARAMETERS
|
136 FLG_HEAP_VALIDATE_ALL
|
137 FLG_HEAP_ENABLE_FREE_CHECK
|
138 FLG_HEAP_ENABLE_TAIL_CHECK
|
139 FLG_USER_STACK_TRACE_DB
|
140 FLG_HEAP_ENABLE_TAGGING
|
141 FLG_HEAP_ENABLE_TAG_BY_DLL
);
143 /* Get page heap flags without checking return value */
144 LdrQueryImageFileExecutionOptions(&ImageName
,
147 (PVOID
)&RtlpDphGlobalFlags
,
148 sizeof(RtlpDphGlobalFlags
),
151 LdrQueryImageFileExecutionOptions(&ImageName
,
152 L
"PageHeapSizeRangeStart",
154 (PVOID
)&RtlpPageHeapSizeRangeStart
,
155 sizeof(RtlpPageHeapSizeRangeStart
),
158 LdrQueryImageFileExecutionOptions(&ImageName
,
159 L
"PageHeapSizeRangeEnd",
161 (PVOID
)&RtlpPageHeapSizeRangeEnd
,
162 sizeof(RtlpPageHeapSizeRangeEnd
),
165 LdrQueryImageFileExecutionOptions(&ImageName
,
166 L
"PageHeapDllRangeStart",
168 (PVOID
)&RtlpPageHeapDllRangeStart
,
169 sizeof(RtlpPageHeapDllRangeStart
),
172 LdrQueryImageFileExecutionOptions(&ImageName
,
173 L
"PageHeapDllRangeEnd",
175 (PVOID
)&RtlpPageHeapDllRangeEnd
,
176 sizeof(RtlpPageHeapDllRangeEnd
),
179 LdrQueryImageFileExecutionOptions(&ImageName
,
180 L
"PageHeapTargetDlls",
182 (PVOID
)RtlpDphTargetDlls
,
183 sizeof(RtlpDphTargetDlls
),
186 /* Now when all parameters are read, enable page heap */
187 RtlpPageHeapEnabled
= TRUE
;
194 LoadCompatibilitySettings(PPEB Peb
)
197 HANDLE UserKey
= NULL
;
200 OBJECT_ATTRIBUTES ObjectAttributes
;
201 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(
202 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
203 UNICODE_STRING ValueName
;
204 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
205 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
207 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
208 SPMajorVersion
, SPMinorVersion
= 0;
210 if (Peb
->ProcessParameters
&&
211 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
213 Status
= RtlOpenCurrentUser(KEY_READ
, &UserKey
);
214 if (!NT_SUCCESS(Status
))
219 InitializeObjectAttributes(&ObjectAttributes
,
221 OBJ_CASE_INSENSITIVE
,
225 Status
= NtOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
227 if (!NT_SUCCESS(Status
))
234 /* query version name for application */
235 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
) ValueBuffer
;
236 Status
= NtQueryValueKey(KeyHandle
,
237 &Peb
->ProcessParameters
->ImagePathName
,
238 KeyValuePartialInformation
,
243 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
251 ValueName
.Length
= ValueInfo
->DataLength
;
252 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
253 ValueName
.Buffer
= (PWSTR
) ValueInfo
->Data
;
255 /* load version info */
256 InitializeObjectAttributes(&ObjectAttributes
,
258 OBJ_CASE_INSENSITIVE
,
262 Status
= NtOpenKey(&SubKeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
264 if (!NT_SUCCESS(Status
))
272 DPRINT("Loading version information for: %wZ\n", &ValueName
);
274 /* read settings from registry */
275 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
277 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
279 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
281 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
284 /* now assign the settings */
285 Peb
->OSMajorVersion
= (ULONG
) MajorVersion
;
286 Peb
->OSMinorVersion
= (ULONG
) MinorVersion
;
287 Peb
->OSBuildNumber
= (USHORT
) BuildNumber
;
288 Peb
->OSPlatformId
= (ULONG
) PlatformId
;
290 /* optional service pack version numbers */
291 if (ReadCompatibilitySetting(SubKeyHandle
,
295 ReadCompatibilitySetting(SubKeyHandle
,
300 Peb
->OSCSDVersion
= ((SPMajorVersion
& 0xFF) << 8) |
301 (SPMinorVersion
& 0xFF);
306 NtClose(SubKeyHandle
);
318 LdrpInit2(PCONTEXT Context
,
319 PVOID SystemArgument1
,
320 PVOID SystemArgument2
)
322 PIMAGE_NT_HEADERS NTHeaders
;
324 PIMAGE_DOS_HEADER PEDosHeader
;
326 PPEB Peb
= NtCurrentPeb();
327 PLDR_DATA_TABLE_ENTRY NtModule
; // ntdll
328 NLSTABLEINFO NlsTable
;
329 WCHAR FullNtDllPath
[MAX_PATH
];
330 SYSTEM_BASIC_INFORMATION SystemInformation
;
332 PVOID BaseAddress
= SystemArgument1
;
334 DPRINT("LdrpInit()\n");
335 DPRINT("Peb %p\n", Peb
);
336 ImageBase
= Peb
->ImageBaseAddress
;
337 DPRINT("ImageBase %p\n", ImageBase
);
339 if (ImageBase
<= (PVOID
) 0x1000)
341 DPRINT("ImageBase is null\n");
342 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
345 /* If MZ header exists */
346 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
347 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
348 DPRINT("PEDosHeader %p\n", PEDosHeader
);
350 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
351 PEDosHeader
->e_lfanew
== 0L ||
352 NTHeaders
->Signature
!= IMAGE_NT_SIGNATURE
)
354 DPRINT1("Image has bad header\n");
355 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
358 /* normalize process parameters */
359 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
361 /* Initialize NLS data */
362 RtlInitNlsTables(Peb
->AnsiCodePageData
,
363 Peb
->OemCodePageData
,
364 Peb
->UnicodeCaseTableData
,
366 RtlResetRtlTranslations(&NlsTable
);
368 /* Get number of processors */
370 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
372 sizeof(SYSTEM_BASIC_INFORMATION
),
375 if (!NT_SUCCESS(Status
))
377 ZwTerminateProcess(NtCurrentProcess(), Status
);
380 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
382 /* Initialize Critical Section Data */
383 RtlpInitDeferedCriticalSection();
385 /* Load execution options */
386 LoadImageFileExecutionOptions(Peb
);
388 /* create process heap */
389 RtlInitializeHeapManager();
390 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
392 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
393 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
396 if (Peb
->ProcessHeap
== 0)
398 DPRINT1("Failed to create process heap\n");
399 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
402 /* Check for correct machine type */
403 if (NTHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
)
405 ULONG_PTR HardErrorParameters
[1];
406 UNICODE_STRING ImageNameU
;
407 ANSI_STRING ImageNameA
;
411 DPRINT1("Image %wZ is for a foreign architecture (0x%x).\n",
412 &Peb
->ProcessParameters
->ImagePathName
, NTHeaders
->FileHeader
.Machine
);
414 /* Get the full image path name */
415 ImageNameU
= Peb
->ProcessParameters
->ImagePathName
;
417 /* Get the file name */
418 Ptr
= Peb
->ProcessParameters
->ImagePathName
.Buffer
+
419 (Peb
->ProcessParameters
->ImagePathName
.Length
/ sizeof(WCHAR
)) -1;
420 while ((Ptr
>= Peb
->ProcessParameters
->ImagePathName
.Buffer
) &&
421 (*Ptr
!= L
'\\')) Ptr
--;
422 ImageNameU
.Buffer
= Ptr
+ 1;
423 ImageNameU
.Length
= Peb
->ProcessParameters
->ImagePathName
.Length
-
424 (ImageNameU
.Buffer
- Peb
->ProcessParameters
->ImagePathName
.Buffer
) * sizeof(WCHAR
);
425 ImageNameU
.MaximumLength
= ImageNameU
.Length
;
427 /*`Convert to ANSI, harderror message needs that */
428 RtlUnicodeStringToAnsiString(&ImageNameA
, &ImageNameU
, TRUE
);
430 /* Raise harderror */
431 HardErrorParameters
[0] = (ULONG_PTR
)&ImageNameA
;
432 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
,
439 RtlFreeAnsiString(&ImageNameA
);
440 ZwTerminateProcess(NtCurrentProcess(), STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
);
443 /* initialized vectored exception handling */
444 RtlpInitializeVectoredExceptionHandling();
446 /* initalize peb lock support */
447 RtlInitializeCriticalSection(&PebLock
);
448 Peb
->FastPebLock
= &PebLock
;
450 /* initialize tls bitmaps */
451 RtlInitializeBitMap(&TlsBitMap
, Peb
->TlsBitmapBits
, TLS_MINIMUM_AVAILABLE
);
452 RtlInitializeBitMap(&TlsExpansionBitMap
, Peb
->TlsExpansionBitmapBits
, TLS_EXPANSION_SLOTS
);
454 Peb
->TlsBitmap
= &TlsBitMap
;
455 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
456 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
458 /* Initialize table of callbacks for the kernel. */
459 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
462 (USER32_CALLBACK_MAXIMUM
+ 1));
463 if (Peb
->KernelCallbackTable
== NULL
)
465 DPRINT1("Failed to create callback table\n");
466 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
469 /* initalize loader lock */
470 RtlInitializeCriticalSection(&LoaderLock
);
471 Peb
->LoaderLock
= &LoaderLock
;
473 /* create loader information */
474 Peb
->Ldr
= (PPEB_LDR_DATA
) RtlAllocateHeap(Peb
->ProcessHeap
,
476 sizeof(PEB_LDR_DATA
));
477 if (Peb
->Ldr
== NULL
)
479 DPRINT1("Failed to create loader data\n");
480 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
483 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
484 Peb
->Ldr
->Initialized
= FALSE
;
485 Peb
->Ldr
->SsHandle
= NULL
;
486 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
487 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
488 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
490 /* Load compatibility settings */
491 LoadCompatibilitySettings(Peb
);
493 /* build full ntdll path */
494 wcscpy(FullNtDllPath
, SharedUserData
->NtSystemRoot
);
495 wcscat(FullNtDllPath
, L
"\\system32\\ntdll.dll");
497 /* add entry for ntdll */
498 NtModule
= (PLDR_DATA_TABLE_ENTRY
)
499 RtlAllocateHeap(Peb
->ProcessHeap
,
501 sizeof(LDR_DATA_TABLE_ENTRY
));
502 if (NtModule
== NULL
)
504 DPRINT1("Failed to create loader module entry (NTDLL)\n");
505 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
507 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
509 NtModule
->DllBase
= BaseAddress
;
510 NtModule
->EntryPoint
= 0; /* no entry point */
511 RtlCreateUnicodeString(&NtModule
->FullDllName
, FullNtDllPath
);
512 RtlCreateUnicodeString(&NtModule
->BaseDllName
, L
"ntdll.dll");
513 NtModule
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
515 NtModule
->LoadCount
= -1; /* don't unload */
516 NtModule
->TlsIndex
= -1;
517 NtModule
->SectionPointer
= NULL
;
518 NtModule
->CheckSum
= 0;
520 NTHeaders
= RtlImageNtHeader(NtModule
->DllBase
);
521 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
522 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
524 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
525 &NtModule
->InLoadOrderLinks
);
526 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
527 &NtModule
->InInitializationOrderModuleList
);
529 /* add entry for executable (becomes first list entry) */
530 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)
531 RtlAllocateHeap(Peb
->ProcessHeap
,
533 sizeof(LDR_DATA_TABLE_ENTRY
));
534 if (ExeModule
== NULL
)
536 DPRINT1("Failed to create loader module infomation\n");
537 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
540 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
542 if ((Peb
->ProcessParameters
== NULL
) ||
543 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
545 DPRINT1("Failed to access the process parameter block\n");
546 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
549 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
550 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
551 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
552 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
554 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule
->BaseDllName
, &ExeModule
->FullDllName
);
556 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
557 ExeModule
->LoadCount
= -1; /* don't unload */
558 ExeModule
->TlsIndex
= -1;
559 ExeModule
->SectionPointer
= NULL
;
560 ExeModule
->CheckSum
= 0;
562 NTHeaders
= RtlImageNtHeader(ExeModule
->DllBase
);
563 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
564 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
566 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
568 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
569 &ExeModule
->InLoadOrderLinks
);
573 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
574 ExeModule
->EntryPoint
= EntryPoint
;
576 /* all required dlls are loaded now */
577 Peb
->Ldr
->Initialized
= TRUE
;
579 /* Check before returning that we can run the image safely. */
580 if (EntryPoint
== NULL
)
582 DPRINT1("Failed to initialize image\n");
583 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
586 /* Break into debugger */
587 if (Peb
->BeingDebugged
)
593 LdrpInit(PCONTEXT Context
,
594 PVOID SystemArgument1
,
595 PVOID SystemArgument2
)
597 if (!LdrpInitialized
)
599 if (!_InterlockedExchange(&LdrpInitLock
, 1))
601 LdrpInit2(Context
, SystemArgument1
, SystemArgument2
);
602 LdrpInitialized
= TRUE
;
606 LARGE_INTEGER Interval
= {{-200000, -1}};
610 NtDelayExecution(FALSE
, &Interval
);
612 while (!LdrpInitialized
);
616 /* attach the thread */
617 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
619 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);