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