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
);
23 /* GLOBALS *******************************************************************/
25 PLDR_DATA_TABLE_ENTRY ExeModule
;
26 static RTL_CRITICAL_SECTION PebLock
;
27 static RTL_CRITICAL_SECTION LoaderLock
;
28 static RTL_BITMAP TlsBitMap
;
29 static RTL_BITMAP TlsExpansionBitMap
;
30 static volatile BOOLEAN LdrpInitialized
= FALSE
;
31 static LONG LdrpInitLock
= 0;
33 #define VALUE_BUFFER_SIZE 256
35 /* FUNCTIONS *****************************************************************/
39 ReadCompatibilitySetting(HANDLE Key
,
41 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
,
44 UNICODE_STRING ValueName
;
48 RtlInitUnicodeString(&ValueName
, Value
);
49 Status
= NtQueryValueKey(Key
,
51 KeyValuePartialInformation
,
56 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_DWORD
))
58 RtlFreeUnicodeString(&ValueName
);
62 RtlCopyMemory(Buffer
, &ValueInfo
->Data
[0], sizeof(DWORD
));
63 RtlFreeUnicodeString(&ValueName
);
69 LoadImageFileExecutionOptions(PPEB Peb
)
71 NTSTATUS Status
= STATUS_SUCCESS
;
73 UNICODE_STRING ValueString
;
74 UNICODE_STRING ImageName
;
75 UNICODE_STRING ImagePathName
;
76 WCHAR ValueBuffer
[64];
79 if (Peb
->ProcessParameters
&&
80 Peb
->ProcessParameters
->ImagePathName
.Length
> 0)
82 DPRINT("%wZ\n", &Peb
->ProcessParameters
->ImagePathName
);
84 ImagePathName
= Peb
->ProcessParameters
->ImagePathName
;
85 ImageName
.Buffer
= ImagePathName
.Buffer
+ ImagePathName
.Length
/ sizeof(WCHAR
);
88 while (ImagePathName
.Buffer
< ImageName
.Buffer
)
91 if (*ImageName
.Buffer
== L
'\\')
98 ImageName
.Length
= ImagePathName
.Length
-
99 (ImageName
.Buffer
- ImagePathName
.Buffer
) * sizeof(WCHAR
);
100 ImageName
.MaximumLength
= ImageName
.Length
+
101 ImagePathName
.MaximumLength
- ImagePathName
.Length
;
103 DPRINT("%wZ\n", &ImageName
);
106 Status
= LdrQueryImageFileExecutionOptions(&ImageName
,
112 if (NT_SUCCESS(Status
))
114 ValueString
.Buffer
= ValueBuffer
;
115 ValueString
.Length
= ValueSize
- sizeof(WCHAR
);
116 ValueString
.MaximumLength
= sizeof(ValueBuffer
);
117 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, &Value
);
118 if (NT_SUCCESS(Status
))
120 Peb
->NtGlobalFlag
|= Value
;
121 DPRINT("GlobalFlag: Key='%S', Value=0x%lx\n", ValueBuffer
, Value
);
133 LoadCompatibilitySettings(PPEB Peb
)
136 HANDLE UserKey
= NULL
;
139 OBJECT_ATTRIBUTES ObjectAttributes
;
140 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(
141 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
142 UNICODE_STRING ValueName
;
143 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
144 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
146 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
147 SPMajorVersion
, SPMinorVersion
= 0;
149 if (Peb
->ProcessParameters
&&
150 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
152 Status
= RtlOpenCurrentUser(KEY_READ
, &UserKey
);
153 if (!NT_SUCCESS(Status
))
158 InitializeObjectAttributes(&ObjectAttributes
,
160 OBJ_CASE_INSENSITIVE
,
164 Status
= NtOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
166 if (!NT_SUCCESS(Status
))
173 /* query version name for application */
174 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
) ValueBuffer
;
175 Status
= NtQueryValueKey(KeyHandle
,
176 &Peb
->ProcessParameters
->ImagePathName
,
177 KeyValuePartialInformation
,
182 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
190 ValueName
.Length
= ValueInfo
->DataLength
;
191 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
192 ValueName
.Buffer
= (PWSTR
) ValueInfo
->Data
;
194 /* load version info */
195 InitializeObjectAttributes(&ObjectAttributes
,
197 OBJ_CASE_INSENSITIVE
,
201 Status
= NtOpenKey(&SubKeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
203 if (!NT_SUCCESS(Status
))
211 DPRINT("Loading version information for: %wZ\n", &ValueName
);
213 /* read settings from registry */
214 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
216 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
218 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
220 if (!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
223 /* now assign the settings */
224 Peb
->OSMajorVersion
= (ULONG
) MajorVersion
;
225 Peb
->OSMinorVersion
= (ULONG
) MinorVersion
;
226 Peb
->OSBuildNumber
= (USHORT
) BuildNumber
;
227 Peb
->OSPlatformId
= (ULONG
) PlatformId
;
229 /* optional service pack version numbers */
230 if (ReadCompatibilitySetting(SubKeyHandle
,
234 ReadCompatibilitySetting(SubKeyHandle
,
239 Peb
->OSCSDVersion
= ((SPMajorVersion
& 0xFF) << 8) |
240 (SPMinorVersion
& 0xFF);
245 NtClose(SubKeyHandle
);
257 LdrpInit2(PCONTEXT Context
,
258 PVOID SystemArgument1
,
259 PVOID SystemArgument2
)
261 PIMAGE_NT_HEADERS NTHeaders
;
263 PIMAGE_DOS_HEADER PEDosHeader
;
265 PPEB Peb
= NtCurrentPeb();
266 PLDR_DATA_TABLE_ENTRY NtModule
; // ntdll
267 NLSTABLEINFO NlsTable
;
268 WCHAR FullNtDllPath
[MAX_PATH
];
269 SYSTEM_BASIC_INFORMATION SystemInformation
;
271 PVOID BaseAddress
= SystemArgument1
;
273 DPRINT("LdrpInit()\n");
274 DPRINT("Peb %p\n", Peb
);
275 ImageBase
= Peb
->ImageBaseAddress
;
276 DPRINT("ImageBase %p\n", ImageBase
);
278 if (ImageBase
<= (PVOID
) 0x1000)
280 DPRINT("ImageBase is null\n");
281 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
284 /* If MZ header exists */
285 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
286 DPRINT("PEDosHeader %p\n", PEDosHeader
);
288 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
289 PEDosHeader
->e_lfanew
== 0L ||
290 *(PULONG
)((PUCHAR
)ImageBase
+ PEDosHeader
->e_lfanew
) != IMAGE_NT_SIGNATURE
)
292 DPRINT1("Image has bad header\n");
293 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
296 /* normalize process parameters */
297 RtlNormalizeProcessParams(Peb
->ProcessParameters
);
299 /* Initialize NLS data */
300 RtlInitNlsTables(Peb
->AnsiCodePageData
,
301 Peb
->OemCodePageData
,
302 Peb
->UnicodeCaseTableData
,
304 RtlResetRtlTranslations(&NlsTable
);
306 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
308 /* Get number of processors */
310 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
312 sizeof(SYSTEM_BASIC_INFORMATION
),
315 if (!NT_SUCCESS(Status
))
317 ZwTerminateProcess(NtCurrentProcess(), Status
);
320 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
322 /* Initialize Critical Section Data */
323 RtlpInitDeferedCriticalSection();
325 /* create process heap */
326 RtlInitializeHeapManager();
327 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
329 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
330 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
333 if (Peb
->ProcessHeap
== 0)
335 DPRINT1("Failed to create process heap\n");
336 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
339 /* initialized vectored exception handling */
340 RtlpInitializeVectoredExceptionHandling();
342 /* initalize peb lock support */
343 RtlInitializeCriticalSection(&PebLock
);
344 Peb
->FastPebLock
= &PebLock
;
345 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
346 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
348 /* initialize tls bitmaps */
349 RtlInitializeBitMap(&TlsBitMap
, Peb
->TlsBitmapBits
, TLS_MINIMUM_AVAILABLE
);
350 RtlInitializeBitMap(&TlsExpansionBitMap
, Peb
->TlsExpansionBitmapBits
, TLS_EXPANSION_SLOTS
);
352 Peb
->TlsBitmap
= &TlsBitMap
;
353 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
354 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
356 /* Initialize table of callbacks for the kernel. */
357 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
360 (USER32_CALLBACK_MAXIMUM
+ 1));
361 if (Peb
->KernelCallbackTable
== NULL
)
363 DPRINT1("Failed to create callback table\n");
364 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
367 /* initalize loader lock */
368 RtlInitializeCriticalSection(&LoaderLock
);
369 Peb
->LoaderLock
= &LoaderLock
;
371 /* create loader information */
372 Peb
->Ldr
= (PPEB_LDR_DATA
) RtlAllocateHeap(Peb
->ProcessHeap
,
374 sizeof(PEB_LDR_DATA
));
375 if (Peb
->Ldr
== NULL
)
377 DPRINT1("Failed to create loader data\n");
378 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
381 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
382 Peb
->Ldr
->Initialized
= FALSE
;
383 Peb
->Ldr
->SsHandle
= NULL
;
384 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
385 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
386 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
388 /* Load compatibility settings */
389 LoadCompatibilitySettings(Peb
);
391 /* Load execution options */
392 LoadImageFileExecutionOptions(Peb
);
394 /* build full ntdll path */
395 wcscpy(FullNtDllPath
, SharedUserData
->NtSystemRoot
);
396 wcscat(FullNtDllPath
, L
"\\system32\\ntdll.dll");
398 /* add entry for ntdll */
399 NtModule
= (PLDR_DATA_TABLE_ENTRY
)
400 RtlAllocateHeap(Peb
->ProcessHeap
,
402 sizeof(LDR_DATA_TABLE_ENTRY
));
403 if (NtModule
== NULL
)
405 DPRINT1("Failed to create loader module entry (NTDLL)\n");
406 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
408 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
410 NtModule
->DllBase
= BaseAddress
;
411 NtModule
->EntryPoint
= 0; /* no entry point */
412 RtlCreateUnicodeString(&NtModule
->FullDllName
, FullNtDllPath
);
413 RtlCreateUnicodeString(&NtModule
->BaseDllName
, L
"ntdll.dll");
414 NtModule
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
416 NtModule
->LoadCount
= -1; /* don't unload */
417 NtModule
->TlsIndex
= -1;
418 NtModule
->SectionPointer
= NULL
;
419 NtModule
->CheckSum
= 0;
421 NTHeaders
= RtlImageNtHeader(NtModule
->DllBase
);
422 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
423 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
425 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
426 &NtModule
->InLoadOrderLinks
);
427 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
428 &NtModule
->InInitializationOrderLinks
);
430 #if DBG || defined(KDBG)
432 LdrpLoadUserModuleSymbols(NtModule
);
434 #endif /* DBG || KDBG */
436 /* add entry for executable (becomes first list entry) */
437 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)
438 RtlAllocateHeap(Peb
->ProcessHeap
,
440 sizeof(LDR_DATA_TABLE_ENTRY
));
441 if (ExeModule
== NULL
)
443 DPRINT1("Failed to create loader module infomation\n");
444 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
447 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
449 if ((Peb
->ProcessParameters
== NULL
) ||
450 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
452 DPRINT1("Failed to access the process parameter block\n");
453 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
456 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
457 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
458 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
459 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
461 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule
->BaseDllName
, &ExeModule
->FullDllName
);
463 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
464 ExeModule
->LoadCount
= -1; /* don't unload */
465 ExeModule
->TlsIndex
= -1;
466 ExeModule
->SectionPointer
= NULL
;
467 ExeModule
->CheckSum
= 0;
469 NTHeaders
= RtlImageNtHeader(ExeModule
->DllBase
);
470 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
471 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
473 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
474 &ExeModule
->InLoadOrderLinks
);
478 #if DBG || defined(KDBG)
480 LdrpLoadUserModuleSymbols(ExeModule
);
482 #endif /* DBG || KDBG */
484 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
485 ExeModule
->EntryPoint
= EntryPoint
;
487 /* all required dlls are loaded now */
488 Peb
->Ldr
->Initialized
= TRUE
;
490 /* Check before returning that we can run the image safely. */
491 if (EntryPoint
== NULL
)
493 DPRINT1("Failed to initialize image\n");
494 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
497 /* Break into debugger */
498 if (Peb
->BeingDebugged
)
504 LdrpInit(PCONTEXT Context
,
505 PVOID SystemArgument1
,
506 PVOID SystemArgument2
)
508 if (!LdrpInitialized
)
510 if (!_InterlockedExchange(&LdrpInitLock
, 1))
512 LdrpInit2(Context
, SystemArgument1
, SystemArgument2
);
513 LdrpInitialized
= TRUE
;
517 LARGE_INTEGER Interval
= {{-200000, -1}};
521 NtDelayExecution(FALSE
, &Interval
);
523 while (!LdrpInitialized
);
527 /* attach the thread */
528 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
530 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);