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
;
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 DPRINT("PEDosHeader %p\n", PEDosHeader
);
349 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
350 PEDosHeader
->e_lfanew
== 0L ||
351 *(PULONG
)((PUCHAR
)ImageBase
+ PEDosHeader
->e_lfanew
) != IMAGE_NT_SIGNATURE
)
353 DPRINT1("Image has bad header\n");
354 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
357 /* normalize process parameters */
358 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
360 /* Initialize NLS data */
361 RtlInitNlsTables(Peb
->AnsiCodePageData
,
362 Peb
->OemCodePageData
,
363 Peb
->UnicodeCaseTableData
,
365 RtlResetRtlTranslations(&NlsTable
);
367 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
369 /* Get number of processors */
371 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
373 sizeof(SYSTEM_BASIC_INFORMATION
),
376 if (!NT_SUCCESS(Status
))
378 ZwTerminateProcess(NtCurrentProcess(), Status
);
381 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
383 /* Initialize Critical Section Data */
384 RtlpInitDeferedCriticalSection();
386 /* Load execution options */
387 LoadImageFileExecutionOptions(Peb
);
389 /* create process heap */
390 RtlInitializeHeapManager();
391 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
393 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
394 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
397 if (Peb
->ProcessHeap
== 0)
399 DPRINT1("Failed to create process heap\n");
400 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
403 /* initialized vectored exception handling */
404 RtlpInitializeVectoredExceptionHandling();
406 /* initalize peb lock support */
407 RtlInitializeCriticalSection(&PebLock
);
408 Peb
->FastPebLock
= &PebLock
;
410 /* initialize tls bitmaps */
411 RtlInitializeBitMap(&TlsBitMap
, Peb
->TlsBitmapBits
, TLS_MINIMUM_AVAILABLE
);
412 RtlInitializeBitMap(&TlsExpansionBitMap
, Peb
->TlsExpansionBitmapBits
, TLS_EXPANSION_SLOTS
);
414 Peb
->TlsBitmap
= &TlsBitMap
;
415 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
416 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
418 /* Initialize table of callbacks for the kernel. */
419 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
422 (USER32_CALLBACK_MAXIMUM
+ 1));
423 if (Peb
->KernelCallbackTable
== NULL
)
425 DPRINT1("Failed to create callback table\n");
426 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
429 /* initalize loader lock */
430 RtlInitializeCriticalSection(&LoaderLock
);
431 Peb
->LoaderLock
= &LoaderLock
;
433 /* create loader information */
434 Peb
->Ldr
= (PPEB_LDR_DATA
) RtlAllocateHeap(Peb
->ProcessHeap
,
436 sizeof(PEB_LDR_DATA
));
437 if (Peb
->Ldr
== NULL
)
439 DPRINT1("Failed to create loader data\n");
440 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
443 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
444 Peb
->Ldr
->Initialized
= FALSE
;
445 Peb
->Ldr
->SsHandle
= NULL
;
446 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
447 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
448 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
450 /* Load compatibility settings */
451 LoadCompatibilitySettings(Peb
);
453 /* build full ntdll path */
454 wcscpy(FullNtDllPath
, SharedUserData
->NtSystemRoot
);
455 wcscat(FullNtDllPath
, L
"\\system32\\ntdll.dll");
457 /* add entry for ntdll */
458 NtModule
= (PLDR_DATA_TABLE_ENTRY
)
459 RtlAllocateHeap(Peb
->ProcessHeap
,
461 sizeof(LDR_DATA_TABLE_ENTRY
));
462 if (NtModule
== NULL
)
464 DPRINT1("Failed to create loader module entry (NTDLL)\n");
465 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
467 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
469 NtModule
->DllBase
= BaseAddress
;
470 NtModule
->EntryPoint
= 0; /* no entry point */
471 RtlCreateUnicodeString(&NtModule
->FullDllName
, FullNtDllPath
);
472 RtlCreateUnicodeString(&NtModule
->BaseDllName
, L
"ntdll.dll");
473 NtModule
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
475 NtModule
->LoadCount
= -1; /* don't unload */
476 NtModule
->TlsIndex
= -1;
477 NtModule
->SectionPointer
= NULL
;
478 NtModule
->CheckSum
= 0;
480 NTHeaders
= RtlImageNtHeader(NtModule
->DllBase
);
481 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
482 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
484 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
485 &NtModule
->InLoadOrderLinks
);
486 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
487 &NtModule
->InInitializationOrderModuleList
);
489 /* add entry for executable (becomes first list entry) */
490 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)
491 RtlAllocateHeap(Peb
->ProcessHeap
,
493 sizeof(LDR_DATA_TABLE_ENTRY
));
494 if (ExeModule
== NULL
)
496 DPRINT1("Failed to create loader module infomation\n");
497 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
500 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
502 if ((Peb
->ProcessParameters
== NULL
) ||
503 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
505 DPRINT1("Failed to access the process parameter block\n");
506 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
509 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
510 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
511 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
512 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
514 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule
->BaseDllName
, &ExeModule
->FullDllName
);
516 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
517 ExeModule
->LoadCount
= -1; /* don't unload */
518 ExeModule
->TlsIndex
= -1;
519 ExeModule
->SectionPointer
= NULL
;
520 ExeModule
->CheckSum
= 0;
522 NTHeaders
= RtlImageNtHeader(ExeModule
->DllBase
);
523 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
524 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
526 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
528 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
529 &ExeModule
->InLoadOrderLinks
);
533 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
534 ExeModule
->EntryPoint
= EntryPoint
;
536 /* all required dlls are loaded now */
537 Peb
->Ldr
->Initialized
= TRUE
;
539 /* Check before returning that we can run the image safely. */
540 if (EntryPoint
== NULL
)
542 DPRINT1("Failed to initialize image\n");
543 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
546 /* Break into debugger */
547 if (Peb
->BeingDebugged
)
553 LdrpInit(PCONTEXT Context
,
554 PVOID SystemArgument1
,
555 PVOID SystemArgument2
)
557 if (!LdrpInitialized
)
559 if (!_InterlockedExchange(&LdrpInitLock
, 1))
561 LdrpInit2(Context
, SystemArgument1
, SystemArgument2
);
562 LdrpInitialized
= TRUE
;
566 LARGE_INTEGER Interval
= {{-200000, -1}};
570 NtDelayExecution(FALSE
, &Interval
);
572 while (!LdrpInitialized
);
576 /* attach the thread */
577 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
579 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);