3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
11 /* INCLUDES *****************************************************************/
13 #include <reactos/config.h>
14 #include <ddk/ntddk.h>
16 #include <ntdll/ldr.h>
17 #include <ntdll/rtl.h>
18 #include <csrss/csrss.h>
19 #include <ntdll/csr.h>
20 #include <user32/callback.h>
23 #include <ntdll/ntdll.h>
26 VOID RtlInitializeHeapManager (VOID);
27 VOID LdrpInitLoader(VOID);
30 /* GLOBALS *******************************************************************/
33 extern unsigned int _image_base__;
35 static CRITICAL_SECTION PebLock;
36 static CRITICAL_SECTION LoaderLock;
37 static RTL_BITMAP TlsBitMap;
39 ULONG NtGlobalFlag = 0;
41 #define VALUE_BUFFER_SIZE 256
44 ReadCompatibilitySetting(HANDLE Key, LPWSTR Value, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo, DWORD *Buffer)
46 UNICODE_STRING ValueName;
50 RtlInitUnicodeString(&ValueName, Value);
51 Status = NtQueryValueKey(Key,
53 KeyValuePartialInformation,
58 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
60 RtlFreeUnicodeString(&ValueName);
63 RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
64 RtlFreeUnicodeString(&ValueName);
69 LoadCompatibilitySettings(PPEB Peb)
72 HANDLE UserKey = NULL;
75 OBJECT_ATTRIBUTES ObjectAttributes;
76 UNICODE_STRING KeyName;
77 UNICODE_STRING ValueName;
78 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
79 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
81 DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
82 SPMajorVersion, SPMinorVersion= 0;
84 if(Peb->ProcessParameters &&
85 (Peb->ProcessParameters->ImagePathName.Length > 0))
87 Status = RtlOpenCurrentUser(KEY_READ,
89 if (!NT_SUCCESS(Status))
94 RtlInitUnicodeStringFromLiteral(&KeyName,
95 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
97 InitializeObjectAttributes(&ObjectAttributes,
103 Status = NtOpenKey(&KeyHandle,
107 if (!NT_SUCCESS(Status))
109 if (UserKey) NtClose(UserKey);
113 /* query version name for application */
114 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
115 Status = NtQueryValueKey(KeyHandle,
116 &Peb->ProcessParameters->ImagePathName,
117 KeyValuePartialInformation,
122 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
125 if (UserKey) NtClose(UserKey);
129 ValueName.Length = ValueInfo->DataLength;
130 ValueName.MaximumLength = ValueInfo->DataLength;
131 ValueName.Buffer = (PWSTR)ValueInfo->Data;
133 /* load version info */
134 InitializeObjectAttributes(&ObjectAttributes,
136 OBJ_CASE_INSENSITIVE,
140 Status = NtOpenKey(&SubKeyHandle,
144 if (!NT_SUCCESS(Status))
147 if (UserKey) NtClose(UserKey);
151 DPRINT("Loading version information for: %wZ\n", &ValueName);
153 /* read settings from registry */
154 if(!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
156 if(!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
158 if(!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
160 if(!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
163 /* now assign the settings */
164 Peb->OSMajorVersion = (ULONG)MajorVersion;
165 Peb->OSMinorVersion = (ULONG)MinorVersion;
166 Peb->OSBuildNumber = (USHORT)BuildNumber;
167 Peb->OSPlatformId = (ULONG)PlatformId;
169 /* optional service pack version numbers */
170 if(ReadCompatibilitySetting(SubKeyHandle, L"SPMajorVersion", ValueInfo, &SPMajorVersion))
171 Peb->SPMajorVersion = (UCHAR)SPMajorVersion;
172 if(ReadCompatibilitySetting(SubKeyHandle, L"SPMinorVersion", ValueInfo, &SPMinorVersion))
173 Peb->SPMinorVersion = (UCHAR)SPMinorVersion;
177 NtClose(SubKeyHandle);
179 if (UserKey) NtClose(UserKey);
186 /* FUNCTIONS *****************************************************************/
189 __true_LdrInitializeThunk (ULONG Unknown1,
194 PIMAGE_NT_HEADERS NTHeaders;
196 PIMAGE_DOS_HEADER PEDosHeader;
199 PLDR_MODULE NtModule; // ntdll
200 PLDR_MODULE ExeModule; // executable
201 NLSTABLEINFO NlsTable;
202 WCHAR FullNtDllPath[MAX_PATH];
204 DPRINT("LdrInitializeThunk()\n");
205 if (NtCurrentPeb()->Ldr != NULL && NtCurrentPeb()->Ldr->Initialized == TRUE)
207 PLIST_ENTRY current_entry;
208 PDLLMAIN_FUNC Entrypoint;
211 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
213 NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
214 while (current_entry !=
215 &NtCurrentPeb()->Ldr->InInitializationOrderModuleList)
217 current = CONTAINING_RECORD(current_entry, LDR_MODULE,
218 InInitializationOrderModuleList);
219 Entrypoint = (PDLLMAIN_FUNC)current->EntryPoint;
220 if (Entrypoint != NULL &&
221 current->BaseAddress != NtCurrentPeb()->ImageBaseAddress)
223 (VOID)Entrypoint(current->BaseAddress, DLL_THREAD_ATTACH, NULL);
225 current_entry = current_entry->Flink;
227 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
231 Peb = (PPEB)(PEB_BASE);
232 DPRINT("Peb %x\n", Peb);
233 ImageBase = Peb->ImageBaseAddress;
234 DPRINT("ImageBase %x\n", ImageBase);
235 if (ImageBase <= (PVOID)0x1000)
237 DPRINT("ImageBase is null\n");
238 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
241 NtGlobalFlag = Peb->NtGlobalFlag;
243 /* If MZ header exists */
244 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
245 DPRINT("PEDosHeader %x\n", PEDosHeader);
246 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
247 PEDosHeader->e_lfanew == 0L ||
248 *(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) != IMAGE_PE_MAGIC)
250 DbgPrint("Image has bad header\n");
251 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
254 /* normalize process parameters */
255 RtlNormalizeProcessParams (Peb->ProcessParameters);
257 /* Initialize NLS data */
258 RtlInitNlsTables (Peb->AnsiCodePageData,
259 Peb->OemCodePageData,
260 Peb->UnicodeCaseTableData,
262 RtlResetRtlTranslations (&NlsTable);
264 NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
266 /* create process heap */
267 RtlInitializeHeapManager();
268 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
270 NTHeaders->OptionalHeader.SizeOfHeapReserve,
271 NTHeaders->OptionalHeader.SizeOfHeapCommit,
274 if (Peb->ProcessHeap == 0)
276 DbgPrint("Failed to create process heap\n");
277 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
280 /* initalize peb lock support */
281 RtlInitializeCriticalSection (&PebLock);
282 Peb->FastPebLock = &PebLock;
283 Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
284 Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
286 /* initialize tls bitmap */
287 RtlInitializeBitMap (&TlsBitMap,
289 TLS_MINIMUM_AVAILABLE);
290 Peb->TlsBitmap = &TlsBitMap;
291 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
293 /* Initialize table of callbacks for the kernel. */
294 Peb->KernelCallbackTable =
295 RtlAllocateHeap(RtlGetProcessHeap(),
297 sizeof(PVOID) * (USER32_CALLBACK_MAXIMUM + 1));
299 /* initalize loader lock */
300 RtlInitializeCriticalSection (&LoaderLock);
301 Peb->LoaderLock = &LoaderLock;
303 /* create loader information */
304 Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,
306 sizeof(PEB_LDR_DATA));
307 if (Peb->Ldr == NULL)
309 DbgPrint("Failed to create loader data\n");
310 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
312 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
313 Peb->Ldr->Initialized = FALSE;
314 Peb->Ldr->SsHandle = NULL;
315 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
316 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
317 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
319 /* Load compatibility settings */
320 LoadCompatibilitySettings(Peb);
322 /* build full ntdll path */
323 wcscpy (FullNtDllPath, SharedUserData->NtSystemRoot);
324 wcscat (FullNtDllPath, L"\\system32\\ntdll.dll");
326 /* add entry for ntdll */
327 NtModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
330 if (NtModule == NULL)
332 DbgPrint("Failed to create loader module entry (NTDLL)\n");
333 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
335 memset(NtModule, 0, sizeof(LDR_MODULE));
337 NtModule->BaseAddress = (PVOID)&_image_base__;
338 NtModule->EntryPoint = 0; /* no entry point */
339 RtlCreateUnicodeString (&NtModule->FullDllName,
341 RtlCreateUnicodeString (&NtModule->BaseDllName,
344 NtModule->LoadCount = -1; /* don't unload */
345 NtModule->TlsIndex = 0;
346 NtModule->SectionHandle = NULL;
347 NtModule->CheckSum = 0;
349 NTHeaders = RtlImageNtHeader (NtModule->BaseAddress);
350 NtModule->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
351 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
353 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
354 &NtModule->InLoadOrderModuleList);
355 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
356 &NtModule->InInitializationOrderModuleList);
360 LdrpLoadUserModuleSymbols(NtModule);
364 /* add entry for executable (becomes first list entry) */
365 ExeModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
368 if (ExeModule == NULL)
370 DbgPrint("Failed to create loader module infomation\n");
371 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
373 ExeModule->BaseAddress = Peb->ImageBaseAddress;
375 if ((Peb->ProcessParameters == NULL) ||
376 (Peb->ProcessParameters->ImagePathName.Length == 0))
378 DbgPrint("Failed to access the process parameter block\n");
379 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
382 RtlCreateUnicodeString(&ExeModule->FullDllName,
383 Peb->ProcessParameters->ImagePathName.Buffer);
384 RtlCreateUnicodeString(&ExeModule->BaseDllName,
385 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
387 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
388 &ExeModule->BaseDllName,
389 &ExeModule->FullDllName);
391 ExeModule->Flags = 0;
392 ExeModule->LoadCount = -1; /* don't unload */
393 ExeModule->TlsIndex = 0;
394 ExeModule->SectionHandle = NULL;
395 ExeModule->CheckSum = 0;
397 NTHeaders = RtlImageNtHeader (ExeModule->BaseAddress);
398 ExeModule->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
399 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
401 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
402 &ExeModule->InLoadOrderModuleList);
408 LdrpLoadUserModuleSymbols(ExeModule);
412 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
413 ExeModule->EntryPoint = (ULONG)EntryPoint;
415 /* all required dlls are loaded now */
416 Peb->Ldr->Initialized = TRUE;
418 /* Check before returning that we can run the image safely. */
419 if (EntryPoint == NULL)
421 DbgPrint("Failed to initialize image\n");
422 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);