Don't include NEVER_LOAD sections in image size.
[reactos.git] / reactos / lib / ntdll / ldr / startup.c
1 /* $Id$
2 *
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)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <reactos/config.h>
14 #include <ddk/ntddk.h>
15 #include <windows.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>
21 #include <rosrtl/string.h>
22
23 #define NDEBUG
24 #include <ntdll/ntdll.h>
25
26
27 VOID RtlInitializeHeapManager (VOID);
28 VOID LdrpInitLoader(VOID);
29
30 /* GLOBALS *******************************************************************/
31
32
33 extern unsigned int _image_base__;
34
35 static CRITICAL_SECTION PebLock;
36 static CRITICAL_SECTION LoaderLock;
37 static RTL_BITMAP TlsBitMap;
38 PLDR_MODULE ExeModule;
39
40 NTSTATUS LdrpAttachThread (VOID);
41
42
43 #define VALUE_BUFFER_SIZE 256
44
45 BOOLEAN FASTCALL
46 ReadCompatibilitySetting(HANDLE Key, LPWSTR Value, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo, DWORD *Buffer)
47 {
48 UNICODE_STRING ValueName;
49 NTSTATUS Status;
50 ULONG Length;
51
52 RtlInitUnicodeString(&ValueName, Value);
53 Status = NtQueryValueKey(Key,
54 &ValueName,
55 KeyValuePartialInformation,
56 ValueInfo,
57 VALUE_BUFFER_SIZE,
58 &Length);
59
60 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
61 {
62 RtlFreeUnicodeString(&ValueName);
63 return FALSE;
64 }
65 RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
66 RtlFreeUnicodeString(&ValueName);
67 return TRUE;
68 }
69
70 VOID FASTCALL
71 LoadImageFileExecutionOptions(PPEB Peb)
72 {
73 NTSTATUS Status = STATUS_SUCCESS;
74 ULONG Value = 0;
75 UNICODE_STRING ValueString;
76 WCHAR ValueBuffer[64];
77 ULONG ValueSize;
78
79 if (Peb->ProcessParameters &&
80 Peb->ProcessParameters->ImagePathName.Length > 0)
81 {
82 /* global flag */
83 Status = LdrQueryImageFileExecutionOptions (&Peb->ProcessParameters->ImagePathName,
84 L"GlobalFlag",
85 REG_SZ,
86 (PVOID)ValueBuffer,
87 sizeof(ValueBuffer),
88 &ValueSize);
89 if (NT_SUCCESS(Status))
90 {
91 ValueString.Buffer = ValueBuffer + 1;
92 ValueString.Length = ValueSize - 2 * sizeof(WCHAR);
93 ValueString.MaximumLength = sizeof(ValueBuffer);
94 RtlUnicodeStringToInteger(&ValueString, 16, &Value);
95 Peb->NtGlobalFlag |= Value;
96 DPRINT("GlobalFlag: Key='%S', Value=%08x\n", ValueBuffer, Value);
97 }
98 /*
99 * FIXME:
100 * read more options
101 */
102 }
103 }
104
105
106
107
108 BOOLEAN FASTCALL
109 LoadCompatibilitySettings(PPEB Peb)
110 {
111 NTSTATUS Status;
112 HANDLE UserKey = NULL;
113 HANDLE KeyHandle;
114 HANDLE SubKeyHandle;
115 OBJECT_ATTRIBUTES ObjectAttributes;
116 UNICODE_STRING KeyName;
117 UNICODE_STRING ValueName;
118 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
119 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
120 ULONG Length;
121 DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
122 SPMajorVersion, SPMinorVersion= 0;
123
124 if(Peb->ProcessParameters &&
125 (Peb->ProcessParameters->ImagePathName.Length > 0))
126 {
127 Status = RtlOpenCurrentUser(KEY_READ,
128 &UserKey);
129 if (!NT_SUCCESS(Status))
130 {
131 return FALSE;
132 }
133
134 RtlRosInitUnicodeStringFromLiteral(&KeyName,
135 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
136
137 InitializeObjectAttributes(&ObjectAttributes,
138 &KeyName,
139 OBJ_CASE_INSENSITIVE,
140 UserKey,
141 NULL);
142
143 Status = NtOpenKey(&KeyHandle,
144 KEY_QUERY_VALUE,
145 &ObjectAttributes);
146
147 if (!NT_SUCCESS(Status))
148 {
149 if (UserKey) NtClose(UserKey);
150 return FALSE;
151 }
152
153 /* query version name for application */
154 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
155 Status = NtQueryValueKey(KeyHandle,
156 &Peb->ProcessParameters->ImagePathName,
157 KeyValuePartialInformation,
158 ValueBuffer,
159 VALUE_BUFFER_SIZE,
160 &Length);
161
162 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
163 {
164 NtClose(KeyHandle);
165 if (UserKey) NtClose(UserKey);
166 return FALSE;
167 }
168
169 ValueName.Length = ValueInfo->DataLength;
170 ValueName.MaximumLength = ValueInfo->DataLength;
171 ValueName.Buffer = (PWSTR)ValueInfo->Data;
172
173 /* load version info */
174 InitializeObjectAttributes(&ObjectAttributes,
175 &ValueName,
176 OBJ_CASE_INSENSITIVE,
177 KeyHandle,
178 NULL);
179
180 Status = NtOpenKey(&SubKeyHandle,
181 KEY_QUERY_VALUE,
182 &ObjectAttributes);
183
184 if (!NT_SUCCESS(Status))
185 {
186 NtClose(KeyHandle);
187 if (UserKey) NtClose(UserKey);
188 return FALSE;
189 }
190
191 DPRINT("Loading version information for: %wZ\n", &ValueName);
192
193 /* read settings from registry */
194 if(!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
195 goto finish;
196 if(!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
197 goto finish;
198 if(!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
199 goto finish;
200 if(!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
201 goto finish;
202
203 /* now assign the settings */
204 Peb->OSMajorVersion = (ULONG)MajorVersion;
205 Peb->OSMinorVersion = (ULONG)MinorVersion;
206 Peb->OSBuildNumber = (USHORT)BuildNumber;
207 Peb->OSPlatformId = (ULONG)PlatformId;
208
209 /* optional service pack version numbers */
210 if(ReadCompatibilitySetting(SubKeyHandle, L"SPMajorVersion", ValueInfo, &SPMajorVersion))
211 Peb->SPMajorVersion = (UCHAR)SPMajorVersion;
212 if(ReadCompatibilitySetting(SubKeyHandle, L"SPMinorVersion", ValueInfo, &SPMinorVersion))
213 Peb->SPMinorVersion = (UCHAR)SPMinorVersion;
214
215 finish:
216 /* we're finished */
217 NtClose(SubKeyHandle);
218 NtClose(KeyHandle);
219 if (UserKey) NtClose(UserKey);
220 return TRUE;
221 }
222 return FALSE;
223 }
224
225 /* FUNCTIONS *****************************************************************/
226
227 VOID STDCALL
228 __true_LdrInitializeThunk (ULONG Unknown1,
229 ULONG Unknown2,
230 ULONG Unknown3,
231 ULONG Unknown4)
232 {
233 PIMAGE_NT_HEADERS NTHeaders;
234 PEPFUNC EntryPoint;
235 PIMAGE_DOS_HEADER PEDosHeader;
236 PVOID ImageBase;
237 PPEB Peb;
238 PLDR_MODULE NtModule; // ntdll
239 NLSTABLEINFO NlsTable;
240 WCHAR FullNtDllPath[MAX_PATH];
241 SYSTEM_BASIC_INFORMATION SystemInformation;
242 NTSTATUS Status;
243
244 DPRINT("LdrInitializeThunk()\n");
245 if (NtCurrentPeb()->Ldr == NULL || NtCurrentPeb()->Ldr->Initialized == FALSE)
246 {
247 Peb = (PPEB)(PEB_BASE);
248 DPRINT("Peb %x\n", Peb);
249 ImageBase = Peb->ImageBaseAddress;
250 DPRINT("ImageBase %x\n", ImageBase);
251 if (ImageBase <= (PVOID)0x1000)
252 {
253 DPRINT("ImageBase is null\n");
254 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
255 }
256
257 /* If MZ header exists */
258 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
259 DPRINT("PEDosHeader %x\n", PEDosHeader);
260
261 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
262 PEDosHeader->e_lfanew == 0L ||
263 *(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) != IMAGE_PE_MAGIC)
264 {
265 DPRINT1("Image has bad header\n");
266 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
267 }
268
269 /* normalize process parameters */
270 RtlNormalizeProcessParams (Peb->ProcessParameters);
271
272 /* Initialize NLS data */
273 RtlInitNlsTables (Peb->AnsiCodePageData,
274 Peb->OemCodePageData,
275 Peb->UnicodeCaseTableData,
276 &NlsTable);
277 RtlResetRtlTranslations (&NlsTable);
278
279 NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
280
281 /* Get number of processors */
282 Status = ZwQuerySystemInformation(SystemBasicInformation,
283 &SystemInformation,
284 sizeof(SYSTEM_BASIC_INFORMATION),
285 NULL);
286 if (!NT_SUCCESS(Status))
287 {
288 ZwTerminateProcess(NtCurrentProcess(), Status);
289 }
290
291 Peb->NumberOfProcessors = SystemInformation.NumberProcessors;
292
293 /* Initialize Critical Section Data */
294 RtlpInitDeferedCriticalSection();
295
296 /* create process heap */
297 RtlInitializeHeapManager();
298 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
299 NULL,
300 NTHeaders->OptionalHeader.SizeOfHeapReserve,
301 NTHeaders->OptionalHeader.SizeOfHeapCommit,
302 NULL,
303 NULL);
304 if (Peb->ProcessHeap == 0)
305 {
306 DPRINT1("Failed to create process heap\n");
307 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
308 }
309
310 /* initalize peb lock support */
311 RtlInitializeCriticalSection (&PebLock);
312 Peb->FastPebLock = &PebLock;
313 Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
314 Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
315
316 /* initialize tls bitmap */
317 RtlInitializeBitMap (&TlsBitMap,
318 Peb->TlsBitmapBits,
319 TLS_MINIMUM_AVAILABLE);
320 Peb->TlsBitmap = &TlsBitMap;
321 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
322
323 /* Initialize table of callbacks for the kernel. */
324 Peb->KernelCallbackTable =
325 RtlAllocateHeap(RtlGetProcessHeap(),
326 0,
327 sizeof(PVOID) * (USER32_CALLBACK_MAXIMUM + 1));
328
329 /* initalize loader lock */
330 RtlInitializeCriticalSection (&LoaderLock);
331 Peb->LoaderLock = &LoaderLock;
332
333 /* create loader information */
334 Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,
335 0,
336 sizeof(PEB_LDR_DATA));
337 if (Peb->Ldr == NULL)
338 {
339 DPRINT1("Failed to create loader data\n");
340 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
341 }
342 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
343 Peb->Ldr->Initialized = FALSE;
344 Peb->Ldr->SsHandle = NULL;
345 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
346 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
347 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
348
349 /* Load compatibility settings */
350 LoadCompatibilitySettings(Peb);
351
352 /* Load execution options */
353 LoadImageFileExecutionOptions(Peb);
354
355 /* build full ntdll path */
356 wcscpy (FullNtDllPath, SharedUserData->NtSystemRoot);
357 wcscat (FullNtDllPath, L"\\system32\\ntdll.dll");
358
359 /* add entry for ntdll */
360 NtModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
361 0,
362 sizeof(LDR_MODULE));
363 if (NtModule == NULL)
364 {
365 DPRINT1("Failed to create loader module entry (NTDLL)\n");
366 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
367 }
368 memset(NtModule, 0, sizeof(LDR_MODULE));
369
370 NtModule->BaseAddress = (PVOID)&_image_base__;
371 NtModule->EntryPoint = 0; /* no entry point */
372 RtlCreateUnicodeString (&NtModule->FullDllName,
373 FullNtDllPath);
374 RtlCreateUnicodeString (&NtModule->BaseDllName,
375 L"ntdll.dll");
376 NtModule->Flags = IMAGE_DLL|ENTRY_PROCESSED;
377
378 NtModule->LoadCount = -1; /* don't unload */
379 NtModule->TlsIndex = -1;
380 NtModule->SectionHandle = NULL;
381 NtModule->CheckSum = 0;
382
383 NTHeaders = RtlImageNtHeader (NtModule->BaseAddress);
384 NtModule->ResidentSize = LdrpGetResidentSize(NTHeaders);
385 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
386
387 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
388 &NtModule->InLoadOrderModuleList);
389 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
390 &NtModule->InInitializationOrderModuleList);
391
392 #if defined(DBG) || defined(KDBG)
393
394 LdrpLoadUserModuleSymbols(NtModule);
395
396 #endif /* DBG || KDBG */
397
398 /* add entry for executable (becomes first list entry) */
399 ExeModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
400 0,
401 sizeof(LDR_MODULE));
402 if (ExeModule == NULL)
403 {
404 DPRINT1("Failed to create loader module infomation\n");
405 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
406 }
407 ExeModule->BaseAddress = Peb->ImageBaseAddress;
408
409 if ((Peb->ProcessParameters == NULL) ||
410 (Peb->ProcessParameters->ImagePathName.Length == 0))
411 {
412 DPRINT1("Failed to access the process parameter block\n");
413 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
414 }
415
416 RtlCreateUnicodeString(&ExeModule->FullDllName,
417 Peb->ProcessParameters->ImagePathName.Buffer);
418 RtlCreateUnicodeString(&ExeModule->BaseDllName,
419 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
420
421 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
422 &ExeModule->BaseDllName,
423 &ExeModule->FullDllName);
424
425 ExeModule->Flags = ENTRY_PROCESSED;
426 ExeModule->LoadCount = -1; /* don't unload */
427 ExeModule->TlsIndex = -1;
428 ExeModule->SectionHandle = NULL;
429 ExeModule->CheckSum = 0;
430
431 NTHeaders = RtlImageNtHeader (ExeModule->BaseAddress);
432 ExeModule->ResidentSize = LdrpGetResidentSize(NTHeaders);
433 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
434
435 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
436 &ExeModule->InLoadOrderModuleList);
437
438 LdrpInitLoader();
439
440 #if defined(DBG) || defined(KDBG)
441
442 LdrpLoadUserModuleSymbols(ExeModule);
443
444 #endif /* DBG || KDBG */
445
446 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
447 ExeModule->EntryPoint = (ULONG)EntryPoint;
448
449 /* all required dlls are loaded now */
450 Peb->Ldr->Initialized = TRUE;
451
452 /* Check before returning that we can run the image safely. */
453 if (EntryPoint == NULL)
454 {
455 DPRINT1("Failed to initialize image\n");
456 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
457 }
458 }
459 /* attach the thread */
460 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
461 LdrpAttachThread();
462 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
463 }
464
465 /* EOF */