[CMAKE]
[reactos.git] / dll / ntdll / ldr / ldrinit.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrinit.c
5 * PURPOSE: User-Mode Process/Thread Startup
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 HKEY ImageExecOptionsKey;
19 HKEY Wow64ExecOptionsKey;
20 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
21 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
22 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
23
24 BOOLEAN LdrpInLdrInit;
25 LONG LdrpProcessInitialized;
26 BOOLEAN LdrpLoaderLockInit;
27 BOOLEAN LdrpLdrDatabaseIsSetup;
28
29 BOOLEAN LdrpDllValidation;
30
31 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
32 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
33 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
34 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
35 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
36
37 RTL_BITMAP TlsBitMap;
38 RTL_BITMAP TlsExpansionBitMap;
39 RTL_BITMAP FlsBitMap;
40 BOOLEAN LdrpImageHasTls;
41 LIST_ENTRY LdrpTlsList;
42 ULONG LdrpNumberOfTlsEntries;
43 ULONG LdrpNumberOfProcessors;
44 PVOID NtDllBase;
45 LARGE_INTEGER RtlpTimeout;
46 BOOLEAN RtlpTimeoutDisable;
47 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
48 LIST_ENTRY LdrpDllNotificationList;
49 HANDLE LdrpKnownDllObjectDirectory;
50 UNICODE_STRING LdrpKnownDllPath;
51 WCHAR LdrpKnownDllPathBuffer[128];
52 UNICODE_STRING LdrpDefaultPath;
53
54 PEB_LDR_DATA PebLdr;
55
56 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
57 RTL_CRITICAL_SECTION LdrpLoaderLock =
58 {
59 &LdrpLoaderLockDebug,
60 -1,
61 0,
62 0,
63 0,
64 0
65 };
66 RTL_CRITICAL_SECTION FastPebLock;
67
68 BOOLEAN ShowSnaps;
69
70 ULONG LdrpFatalHardErrorCount;
71
72 //extern LIST_ENTRY RtlCriticalSectionList;
73
74 VOID RtlpInitializeVectoredExceptionHandling(VOID);
75 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
76 VOID RtlInitializeHeapManager(VOID);
77 extern BOOLEAN RtlpPageHeapEnabled;
78 extern ULONG RtlpDphGlobalFlags;
79
80 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
81 NTSTATUS NTAPI
82 LdrpInitializeProcess_(PCONTEXT Context,
83 PVOID SystemArgument1);
84
85
86 /* FUNCTIONS *****************************************************************/
87
88 /*
89 * @implemented
90 */
91 NTSTATUS
92 NTAPI
93 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
94 IN BOOLEAN Wow64,
95 OUT PHKEY NewKeyHandle)
96 {
97 PHKEY RootKeyLocation;
98 HANDLE RootKey;
99 UNICODE_STRING SubKeyString;
100 OBJECT_ATTRIBUTES ObjectAttributes;
101 NTSTATUS Status;
102 PWCHAR p1;
103
104 /* Check which root key to open */
105 if (Wow64)
106 RootKeyLocation = &Wow64ExecOptionsKey;
107 else
108 RootKeyLocation = &ImageExecOptionsKey;
109
110 /* Get the current key */
111 RootKey = *RootKeyLocation;
112
113 /* Setup the object attributes */
114 InitializeObjectAttributes(&ObjectAttributes,
115 Wow64 ?
116 &Wow64OptionsString : &ImageExecOptionsString,
117 OBJ_CASE_INSENSITIVE,
118 NULL,
119 NULL);
120
121 /* Open the root key */
122 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
123 if (NT_SUCCESS(Status))
124 {
125 /* Write the key handle */
126 if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0)
127 {
128 /* Someone already opened it, use it instead */
129 NtClose(RootKey);
130 RootKey = *RootKeyLocation;
131 }
132
133 /* Extract the name */
134 SubKeyString = *SubKey;
135 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
136 while (SubKey->Length)
137 {
138 if (p1[-1] == L'\\') break;
139 p1--;
140 SubKeyString.Length -= sizeof(*p1);
141 }
142 SubKeyString.Buffer = p1;
143 SubKeyString.Length = SubKeyString.MaximumLength - SubKeyString.Length - sizeof(WCHAR);
144
145 /* Setup the object attributes */
146 InitializeObjectAttributes(&ObjectAttributes,
147 &SubKeyString,
148 OBJ_CASE_INSENSITIVE,
149 RootKey,
150 NULL);
151
152 /* Open the setting key */
153 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
154 }
155
156 /* Return to caller */
157 return Status;
158 }
159
160 /*
161 * @implemented
162 */
163 NTSTATUS
164 NTAPI
165 LdrQueryImageFileKeyOption(IN HKEY KeyHandle,
166 IN PCWSTR ValueName,
167 IN ULONG Type,
168 OUT PVOID Buffer,
169 IN ULONG BufferSize,
170 OUT PULONG ReturnedLength OPTIONAL)
171 {
172 ULONG KeyInfo[256];
173 UNICODE_STRING ValueNameString, IntegerString;
174 ULONG KeyInfoSize, ResultSize;
175 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
176 BOOLEAN FreeHeap = FALSE;
177 NTSTATUS Status;
178
179 /* Build a string for the value name */
180 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
181 if (!NT_SUCCESS(Status)) return Status;
182
183 /* Query the value */
184 Status = NtQueryValueKey(KeyHandle,
185 &ValueNameString,
186 KeyValuePartialInformation,
187 KeyValueInformation,
188 sizeof(KeyInfo),
189 &ResultSize);
190 if (Status == STATUS_BUFFER_OVERFLOW)
191 {
192 /* Our local buffer wasn't enough, allocate one */
193 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
194 KeyValueInformation->DataLength;
195 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
196 0,
197 KeyInfoSize);
198 if (KeyInfo == NULL)
199 {
200 /* Give up this time */
201 Status = STATUS_NO_MEMORY;
202 }
203
204 /* Try again */
205 Status = NtQueryValueKey(KeyHandle,
206 &ValueNameString,
207 KeyValuePartialInformation,
208 KeyValueInformation,
209 KeyInfoSize,
210 &ResultSize);
211 FreeHeap = TRUE;
212 }
213
214 /* Check for success */
215 if (NT_SUCCESS(Status))
216 {
217 /* Handle binary data */
218 if (KeyValueInformation->Type == REG_BINARY)
219 {
220 /* Check validity */
221 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
222 {
223 /* Copy into buffer */
224 RtlMoveMemory(Buffer,
225 &KeyValueInformation->Data,
226 KeyValueInformation->DataLength);
227 }
228 else
229 {
230 Status = STATUS_BUFFER_OVERFLOW;
231 }
232
233 /* Copy the result length */
234 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
235 }
236 else if (KeyValueInformation->Type == REG_DWORD)
237 {
238 /* Check for valid type */
239 if (KeyValueInformation->Type != Type)
240 {
241 /* Error */
242 Status = STATUS_OBJECT_TYPE_MISMATCH;
243 }
244 else
245 {
246 /* Check validity */
247 if ((Buffer) &&
248 (BufferSize == sizeof(ULONG)) &&
249 (KeyValueInformation->DataLength <= BufferSize))
250 {
251 /* Copy into buffer */
252 RtlMoveMemory(Buffer,
253 &KeyValueInformation->Data,
254 KeyValueInformation->DataLength);
255 }
256 else
257 {
258 Status = STATUS_BUFFER_OVERFLOW;
259 }
260
261 /* Copy the result length */
262 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
263 }
264 }
265 else if (KeyValueInformation->Type != REG_SZ)
266 {
267 /* We got something weird */
268 Status = STATUS_OBJECT_TYPE_MISMATCH;
269 }
270 else
271 {
272 /* String, check what you requested */
273 if (Type == REG_DWORD)
274 {
275 /* Validate */
276 if (BufferSize != sizeof(ULONG))
277 {
278 /* Invalid size */
279 BufferSize = 0;
280 Status = STATUS_INFO_LENGTH_MISMATCH;
281 }
282 else
283 {
284 /* OK, we know what you want... */
285 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
286 IntegerString.Length = KeyValueInformation->DataLength -
287 sizeof(WCHAR);
288 IntegerString.MaximumLength = KeyValueInformation->DataLength;
289 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
290 }
291 }
292 else
293 {
294 /* Validate */
295 if (KeyValueInformation->DataLength > BufferSize)
296 {
297 /* Invalid */
298 Status = STATUS_BUFFER_OVERFLOW;
299 }
300 else
301 {
302 /* Set the size */
303 BufferSize = KeyValueInformation->DataLength;
304 }
305
306 /* Copy the string */
307 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
308 }
309
310 /* Copy the result length */
311 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
312 }
313 }
314
315 /* Check if buffer was in heap */
316 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
317
318 /* Close key and return */
319 NtClose(KeyHandle);
320 return Status;
321 }
322
323 /*
324 * @implemented
325 */
326 NTSTATUS
327 NTAPI
328 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
329 IN PCWSTR ValueName,
330 IN ULONG Type,
331 OUT PVOID Buffer,
332 IN ULONG BufferSize,
333 OUT PULONG ReturnedLength OPTIONAL,
334 IN BOOLEAN Wow64)
335 {
336 NTSTATUS Status;
337 HKEY KeyHandle;
338
339 /* Open a handle to the key */
340 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
341
342 /* Check for success */
343 if (NT_SUCCESS(Status))
344 {
345 /* Query the data */
346 Status = LdrQueryImageFileKeyOption(KeyHandle,
347 ValueName,
348 Type,
349 Buffer,
350 BufferSize,
351 ReturnedLength);
352
353 /* Close the key */
354 NtClose(KeyHandle);
355 }
356
357 /* Return to caller */
358 return Status;
359 }
360
361 /*
362 * @implemented
363 */
364 NTSTATUS
365 NTAPI
366 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
367 IN PCWSTR ValueName,
368 IN ULONG Type,
369 OUT PVOID Buffer,
370 IN ULONG BufferSize,
371 OUT PULONG ReturnedLength OPTIONAL)
372 {
373 /* Call the newer function */
374 return LdrQueryImageFileExecutionOptionsEx(SubKey,
375 ValueName,
376 Type,
377 Buffer,
378 BufferSize,
379 ReturnedLength,
380 FALSE);
381 }
382
383 VOID
384 NTAPI
385 LdrpEnsureLoaderLockIsHeld()
386 {
387 // Ignored atm
388 }
389
390 PVOID
391 NTAPI
392 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
393 {
394 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
395 ULONG DirSize;
396 PVOID Cookie = NULL;
397
398 /* Check NT header first */
399 if (!RtlImageNtHeader(BaseAddress)) return NULL;
400
401 /* Get the pointer to the config directory */
402 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
403 TRUE,
404 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
405 &DirSize);
406
407 /* Check for sanity */
408 if (!ConfigDir ||
409 (DirSize != 64 && ConfigDir->Size != DirSize) ||
410 (ConfigDir->Size < 0x48))
411 return NULL;
412
413 /* Now get the cookie */
414 Cookie = (PVOID)ConfigDir->SecurityCookie;
415
416 /* Check this cookie */
417 if (Cookie == NULL ||
418 (PCHAR)Cookie <= (PCHAR)BaseAddress ||
419 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
420 {
421 Cookie = NULL;
422 }
423
424 /* Return validated security cookie */
425 return Cookie;
426 }
427
428 PVOID
429 NTAPI
430 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
431 {
432 PVOID Cookie;
433
434 /* Fetch address of the cookie */
435 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
436
437 if (Cookie)
438 {
439 UNIMPLEMENTED;
440 Cookie = NULL;
441 }
442
443 return Cookie;
444 }
445
446 NTSTATUS
447 NTAPI
448 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
449 {
450 PLDR_DATA_TABLE_ENTRY LocalArray[16];
451 PLIST_ENTRY ListHead;
452 PLIST_ENTRY NextEntry;
453 PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
454 PVOID EntryPoint;
455 ULONG Count, i;
456 //ULONG BreakOnInit;
457 NTSTATUS Status = STATUS_SUCCESS;
458 PPEB Peb = NtCurrentPeb();
459 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
460 ULONG BreakOnDllLoad;
461 PTEB OldTldTeb;
462 BOOLEAN DllStatus;
463
464 DPRINT("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry->BaseDllName);
465
466 /* Check the Loader Lock */
467 LdrpEnsureLoaderLockIsHeld();
468
469 /* Get the number of entries to call */
470 if ((Count = LdrpClearLoadInProgress()))
471 {
472 /* Check if we can use our local buffer */
473 if (Count > 16)
474 {
475 /* Allocate space for all the entries */
476 LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
477 0,
478 Count * sizeof(LdrRootEntry));
479 if (!LdrRootEntry) return STATUS_NO_MEMORY;
480 }
481 else
482 {
483 /* Use our local array */
484 LdrRootEntry = LocalArray;
485 }
486 }
487 else
488 {
489 /* Don't need one */
490 LdrRootEntry = NULL;
491 }
492
493 /* Show debug message */
494 if (ShowSnaps)
495 {
496 DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n",
497 NtCurrentTeb()->RealClientId.UniqueThread,
498 NtCurrentTeb()->RealClientId.UniqueProcess,
499 &Peb->ProcessParameters->ImagePathName);
500 }
501
502 /* Loop in order */
503 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
504 NextEntry = ListHead->Flink;
505 i = 0;
506 while (NextEntry != ListHead)
507 {
508 /* Get the Data Entry */
509 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
510
511 /* Check if we have a Root Entry */
512 if (LdrRootEntry)
513 {
514 /* Check flags */
515 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
516 {
517 /* Setup the Cookie for the DLL */
518 LdrpInitSecurityCookie(LdrEntry);
519
520 /* Check for valid entrypoint */
521 if (LdrEntry->EntryPoint)
522 {
523 /* Write in array */
524 LdrRootEntry[i] = LdrEntry;
525
526 /* Display debug message */
527 if (ShowSnaps)
528 {
529 DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
530 NtCurrentTeb()->RealClientId.UniqueThread,
531 NtCurrentTeb()->RealClientId.UniqueProcess,
532 &LdrEntry->FullDllName,
533 LdrEntry->EntryPoint);
534 }
535 i++;
536 }
537 }
538 }
539
540 /* Set the flag */
541 LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
542 NextEntry = NextEntry->Flink;
543 }
544
545 /* If we got a context, then we have to call Kernel32 for TS support */
546 if (Context)
547 {
548 /* Check if we have one */
549 //if (Kernel32ProcessInitPostImportfunction)
550 //{
551 /* Call it */
552 //Kernel32ProcessInitPostImportfunction();
553 //}
554
555 /* Clear it */
556 //Kernel32ProcessInitPostImportfunction = NULL;
557 UNIMPLEMENTED;
558 }
559
560 /* No root entry? return */
561 if (!LdrRootEntry) return STATUS_SUCCESS;
562
563 /* Set the TLD TEB */
564 OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
565 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
566
567 /* Loop */
568 i = 0;
569 while (i < Count)
570 {
571 /* Get an entry */
572 LdrEntry = LdrRootEntry[i];
573
574 /* FIXME: Verify NX Compat */
575
576 /* Move to next entry */
577 i++;
578
579 /* Get its entrypoint */
580 EntryPoint = LdrEntry->EntryPoint;
581
582 /* Are we being debugged? */
583 BreakOnDllLoad = 0;
584 if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
585 {
586 /* Check if we should break on load */
587 Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
588 L"BreakOnDllLoad",
589 REG_DWORD,
590 &BreakOnDllLoad,
591 sizeof(ULONG),
592 NULL);
593 if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
594 }
595
596 /* Break if aksed */
597 if (BreakOnDllLoad)
598 {
599 /* Check if we should show a message */
600 if (ShowSnaps)
601 {
602 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
603 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
604 }
605
606 /* Break in debugger */
607 DbgBreakPoint();
608 }
609
610 /* Make sure we have an entrypoint */
611 if (EntryPoint)
612 {
613 /* Save the old Dll Initializer and write the current one */
614 OldInitializer = LdrpCurrentDllInitializer;
615 LdrpCurrentDllInitializer = LdrEntry;
616
617 /* Set up the Act Ctx */
618 ActCtx.Size = sizeof(ActCtx);
619 ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
620 RtlZeroMemory(&ActCtx, sizeof(ActCtx));
621
622 /* Activate the ActCtx */
623 RtlActivateActivationContextUnsafeFast(&ActCtx,
624 LdrEntry->EntryPointActivationContext);
625
626 /* Check if it has TLS */
627 if (LdrEntry->TlsIndex && Context)
628 {
629 /* Call TLS */
630 LdrpTlsCallback(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
631 }
632
633 /* Call the Entrypoint */
634 if (ShowSnaps)
635 {
636 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
637 &LdrEntry->BaseDllName, EntryPoint);
638 }
639 DllStatus = LdrpCallDllEntry(EntryPoint,
640 LdrEntry->DllBase,
641 DLL_PROCESS_ATTACH,
642 Context);
643
644 /* Deactivate the ActCtx */
645 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
646
647 /* Save the Current DLL Initializer */
648 LdrpCurrentDllInitializer = OldInitializer;
649
650 /* Mark the entry as processed */
651 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
652
653 /* Fail if DLL init failed */
654 if (!DllStatus)
655 {
656 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
657 &LdrEntry->BaseDllName, EntryPoint);
658
659 Status = STATUS_DLL_INIT_FAILED;
660 goto Quickie;
661 }
662 }
663 }
664
665 /* Loop in order */
666 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
667 NextEntry = NextEntry->Flink;
668 while (NextEntry != ListHead)
669 {
670 /* Get the Data Entrry */
671 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
672
673 /* FIXME: Verify NX Compat */
674 // LdrpCheckNXCompatibility()
675
676 /* Next entry */
677 NextEntry = NextEntry->Flink;
678 }
679
680 /* Check for TLS */
681 if (LdrpImageHasTls && Context)
682 {
683 /* Set up the Act Ctx */
684 ActCtx.Size = sizeof(ActCtx);
685 ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
686 RtlZeroMemory(&ActCtx, sizeof(ActCtx));
687
688 /* Activate the ActCtx */
689 RtlActivateActivationContextUnsafeFast(&ActCtx,
690 LdrpImageEntry->EntryPointActivationContext);
691
692 /* Do TLS callbacks */
693 LdrpTlsCallback(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
694
695 /* Deactivate the ActCtx */
696 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
697 }
698
699 Quickie:
700 /* Restore old TEB */
701 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
702
703 /* Check if the array is in the heap */
704 if (LdrRootEntry != LocalArray)
705 {
706 /* Free the array */
707 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
708 }
709
710 /* Return to caller */
711 DPRINT("LdrpRunInitializeRoutines() done\n");
712 return Status;
713 }
714
715 NTSTATUS
716 NTAPI
717 LdrpInitializeTls(VOID)
718 {
719 PLIST_ENTRY NextEntry, ListHead;
720 PLDR_DATA_TABLE_ENTRY LdrEntry;
721 PIMAGE_TLS_DIRECTORY TlsDirectory;
722 PLDRP_TLS_DATA TlsData;
723 ULONG Size;
724
725 /* Initialize the TLS List */
726 InitializeListHead(&LdrpTlsList);
727
728 /* Loop all the modules */
729 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
730 NextEntry = ListHead->Flink;
731 while (ListHead != NextEntry)
732 {
733 /* Get the entry */
734 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
735 NextEntry = NextEntry->Flink;
736
737 /* Get the TLS directory */
738 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
739 TRUE,
740 IMAGE_DIRECTORY_ENTRY_TLS,
741 &Size);
742
743 /* Check if we have a directory */
744 if (!TlsDirectory) continue;
745
746 /* Check if the image has TLS */
747 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
748
749 /* Show debug message */
750 if (ShowSnaps)
751 {
752 DPRINT1("LDR: Tls Found in %wZ at %p\n",
753 &LdrEntry->BaseDllName,
754 TlsDirectory);
755 }
756
757 /* Allocate an entry */
758 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
759 if (!TlsData) return STATUS_NO_MEMORY;
760
761 /* Lock the DLL and mark it for TLS Usage */
762 LdrEntry->LoadCount = -1;
763 LdrEntry->TlsIndex = -1;
764
765 /* Save the cached TLS data */
766 TlsData->TlsDirectory = *TlsDirectory;
767 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
768
769 /* Update the index */
770 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
771 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
772 }
773
774 /* Done setting up TLS, allocate entries */
775 return LdrpAllocateTls();
776 }
777
778 NTSTATUS
779 NTAPI
780 LdrpAllocateTls(VOID)
781 {
782 PTEB Teb = NtCurrentTeb();
783 PLIST_ENTRY NextEntry, ListHead;
784 PLDRP_TLS_DATA TlsData;
785 ULONG TlsDataSize;
786 PVOID *TlsVector;
787
788 /* Check if we have any entries */
789 if (!LdrpNumberOfTlsEntries)
790 return STATUS_SUCCESS;
791
792 /* Allocate the vector array */
793 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
794 0,
795 LdrpNumberOfTlsEntries * sizeof(PVOID));
796 if (!TlsVector) return STATUS_NO_MEMORY;
797 Teb->ThreadLocalStoragePointer = TlsVector;
798
799 /* Loop the TLS Array */
800 ListHead = &LdrpTlsList;
801 NextEntry = ListHead->Flink;
802 while (NextEntry != ListHead)
803 {
804 /* Get the entry */
805 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
806 NextEntry = NextEntry->Flink;
807
808 /* Allocate this vector */
809 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
810 TlsData->TlsDirectory.StartAddressOfRawData;
811 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
812 0,
813 TlsDataSize);
814 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
815 {
816 /* Out of memory */
817 return STATUS_NO_MEMORY;
818 }
819
820 /* Show debug message */
821 if (ShowSnaps)
822 {
823 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
824 TlsVector,
825 TlsData->TlsDirectory.Characteristics,
826 &TlsVector[TlsData->TlsDirectory.Characteristics],
827 TlsData->TlsDirectory.StartAddressOfRawData,
828 TlsVector[TlsData->TlsDirectory.Characteristics]);
829 }
830
831 /* Copy the data */
832 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
833 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
834 TlsDataSize);
835 }
836
837 /* Done */
838 return STATUS_SUCCESS;
839 }
840
841 VOID
842 NTAPI
843 LdrpFreeTls(VOID)
844 {
845 PLIST_ENTRY ListHead, NextEntry;
846 PLDRP_TLS_DATA TlsData;
847 PVOID *TlsVector;
848 PTEB Teb = NtCurrentTeb();
849
850 /* Get a pointer to the vector array */
851 TlsVector = Teb->ThreadLocalStoragePointer;
852 if (!TlsVector) return;
853
854 /* Loop through it */
855 ListHead = &LdrpTlsList;
856 NextEntry = ListHead->Flink;
857 while (NextEntry != ListHead)
858 {
859 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
860 NextEntry = NextEntry->Flink;
861
862 /* Free each entry */
863 if (TlsVector[TlsData->TlsDirectory.Characteristics])
864 {
865 RtlFreeHeap(RtlGetProcessHeap(),
866 0,
867 TlsVector[TlsData->TlsDirectory.Characteristics]);
868 }
869 }
870
871 /* Free the array itself */
872 RtlFreeHeap(RtlGetProcessHeap(),
873 0,
874 TlsVector);
875 }
876
877 NTSTATUS
878 NTAPI
879 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PULONG Options)
880 {
881 UNIMPLEMENTED;
882 *Options = 0;
883 return STATUS_SUCCESS;
884 }
885
886 VOID
887 NTAPI
888 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
889 {
890 UNIMPLEMENTED;
891 }
892
893 NTSTATUS
894 NTAPI
895 LdrpInitializeProcess(IN PCONTEXT Context,
896 IN PVOID SystemArgument1)
897 {
898 RTL_HEAP_PARAMETERS HeapParameters;
899 ULONG ComSectionSize;
900 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
901 PVOID OldShimData;
902 OBJECT_ATTRIBUTES ObjectAttributes;
903 //UNICODE_STRING LocalFileName, FullImageName;
904 HANDLE SymLinkHandle;
905 //ULONG DebugHeapOnly;
906 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
907 PPEB Peb = NtCurrentPeb();
908 BOOLEAN IsDotNetImage = FALSE;
909 BOOLEAN FreeCurDir = FALSE;
910 //HKEY CompatKey;
911 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
912 //LPWSTR ImagePathBuffer;
913 ULONG ConfigSize;
914 UNICODE_STRING CurrentDirectory;
915 ULONG ExecuteOptions;
916 ULONG HeapFlags;
917 PIMAGE_NT_HEADERS NtHeader;
918 LPWSTR NtDllName = NULL;
919 NTSTATUS Status;
920 NLSTABLEINFO NlsTable;
921 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
922 PTEB Teb = NtCurrentTeb();
923 PLIST_ENTRY ListHead;
924 PLIST_ENTRY NextEntry;
925 ULONG i;
926 PWSTR ImagePath;
927 ULONG DebugProcessHeapOnly = 0;
928 WCHAR FullNtDllPath[MAX_PATH];
929 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
930 PWCHAR Current;
931
932 /* Set a NULL SEH Filter */
933 RtlSetUnhandledExceptionFilter(NULL);
934
935 /* Get the image path */
936 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
937
938 /* Check if it's normalized */
939 if (Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED)
940 {
941 /* Normalize it*/
942 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
943 }
944
945 /* Create a unicode string for the Image Path */
946 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
947 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
948 ImagePathName.Buffer = ImagePath;
949
950 /* Get the NT Headers */
951 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
952
953 /* Get the execution options */
954 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &ExecuteOptions);
955
956 /* Check if this is a .NET executable */
957 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
958 TRUE,
959 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
960 &ComSectionSize))
961 {
962 /* Remeber this for later */
963 IsDotNetImage = TRUE;
964 }
965
966 /* Save the NTDLL Base address */
967 NtDllBase = SystemArgument1;
968
969 /* If this is a Native Image */
970 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
971 {
972 /* Then do DLL Validation */
973 LdrpDllValidation = TRUE;
974 }
975
976 /* Save the old Shim Data */
977 OldShimData = Peb->pShimData;
978
979 /* Clear it */
980 Peb->pShimData = NULL;
981
982 /* Save the number of processors and CS Timeout */
983 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
984 RtlpTimeout = Peb->CriticalSectionTimeout;
985
986 /* Normalize the parameters */
987 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
988 ProcessParameters = Peb->ProcessParameters;
989 if (ProcessParameters)
990 {
991 /* Save the Image and Command Line Names */
992 ImageFileName = ProcessParameters->ImagePathName;
993 CommandLine = ProcessParameters->CommandLine;
994 }
995 else
996 {
997 /* It failed, initialize empty strings */
998 RtlInitUnicodeString(&ImageFileName, NULL);
999 RtlInitUnicodeString(&CommandLine, NULL);
1000 }
1001
1002 /* Initialize NLS data */
1003 RtlInitNlsTables(Peb->AnsiCodePageData,
1004 Peb->OemCodePageData,
1005 Peb->UnicodeCaseTableData,
1006 &NlsTable);
1007
1008 /* Reset NLS Translations */
1009 RtlResetRtlTranslations(&NlsTable);
1010
1011 /* Get the Image Config Directory */
1012 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1013 TRUE,
1014 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1015 &ConfigSize);
1016
1017 /* Setup the Heap Parameters */
1018 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1019 HeapFlags = HEAP_GROWABLE;
1020 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1021
1022 /* Check if we have Configuration Data */
1023 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1024 {
1025 /* FIXME: Custom heap settings and misc. */
1026 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1027 }
1028
1029 /* Check for custom affinity mask */
1030 if (Peb->ImageProcessAffinityMask)
1031 {
1032 /* Set it */
1033 Status = NtSetInformationProcess(NtCurrentProcess(),
1034 ProcessAffinityMask,
1035 &Peb->ImageProcessAffinityMask,
1036 sizeof(Peb->ImageProcessAffinityMask));
1037 }
1038
1039 /* Check if verbose debugging (ShowSnaps) was requested */
1040 ShowSnaps = TRUE;//Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1041
1042 /* Start verbose debugging messages right now if they were requested */
1043 if (ShowSnaps)
1044 {
1045 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1046 Teb->ClientId.UniqueProcess,
1047 &CommandLine);
1048 }
1049
1050 /* If the timeout is too long */
1051 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1052 {
1053 /* Then disable CS Timeout */
1054 RtlpTimeoutDisable = TRUE;
1055 }
1056
1057 /* Initialize Critical Section Data */
1058 RtlpInitDeferedCriticalSection();
1059
1060 /* Initialize VEH Call lists */
1061 RtlpInitializeVectoredExceptionHandling();
1062
1063 /* Set TLS/FLS Bitmap data */
1064 Peb->FlsBitmap = &FlsBitMap;
1065 Peb->TlsBitmap = &TlsBitMap;
1066 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1067
1068 /* Initialize FLS Bitmap */
1069 RtlInitializeBitMap(&FlsBitMap,
1070 Peb->FlsBitmapBits,
1071 FLS_MAXIMUM_AVAILABLE);
1072 RtlSetBit(&FlsBitMap, 0);
1073
1074 /* Initialize TLS Bitmap */
1075 RtlInitializeBitMap(&TlsBitMap,
1076 Peb->TlsBitmapBits,
1077 TLS_MINIMUM_AVAILABLE);
1078 RtlSetBit(&TlsBitMap, 0);
1079 RtlInitializeBitMap(&TlsExpansionBitMap,
1080 Peb->TlsExpansionBitmapBits,
1081 TLS_EXPANSION_SLOTS);
1082 RtlSetBit(&TlsExpansionBitMap, 0);
1083
1084 /* Initialize the Hash Table */
1085 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1086 {
1087 InitializeListHead(&LdrpHashTable[i]);
1088 }
1089
1090 /* Initialize the Loader Lock */
1091 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1092 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1093 UNIMPLEMENTED;
1094 LdrpLoaderLockInit = TRUE;
1095
1096 /* Check if User Stack Trace Database support was requested */
1097 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1098 {
1099 DPRINT1("We don't support user stack trace databases yet\n");
1100 }
1101
1102 /* Setup Fast PEB Lock */
1103 RtlInitializeCriticalSection(&FastPebLock);
1104 Peb->FastPebLock = &FastPebLock;
1105 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1106 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1107
1108 /* Setup Callout Lock and Notification list */
1109 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1110 InitializeListHead(&LdrpDllNotificationList);
1111
1112 /* For old executables, use 16-byte aligned heap */
1113 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1114 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1115 {
1116 HeapFlags |= HEAP_CREATE_ALIGN_16;
1117 }
1118
1119 /* Setup the Heap */
1120 RtlInitializeHeapManager();
1121 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1122 NULL,
1123 NtHeader->OptionalHeader.SizeOfHeapReserve,
1124 NtHeader->OptionalHeader.SizeOfHeapCommit,
1125 NULL,
1126 &HeapParameters);
1127
1128 if (!Peb->ProcessHeap)
1129 {
1130 DPRINT1("Failed to create process heap\n");
1131 return STATUS_NO_MEMORY;
1132 }
1133
1134 /* Allocate an Activation Context Stack */
1135 Status = RtlAllocateActivationContextStack((PVOID *)&Teb->ActivationContextStackPointer);
1136 if (!NT_SUCCESS(Status)) return Status;
1137
1138 // FIXME: Loader private heap is missing
1139 DPRINT1("Loader private heap is missing\n");
1140
1141 /* Check for Debug Heap */
1142 DPRINT1("Check for a debug heap is missing\n");
1143 if (FALSE)
1144 {
1145 /* Query the setting */
1146 Status = LdrQueryImageFileKeyOption(NULL,//hKey
1147 L"DebugProcessHeapOnly",
1148 REG_DWORD,
1149 &DebugProcessHeapOnly,
1150 sizeof(ULONG),
1151 NULL);
1152
1153 if (NT_SUCCESS(Status))
1154 {
1155 /* Reset DPH if requested */
1156 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1157 {
1158 RtlpDphGlobalFlags &= ~0x40;
1159 RtlpPageHeapEnabled = FALSE;
1160 }
1161 }
1162 }
1163
1164 /* Build the NTDLL Path */
1165 FullPath.Buffer = FullNtDllPath;
1166 FullPath.Length = 0;
1167 FullPath.MaximumLength = sizeof(FullNtDllPath);
1168 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1169 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1170 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1171
1172 /* Open the Known DLLs directory */
1173 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1174 InitializeObjectAttributes(&ObjectAttributes,
1175 &KnownDllString,
1176 OBJ_CASE_INSENSITIVE,
1177 NULL,
1178 NULL);
1179 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1180 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1181 &ObjectAttributes);
1182
1183 /* Check if it exists */
1184 if (!NT_SUCCESS(Status))
1185 {
1186 /* It doesn't, so assume System32 */
1187 LdrpKnownDllObjectDirectory = NULL;
1188 RtlInitUnicodeString(&LdrpKnownDllPath, FullPath.Buffer);
1189 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1190 }
1191 else
1192 {
1193 /* Open the Known DLLs Path */
1194 InitializeObjectAttributes(&ObjectAttributes,
1195 &KnownDllString,
1196 OBJ_CASE_INSENSITIVE,
1197 LdrpKnownDllObjectDirectory,
1198 NULL);
1199 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1200 SYMBOLIC_LINK_QUERY,
1201 &ObjectAttributes);
1202 if (NT_SUCCESS(Status))
1203 {
1204 /* Query the path */
1205 LdrpKnownDllPath.Length = 0;
1206 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1207 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1208 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1209 NtClose(SymLinkHandle);
1210 if (!NT_SUCCESS(Status))
1211 {
1212 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1213 return Status;
1214 }
1215 }
1216 }
1217
1218 /* If we have process parameters, get the default path and current path */
1219 if (ProcessParameters)
1220 {
1221 /* Check if we have a Dll Path */
1222 if (ProcessParameters->DllPath.Length)
1223 {
1224 /* Get the path */
1225 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1226 }
1227 else
1228 {
1229 /* We need a valid path */
1230 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1231 }
1232
1233 /* Set the current directory */
1234 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1235
1236 /* Check if it's empty or invalid */
1237 if ((!CurrentDirectory.Buffer) ||
1238 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1239 (!CurrentDirectory.Length))
1240 {
1241 /* Allocate space for the buffer */
1242 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1243 0,
1244 3 * sizeof(WCHAR) +
1245 sizeof(UNICODE_NULL));
1246
1247 /* Copy the drive of the system root */
1248 RtlMoveMemory(CurrentDirectory.Buffer,
1249 SharedUserData->NtSystemRoot,
1250 3 * sizeof(WCHAR));
1251 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1252 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1253 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1254
1255 FreeCurDir = TRUE;
1256 }
1257 else
1258 {
1259 /* Use the local buffer */
1260 CurrentDirectory.Length = NtSystemRoot.Length;
1261 CurrentDirectory.Buffer = NtSystemRoot.Buffer;
1262 }
1263 }
1264
1265 /* Setup Loader Data */
1266 Peb->Ldr = &PebLdr;
1267 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1268 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1269 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1270 PebLdr.Length = sizeof(PEB_LDR_DATA);
1271 PebLdr.Initialized = TRUE;
1272
1273 /* Allocate a data entry for the Image */
1274 LdrpImageEntry = NtLdrEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1275
1276 /* Set it up */
1277 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1278 NtLdrEntry->LoadCount = -1;
1279 NtLdrEntry->EntryPointActivationContext = 0;
1280 NtLdrEntry->FullDllName.Length = ImageFileName.Length;
1281 NtLdrEntry->FullDllName.Buffer = ImageFileName.Buffer;
1282 if (IsDotNetImage)
1283 NtLdrEntry->Flags = LDRP_COR_IMAGE;
1284 else
1285 NtLdrEntry->Flags = 0;
1286
1287 /* Check if the name is empty */
1288 if (!ImageFileName.Buffer[0])
1289 {
1290 /* Use the same Base name */
1291 NtLdrEntry->BaseDllName = NtLdrEntry->BaseDllName;
1292 }
1293 else
1294 {
1295 /* Find the last slash */
1296 Current = ImageFileName.Buffer;
1297 while (*Current)
1298 {
1299 if (*Current++ == '\\')
1300 {
1301 /* Set this path */
1302 NtDllName = Current;
1303 }
1304 }
1305
1306 /* Did we find anything? */
1307 if (!NtDllName)
1308 {
1309 /* Use the same Base name */
1310 NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
1311 }
1312 else
1313 {
1314 /* Setup the name */
1315 NtLdrEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
1316 NtLdrEntry->BaseDllName.MaximumLength = NtLdrEntry->BaseDllName.Length + sizeof(WCHAR);
1317 NtLdrEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
1318 (ImageFileName.Length - NtLdrEntry->BaseDllName.Length));
1319 }
1320 }
1321
1322 /* Processing done, insert it */
1323 LdrpInsertMemoryTableEntry(NtLdrEntry);
1324 NtLdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
1325
1326 /* Now add an entry for NTDLL */
1327 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
1328 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
1329 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1330 NtLdrEntry->LoadCount = -1;
1331 NtLdrEntry->EntryPointActivationContext = 0;
1332 //NtLdrEntry->BaseDllName.Length = NtSystemRoot.Length;
1333 //RtlAppendUnicodeStringToString(&NtSystemRoot, &NtDllString);
1334 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
1335 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
1336 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
1337
1338 // FIXME: Full DLL name?!
1339
1340 /* Processing done, insert it */
1341 LdrpNtDllDataTableEntry = NtLdrEntry;
1342 LdrpInsertMemoryTableEntry(NtLdrEntry);
1343
1344 /* Let the world know */
1345 if (ShowSnaps)
1346 {
1347 DPRINT1("LDR: NEW PROCESS\n");
1348 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
1349 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
1350 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
1351 }
1352
1353 /* Link the Init Order List */
1354 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
1355 &LdrpNtDllDataTableEntry->InInitializationOrderModuleList);
1356
1357 /* Set the current directory */
1358 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
1359 if (!NT_SUCCESS(Status))
1360 {
1361 /* We failed, check if we should free it */
1362 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1363
1364 /* Set it to the NT Root */
1365 CurrentDirectory = NtSystemRoot;
1366 RtlSetCurrentDirectory_U(&CurrentDirectory);
1367 }
1368 else
1369 {
1370 /* We're done with it, free it */
1371 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1372 }
1373
1374 /* Check if we should look for a .local file */
1375 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
1376 {
1377 /* FIXME */
1378 DPRINT1("We don't support .local overrides yet\n");
1379 }
1380
1381 /* Check if the Application Verifier was enabled */
1382 if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK)
1383 {
1384 /* FIXME */
1385 DPRINT1("We don't support Application Verifier yet\n");
1386 }
1387
1388 if (IsDotNetImage)
1389 {
1390 /* FIXME */
1391 DPRINT1("We don't support .NET applications yet\n");
1392 }
1393
1394 /* FIXME: Load support for Terminal Services */
1395 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1396 {
1397 /* Load kernel32 and call BasePostImportInit... */
1398 DPRINT1("Unimplemented codepath!\n");
1399 }
1400
1401 /* Walk the IAT and load all the DLLs */
1402 LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
1403
1404 /* Check if relocation is needed */
1405 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
1406 {
1407 DPRINT("LDR: Performing relocations\n");
1408 Status = LdrPerformRelocations(NtHeader, Peb->ImageBaseAddress);
1409 if (!NT_SUCCESS(Status))
1410 {
1411 DPRINT1("LdrPerformRelocations() failed\n");
1412 return STATUS_INVALID_IMAGE_FORMAT;
1413 }
1414 }
1415
1416 /* Lock the DLLs */
1417 ListHead = &Peb->Ldr->InLoadOrderModuleList;
1418 NextEntry = ListHead->Flink;
1419 while (ListHead != NextEntry)
1420 {
1421 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1422 NtLdrEntry->LoadCount = -1;
1423 NextEntry = NextEntry->Flink;
1424 }
1425
1426 /* Phase 0 is done */
1427 LdrpLdrDatabaseIsSetup = TRUE;
1428
1429 /* Initialize TLS */
1430 Status = LdrpInitializeTls();
1431 if (!NT_SUCCESS(Status))
1432 {
1433 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
1434 Status);
1435 return Status;
1436 }
1437
1438 /* FIXME Mark the DLL Ranges for Stack Traces later */
1439
1440 /* Notify the debugger now */
1441 if (Peb->BeingDebugged)
1442 {
1443 /* Break */
1444 DbgBreakPoint();
1445
1446 /* Update show snaps again */
1447 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1448 }
1449
1450 /* Validate the Image for MP Usage */
1451 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
1452
1453 /* Check NX Options */
1454 if (SharedUserData->NXSupportPolicy == 1)
1455 {
1456 ExecuteOptions = 0xD;
1457 }
1458 else if (!SharedUserData->NXSupportPolicy)
1459 {
1460 ExecuteOptions = 0xA;
1461 }
1462
1463 /* Let Mm know */
1464 ZwSetInformationProcess(NtCurrentProcess(),
1465 ProcessExecuteFlags,
1466 &ExecuteOptions,
1467 sizeof(ULONG));
1468
1469 /* Check if we had Shim Data */
1470 if (OldShimData)
1471 {
1472 /* Load the Shim Engine */
1473 Peb->AppCompatInfo = NULL;
1474 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
1475 DPRINT1("We do not support shims yet\n");
1476 }
1477 else
1478 {
1479 /* Check for Application Compatibility Goo */
1480 //LdrQueryApplicationCompatibilityGoo(hKey);
1481 DPRINT1("Querying app compat hacks is missing!\n");
1482 }
1483
1484 /*
1485 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
1486 * incompatible images.
1487 */
1488
1489 /* Now call the Init Routines */
1490 Status = LdrpRunInitializeRoutines(Context);
1491 if (!NT_SUCCESS(Status))
1492 {
1493 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
1494 Status);
1495 return Status;
1496 }
1497
1498 /* FIXME: Unload the Shim Engine if it was loaded */
1499
1500 /* Check if we have a user-defined Post Process Routine */
1501 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
1502 {
1503 DPRINT1("CP\n");
1504 /* Call it */
1505 Peb->PostProcessInitRoutine();
1506 }
1507
1508 ///* Close the key if we have one opened */
1509 //if (hKey) NtClose(hKey);
1510 DbgBreakPoint();
1511 /* Return status */
1512 return Status;
1513 }
1514
1515 VOID
1516 NTAPI
1517 LdrpInitFailure(NTSTATUS Status)
1518 {
1519 ULONG Response;
1520
1521 /* Print a debug message */
1522 DPRINT1("LDR: Process initialization failure; NTSTATUS = %08lx\n", Status);
1523
1524 /* Raise a hard error */
1525 if (!LdrpFatalHardErrorCount)
1526 {
1527 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
1528 }
1529 }
1530
1531 VOID
1532 NTAPI
1533 LdrpInit(PCONTEXT Context,
1534 PVOID SystemArgument1,
1535 PVOID SystemArgument2)
1536 {
1537 LARGE_INTEGER Timeout;
1538 PTEB Teb = NtCurrentTeb();
1539 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
1540 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
1541 PPEB Peb = NtCurrentPeb();
1542
1543 DPRINT("LdrpInit()\n");
1544
1545 /* Check if we have a deallocation stack */
1546 if (!Teb->DeallocationStack)
1547 {
1548 /* We don't, set one */
1549 Status = NtQueryVirtualMemory(NtCurrentProcess(),
1550 Teb->NtTib.StackLimit,
1551 MemoryBasicInformation,
1552 &MemoryBasicInfo,
1553 sizeof(MEMORY_BASIC_INFORMATION),
1554 NULL);
1555 if (!NT_SUCCESS(Status))
1556 {
1557 /* Fail */
1558 LdrpInitFailure(Status);
1559 RtlRaiseStatus(Status);
1560 return;
1561 }
1562
1563 /* Set the stack */
1564 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
1565 }
1566
1567 /* Now check if the process is already being initialized */
1568 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
1569 1,
1570 0) == 1)
1571 {
1572 /* Set the timeout to 30 seconds */
1573 Timeout.QuadPart = Int32x32To64(30, -10000);
1574
1575 /* Make sure the status hasn't changed */
1576 while (!LdrpProcessInitialized)
1577 {
1578 /* Do the wait */
1579 ZwDelayExecution(FALSE, &Timeout);
1580 }
1581 }
1582
1583 /* Check if we have already setup LDR data */
1584 if (!Peb->Ldr)
1585 {
1586 /* Setup the Loader Lock */
1587 Peb->LoaderLock = &LdrpLoaderLock;
1588
1589 /* Let other code know we're initializing */
1590 LdrpInLdrInit = TRUE;
1591
1592 /* Protect with SEH */
1593 _SEH2_TRY
1594 {
1595 /* Initialize the Process */
1596 LoaderStatus = LdrpInitializeProcess_(Context,
1597 SystemArgument1);
1598
1599 /* Check for success and if MinimumStackCommit was requested */
1600 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
1601 {
1602 /* Enforce the limit */
1603 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
1604 UNIMPLEMENTED;
1605 }
1606 }
1607 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1608 {
1609 /* Fail with the SEH error */
1610 LoaderStatus = _SEH2_GetExceptionCode();
1611 }
1612 _SEH2_END;
1613
1614 /* We're not initializing anymore */
1615 LdrpInLdrInit = FALSE;
1616
1617 /* Check if init worked */
1618 if (NT_SUCCESS(LoaderStatus))
1619 {
1620 /* Set the process as Initialized */
1621 _InterlockedIncrement(&LdrpProcessInitialized);
1622 }
1623 }
1624 else
1625 {
1626 /* Loader data is there... is this a fork() ? */
1627 if(Peb->InheritedAddressSpace)
1628 {
1629 /* Handle the fork() */
1630 //LoaderStatus = LdrpForkProcess();
1631 LoaderStatus = STATUS_NOT_IMPLEMENTED;
1632 UNIMPLEMENTED;
1633 }
1634 else
1635 {
1636 /* This is a new thread initializing */
1637 LdrpInitializeThread(Context);
1638 }
1639 }
1640
1641 /* All done, test alert the thread */
1642 NtTestAlert();
1643
1644 /* Return */
1645 if (!NT_SUCCESS(LoaderStatus))
1646 {
1647 /* Fail */
1648 LdrpInitFailure(LoaderStatus);
1649 RtlRaiseStatus(LoaderStatus);
1650 }
1651 }
1652
1653 /* EOF */