[MSI]
[reactos.git] / reactos / 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 /* Reset status back to STATUS_SUCCESS */
596 Status = STATUS_SUCCESS;
597 }
598
599 /* Break if aksed */
600 if (BreakOnDllLoad)
601 {
602 /* Check if we should show a message */
603 if (ShowSnaps)
604 {
605 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
606 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
607 }
608
609 /* Break in debugger */
610 DbgBreakPoint();
611 }
612
613 /* Make sure we have an entrypoint */
614 if (EntryPoint)
615 {
616 /* Save the old Dll Initializer and write the current one */
617 OldInitializer = LdrpCurrentDllInitializer;
618 LdrpCurrentDllInitializer = LdrEntry;
619
620 /* Set up the Act Ctx */
621 ActCtx.Size = sizeof(ActCtx);
622 ActCtx.Format = 1;
623 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
624
625 /* Activate the ActCtx */
626 RtlActivateActivationContextUnsafeFast(&ActCtx,
627 LdrEntry->EntryPointActivationContext);
628
629 /* Check if it has TLS */
630 if (LdrEntry->TlsIndex && Context)
631 {
632 /* Call TLS */
633 LdrpTlsCallback(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
634 }
635
636 /* Call the Entrypoint */
637 if (ShowSnaps)
638 {
639 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
640 &LdrEntry->BaseDllName, EntryPoint);
641 }
642 DllStatus = LdrpCallDllEntry(EntryPoint,
643 LdrEntry->DllBase,
644 DLL_PROCESS_ATTACH,
645 Context);
646
647 /* Deactivate the ActCtx */
648 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
649
650 /* Save the Current DLL Initializer */
651 LdrpCurrentDllInitializer = OldInitializer;
652
653 /* Mark the entry as processed */
654 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
655
656 /* Fail if DLL init failed */
657 if (!DllStatus)
658 {
659 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
660 &LdrEntry->BaseDllName, EntryPoint);
661
662 Status = STATUS_DLL_INIT_FAILED;
663 goto Quickie;
664 }
665 }
666 }
667
668 /* Loop in order */
669 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
670 NextEntry = NextEntry->Flink;
671 while (NextEntry != ListHead)
672 {
673 /* Get the Data Entrry */
674 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
675
676 /* FIXME: Verify NX Compat */
677 // LdrpCheckNXCompatibility()
678
679 /* Next entry */
680 NextEntry = NextEntry->Flink;
681 }
682
683 /* Check for TLS */
684 if (LdrpImageHasTls && Context)
685 {
686 /* Set up the Act Ctx */
687 ActCtx.Size = sizeof(ActCtx);
688 ActCtx.Format = 1;
689 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
690
691 /* Activate the ActCtx */
692 RtlActivateActivationContextUnsafeFast(&ActCtx,
693 LdrpImageEntry->EntryPointActivationContext);
694
695 /* Do TLS callbacks */
696 LdrpTlsCallback(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
697
698 /* Deactivate the ActCtx */
699 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
700 }
701
702 Quickie:
703 /* Restore old TEB */
704 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
705
706 /* Check if the array is in the heap */
707 if (LdrRootEntry != LocalArray)
708 {
709 /* Free the array */
710 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
711 }
712
713 /* Return to caller */
714 DPRINT("LdrpRunInitializeRoutines() done\n");
715 return Status;
716 }
717
718 NTSTATUS
719 NTAPI
720 LdrpInitializeTls(VOID)
721 {
722 PLIST_ENTRY NextEntry, ListHead;
723 PLDR_DATA_TABLE_ENTRY LdrEntry;
724 PIMAGE_TLS_DIRECTORY TlsDirectory;
725 PLDRP_TLS_DATA TlsData;
726 ULONG Size;
727
728 /* Initialize the TLS List */
729 InitializeListHead(&LdrpTlsList);
730
731 /* Loop all the modules */
732 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
733 NextEntry = ListHead->Flink;
734 while (ListHead != NextEntry)
735 {
736 /* Get the entry */
737 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
738 NextEntry = NextEntry->Flink;
739
740 /* Get the TLS directory */
741 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
742 TRUE,
743 IMAGE_DIRECTORY_ENTRY_TLS,
744 &Size);
745
746 /* Check if we have a directory */
747 if (!TlsDirectory) continue;
748
749 /* Check if the image has TLS */
750 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
751
752 /* Show debug message */
753 if (ShowSnaps)
754 {
755 DPRINT1("LDR: Tls Found in %wZ at %p\n",
756 &LdrEntry->BaseDllName,
757 TlsDirectory);
758 }
759
760 /* Allocate an entry */
761 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
762 if (!TlsData) return STATUS_NO_MEMORY;
763
764 /* Lock the DLL and mark it for TLS Usage */
765 LdrEntry->LoadCount = -1;
766 LdrEntry->TlsIndex = -1;
767
768 /* Save the cached TLS data */
769 TlsData->TlsDirectory = *TlsDirectory;
770 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
771
772 /* Update the index */
773 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
774 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
775 }
776
777 /* Done setting up TLS, allocate entries */
778 return LdrpAllocateTls();
779 }
780
781 NTSTATUS
782 NTAPI
783 LdrpAllocateTls(VOID)
784 {
785 PTEB Teb = NtCurrentTeb();
786 PLIST_ENTRY NextEntry, ListHead;
787 PLDRP_TLS_DATA TlsData;
788 ULONG TlsDataSize;
789 PVOID *TlsVector;
790
791 /* Check if we have any entries */
792 if (!LdrpNumberOfTlsEntries)
793 return STATUS_SUCCESS;
794
795 /* Allocate the vector array */
796 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
797 0,
798 LdrpNumberOfTlsEntries * sizeof(PVOID));
799 if (!TlsVector) return STATUS_NO_MEMORY;
800 Teb->ThreadLocalStoragePointer = TlsVector;
801
802 /* Loop the TLS Array */
803 ListHead = &LdrpTlsList;
804 NextEntry = ListHead->Flink;
805 while (NextEntry != ListHead)
806 {
807 /* Get the entry */
808 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
809 NextEntry = NextEntry->Flink;
810
811 /* Allocate this vector */
812 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
813 TlsData->TlsDirectory.StartAddressOfRawData;
814 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
815 0,
816 TlsDataSize);
817 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
818 {
819 /* Out of memory */
820 return STATUS_NO_MEMORY;
821 }
822
823 /* Show debug message */
824 if (ShowSnaps)
825 {
826 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
827 TlsVector,
828 TlsData->TlsDirectory.Characteristics,
829 &TlsVector[TlsData->TlsDirectory.Characteristics],
830 TlsData->TlsDirectory.StartAddressOfRawData,
831 TlsVector[TlsData->TlsDirectory.Characteristics]);
832 }
833
834 /* Copy the data */
835 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
836 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
837 TlsDataSize);
838 }
839
840 /* Done */
841 return STATUS_SUCCESS;
842 }
843
844 VOID
845 NTAPI
846 LdrpFreeTls(VOID)
847 {
848 PLIST_ENTRY ListHead, NextEntry;
849 PLDRP_TLS_DATA TlsData;
850 PVOID *TlsVector;
851 PTEB Teb = NtCurrentTeb();
852
853 /* Get a pointer to the vector array */
854 TlsVector = Teb->ThreadLocalStoragePointer;
855 if (!TlsVector) return;
856
857 /* Loop through it */
858 ListHead = &LdrpTlsList;
859 NextEntry = ListHead->Flink;
860 while (NextEntry != ListHead)
861 {
862 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
863 NextEntry = NextEntry->Flink;
864
865 /* Free each entry */
866 if (TlsVector[TlsData->TlsDirectory.Characteristics])
867 {
868 RtlFreeHeap(RtlGetProcessHeap(),
869 0,
870 TlsVector[TlsData->TlsDirectory.Characteristics]);
871 }
872 }
873
874 /* Free the array itself */
875 RtlFreeHeap(RtlGetProcessHeap(),
876 0,
877 TlsVector);
878 }
879
880 NTSTATUS
881 NTAPI
882 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PULONG Options)
883 {
884 UNIMPLEMENTED;
885 *Options = 0;
886 return STATUS_SUCCESS;
887 }
888
889 VOID
890 NTAPI
891 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
892 {
893 UNIMPLEMENTED;
894 }
895
896 NTSTATUS
897 NTAPI
898 LdrpInitializeProcess(IN PCONTEXT Context,
899 IN PVOID SystemArgument1)
900 {
901 RTL_HEAP_PARAMETERS HeapParameters;
902 ULONG ComSectionSize;
903 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
904 PVOID OldShimData;
905 OBJECT_ATTRIBUTES ObjectAttributes;
906 //UNICODE_STRING LocalFileName, FullImageName;
907 HANDLE SymLinkHandle;
908 //ULONG DebugHeapOnly;
909 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
910 PPEB Peb = NtCurrentPeb();
911 BOOLEAN IsDotNetImage = FALSE;
912 BOOLEAN FreeCurDir = FALSE;
913 //HKEY CompatKey;
914 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
915 //LPWSTR ImagePathBuffer;
916 ULONG ConfigSize;
917 UNICODE_STRING CurrentDirectory;
918 ULONG ExecuteOptions;
919 ULONG HeapFlags;
920 PIMAGE_NT_HEADERS NtHeader;
921 LPWSTR NtDllName = NULL;
922 NTSTATUS Status;
923 NLSTABLEINFO NlsTable;
924 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
925 PTEB Teb = NtCurrentTeb();
926 PLIST_ENTRY ListHead;
927 PLIST_ENTRY NextEntry;
928 ULONG i;
929 PWSTR ImagePath;
930 ULONG DebugProcessHeapOnly = 0;
931 WCHAR FullNtDllPath[MAX_PATH];
932 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
933 PWCHAR Current;
934
935 /* Set a NULL SEH Filter */
936 RtlSetUnhandledExceptionFilter(NULL);
937
938 /* Get the image path */
939 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
940
941 /* Check if it's normalized */
942 if (Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED)
943 {
944 /* Normalize it*/
945 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
946 }
947
948 /* Create a unicode string for the Image Path */
949 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
950 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
951 ImagePathName.Buffer = ImagePath;
952
953 /* Get the NT Headers */
954 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
955
956 /* Get the execution options */
957 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &ExecuteOptions);
958
959 /* Check if this is a .NET executable */
960 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
961 TRUE,
962 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
963 &ComSectionSize))
964 {
965 /* Remeber this for later */
966 IsDotNetImage = TRUE;
967 }
968
969 /* Save the NTDLL Base address */
970 NtDllBase = SystemArgument1;
971
972 /* If this is a Native Image */
973 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
974 {
975 /* Then do DLL Validation */
976 LdrpDllValidation = TRUE;
977 }
978
979 /* Save the old Shim Data */
980 OldShimData = Peb->pShimData;
981
982 /* Clear it */
983 Peb->pShimData = NULL;
984
985 /* Save the number of processors and CS Timeout */
986 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
987 RtlpTimeout = Peb->CriticalSectionTimeout;
988
989 /* Normalize the parameters */
990 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
991 ProcessParameters = Peb->ProcessParameters;
992 if (ProcessParameters)
993 {
994 /* Save the Image and Command Line Names */
995 ImageFileName = ProcessParameters->ImagePathName;
996 CommandLine = ProcessParameters->CommandLine;
997 }
998 else
999 {
1000 /* It failed, initialize empty strings */
1001 RtlInitUnicodeString(&ImageFileName, NULL);
1002 RtlInitUnicodeString(&CommandLine, NULL);
1003 }
1004
1005 /* Initialize NLS data */
1006 RtlInitNlsTables(Peb->AnsiCodePageData,
1007 Peb->OemCodePageData,
1008 Peb->UnicodeCaseTableData,
1009 &NlsTable);
1010
1011 /* Reset NLS Translations */
1012 RtlResetRtlTranslations(&NlsTable);
1013
1014 /* Get the Image Config Directory */
1015 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1016 TRUE,
1017 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1018 &ConfigSize);
1019
1020 /* Setup the Heap Parameters */
1021 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1022 HeapFlags = HEAP_GROWABLE;
1023 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1024
1025 /* Check if we have Configuration Data */
1026 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1027 {
1028 /* FIXME: Custom heap settings and misc. */
1029 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1030 }
1031
1032 /* Check for custom affinity mask */
1033 if (Peb->ImageProcessAffinityMask)
1034 {
1035 /* Set it */
1036 Status = NtSetInformationProcess(NtCurrentProcess(),
1037 ProcessAffinityMask,
1038 &Peb->ImageProcessAffinityMask,
1039 sizeof(Peb->ImageProcessAffinityMask));
1040 }
1041
1042 /* Check if verbose debugging (ShowSnaps) was requested */
1043 ShowSnaps = TRUE;//Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1044
1045 /* Start verbose debugging messages right now if they were requested */
1046 if (ShowSnaps)
1047 {
1048 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1049 Teb->ClientId.UniqueProcess,
1050 &CommandLine);
1051 }
1052
1053 /* If the timeout is too long */
1054 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1055 {
1056 /* Then disable CS Timeout */
1057 RtlpTimeoutDisable = TRUE;
1058 }
1059
1060 /* Initialize Critical Section Data */
1061 RtlpInitDeferedCriticalSection();
1062
1063 /* Initialize VEH Call lists */
1064 RtlpInitializeVectoredExceptionHandling();
1065
1066 /* Set TLS/FLS Bitmap data */
1067 Peb->FlsBitmap = &FlsBitMap;
1068 Peb->TlsBitmap = &TlsBitMap;
1069 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1070
1071 /* Initialize FLS Bitmap */
1072 RtlInitializeBitMap(&FlsBitMap,
1073 Peb->FlsBitmapBits,
1074 FLS_MAXIMUM_AVAILABLE);
1075 RtlSetBit(&FlsBitMap, 0);
1076
1077 /* Initialize TLS Bitmap */
1078 RtlInitializeBitMap(&TlsBitMap,
1079 Peb->TlsBitmapBits,
1080 TLS_MINIMUM_AVAILABLE);
1081 RtlSetBit(&TlsBitMap, 0);
1082 RtlInitializeBitMap(&TlsExpansionBitMap,
1083 Peb->TlsExpansionBitmapBits,
1084 TLS_EXPANSION_SLOTS);
1085 RtlSetBit(&TlsExpansionBitMap, 0);
1086
1087 /* Initialize the Hash Table */
1088 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1089 {
1090 InitializeListHead(&LdrpHashTable[i]);
1091 }
1092
1093 /* Initialize the Loader Lock */
1094 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1095 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1096 UNIMPLEMENTED;
1097 LdrpLoaderLockInit = TRUE;
1098
1099 /* Check if User Stack Trace Database support was requested */
1100 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1101 {
1102 DPRINT1("We don't support user stack trace databases yet\n");
1103 }
1104
1105 /* Setup Fast PEB Lock */
1106 RtlInitializeCriticalSection(&FastPebLock);
1107 Peb->FastPebLock = &FastPebLock;
1108 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1109 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1110
1111 /* Setup Callout Lock and Notification list */
1112 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1113 InitializeListHead(&LdrpDllNotificationList);
1114
1115 /* For old executables, use 16-byte aligned heap */
1116 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1117 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1118 {
1119 HeapFlags |= HEAP_CREATE_ALIGN_16;
1120 }
1121
1122 /* Setup the Heap */
1123 RtlInitializeHeapManager();
1124 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1125 NULL,
1126 NtHeader->OptionalHeader.SizeOfHeapReserve,
1127 NtHeader->OptionalHeader.SizeOfHeapCommit,
1128 NULL,
1129 &HeapParameters);
1130
1131 if (!Peb->ProcessHeap)
1132 {
1133 DPRINT1("Failed to create process heap\n");
1134 return STATUS_NO_MEMORY;
1135 }
1136
1137 /* Allocate an Activation Context Stack */
1138 Status = RtlAllocateActivationContextStack((PVOID *)&Teb->ActivationContextStackPointer);
1139 if (!NT_SUCCESS(Status)) return Status;
1140
1141 // FIXME: Loader private heap is missing
1142 DPRINT1("Loader private heap is missing\n");
1143
1144 /* Check for Debug Heap */
1145 DPRINT1("Check for a debug heap is missing\n");
1146 if (FALSE)
1147 {
1148 /* Query the setting */
1149 Status = LdrQueryImageFileKeyOption(NULL,//hKey
1150 L"DebugProcessHeapOnly",
1151 REG_DWORD,
1152 &DebugProcessHeapOnly,
1153 sizeof(ULONG),
1154 NULL);
1155
1156 if (NT_SUCCESS(Status))
1157 {
1158 /* Reset DPH if requested */
1159 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1160 {
1161 RtlpDphGlobalFlags &= ~0x40;
1162 RtlpPageHeapEnabled = FALSE;
1163 }
1164 }
1165 }
1166
1167 /* Build the NTDLL Path */
1168 FullPath.Buffer = FullNtDllPath;
1169 FullPath.Length = 0;
1170 FullPath.MaximumLength = sizeof(FullNtDllPath);
1171 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1172 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1173 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1174
1175 /* Open the Known DLLs directory */
1176 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1177 InitializeObjectAttributes(&ObjectAttributes,
1178 &KnownDllString,
1179 OBJ_CASE_INSENSITIVE,
1180 NULL,
1181 NULL);
1182 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1183 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1184 &ObjectAttributes);
1185
1186 /* Check if it exists */
1187 if (!NT_SUCCESS(Status))
1188 {
1189 /* It doesn't, so assume System32 */
1190 LdrpKnownDllObjectDirectory = NULL;
1191 RtlInitUnicodeString(&LdrpKnownDllPath, FullPath.Buffer);
1192 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1193 }
1194 else
1195 {
1196 /* Open the Known DLLs Path */
1197 InitializeObjectAttributes(&ObjectAttributes,
1198 &KnownDllString,
1199 OBJ_CASE_INSENSITIVE,
1200 LdrpKnownDllObjectDirectory,
1201 NULL);
1202 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1203 SYMBOLIC_LINK_QUERY,
1204 &ObjectAttributes);
1205 if (NT_SUCCESS(Status))
1206 {
1207 /* Query the path */
1208 LdrpKnownDllPath.Length = 0;
1209 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1210 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1211 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1212 NtClose(SymLinkHandle);
1213 if (!NT_SUCCESS(Status))
1214 {
1215 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1216 return Status;
1217 }
1218 }
1219 }
1220
1221 /* If we have process parameters, get the default path and current path */
1222 if (ProcessParameters)
1223 {
1224 /* Check if we have a Dll Path */
1225 if (ProcessParameters->DllPath.Length)
1226 {
1227 /* Get the path */
1228 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1229 }
1230 else
1231 {
1232 /* We need a valid path */
1233 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1234 }
1235
1236 /* Set the current directory */
1237 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1238
1239 /* Check if it's empty or invalid */
1240 if ((!CurrentDirectory.Buffer) ||
1241 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1242 (!CurrentDirectory.Length))
1243 {
1244 /* Allocate space for the buffer */
1245 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1246 0,
1247 3 * sizeof(WCHAR) +
1248 sizeof(UNICODE_NULL));
1249
1250 /* Copy the drive of the system root */
1251 RtlMoveMemory(CurrentDirectory.Buffer,
1252 SharedUserData->NtSystemRoot,
1253 3 * sizeof(WCHAR));
1254 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1255 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1256 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1257
1258 FreeCurDir = TRUE;
1259 }
1260 else
1261 {
1262 /* Use the local buffer */
1263 CurrentDirectory.Length = NtSystemRoot.Length;
1264 CurrentDirectory.Buffer = NtSystemRoot.Buffer;
1265 }
1266 }
1267
1268 /* Setup Loader Data */
1269 Peb->Ldr = &PebLdr;
1270 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1271 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1272 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1273 PebLdr.Length = sizeof(PEB_LDR_DATA);
1274 PebLdr.Initialized = TRUE;
1275
1276 /* Allocate a data entry for the Image */
1277 LdrpImageEntry = NtLdrEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1278
1279 /* Set it up */
1280 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1281 NtLdrEntry->LoadCount = -1;
1282 NtLdrEntry->EntryPointActivationContext = 0;
1283 NtLdrEntry->FullDllName.Length = ImageFileName.Length;
1284 NtLdrEntry->FullDllName.Buffer = ImageFileName.Buffer;
1285 if (IsDotNetImage)
1286 NtLdrEntry->Flags = LDRP_COR_IMAGE;
1287 else
1288 NtLdrEntry->Flags = 0;
1289
1290 /* Check if the name is empty */
1291 if (!ImageFileName.Buffer[0])
1292 {
1293 /* Use the same Base name */
1294 NtLdrEntry->BaseDllName = NtLdrEntry->BaseDllName;
1295 }
1296 else
1297 {
1298 /* Find the last slash */
1299 Current = ImageFileName.Buffer;
1300 while (*Current)
1301 {
1302 if (*Current++ == '\\')
1303 {
1304 /* Set this path */
1305 NtDllName = Current;
1306 }
1307 }
1308
1309 /* Did we find anything? */
1310 if (!NtDllName)
1311 {
1312 /* Use the same Base name */
1313 NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
1314 }
1315 else
1316 {
1317 /* Setup the name */
1318 NtLdrEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
1319 NtLdrEntry->BaseDllName.MaximumLength = NtLdrEntry->BaseDllName.Length + sizeof(WCHAR);
1320 NtLdrEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
1321 (ImageFileName.Length - NtLdrEntry->BaseDllName.Length));
1322 }
1323 }
1324
1325 /* Processing done, insert it */
1326 LdrpInsertMemoryTableEntry(NtLdrEntry);
1327 NtLdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
1328
1329 /* Now add an entry for NTDLL */
1330 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
1331 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
1332 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1333 NtLdrEntry->LoadCount = -1;
1334 NtLdrEntry->EntryPointActivationContext = 0;
1335 //NtLdrEntry->BaseDllName.Length = NtSystemRoot.Length;
1336 //RtlAppendUnicodeStringToString(&NtSystemRoot, &NtDllString);
1337 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
1338 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
1339 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
1340
1341 // FIXME: Full DLL name?!
1342
1343 /* Processing done, insert it */
1344 LdrpNtDllDataTableEntry = NtLdrEntry;
1345 LdrpInsertMemoryTableEntry(NtLdrEntry);
1346
1347 /* Let the world know */
1348 if (ShowSnaps)
1349 {
1350 DPRINT1("LDR: NEW PROCESS\n");
1351 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
1352 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
1353 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
1354 }
1355
1356 /* Link the Init Order List */
1357 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
1358 &LdrpNtDllDataTableEntry->InInitializationOrderModuleList);
1359
1360 /* Set the current directory */
1361 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
1362 if (!NT_SUCCESS(Status))
1363 {
1364 /* We failed, check if we should free it */
1365 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1366
1367 /* Set it to the NT Root */
1368 CurrentDirectory = NtSystemRoot;
1369 RtlSetCurrentDirectory_U(&CurrentDirectory);
1370 }
1371 else
1372 {
1373 /* We're done with it, free it */
1374 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1375 }
1376
1377 /* Check if we should look for a .local file */
1378 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
1379 {
1380 /* FIXME */
1381 DPRINT1("We don't support .local overrides yet\n");
1382 }
1383
1384 /* Check if the Application Verifier was enabled */
1385 if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK)
1386 {
1387 /* FIXME */
1388 DPRINT1("We don't support Application Verifier yet\n");
1389 }
1390
1391 if (IsDotNetImage)
1392 {
1393 /* FIXME */
1394 DPRINT1("We don't support .NET applications yet\n");
1395 }
1396
1397 /* FIXME: Load support for Terminal Services */
1398 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1399 {
1400 /* Load kernel32 and call BasePostImportInit... */
1401 DPRINT1("Unimplemented codepath!\n");
1402 }
1403
1404 /* Walk the IAT and load all the DLLs */
1405 LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
1406
1407 /* Check if relocation is needed */
1408 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
1409 {
1410 DPRINT("LDR: Performing relocations\n");
1411 Status = LdrPerformRelocations(NtHeader, Peb->ImageBaseAddress);
1412 if (!NT_SUCCESS(Status))
1413 {
1414 DPRINT1("LdrPerformRelocations() failed\n");
1415 return STATUS_INVALID_IMAGE_FORMAT;
1416 }
1417 }
1418
1419 /* Lock the DLLs */
1420 ListHead = &Peb->Ldr->InLoadOrderModuleList;
1421 NextEntry = ListHead->Flink;
1422 while (ListHead != NextEntry)
1423 {
1424 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1425 NtLdrEntry->LoadCount = -1;
1426 NextEntry = NextEntry->Flink;
1427 }
1428
1429 /* Phase 0 is done */
1430 LdrpLdrDatabaseIsSetup = TRUE;
1431
1432 /* Initialize TLS */
1433 Status = LdrpInitializeTls();
1434 if (!NT_SUCCESS(Status))
1435 {
1436 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
1437 Status);
1438 return Status;
1439 }
1440
1441 /* FIXME Mark the DLL Ranges for Stack Traces later */
1442
1443 /* Notify the debugger now */
1444 if (Peb->BeingDebugged)
1445 {
1446 /* Break */
1447 DbgBreakPoint();
1448
1449 /* Update show snaps again */
1450 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1451 }
1452
1453 /* Validate the Image for MP Usage */
1454 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
1455
1456 /* Check NX Options */
1457 if (SharedUserData->NXSupportPolicy == 1)
1458 {
1459 ExecuteOptions = 0xD;
1460 }
1461 else if (!SharedUserData->NXSupportPolicy)
1462 {
1463 ExecuteOptions = 0xA;
1464 }
1465
1466 /* Let Mm know */
1467 ZwSetInformationProcess(NtCurrentProcess(),
1468 ProcessExecuteFlags,
1469 &ExecuteOptions,
1470 sizeof(ULONG));
1471
1472 /* Check if we had Shim Data */
1473 if (OldShimData)
1474 {
1475 /* Load the Shim Engine */
1476 Peb->AppCompatInfo = NULL;
1477 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
1478 DPRINT1("We do not support shims yet\n");
1479 }
1480 else
1481 {
1482 /* Check for Application Compatibility Goo */
1483 //LdrQueryApplicationCompatibilityGoo(hKey);
1484 DPRINT1("Querying app compat hacks is missing!\n");
1485 }
1486
1487 /*
1488 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
1489 * incompatible images.
1490 */
1491
1492 /* Now call the Init Routines */
1493 Status = LdrpRunInitializeRoutines(Context);
1494 if (!NT_SUCCESS(Status))
1495 {
1496 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
1497 Status);
1498 return Status;
1499 }
1500
1501 /* FIXME: Unload the Shim Engine if it was loaded */
1502
1503 /* Check if we have a user-defined Post Process Routine */
1504 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
1505 {
1506 DPRINT1("CP\n");
1507 /* Call it */
1508 Peb->PostProcessInitRoutine();
1509 }
1510
1511 ///* Close the key if we have one opened */
1512 //if (hKey) NtClose(hKey);
1513 DbgBreakPoint();
1514 /* Return status */
1515 return Status;
1516 }
1517
1518 VOID
1519 NTAPI
1520 LdrpInitFailure(NTSTATUS Status)
1521 {
1522 ULONG Response;
1523
1524 /* Print a debug message */
1525 DPRINT1("LDR: Process initialization failure; NTSTATUS = %08lx\n", Status);
1526
1527 /* Raise a hard error */
1528 if (!LdrpFatalHardErrorCount)
1529 {
1530 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
1531 }
1532 }
1533
1534 VOID
1535 NTAPI
1536 LdrpInit(PCONTEXT Context,
1537 PVOID SystemArgument1,
1538 PVOID SystemArgument2)
1539 {
1540 LARGE_INTEGER Timeout;
1541 PTEB Teb = NtCurrentTeb();
1542 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
1543 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
1544 PPEB Peb = NtCurrentPeb();
1545
1546 DPRINT("LdrpInit()\n");
1547
1548 /* Check if we have a deallocation stack */
1549 if (!Teb->DeallocationStack)
1550 {
1551 /* We don't, set one */
1552 Status = NtQueryVirtualMemory(NtCurrentProcess(),
1553 Teb->NtTib.StackLimit,
1554 MemoryBasicInformation,
1555 &MemoryBasicInfo,
1556 sizeof(MEMORY_BASIC_INFORMATION),
1557 NULL);
1558 if (!NT_SUCCESS(Status))
1559 {
1560 /* Fail */
1561 LdrpInitFailure(Status);
1562 RtlRaiseStatus(Status);
1563 return;
1564 }
1565
1566 /* Set the stack */
1567 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
1568 }
1569
1570 /* Now check if the process is already being initialized */
1571 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
1572 1,
1573 0) == 1)
1574 {
1575 /* Set the timeout to 30 seconds */
1576 Timeout.QuadPart = Int32x32To64(30, -10000);
1577
1578 /* Make sure the status hasn't changed */
1579 while (!LdrpProcessInitialized)
1580 {
1581 /* Do the wait */
1582 ZwDelayExecution(FALSE, &Timeout);
1583 }
1584 }
1585
1586 /* Check if we have already setup LDR data */
1587 if (!Peb->Ldr)
1588 {
1589 /* Setup the Loader Lock */
1590 Peb->LoaderLock = &LdrpLoaderLock;
1591
1592 /* Let other code know we're initializing */
1593 LdrpInLdrInit = TRUE;
1594
1595 /* Protect with SEH */
1596 _SEH2_TRY
1597 {
1598 /* Initialize the Process */
1599 LoaderStatus = LdrpInitializeProcess_(Context,
1600 SystemArgument1);
1601
1602 /* Check for success and if MinimumStackCommit was requested */
1603 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
1604 {
1605 /* Enforce the limit */
1606 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
1607 UNIMPLEMENTED;
1608 }
1609 }
1610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1611 {
1612 /* Fail with the SEH error */
1613 LoaderStatus = _SEH2_GetExceptionCode();
1614 }
1615 _SEH2_END;
1616
1617 /* We're not initializing anymore */
1618 LdrpInLdrInit = FALSE;
1619
1620 /* Check if init worked */
1621 if (NT_SUCCESS(LoaderStatus))
1622 {
1623 /* Set the process as Initialized */
1624 _InterlockedIncrement(&LdrpProcessInitialized);
1625 }
1626 }
1627 else
1628 {
1629 /* Loader data is there... is this a fork() ? */
1630 if(Peb->InheritedAddressSpace)
1631 {
1632 /* Handle the fork() */
1633 //LoaderStatus = LdrpForkProcess();
1634 LoaderStatus = STATUS_NOT_IMPLEMENTED;
1635 UNIMPLEMENTED;
1636 }
1637 else
1638 {
1639 /* This is a new thread initializing */
1640 LdrpInitializeThread(Context);
1641 }
1642 }
1643
1644 /* All done, test alert the thread */
1645 NtTestAlert();
1646
1647 /* Return */
1648 if (!NT_SUCCESS(LoaderStatus))
1649 {
1650 /* Fail */
1651 LdrpInitFailure(LoaderStatus);
1652 RtlRaiseStatus(LoaderStatus);
1653 }
1654 }
1655
1656 /* EOF */