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 RtlpPageHeapGlobalFlags
, RtlpPageHeapSizeRangeStart
, RtlpPageHeapSizeRangeEnd
;
78 extern ULONG RtlpPageHeapDllRangeStart
, RtlpPageHeapDllRangeEnd
;
79 extern WCHAR RtlpPageHeapTargetDlls
[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
)&RtlpPageHeapGlobalFlags
,
148 sizeof(RtlpPageHeapGlobalFlags
),
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
)RtlpPageHeapTargetDlls
,
183 sizeof(RtlpPageHeapTargetDlls
),
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
;
335 DPRINT("LdrpInit()\n");
336 DPRINT("Peb %p\n", Peb
);
337 ImageBase
= Peb
->ImageBaseAddress
;
338 DPRINT("ImageBase %p\n", ImageBase
);
340 if (ImageBase
<= (PVOID
) 0x1000)
342 DPRINT("ImageBase is null\n");
343 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
346 /* If MZ header exists */
347 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
348 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
349 DPRINT("PEDosHeader %p\n", PEDosHeader
);
351 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
352 PEDosHeader
->e_lfanew
== 0L ||
353 NTHeaders
->Signature
!= IMAGE_NT_SIGNATURE
)
355 DPRINT1("Image has bad header\n");
356 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
359 if (NTHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
)
361 DPRINT1("Image is for a foreign architecture (0x%x).\n",
362 NTHeaders
->FileHeader
.Machine
);
363 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH
, 0, 0, NULL
, OptionOk
, &ErrorResponse
);
364 ZwTerminateProcess(NtCurrentProcess(), STATUS_IMAGE_MACHINE_TYPE_MISMATCH
);
367 /* normalize process parameters */
368 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
370 /* Initialize NLS data */
371 RtlInitNlsTables(Peb
->AnsiCodePageData
,
372 Peb
->OemCodePageData
,
373 Peb
->UnicodeCaseTableData
,
375 RtlResetRtlTranslations(&NlsTable
);
377 /* Get number of processors */
379 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
381 sizeof(SYSTEM_BASIC_INFORMATION
),
384 if (!NT_SUCCESS(Status
))
386 ZwTerminateProcess(NtCurrentProcess(), Status
);
389 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
391 /* Initialize Critical Section Data */
392 RtlpInitDeferedCriticalSection();
394 /* Load execution options */
395 LoadImageFileExecutionOptions(Peb
);
397 /* create process heap */
398 RtlInitializeHeapManager();
399 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
401 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
402 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
405 if (Peb
->ProcessHeap
== 0)
407 DPRINT1("Failed to create process heap\n");
408 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
411 /* initialized vectored exception handling */
412 RtlpInitializeVectoredExceptionHandling();
414 /* initalize peb lock support */
415 RtlInitializeCriticalSection(&PebLock
);
416 Peb
->FastPebLock
= &PebLock
;
418 /* initialize tls bitmaps */
419 RtlInitializeBitMap(&TlsBitMap
, Peb
->TlsBitmapBits
, TLS_MINIMUM_AVAILABLE
);
420 RtlInitializeBitMap(&TlsExpansionBitMap
, Peb
->TlsExpansionBitmapBits
, TLS_EXPANSION_SLOTS
);
422 Peb
->TlsBitmap
= &TlsBitMap
;
423 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
424 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
426 /* Initialize table of callbacks for the kernel. */
427 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
430 (USER32_CALLBACK_MAXIMUM
+ 1));
431 if (Peb
->KernelCallbackTable
== NULL
)
433 DPRINT1("Failed to create callback table\n");
434 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
437 /* initalize loader lock */
438 RtlInitializeCriticalSection(&LoaderLock
);
439 Peb
->LoaderLock
= &LoaderLock
;
441 /* create loader information */
442 Peb
->Ldr
= (PPEB_LDR_DATA
) RtlAllocateHeap(Peb
->ProcessHeap
,
444 sizeof(PEB_LDR_DATA
));
445 if (Peb
->Ldr
== NULL
)
447 DPRINT1("Failed to create loader data\n");
448 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
451 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
452 Peb
->Ldr
->Initialized
= FALSE
;
453 Peb
->Ldr
->SsHandle
= NULL
;
454 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
455 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
456 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
458 /* Load compatibility settings */
459 LoadCompatibilitySettings(Peb
);
461 /* build full ntdll path */
462 wcscpy(FullNtDllPath
, SharedUserData
->NtSystemRoot
);
463 wcscat(FullNtDllPath
, L
"\\system32\\ntdll.dll");
465 /* add entry for ntdll */
466 NtModule
= (PLDR_DATA_TABLE_ENTRY
)
467 RtlAllocateHeap(Peb
->ProcessHeap
,
469 sizeof(LDR_DATA_TABLE_ENTRY
));
470 if (NtModule
== NULL
)
472 DPRINT1("Failed to create loader module entry (NTDLL)\n");
473 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
475 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
477 NtModule
->DllBase
= BaseAddress
;
478 NtModule
->EntryPoint
= 0; /* no entry point */
479 RtlCreateUnicodeString(&NtModule
->FullDllName
, FullNtDllPath
);
480 RtlCreateUnicodeString(&NtModule
->BaseDllName
, L
"ntdll.dll");
481 NtModule
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
483 NtModule
->LoadCount
= -1; /* don't unload */
484 NtModule
->TlsIndex
= -1;
485 NtModule
->SectionPointer
= NULL
;
486 NtModule
->CheckSum
= 0;
488 NTHeaders
= RtlImageNtHeader(NtModule
->DllBase
);
489 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
490 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
492 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
493 &NtModule
->InLoadOrderLinks
);
494 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
495 &NtModule
->InInitializationOrderModuleList
);
497 /* add entry for executable (becomes first list entry) */
498 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)
499 RtlAllocateHeap(Peb
->ProcessHeap
,
501 sizeof(LDR_DATA_TABLE_ENTRY
));
502 if (ExeModule
== NULL
)
504 DPRINT1("Failed to create loader module infomation\n");
505 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
508 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
510 if ((Peb
->ProcessParameters
== NULL
) ||
511 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
513 DPRINT1("Failed to access the process parameter block\n");
514 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
517 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
518 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
519 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
520 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
522 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule
->BaseDllName
, &ExeModule
->FullDllName
);
524 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
525 ExeModule
->LoadCount
= -1; /* don't unload */
526 ExeModule
->TlsIndex
= -1;
527 ExeModule
->SectionPointer
= NULL
;
528 ExeModule
->CheckSum
= 0;
530 NTHeaders
= RtlImageNtHeader(ExeModule
->DllBase
);
531 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
532 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
534 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
536 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
537 &ExeModule
->InLoadOrderLinks
);
541 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
542 ExeModule
->EntryPoint
= EntryPoint
;
544 /* all required dlls are loaded now */
545 Peb
->Ldr
->Initialized
= TRUE
;
547 /* Check before returning that we can run the image safely. */
548 if (EntryPoint
== NULL
)
550 DPRINT1("Failed to initialize image\n");
551 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
554 /* Break into debugger */
555 if (Peb
->BeingDebugged
)
561 LdrpInit(PCONTEXT Context
,
562 PVOID SystemArgument1
,
563 PVOID SystemArgument2
)
565 if (!LdrpInitialized
)
567 if (!_InterlockedExchange(&LdrpInitLock
, 1))
569 LdrpInit2(Context
, SystemArgument1
, SystemArgument2
);
570 LdrpInitialized
= TRUE
;
574 LARGE_INTEGER Interval
= {{-200000, -1}};
578 NtDelayExecution(FALSE
, &Interval
);
580 while (!LdrpInitialized
);
584 /* attach the thread */
585 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
587 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);