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