6a74ef8121a83b4cb5ad997cd61bb78503b71502
[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
14 #define NDEBUG
15 #include <debug.h>
16
17
18 /* GLOBALS *******************************************************************/
19
20 HANDLE ImageExecOptionsKey;
21 HANDLE Wow64ExecOptionsKey;
22 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
23 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
24 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
25
26 BOOLEAN LdrpInLdrInit;
27 LONG LdrpProcessInitialized;
28 BOOLEAN LdrpLoaderLockInit;
29 BOOLEAN LdrpLdrDatabaseIsSetup;
30 BOOLEAN LdrpShutdownInProgress;
31 HANDLE LdrpShutdownThreadId;
32
33 BOOLEAN LdrpDllValidation;
34
35 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
36 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
37 WCHAR StringBuffer[156];
38 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
39 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
40 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
41
42 RTL_BITMAP TlsBitMap;
43 RTL_BITMAP TlsExpansionBitMap;
44 RTL_BITMAP FlsBitMap;
45 BOOLEAN LdrpImageHasTls;
46 LIST_ENTRY LdrpTlsList;
47 ULONG LdrpNumberOfTlsEntries;
48 ULONG LdrpNumberOfProcessors;
49 PVOID NtDllBase;
50 extern LARGE_INTEGER RtlpTimeout;
51 BOOLEAN RtlpTimeoutDisable;
52 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
53 LIST_ENTRY LdrpDllNotificationList;
54 HANDLE LdrpKnownDllObjectDirectory;
55 UNICODE_STRING LdrpKnownDllPath;
56 WCHAR LdrpKnownDllPathBuffer[128];
57 UNICODE_STRING LdrpDefaultPath;
58
59 PEB_LDR_DATA PebLdr;
60
61 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
62 RTL_CRITICAL_SECTION LdrpLoaderLock =
63 {
64 &LdrpLoaderLockDebug,
65 -1,
66 0,
67 0,
68 0,
69 0
70 };
71 RTL_CRITICAL_SECTION FastPebLock;
72
73 BOOLEAN ShowSnaps;
74
75 ULONG LdrpFatalHardErrorCount;
76 ULONG LdrpActiveUnloadCount;
77
78 //extern LIST_ENTRY RtlCriticalSectionList;
79
80 VOID RtlpInitializeVectoredExceptionHandling(VOID);
81 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
82 VOID NTAPI RtlInitializeHeapManager(VOID);
83 extern BOOLEAN RtlpPageHeapEnabled;
84
85 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
86 ULONG RtlpShutdownProcessFlags; // TODO: Use it
87
88 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
89 void actctx_init(void);
90
91 #ifdef _WIN64
92 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
93 #else
94 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
95 #endif
96
97 /* FUNCTIONS *****************************************************************/
98
99 /*
100 * @implemented
101 */
102 NTSTATUS
103 NTAPI
104 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
105 IN BOOLEAN Wow64,
106 OUT PHANDLE NewKeyHandle)
107 {
108 PHANDLE RootKeyLocation;
109 HANDLE RootKey;
110 UNICODE_STRING SubKeyString;
111 OBJECT_ATTRIBUTES ObjectAttributes;
112 NTSTATUS Status;
113 PWCHAR p1;
114
115 /* Check which root key to open */
116 if (Wow64)
117 RootKeyLocation = &Wow64ExecOptionsKey;
118 else
119 RootKeyLocation = &ImageExecOptionsKey;
120
121 /* Get the current key */
122 RootKey = *RootKeyLocation;
123
124 /* Setup the object attributes */
125 InitializeObjectAttributes(&ObjectAttributes,
126 Wow64 ?
127 &Wow64OptionsString : &ImageExecOptionsString,
128 OBJ_CASE_INSENSITIVE,
129 NULL,
130 NULL);
131
132 /* Open the root key */
133 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
134 if (NT_SUCCESS(Status))
135 {
136 /* Write the key handle */
137 if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0)
138 {
139 /* Someone already opened it, use it instead */
140 NtClose(RootKey);
141 RootKey = *RootKeyLocation;
142 }
143
144 /* Extract the name */
145 SubKeyString = *SubKey;
146 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
147 while (SubKeyString.Length)
148 {
149 if (p1[-1] == L'\\') break;
150 p1--;
151 SubKeyString.Length -= sizeof(*p1);
152 }
153 SubKeyString.Buffer = p1;
154 SubKeyString.Length = SubKey->Length - SubKeyString.Length;
155
156 /* Setup the object attributes */
157 InitializeObjectAttributes(&ObjectAttributes,
158 &SubKeyString,
159 OBJ_CASE_INSENSITIVE,
160 RootKey,
161 NULL);
162
163 /* Open the setting key */
164 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
165 }
166
167 /* Return to caller */
168 return Status;
169 }
170
171 /*
172 * @implemented
173 */
174 NTSTATUS
175 NTAPI
176 LdrQueryImageFileKeyOption(IN HANDLE KeyHandle,
177 IN PCWSTR ValueName,
178 IN ULONG Type,
179 OUT PVOID Buffer,
180 IN ULONG BufferSize,
181 OUT PULONG ReturnedLength OPTIONAL)
182 {
183 ULONG KeyInfo[256];
184 UNICODE_STRING ValueNameString, IntegerString;
185 ULONG KeyInfoSize, ResultSize;
186 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
187 BOOLEAN FreeHeap = FALSE;
188 NTSTATUS Status;
189
190 /* Build a string for the value name */
191 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
192 if (!NT_SUCCESS(Status)) return Status;
193
194 /* Query the value */
195 Status = ZwQueryValueKey(KeyHandle,
196 &ValueNameString,
197 KeyValuePartialInformation,
198 KeyValueInformation,
199 sizeof(KeyInfo),
200 &ResultSize);
201 if (Status == STATUS_BUFFER_OVERFLOW)
202 {
203 /* Our local buffer wasn't enough, allocate one */
204 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
205 KeyValueInformation->DataLength;
206 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
207 0,
208 KeyInfoSize);
209 if (KeyValueInformation != NULL)
210 {
211 /* Try again */
212 Status = ZwQueryValueKey(KeyHandle,
213 &ValueNameString,
214 KeyValuePartialInformation,
215 KeyValueInformation,
216 KeyInfoSize,
217 &ResultSize);
218 FreeHeap = TRUE;
219 }
220 else
221 {
222 /* Give up this time */
223 Status = STATUS_NO_MEMORY;
224 }
225 }
226
227 /* Check for success */
228 if (NT_SUCCESS(Status))
229 {
230 /* Handle binary data */
231 if (KeyValueInformation->Type == REG_BINARY)
232 {
233 /* Check validity */
234 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
235 {
236 /* Copy into buffer */
237 RtlMoveMemory(Buffer,
238 &KeyValueInformation->Data,
239 KeyValueInformation->DataLength);
240 }
241 else
242 {
243 Status = STATUS_BUFFER_OVERFLOW;
244 }
245
246 /* Copy the result length */
247 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
248 }
249 else if (KeyValueInformation->Type == REG_DWORD)
250 {
251 /* Check for valid type */
252 if (KeyValueInformation->Type != Type)
253 {
254 /* Error */
255 Status = STATUS_OBJECT_TYPE_MISMATCH;
256 }
257 else
258 {
259 /* Check validity */
260 if ((Buffer) &&
261 (BufferSize == sizeof(ULONG)) &&
262 (KeyValueInformation->DataLength <= BufferSize))
263 {
264 /* Copy into buffer */
265 RtlMoveMemory(Buffer,
266 &KeyValueInformation->Data,
267 KeyValueInformation->DataLength);
268 }
269 else
270 {
271 Status = STATUS_BUFFER_OVERFLOW;
272 }
273
274 /* Copy the result length */
275 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
276 }
277 }
278 else if (KeyValueInformation->Type != REG_SZ)
279 {
280 /* We got something weird */
281 Status = STATUS_OBJECT_TYPE_MISMATCH;
282 }
283 else
284 {
285 /* String, check what you requested */
286 if (Type == REG_DWORD)
287 {
288 /* Validate */
289 if (BufferSize != sizeof(ULONG))
290 {
291 /* Invalid size */
292 BufferSize = 0;
293 Status = STATUS_INFO_LENGTH_MISMATCH;
294 }
295 else
296 {
297 /* OK, we know what you want... */
298 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
299 IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
300 sizeof(WCHAR);
301 IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
302 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
303 }
304 }
305 else
306 {
307 /* Validate */
308 if (KeyValueInformation->DataLength > BufferSize)
309 {
310 /* Invalid */
311 Status = STATUS_BUFFER_OVERFLOW;
312 }
313 else
314 {
315 /* Set the size */
316 BufferSize = KeyValueInformation->DataLength;
317 }
318
319 /* Copy the string */
320 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
321 }
322
323 /* Copy the result length */
324 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
325 }
326 }
327
328 /* Check if buffer was in heap */
329 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
330
331 /* Return status */
332 return Status;
333 }
334
335 /*
336 * @implemented
337 */
338 NTSTATUS
339 NTAPI
340 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
341 IN PCWSTR ValueName,
342 IN ULONG Type,
343 OUT PVOID Buffer,
344 IN ULONG BufferSize,
345 OUT PULONG ReturnedLength OPTIONAL,
346 IN BOOLEAN Wow64)
347 {
348 NTSTATUS Status;
349 HANDLE KeyHandle;
350
351 /* Open a handle to the key */
352 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
353
354 /* Check for success */
355 if (NT_SUCCESS(Status))
356 {
357 /* Query the data */
358 Status = LdrQueryImageFileKeyOption(KeyHandle,
359 ValueName,
360 Type,
361 Buffer,
362 BufferSize,
363 ReturnedLength);
364
365 /* Close the key */
366 NtClose(KeyHandle);
367 }
368
369 /* Return to caller */
370 return Status;
371 }
372
373 /*
374 * @implemented
375 */
376 NTSTATUS
377 NTAPI
378 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
379 IN PCWSTR ValueName,
380 IN ULONG Type,
381 OUT PVOID Buffer,
382 IN ULONG BufferSize,
383 OUT PULONG ReturnedLength OPTIONAL)
384 {
385 /* Call the newer function */
386 return LdrQueryImageFileExecutionOptionsEx(SubKey,
387 ValueName,
388 Type,
389 Buffer,
390 BufferSize,
391 ReturnedLength,
392 FALSE);
393 }
394
395 VOID
396 NTAPI
397 LdrpEnsureLoaderLockIsHeld()
398 {
399 // Ignored atm
400 }
401
402 PVOID
403 NTAPI
404 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
405 {
406 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
407 ULONG DirSize;
408 PVOID Cookie = NULL;
409
410 /* Check NT header first */
411 if (!RtlImageNtHeader(BaseAddress)) return NULL;
412
413 /* Get the pointer to the config directory */
414 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
415 TRUE,
416 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
417 &DirSize);
418
419 /* Check for sanity */
420 if (!ConfigDir ||
421 (DirSize != 64 && ConfigDir->Size != DirSize) ||
422 (ConfigDir->Size < 0x48))
423 return NULL;
424
425 /* Now get the cookie */
426 Cookie = (PVOID)ConfigDir->SecurityCookie;
427
428 /* Check this cookie */
429 if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
430 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
431 {
432 Cookie = NULL;
433 }
434
435 /* Return validated security cookie */
436 return Cookie;
437 }
438
439 PVOID
440 NTAPI
441 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
442 {
443 PULONG_PTR Cookie;
444 LARGE_INTEGER Counter;
445 ULONG_PTR NewCookie;
446
447 /* Fetch address of the cookie */
448 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
449
450 if (Cookie)
451 {
452 /* Check if it's a default one */
453 if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
454 (*Cookie == 0xBB40))
455 {
456 /* Make up a cookie from a bunch of values which may uniquely represent
457 current moment of time, environment, etc */
458 NtQueryPerformanceCounter(&Counter, NULL);
459
460 NewCookie = Counter.LowPart ^ Counter.HighPart;
461 NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueProcess;
462 NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueThread;
463
464 /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
465 while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
466 {
467 YieldProcessor();
468 };
469
470 /* Calculate the milliseconds value and xor it to the cookie */
471 NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
472 (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
473
474 /* Make the cookie 16bit if necessary */
475 if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
476
477 /* If the result is 0 or the same as we got, just subtract one from the existing value
478 and that's it */
479 if ((NewCookie == 0) || (NewCookie == *Cookie))
480 {
481 NewCookie = *Cookie - 1;
482 }
483
484 /* Set the new cookie value */
485 *Cookie = NewCookie;
486 }
487 }
488
489 return Cookie;
490 }
491
492 VOID
493 NTAPI
494 LdrpInitializeThread(IN PCONTEXT Context)
495 {
496 PPEB Peb = NtCurrentPeb();
497 PLDR_DATA_TABLE_ENTRY LdrEntry;
498 PLIST_ENTRY NextEntry, ListHead;
499 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
500 NTSTATUS Status;
501 PVOID EntryPoint;
502
503 DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n",
504 &LdrpImageEntry->BaseDllName,
505 NtCurrentTeb()->RealClientId.UniqueProcess,
506 NtCurrentTeb()->RealClientId.UniqueThread);
507
508 /* Allocate an Activation Context Stack */
509 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
510 Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
511 if (!NT_SUCCESS(Status))
512 {
513 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
514 }
515
516 /* Make sure we are not shutting down */
517 if (LdrpShutdownInProgress) return;
518
519 /* Allocate TLS */
520 LdrpAllocateTls();
521
522 /* Start at the beginning */
523 ListHead = &Peb->Ldr->InMemoryOrderModuleList;
524 NextEntry = ListHead->Flink;
525 while (NextEntry != ListHead)
526 {
527 /* Get the current entry */
528 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
529
530 /* Make sure it's not ourselves */
531 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
532 {
533 /* Check if we should call */
534 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
535 {
536 /* Get the entrypoint */
537 EntryPoint = LdrEntry->EntryPoint;
538
539 /* Check if we are ready to call it */
540 if ((EntryPoint) &&
541 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
542 (LdrEntry->Flags & LDRP_IMAGE_DLL))
543 {
544 /* Set up the Act Ctx */
545 ActCtx.Size = sizeof(ActCtx);
546 ActCtx.Format = 1;
547 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
548
549 /* Activate the ActCtx */
550 RtlActivateActivationContextUnsafeFast(&ActCtx,
551 LdrEntry->EntryPointActivationContext);
552
553 /* Check if it has TLS */
554 if (LdrEntry->TlsIndex)
555 {
556 /* Make sure we're not shutting down */
557 if (!LdrpShutdownInProgress)
558 {
559 /* Call TLS */
560 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
561 }
562 }
563
564 /* Make sure we're not shutting down */
565 if (!LdrpShutdownInProgress)
566 {
567 /* Call the Entrypoint */
568 DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
569 &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
570 NtCurrentTeb()->RealClientId.UniqueProcess,
571 NtCurrentTeb()->RealClientId.UniqueThread);
572 LdrpCallInitRoutine(LdrEntry->EntryPoint,
573 LdrEntry->DllBase,
574 DLL_THREAD_ATTACH,
575 NULL);
576 }
577
578 /* Deactivate the ActCtx */
579 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
580 }
581 }
582 }
583
584 /* Next entry */
585 NextEntry = NextEntry->Flink;
586 }
587
588 /* Check for TLS */
589 if (LdrpImageHasTls && !LdrpShutdownInProgress)
590 {
591 /* Set up the Act Ctx */
592 ActCtx.Size = sizeof(ActCtx);
593 ActCtx.Format = 1;
594 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
595
596 /* Activate the ActCtx */
597 RtlActivateActivationContextUnsafeFast(&ActCtx,
598 LdrpImageEntry->EntryPointActivationContext);
599
600 /* Do TLS callbacks */
601 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
602
603 /* Deactivate the ActCtx */
604 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
605 }
606
607 DPRINT("LdrpInitializeThread() done\n");
608 }
609
610 NTSTATUS
611 NTAPI
612 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
613 {
614 PLDR_DATA_TABLE_ENTRY LocalArray[16];
615 PLIST_ENTRY ListHead;
616 PLIST_ENTRY NextEntry;
617 PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
618 PVOID EntryPoint;
619 ULONG Count, i;
620 //ULONG BreakOnInit;
621 NTSTATUS Status = STATUS_SUCCESS;
622 PPEB Peb = NtCurrentPeb();
623 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
624 ULONG BreakOnDllLoad;
625 PTEB OldTldTeb;
626 BOOLEAN DllStatus;
627
628 DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
629 &LdrpImageEntry->BaseDllName,
630 NtCurrentTeb()->RealClientId.UniqueProcess,
631 NtCurrentTeb()->RealClientId.UniqueThread);
632
633 /* Check the Loader Lock */
634 LdrpEnsureLoaderLockIsHeld();
635
636 /* Get the number of entries to call */
637 if ((Count = LdrpClearLoadInProgress()))
638 {
639 /* Check if we can use our local buffer */
640 if (Count > 16)
641 {
642 /* Allocate space for all the entries */
643 LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
644 0,
645 Count * sizeof(*LdrRootEntry));
646 if (!LdrRootEntry) return STATUS_NO_MEMORY;
647 }
648 else
649 {
650 /* Use our local array */
651 LdrRootEntry = LocalArray;
652 }
653 }
654 else
655 {
656 /* Don't need one */
657 LdrRootEntry = NULL;
658 }
659
660 /* Show debug message */
661 if (ShowSnaps)
662 {
663 DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
664 NtCurrentTeb()->RealClientId.UniqueThread,
665 NtCurrentTeb()->RealClientId.UniqueProcess,
666 &Peb->ProcessParameters->ImagePathName);
667 }
668
669 /* Loop in order */
670 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
671 NextEntry = ListHead->Flink;
672 i = 0;
673 while (NextEntry != ListHead)
674 {
675 /* Get the Data Entry */
676 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
677
678 /* Check if we have a Root Entry */
679 if (LdrRootEntry)
680 {
681 /* Check flags */
682 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
683 {
684 /* Setup the Cookie for the DLL */
685 LdrpInitSecurityCookie(LdrEntry);
686
687 /* Check for valid entrypoint */
688 if (LdrEntry->EntryPoint)
689 {
690 /* Write in array */
691 ASSERT(i < Count);
692 LdrRootEntry[i] = LdrEntry;
693
694 /* Display debug message */
695 if (ShowSnaps)
696 {
697 DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
698 NtCurrentTeb()->RealClientId.UniqueThread,
699 NtCurrentTeb()->RealClientId.UniqueProcess,
700 &LdrEntry->FullDllName,
701 LdrEntry->EntryPoint);
702 }
703 i++;
704 }
705 }
706 }
707
708 /* Set the flag */
709 LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
710 NextEntry = NextEntry->Flink;
711 }
712
713 /* If we got a context, then we have to call Kernel32 for TS support */
714 if (Context)
715 {
716 /* Check if we have one */
717 //if (Kernel32ProcessInitPostImportfunction)
718 //{
719 /* Call it */
720 //Kernel32ProcessInitPostImportfunction();
721 //}
722
723 /* Clear it */
724 //Kernel32ProcessInitPostImportfunction = NULL;
725 //UNIMPLEMENTED;
726 }
727
728 /* No root entry? return */
729 if (!LdrRootEntry) return STATUS_SUCCESS;
730
731 /* Set the TLD TEB */
732 OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
733 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
734
735 /* Loop */
736 i = 0;
737 while (i < Count)
738 {
739 /* Get an entry */
740 LdrEntry = LdrRootEntry[i];
741
742 /* FIXME: Verify NX Compat */
743
744 /* Move to next entry */
745 i++;
746
747 /* Get its entrypoint */
748 EntryPoint = LdrEntry->EntryPoint;
749
750 /* Are we being debugged? */
751 BreakOnDllLoad = 0;
752 if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
753 {
754 /* Check if we should break on load */
755 Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
756 L"BreakOnDllLoad",
757 REG_DWORD,
758 &BreakOnDllLoad,
759 sizeof(ULONG),
760 NULL);
761 if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
762
763 /* Reset status back to STATUS_SUCCESS */
764 Status = STATUS_SUCCESS;
765 }
766
767 /* Break if aksed */
768 if (BreakOnDllLoad)
769 {
770 /* Check if we should show a message */
771 if (ShowSnaps)
772 {
773 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
774 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
775 }
776
777 /* Break in debugger */
778 DbgBreakPoint();
779 }
780
781 /* Make sure we have an entrypoint */
782 if (EntryPoint)
783 {
784 /* Save the old Dll Initializer and write the current one */
785 OldInitializer = LdrpCurrentDllInitializer;
786 LdrpCurrentDllInitializer = LdrEntry;
787
788 /* Set up the Act Ctx */
789 ActCtx.Size = sizeof(ActCtx);
790 ActCtx.Format = 1;
791 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
792
793 /* Activate the ActCtx */
794 RtlActivateActivationContextUnsafeFast(&ActCtx,
795 LdrEntry->EntryPointActivationContext);
796
797 /* Check if it has TLS */
798 if (LdrEntry->TlsIndex && Context)
799 {
800 /* Call TLS */
801 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
802 }
803
804 /* Call the Entrypoint */
805 if (ShowSnaps)
806 {
807 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
808 &LdrEntry->BaseDllName, EntryPoint);
809 }
810 DllStatus = LdrpCallInitRoutine(EntryPoint,
811 LdrEntry->DllBase,
812 DLL_PROCESS_ATTACH,
813 Context);
814
815 /* Deactivate the ActCtx */
816 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
817
818 /* Save the Current DLL Initializer */
819 LdrpCurrentDllInitializer = OldInitializer;
820
821 /* Mark the entry as processed */
822 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
823
824 /* Fail if DLL init failed */
825 if (!DllStatus)
826 {
827 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
828 &LdrEntry->BaseDllName, EntryPoint);
829
830 Status = STATUS_DLL_INIT_FAILED;
831 goto Quickie;
832 }
833 }
834 }
835
836 /* Loop in order */
837 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
838 NextEntry = NextEntry->Flink;
839 while (NextEntry != ListHead)
840 {
841 /* Get the Data Entrry */
842 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
843
844 /* FIXME: Verify NX Compat */
845 // LdrpCheckNXCompatibility()
846
847 /* Next entry */
848 NextEntry = NextEntry->Flink;
849 }
850
851 /* Check for TLS */
852 if (LdrpImageHasTls && Context)
853 {
854 /* Set up the Act Ctx */
855 ActCtx.Size = sizeof(ActCtx);
856 ActCtx.Format = 1;
857 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
858
859 /* Activate the ActCtx */
860 RtlActivateActivationContextUnsafeFast(&ActCtx,
861 LdrpImageEntry->EntryPointActivationContext);
862
863 /* Do TLS callbacks */
864 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
865
866 /* Deactivate the ActCtx */
867 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
868 }
869
870 Quickie:
871 /* Restore old TEB */
872 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
873
874 /* Check if the array is in the heap */
875 if (LdrRootEntry != LocalArray)
876 {
877 /* Free the array */
878 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
879 }
880
881 /* Return to caller */
882 DPRINT("LdrpRunInitializeRoutines() done\n");
883 return Status;
884 }
885
886 /*
887 * @implemented
888 */
889 NTSTATUS
890 NTAPI
891 LdrShutdownProcess(VOID)
892 {
893 PPEB Peb = NtCurrentPeb();
894 PLDR_DATA_TABLE_ENTRY LdrEntry;
895 PLIST_ENTRY NextEntry, ListHead;
896 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
897 PVOID EntryPoint;
898
899 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
900 if (LdrpShutdownInProgress) return STATUS_SUCCESS;
901
902 /* Tell the Shim Engine */
903 //if (ShimsEnabled)
904 //{
905 /* FIXME */
906 //}
907
908 /* Tell the world */
909 if (ShowSnaps)
910 {
911 DPRINT1("\n");
912 }
913
914 /* Set the shutdown variables */
915 LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
916 LdrpShutdownInProgress = TRUE;
917
918 /* Enter the Loader Lock */
919 RtlEnterCriticalSection(&LdrpLoaderLock);
920
921 /* Cleanup trace logging data (Etw) */
922 if (SharedUserData->TraceLogging)
923 {
924 /* FIXME */
925 DPRINT1("We don't support Etw yet.\n");
926 }
927
928 /* Start at the end */
929 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
930 NextEntry = ListHead->Blink;
931 while (NextEntry != ListHead)
932 {
933 /* Get the current entry */
934 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
935 NextEntry = NextEntry->Blink;
936
937 /* Make sure it's not ourselves */
938 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
939 {
940 /* Get the entrypoint */
941 EntryPoint = LdrEntry->EntryPoint;
942
943 /* Check if we are ready to call it */
944 if (EntryPoint &&
945 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
946 LdrEntry->Flags)
947 {
948 /* Set up the Act Ctx */
949 ActCtx.Size = sizeof(ActCtx);
950 ActCtx.Format = 1;
951 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
952
953 /* Activate the ActCtx */
954 RtlActivateActivationContextUnsafeFast(&ActCtx,
955 LdrEntry->EntryPointActivationContext);
956
957 /* Check if it has TLS */
958 if (LdrEntry->TlsIndex)
959 {
960 /* Call TLS */
961 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH);
962 }
963
964 /* Call the Entrypoint */
965 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
966 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
967 LdrpCallInitRoutine(EntryPoint,
968 LdrEntry->DllBase,
969 DLL_PROCESS_DETACH,
970 (PVOID)1);
971
972 /* Deactivate the ActCtx */
973 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
974 }
975 }
976 }
977
978 /* Check for TLS */
979 if (LdrpImageHasTls)
980 {
981 /* Set up the Act Ctx */
982 ActCtx.Size = sizeof(ActCtx);
983 ActCtx.Format = 1;
984 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
985
986 /* Activate the ActCtx */
987 RtlActivateActivationContextUnsafeFast(&ActCtx,
988 LdrpImageEntry->EntryPointActivationContext);
989
990 /* Do TLS callbacks */
991 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_DETACH);
992
993 /* Deactivate the ActCtx */
994 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
995 }
996
997 /* FIXME: Do Heap detection and Etw final shutdown */
998
999 /* Release the lock */
1000 RtlLeaveCriticalSection(&LdrpLoaderLock);
1001 DPRINT("LdrpShutdownProcess() done\n");
1002
1003 return STATUS_SUCCESS;
1004 }
1005
1006 /*
1007 * @implemented
1008 */
1009 NTSTATUS
1010 NTAPI
1011 LdrShutdownThread(VOID)
1012 {
1013 PPEB Peb = NtCurrentPeb();
1014 PTEB Teb = NtCurrentTeb();
1015 PLDR_DATA_TABLE_ENTRY LdrEntry;
1016 PLIST_ENTRY NextEntry, ListHead;
1017 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1018 PVOID EntryPoint;
1019
1020 DPRINT("LdrShutdownThread() called for %wZ\n",
1021 &LdrpImageEntry->BaseDllName);
1022
1023 /* Cleanup trace logging data (Etw) */
1024 if (SharedUserData->TraceLogging)
1025 {
1026 /* FIXME */
1027 DPRINT1("We don't support Etw yet.\n");
1028 }
1029
1030 /* Get the Ldr Lock */
1031 RtlEnterCriticalSection(&LdrpLoaderLock);
1032
1033 /* Start at the end */
1034 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1035 NextEntry = ListHead->Blink;
1036 while (NextEntry != ListHead)
1037 {
1038 /* Get the current entry */
1039 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
1040 NextEntry = NextEntry->Blink;
1041
1042 /* Make sure it's not ourselves */
1043 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1044 {
1045 /* Check if we should call */
1046 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1047 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1048 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1049 {
1050 /* Get the entrypoint */
1051 EntryPoint = LdrEntry->EntryPoint;
1052
1053 /* Check if we are ready to call it */
1054 if (EntryPoint)
1055 {
1056 /* Set up the Act Ctx */
1057 ActCtx.Size = sizeof(ActCtx);
1058 ActCtx.Format = 1;
1059 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1060
1061 /* Activate the ActCtx */
1062 RtlActivateActivationContextUnsafeFast(&ActCtx,
1063 LdrEntry->EntryPointActivationContext);
1064
1065 /* Check if it has TLS */
1066 if (LdrEntry->TlsIndex)
1067 {
1068 /* Make sure we're not shutting down */
1069 if (!LdrpShutdownInProgress)
1070 {
1071 /* Call TLS */
1072 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH);
1073 }
1074 }
1075
1076 /* Make sure we're not shutting down */
1077 if (!LdrpShutdownInProgress)
1078 {
1079 /* Call the Entrypoint */
1080 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1081 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1082 LdrpCallInitRoutine(EntryPoint,
1083 LdrEntry->DllBase,
1084 DLL_THREAD_DETACH,
1085 NULL);
1086 }
1087
1088 /* Deactivate the ActCtx */
1089 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1090 }
1091 }
1092 }
1093 }
1094
1095 /* Check for TLS */
1096 if (LdrpImageHasTls)
1097 {
1098 /* Set up the Act Ctx */
1099 ActCtx.Size = sizeof(ActCtx);
1100 ActCtx.Format = 1;
1101 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1102
1103 /* Activate the ActCtx */
1104 RtlActivateActivationContextUnsafeFast(&ActCtx,
1105 LdrpImageEntry->EntryPointActivationContext);
1106
1107 /* Do TLS callbacks */
1108 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_DETACH);
1109
1110 /* Deactivate the ActCtx */
1111 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1112 }
1113
1114 /* Free TLS */
1115 LdrpFreeTls();
1116 RtlLeaveCriticalSection(&LdrpLoaderLock);
1117
1118 /* Check for expansion slots */
1119 if (Teb->TlsExpansionSlots)
1120 {
1121 /* Free expansion slots */
1122 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1123 }
1124
1125 /* Check for FLS Data */
1126 if (Teb->FlsData)
1127 {
1128 /* FIXME */
1129 DPRINT1("We don't support FLS Data yet\n");
1130 }
1131
1132 /* Check for Fiber data */
1133 if (Teb->HasFiberData)
1134 {
1135 /* Free Fiber data*/
1136 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1137 Teb->NtTib.FiberData = NULL;
1138 }
1139
1140 /* Free the activation context stack */
1141 RtlFreeThreadActivationContextStack();
1142 DPRINT("LdrShutdownThread() done\n");
1143
1144 return STATUS_SUCCESS;
1145 }
1146
1147 NTSTATUS
1148 NTAPI
1149 LdrpInitializeTls(VOID)
1150 {
1151 PLIST_ENTRY NextEntry, ListHead;
1152 PLDR_DATA_TABLE_ENTRY LdrEntry;
1153 PIMAGE_TLS_DIRECTORY TlsDirectory;
1154 PLDRP_TLS_DATA TlsData;
1155 ULONG Size;
1156
1157 /* Initialize the TLS List */
1158 InitializeListHead(&LdrpTlsList);
1159
1160 /* Loop all the modules */
1161 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1162 NextEntry = ListHead->Flink;
1163 while (ListHead != NextEntry)
1164 {
1165 /* Get the entry */
1166 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1167 NextEntry = NextEntry->Flink;
1168
1169 /* Get the TLS directory */
1170 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1171 TRUE,
1172 IMAGE_DIRECTORY_ENTRY_TLS,
1173 &Size);
1174
1175 /* Check if we have a directory */
1176 if (!TlsDirectory) continue;
1177
1178 /* Check if the image has TLS */
1179 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1180
1181 /* Show debug message */
1182 if (ShowSnaps)
1183 {
1184 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1185 &LdrEntry->BaseDllName,
1186 TlsDirectory);
1187 }
1188
1189 /* Allocate an entry */
1190 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1191 if (!TlsData) return STATUS_NO_MEMORY;
1192
1193 /* Lock the DLL and mark it for TLS Usage */
1194 LdrEntry->LoadCount = -1;
1195 LdrEntry->TlsIndex = -1;
1196
1197 /* Save the cached TLS data */
1198 TlsData->TlsDirectory = *TlsDirectory;
1199 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1200
1201 /* Update the index */
1202 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1203 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1204 }
1205
1206 /* Done setting up TLS, allocate entries */
1207 return LdrpAllocateTls();
1208 }
1209
1210 NTSTATUS
1211 NTAPI
1212 LdrpAllocateTls(VOID)
1213 {
1214 PTEB Teb = NtCurrentTeb();
1215 PLIST_ENTRY NextEntry, ListHead;
1216 PLDRP_TLS_DATA TlsData;
1217 SIZE_T TlsDataSize;
1218 PVOID *TlsVector;
1219
1220 /* Check if we have any entries */
1221 if (!LdrpNumberOfTlsEntries)
1222 return STATUS_SUCCESS;
1223
1224 /* Allocate the vector array */
1225 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1226 0,
1227 LdrpNumberOfTlsEntries * sizeof(PVOID));
1228 if (!TlsVector) return STATUS_NO_MEMORY;
1229 Teb->ThreadLocalStoragePointer = TlsVector;
1230
1231 /* Loop the TLS Array */
1232 ListHead = &LdrpTlsList;
1233 NextEntry = ListHead->Flink;
1234 while (NextEntry != ListHead)
1235 {
1236 /* Get the entry */
1237 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1238 NextEntry = NextEntry->Flink;
1239
1240 /* Allocate this vector */
1241 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1242 TlsData->TlsDirectory.StartAddressOfRawData;
1243 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1244 0,
1245 TlsDataSize);
1246 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1247 {
1248 /* Out of memory */
1249 return STATUS_NO_MEMORY;
1250 }
1251
1252 /* Show debug message */
1253 if (ShowSnaps)
1254 {
1255 DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1256 TlsVector,
1257 TlsData->TlsDirectory.Characteristics,
1258 &TlsVector[TlsData->TlsDirectory.Characteristics],
1259 TlsData->TlsDirectory.StartAddressOfRawData,
1260 TlsVector[TlsData->TlsDirectory.Characteristics]);
1261 }
1262
1263 /* Copy the data */
1264 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1265 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1266 TlsDataSize);
1267 }
1268
1269 /* Done */
1270 return STATUS_SUCCESS;
1271 }
1272
1273 VOID
1274 NTAPI
1275 LdrpFreeTls(VOID)
1276 {
1277 PLIST_ENTRY ListHead, NextEntry;
1278 PLDRP_TLS_DATA TlsData;
1279 PVOID *TlsVector;
1280 PTEB Teb = NtCurrentTeb();
1281
1282 /* Get a pointer to the vector array */
1283 TlsVector = Teb->ThreadLocalStoragePointer;
1284 if (!TlsVector) return;
1285
1286 /* Loop through it */
1287 ListHead = &LdrpTlsList;
1288 NextEntry = ListHead->Flink;
1289 while (NextEntry != ListHead)
1290 {
1291 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1292 NextEntry = NextEntry->Flink;
1293
1294 /* Free each entry */
1295 if (TlsVector[TlsData->TlsDirectory.Characteristics])
1296 {
1297 RtlFreeHeap(RtlGetProcessHeap(),
1298 0,
1299 TlsVector[TlsData->TlsDirectory.Characteristics]);
1300 }
1301 }
1302
1303 /* Free the array itself */
1304 RtlFreeHeap(RtlGetProcessHeap(),
1305 0,
1306 TlsVector);
1307 }
1308
1309 NTSTATUS
1310 NTAPI
1311 LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName, PPEB Peb, BOOLEAN SystemWide, BOOLEAN ReadAdvancedOptions)
1312 {
1313 /* If global flags request DPH, perform some additional actions */
1314 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
1315 {
1316 // TODO: Read advanced DPH flags from the registry if requested
1317 if (ReadAdvancedOptions)
1318 {
1319 UNIMPLEMENTED;
1320 }
1321
1322 /* Enable page heap */
1323 RtlpPageHeapEnabled = TRUE;
1324 }
1325
1326 return STATUS_SUCCESS;
1327 }
1328
1329 NTSTATUS
1330 NTAPI
1331 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
1332 {
1333 NTSTATUS Status;
1334 HANDLE KeyHandle;
1335 ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1336
1337 /* Return error if we were not provided a pointer where to save the options key handle */
1338 if (!OptionsKey) return STATUS_INVALID_HANDLE;
1339
1340 /* Zero initialize the optinos key pointer */
1341 *OptionsKey = NULL;
1342
1343 /* Open the options key */
1344 Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1345
1346 /* Save it if it was opened successfully */
1347 if (NT_SUCCESS(Status))
1348 *OptionsKey = KeyHandle;
1349
1350 if (KeyHandle)
1351 {
1352 /* There are image specific options, read them starting with NXCOMPAT */
1353 Status = LdrQueryImageFileKeyOption(KeyHandle,
1354 L"ExecuteOptions",
1355 4,
1356 &ExecuteOptions,
1357 sizeof(ExecuteOptions),
1358 0);
1359
1360 if (NT_SUCCESS(Status))
1361 {
1362 /* TODO: Set execution options for the process */
1363 /*
1364 if (ExecuteOptions == 0)
1365 ExecuteOptions = 1;
1366 else
1367 ExecuteOptions = 2;
1368 ZwSetInformationProcess(NtCurrentProcess(),
1369 ProcessExecuteFlags,
1370 &ExecuteOptions,
1371 sizeof(ULONG));*/
1372
1373 }
1374
1375 /* Check if this image uses large pages */
1376 if (Peb->ImageUsesLargePages)
1377 {
1378 /* TODO: If it does, open large page key */
1379 UNIMPLEMENTED;
1380 }
1381
1382 /* Get various option values */
1383 LdrQueryImageFileKeyOption(KeyHandle,
1384 L"DisableHeapLookaside",
1385 REG_DWORD,
1386 &RtlpDisableHeapLookaside,
1387 sizeof(RtlpDisableHeapLookaside),
1388 NULL);
1389
1390 LdrQueryImageFileKeyOption(KeyHandle,
1391 L"ShutdownFlags",
1392 REG_DWORD,
1393 &RtlpShutdownProcessFlags,
1394 sizeof(RtlpShutdownProcessFlags),
1395 NULL);
1396
1397 LdrQueryImageFileKeyOption(KeyHandle,
1398 L"MinimumStackCommitInBytes",
1399 REG_DWORD,
1400 &MinimumStackCommit,
1401 sizeof(MinimumStackCommit),
1402 NULL);
1403
1404 /* Update PEB's minimum stack commit if it's lower */
1405 if (Peb->MinimumStackCommit < MinimumStackCommit)
1406 Peb->MinimumStackCommit = MinimumStackCommit;
1407
1408 /* Set the global flag */
1409 Status = LdrQueryImageFileKeyOption(KeyHandle,
1410 L"GlobalFlag",
1411 REG_DWORD,
1412 &GlobalFlag,
1413 sizeof(GlobalFlag),
1414 NULL);
1415
1416 if (NT_SUCCESS(Status))
1417 Peb->NtGlobalFlag = GlobalFlag;
1418 else
1419 GlobalFlag = 0;
1420
1421 /* Call AVRF if necessary */
1422 if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
1423 {
1424 Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE, FALSE);
1425 if (!NT_SUCCESS(Status))
1426 {
1427 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1428 }
1429 }
1430 }
1431 else
1432 {
1433 /* There are no image-specific options, so perform global initialization */
1434 if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
1435 {
1436 /* Initialize app verifier package */
1437 Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE, FALSE);
1438 if (!NT_SUCCESS(Status))
1439 {
1440 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1441 }
1442 }
1443 }
1444
1445 return STATUS_SUCCESS;
1446 }
1447
1448 VOID
1449 NTAPI
1450 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1451 {
1452 UNIMPLEMENTED;
1453 }
1454
1455 NTSTATUS
1456 NTAPI
1457 LdrpInitializeProcess(IN PCONTEXT Context,
1458 IN PVOID SystemArgument1)
1459 {
1460 RTL_HEAP_PARAMETERS HeapParameters;
1461 ULONG ComSectionSize;
1462 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1463 PVOID OldShimData;
1464 OBJECT_ATTRIBUTES ObjectAttributes;
1465 //UNICODE_STRING LocalFileName, FullImageName;
1466 HANDLE SymLinkHandle;
1467 //ULONG DebugHeapOnly;
1468 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1469 PPEB Peb = NtCurrentPeb();
1470 BOOLEAN IsDotNetImage = FALSE;
1471 BOOLEAN FreeCurDir = FALSE;
1472 //HANDLE CompatKey;
1473 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1474 //LPWSTR ImagePathBuffer;
1475 ULONG ConfigSize;
1476 UNICODE_STRING CurrentDirectory;
1477 HANDLE OptionsKey;
1478 ULONG HeapFlags;
1479 PIMAGE_NT_HEADERS NtHeader;
1480 LPWSTR NtDllName = NULL;
1481 NTSTATUS Status, ImportStatus;
1482 NLSTABLEINFO NlsTable;
1483 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1484 PTEB Teb = NtCurrentTeb();
1485 PLIST_ENTRY ListHead;
1486 PLIST_ENTRY NextEntry;
1487 ULONG i;
1488 PWSTR ImagePath;
1489 ULONG DebugProcessHeapOnly = 0;
1490 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1491 PWCHAR Current;
1492 ULONG ExecuteOptions = 0;
1493 PVOID ViewBase;
1494
1495 /* Set a NULL SEH Filter */
1496 RtlSetUnhandledExceptionFilter(NULL);
1497
1498 /* Get the image path */
1499 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1500
1501 /* Check if it's not normalized */
1502 if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1503 {
1504 /* Normalize it*/
1505 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1506 }
1507
1508 /* Create a unicode string for the Image Path */
1509 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1510 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1511 ImagePathName.Buffer = ImagePath;
1512
1513 /* Get the NT Headers */
1514 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1515
1516 /* Get the execution options */
1517 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1518
1519 /* Check if this is a .NET executable */
1520 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1521 TRUE,
1522 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1523 &ComSectionSize))
1524 {
1525 /* Remeber this for later */
1526 IsDotNetImage = TRUE;
1527 }
1528
1529 /* Save the NTDLL Base address */
1530 NtDllBase = SystemArgument1;
1531
1532 /* If this is a Native Image */
1533 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1534 {
1535 /* Then do DLL Validation */
1536 LdrpDllValidation = TRUE;
1537 }
1538
1539 /* Save the old Shim Data */
1540 OldShimData = Peb->pShimData;
1541
1542 /* Clear it */
1543 Peb->pShimData = NULL;
1544
1545 /* Save the number of processors and CS Timeout */
1546 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1547 RtlpTimeout = Peb->CriticalSectionTimeout;
1548
1549 /* Normalize the parameters */
1550 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1551 if (ProcessParameters)
1552 {
1553 /* Save the Image and Command Line Names */
1554 ImageFileName = ProcessParameters->ImagePathName;
1555 CommandLine = ProcessParameters->CommandLine;
1556 }
1557 else
1558 {
1559 /* It failed, initialize empty strings */
1560 RtlInitUnicodeString(&ImageFileName, NULL);
1561 RtlInitUnicodeString(&CommandLine, NULL);
1562 }
1563
1564 /* Initialize NLS data */
1565 RtlInitNlsTables(Peb->AnsiCodePageData,
1566 Peb->OemCodePageData,
1567 Peb->UnicodeCaseTableData,
1568 &NlsTable);
1569
1570 /* Reset NLS Translations */
1571 RtlResetRtlTranslations(&NlsTable);
1572
1573 /* Get the Image Config Directory */
1574 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1575 TRUE,
1576 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1577 &ConfigSize);
1578
1579 /* Setup the Heap Parameters */
1580 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1581 HeapFlags = HEAP_GROWABLE;
1582 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1583
1584 /* Check if we have Configuration Data */
1585 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1586 {
1587 /* FIXME: Custom heap settings and misc. */
1588 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1589 }
1590
1591 /* Check for custom affinity mask */
1592 if (Peb->ImageProcessAffinityMask)
1593 {
1594 /* Set it */
1595 Status = NtSetInformationProcess(NtCurrentProcess(),
1596 ProcessAffinityMask,
1597 &Peb->ImageProcessAffinityMask,
1598 sizeof(Peb->ImageProcessAffinityMask));
1599 }
1600
1601 /* Check if verbose debugging (ShowSnaps) was requested */
1602 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1603
1604 /* Start verbose debugging messages right now if they were requested */
1605 if (ShowSnaps)
1606 {
1607 DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1608 Teb->ClientId.UniqueProcess,
1609 &CommandLine);
1610 }
1611
1612 /* If the timeout is too long */
1613 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1614 {
1615 /* Then disable CS Timeout */
1616 RtlpTimeoutDisable = TRUE;
1617 }
1618
1619 /* Initialize Critical Section Data */
1620 RtlpInitDeferedCriticalSection();
1621
1622 /* Initialize VEH Call lists */
1623 RtlpInitializeVectoredExceptionHandling();
1624
1625 /* Set TLS/FLS Bitmap data */
1626 Peb->FlsBitmap = &FlsBitMap;
1627 Peb->TlsBitmap = &TlsBitMap;
1628 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1629
1630 /* Initialize FLS Bitmap */
1631 RtlInitializeBitMap(&FlsBitMap,
1632 Peb->FlsBitmapBits,
1633 FLS_MAXIMUM_AVAILABLE);
1634 RtlSetBit(&FlsBitMap, 0);
1635
1636 /* Initialize TLS Bitmap */
1637 RtlInitializeBitMap(&TlsBitMap,
1638 Peb->TlsBitmapBits,
1639 TLS_MINIMUM_AVAILABLE);
1640 RtlSetBit(&TlsBitMap, 0);
1641 RtlInitializeBitMap(&TlsExpansionBitMap,
1642 Peb->TlsExpansionBitmapBits,
1643 TLS_EXPANSION_SLOTS);
1644 RtlSetBit(&TlsExpansionBitMap, 0);
1645
1646 /* Initialize the Hash Table */
1647 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1648 {
1649 InitializeListHead(&LdrpHashTable[i]);
1650 }
1651
1652 /* Initialize the Loader Lock */
1653 // FIXME: What's the point of initing it manually, if two lines lower
1654 // a call to RtlInitializeCriticalSection() is being made anyway?
1655 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1656 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1657 RtlInitializeCriticalSection(&LdrpLoaderLock);
1658 LdrpLoaderLockInit = TRUE;
1659
1660 /* Check if User Stack Trace Database support was requested */
1661 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1662 {
1663 DPRINT1("We don't support user stack trace databases yet\n");
1664 }
1665
1666 /* Setup Fast PEB Lock */
1667 RtlInitializeCriticalSection(&FastPebLock);
1668 Peb->FastPebLock = &FastPebLock;
1669 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1670 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1671
1672 /* Setup Callout Lock and Notification list */
1673 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1674 InitializeListHead(&LdrpDllNotificationList);
1675
1676 /* For old executables, use 16-byte aligned heap */
1677 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1678 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1679 {
1680 HeapFlags |= HEAP_CREATE_ALIGN_16;
1681 }
1682
1683 /* Setup the Heap */
1684 RtlInitializeHeapManager();
1685 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1686 NULL,
1687 NtHeader->OptionalHeader.SizeOfHeapReserve,
1688 NtHeader->OptionalHeader.SizeOfHeapCommit,
1689 NULL,
1690 &HeapParameters);
1691
1692 if (!Peb->ProcessHeap)
1693 {
1694 DPRINT1("Failed to create process heap\n");
1695 return STATUS_NO_MEMORY;
1696 }
1697
1698 /* Allocate an Activation Context Stack */
1699 Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
1700 if (!NT_SUCCESS(Status)) return Status;
1701
1702 // FIXME: Loader private heap is missing
1703 //DPRINT1("Loader private heap is missing\n");
1704
1705 /* Check for Debug Heap */
1706 if (OptionsKey)
1707 {
1708 /* Query the setting */
1709 Status = LdrQueryImageFileKeyOption(OptionsKey,
1710 L"DebugProcessHeapOnly",
1711 REG_DWORD,
1712 &DebugProcessHeapOnly,
1713 sizeof(ULONG),
1714 NULL);
1715
1716 if (NT_SUCCESS(Status))
1717 {
1718 /* Reset DPH if requested */
1719 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1720 {
1721 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
1722 RtlpPageHeapEnabled = FALSE;
1723 }
1724 }
1725 }
1726
1727 /* Build the NTDLL Path */
1728 FullPath.Buffer = StringBuffer;
1729 FullPath.Length = 0;
1730 FullPath.MaximumLength = sizeof(StringBuffer);
1731 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1732 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1733 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1734
1735 /* Open the Known DLLs directory */
1736 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1737 InitializeObjectAttributes(&ObjectAttributes,
1738 &KnownDllString,
1739 OBJ_CASE_INSENSITIVE,
1740 NULL,
1741 NULL);
1742 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1743 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1744 &ObjectAttributes);
1745
1746 /* Check if it exists */
1747 if (NT_SUCCESS(Status))
1748 {
1749 /* Open the Known DLLs Path */
1750 RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
1751 InitializeObjectAttributes(&ObjectAttributes,
1752 &KnownDllString,
1753 OBJ_CASE_INSENSITIVE,
1754 LdrpKnownDllObjectDirectory,
1755 NULL);
1756 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1757 SYMBOLIC_LINK_QUERY,
1758 &ObjectAttributes);
1759 if (NT_SUCCESS(Status))
1760 {
1761 /* Query the path */
1762 LdrpKnownDllPath.Length = 0;
1763 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1764 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1765 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1766 NtClose(SymLinkHandle);
1767 if (!NT_SUCCESS(Status))
1768 {
1769 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1770 return Status;
1771 }
1772 }
1773 }
1774
1775 /* Check if we failed */
1776 if (!NT_SUCCESS(Status))
1777 {
1778 /* Assume System32 */
1779 LdrpKnownDllObjectDirectory = NULL;
1780 RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
1781 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1782 }
1783
1784 /* If we have process parameters, get the default path and current path */
1785 if (ProcessParameters)
1786 {
1787 /* Check if we have a Dll Path */
1788 if (ProcessParameters->DllPath.Length)
1789 {
1790 /* Get the path */
1791 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1792 }
1793 else
1794 {
1795 /* We need a valid path */
1796 DPRINT1("No valid DllPath was given!\n");
1797 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1798 }
1799
1800 /* Set the current directory */
1801 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1802
1803 /* Check if it's empty or invalid */
1804 if ((!CurrentDirectory.Buffer) ||
1805 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1806 (!CurrentDirectory.Length))
1807 {
1808 /* Allocate space for the buffer */
1809 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1810 0,
1811 3 * sizeof(WCHAR) +
1812 sizeof(UNICODE_NULL));
1813 if (!CurrentDirectory.Buffer)
1814 {
1815 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1816 // FIXME: And what?
1817 }
1818
1819 /* Copy the drive of the system root */
1820 RtlMoveMemory(CurrentDirectory.Buffer,
1821 SharedUserData->NtSystemRoot,
1822 3 * sizeof(WCHAR));
1823 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1824 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1825 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1826
1827 FreeCurDir = TRUE;
1828 DPRINT("Using dynamically allocd curdir\n");
1829 }
1830 else
1831 {
1832 /* Use the local buffer */
1833 DPRINT("Using local system root\n");
1834 }
1835 }
1836
1837 /* Setup Loader Data */
1838 Peb->Ldr = &PebLdr;
1839 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1840 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1841 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1842 PebLdr.Length = sizeof(PEB_LDR_DATA);
1843 PebLdr.Initialized = TRUE;
1844
1845 /* Allocate a data entry for the Image */
1846 LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1847
1848 /* Set it up */
1849 LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
1850 LdrpImageEntry->LoadCount = -1;
1851 LdrpImageEntry->EntryPointActivationContext = 0;
1852 LdrpImageEntry->FullDllName = ImageFileName;
1853
1854 if (IsDotNetImage)
1855 LdrpImageEntry->Flags = LDRP_COR_IMAGE;
1856 else
1857 LdrpImageEntry->Flags = 0;
1858
1859 /* Check if the name is empty */
1860 if (!ImageFileName.Buffer[0])
1861 {
1862 /* Use the same Base name */
1863 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
1864 }
1865 else
1866 {
1867 /* Find the last slash */
1868 Current = ImageFileName.Buffer;
1869 while (*Current)
1870 {
1871 if (*Current++ == '\\')
1872 {
1873 /* Set this path */
1874 NtDllName = Current;
1875 }
1876 }
1877
1878 /* Did we find anything? */
1879 if (!NtDllName)
1880 {
1881 /* Use the same Base name */
1882 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
1883 }
1884 else
1885 {
1886 /* Setup the name */
1887 LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
1888 LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
1889 LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
1890 (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
1891 }
1892 }
1893
1894 /* Processing done, insert it */
1895 LdrpInsertMemoryTableEntry(LdrpImageEntry);
1896 LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
1897
1898 /* Now add an entry for NTDLL */
1899 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
1900 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
1901 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1902 NtLdrEntry->LoadCount = -1;
1903 NtLdrEntry->EntryPointActivationContext = 0;
1904
1905 NtLdrEntry->FullDllName.Length = FullPath.Length;
1906 NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
1907 NtLdrEntry->FullDllName.Buffer = StringBuffer;
1908 RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
1909
1910 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
1911 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
1912 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
1913
1914 /* Processing done, insert it */
1915 LdrpNtDllDataTableEntry = NtLdrEntry;
1916 LdrpInsertMemoryTableEntry(NtLdrEntry);
1917
1918 /* Let the world know */
1919 if (ShowSnaps)
1920 {
1921 DPRINT1("LDR: NEW PROCESS\n");
1922 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
1923 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
1924 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
1925 }
1926
1927 /* Link the Init Order List */
1928 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
1929 &LdrpNtDllDataTableEntry->InInitializationOrderModuleList);
1930
1931 /* Initialize Wine's active context implementation for the current process */
1932 actctx_init();
1933
1934 /* Set the current directory */
1935 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
1936 if (!NT_SUCCESS(Status))
1937 {
1938 /* We failed, check if we should free it */
1939 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1940
1941 /* Set it to the NT Root */
1942 CurrentDirectory = NtSystemRoot;
1943 RtlSetCurrentDirectory_U(&CurrentDirectory);
1944 }
1945 else
1946 {
1947 /* We're done with it, free it */
1948 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
1949 }
1950
1951 /* Check if we should look for a .local file */
1952 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
1953 {
1954 /* FIXME */
1955 DPRINT1("We don't support .local overrides yet\n");
1956 }
1957
1958 /* Check if the Application Verifier was enabled */
1959 if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK)
1960 {
1961 /* FIXME */
1962 DPRINT1("We don't support Application Verifier yet\n");
1963 }
1964
1965 if (IsDotNetImage)
1966 {
1967 /* FIXME */
1968 DPRINT1("We don't support .NET applications yet\n");
1969 }
1970
1971 /* FIXME: Load support for Terminal Services */
1972 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
1973 {
1974 /* Load kernel32 and call BasePostImportInit... */
1975 DPRINT("Unimplemented codepath!\n");
1976 }
1977
1978 /* Walk the IAT and load all the DLLs */
1979 ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
1980
1981 /* Check if relocation is needed */
1982 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
1983 {
1984 DPRINT1("LDR: Performing EXE relocation\n");
1985
1986 /* Change the protection to prepare for relocation */
1987 ViewBase = Peb->ImageBaseAddress;
1988 Status = LdrpSetProtection(ViewBase, FALSE);
1989 if (!NT_SUCCESS(Status)) return Status;
1990
1991 /* Do the relocation */
1992 Status = LdrRelocateImageWithBias(ViewBase,
1993 0LL,
1994 NULL,
1995 STATUS_SUCCESS,
1996 STATUS_CONFLICTING_ADDRESSES,
1997 STATUS_INVALID_IMAGE_FORMAT);
1998 if (!NT_SUCCESS(Status))
1999 {
2000 DPRINT1("LdrRelocateImageWithBias() failed\n");
2001 return Status;
2002 }
2003
2004 /* Check if a start context was provided */
2005 if (Context)
2006 {
2007 DPRINT1("WARNING: Relocated EXE Context");
2008 UNIMPLEMENTED; // We should support this
2009 return STATUS_INVALID_IMAGE_FORMAT;
2010 }
2011
2012 /* Restore the protection */
2013 Status = LdrpSetProtection(ViewBase, TRUE);
2014 if (!NT_SUCCESS(Status)) return Status;
2015 }
2016
2017 /* Lock the DLLs */
2018 ListHead = &Peb->Ldr->InLoadOrderModuleList;
2019 NextEntry = ListHead->Flink;
2020 while (ListHead != NextEntry)
2021 {
2022 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2023 NtLdrEntry->LoadCount = -1;
2024 NextEntry = NextEntry->Flink;
2025 }
2026
2027 /* Phase 0 is done */
2028 LdrpLdrDatabaseIsSetup = TRUE;
2029
2030 /* Check whether all static imports were properly loaded and return here */
2031 if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2032
2033 /* Initialize TLS */
2034 Status = LdrpInitializeTls();
2035 if (!NT_SUCCESS(Status))
2036 {
2037 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2038 Status);
2039 return Status;
2040 }
2041
2042 /* FIXME Mark the DLL Ranges for Stack Traces later */
2043
2044 /* Notify the debugger now */
2045 if (Peb->BeingDebugged)
2046 {
2047 /* Break */
2048 DbgBreakPoint();
2049
2050 /* Update show snaps again */
2051 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2052 }
2053
2054 /* Validate the Image for MP Usage */
2055 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2056
2057 /* Check NX Options */
2058 if (SharedUserData->NXSupportPolicy == 1)
2059 {
2060 ExecuteOptions = 0xD;
2061 }
2062 else if (!SharedUserData->NXSupportPolicy)
2063 {
2064 ExecuteOptions = 0xA;
2065 }
2066
2067 /* Let Mm know */
2068 ZwSetInformationProcess(NtCurrentProcess(),
2069 ProcessExecuteFlags,
2070 &ExecuteOptions,
2071 sizeof(ULONG));
2072
2073 // FIXME: Should be done by Application Compatibility features,
2074 // by reading the registry, etc...
2075 // For now, this is the old code from ntdll!RtlGetVersion().
2076 RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2077 if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2078 {
2079 WCHAR szCSDVersion[128];
2080 LONG i;
2081 ULONG Length = ARRAYSIZE(szCSDVersion) - 1;
2082 i = _snwprintf(szCSDVersion, Length,
2083 L"Service Pack %d",
2084 ((Peb->OSCSDVersion >> 8) & 0xFF));
2085 if (i < 0)
2086 {
2087 /* Null-terminate if it was overflowed */
2088 szCSDVersion[Length] = UNICODE_NULL;
2089 }
2090
2091 Length *= sizeof(WCHAR);
2092 Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2093 0,
2094 Length + sizeof(UNICODE_NULL));
2095 if (Peb->CSDVersion.Buffer)
2096 {
2097 Peb->CSDVersion.Length = Length;
2098 Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2099
2100 RtlCopyMemory(Peb->CSDVersion.Buffer,
2101 szCSDVersion,
2102 Peb->CSDVersion.MaximumLength);
2103 Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2104 }
2105 }
2106
2107 /* Check if we had Shim Data */
2108 if (OldShimData)
2109 {
2110 /* Load the Shim Engine */
2111 Peb->AppCompatInfo = NULL;
2112 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
2113 DPRINT1("We do not support shims yet\n");
2114 }
2115 else
2116 {
2117 /* Check for Application Compatibility Goo */
2118 //LdrQueryApplicationCompatibilityGoo(hKey);
2119 DPRINT("Querying app compat hacks is missing!\n");
2120 }
2121
2122 /*
2123 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2124 * incompatible images.
2125 */
2126
2127 /* Now call the Init Routines */
2128 Status = LdrpRunInitializeRoutines(Context);
2129 if (!NT_SUCCESS(Status))
2130 {
2131 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2132 Status);
2133 return Status;
2134 }
2135
2136 /* FIXME: Unload the Shim Engine if it was loaded */
2137
2138 /* Check if we have a user-defined Post Process Routine */
2139 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2140 {
2141 /* Call it */
2142 Peb->PostProcessInitRoutine();
2143 }
2144
2145 /* Close the key if we have one opened */
2146 if (OptionsKey) NtClose(OptionsKey);
2147
2148 /* Return status */
2149 return Status;
2150 }
2151
2152 VOID
2153 NTAPI
2154 LdrpInitFailure(NTSTATUS Status)
2155 {
2156 ULONG Response;
2157 PPEB Peb = NtCurrentPeb();
2158
2159 /* Print a debug message */
2160 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2161 &Peb->ProcessParameters->ImagePathName, Status);
2162
2163 /* Raise a hard error */
2164 if (!LdrpFatalHardErrorCount)
2165 {
2166 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2167 }
2168 }
2169
2170 VOID
2171 NTAPI
2172 LdrpInit(PCONTEXT Context,
2173 PVOID SystemArgument1,
2174 PVOID SystemArgument2)
2175 {
2176 LARGE_INTEGER Timeout;
2177 PTEB Teb = NtCurrentTeb();
2178 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2179 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2180 PPEB Peb = NtCurrentPeb();
2181
2182 DPRINT("LdrpInit() %p/%p\n",
2183 NtCurrentTeb()->RealClientId.UniqueProcess,
2184 NtCurrentTeb()->RealClientId.UniqueThread);
2185
2186 /* Check if we have a deallocation stack */
2187 if (!Teb->DeallocationStack)
2188 {
2189 /* We don't, set one */
2190 Status = NtQueryVirtualMemory(NtCurrentProcess(),
2191 Teb->NtTib.StackLimit,
2192 MemoryBasicInformation,
2193 &MemoryBasicInfo,
2194 sizeof(MEMORY_BASIC_INFORMATION),
2195 NULL);
2196 if (!NT_SUCCESS(Status))
2197 {
2198 /* Fail */
2199 LdrpInitFailure(Status);
2200 RtlRaiseStatus(Status);
2201 return;
2202 }
2203
2204 /* Set the stack */
2205 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2206 }
2207
2208 /* Now check if the process is already being initialized */
2209 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2210 1,
2211 0) == 1)
2212 {
2213 /* Set the timeout to 30 seconds */
2214 Timeout.QuadPart = Int32x32To64(30, -10000);
2215
2216 /* Make sure the status hasn't changed */
2217 while (!LdrpProcessInitialized)
2218 {
2219 /* Do the wait */
2220 ZwDelayExecution(FALSE, &Timeout);
2221 }
2222 }
2223
2224 /* Check if we have already setup LDR data */
2225 if (!Peb->Ldr)
2226 {
2227 /* Setup the Loader Lock */
2228 Peb->LoaderLock = &LdrpLoaderLock;
2229
2230 /* Let other code know we're initializing */
2231 LdrpInLdrInit = TRUE;
2232
2233 /* Protect with SEH */
2234 _SEH2_TRY
2235 {
2236 /* Initialize the Process */
2237 LoaderStatus = LdrpInitializeProcess(Context,
2238 SystemArgument1);
2239
2240 /* Check for success and if MinimumStackCommit was requested */
2241 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2242 {
2243 /* Enforce the limit */
2244 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2245 UNIMPLEMENTED;
2246 }
2247 }
2248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2249 {
2250 /* Fail with the SEH error */
2251 LoaderStatus = _SEH2_GetExceptionCode();
2252 }
2253 _SEH2_END;
2254
2255 /* We're not initializing anymore */
2256 LdrpInLdrInit = FALSE;
2257
2258 /* Check if init worked */
2259 if (NT_SUCCESS(LoaderStatus))
2260 {
2261 /* Set the process as Initialized */
2262 _InterlockedIncrement(&LdrpProcessInitialized);
2263 }
2264 }
2265 else
2266 {
2267 /* Loader data is there... is this a fork() ? */
2268 if(Peb->InheritedAddressSpace)
2269 {
2270 /* Handle the fork() */
2271 //LoaderStatus = LdrpForkProcess();
2272 LoaderStatus = STATUS_NOT_IMPLEMENTED;
2273 UNIMPLEMENTED;
2274 }
2275 else
2276 {
2277 /* This is a new thread initializing */
2278 LdrpInitializeThread(Context);
2279 }
2280 }
2281
2282 /* All done, test alert the thread */
2283 NtTestAlert();
2284
2285 /* Return */
2286 if (!NT_SUCCESS(LoaderStatus))
2287 {
2288 /* Fail */
2289 LdrpInitFailure(LoaderStatus);
2290 RtlRaiseStatus(LoaderStatus);
2291 }
2292 }
2293
2294 /* EOF */