xref: /reactos/dll/ntdll/ldr/ldrinit.c (revision d0ed4fdb)
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 BOOLEAN
1541 NTAPI
1542 LdrpDisableProcessCompatGuidDetection(VOID)
1543 {
1544     UNICODE_STRING PolicyKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\Software\\Policies\\Microsoft\\Windows\\AppCompat");
1545     UNICODE_STRING DisableDetection = RTL_CONSTANT_STRING(L"DisableCompatGuidDetection");
1546     OBJECT_ATTRIBUTES PolicyKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&PolicyKey, OBJ_CASE_INSENSITIVE);
1547     KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
1548     ULONG ResultLength;
1549     NTSTATUS Status;
1550     HANDLE KeyHandle;
1551 
1552     Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &PolicyKeyAttributes);
1553     if (NT_SUCCESS(Status))
1554     {
1555         Status = NtQueryValueKey(KeyHandle,
1556                                  &DisableDetection,
1557                                  KeyValuePartialInformation,
1558                                  &KeyInfo,
1559                                  sizeof(KeyInfo),
1560                                  &ResultLength);
1561         NtClose(KeyHandle);
1562         if ((NT_SUCCESS(Status)) &&
1563             (KeyInfo.Type == REG_DWORD) &&
1564             (KeyInfo.DataLength == sizeof(ULONG)) &&
1565             (KeyInfo.Data[0] == TRUE))
1566         {
1567             return TRUE;
1568         }
1569     }
1570     return FALSE;
1571 }
1572 
1573 
1574 VOID
1575 NTAPI
1576 LdrpInitializeProcessCompat(PVOID pProcessActctx, PVOID* pOldShimData)
1577 {
1578     static const struct
1579     {
1580         const GUID* Guid;
1581         const DWORD Version;
1582     } KnownCompatGuids[] = {
1583         { &COMPAT_GUID_WIN10, _WIN32_WINNT_WIN10 },
1584         { &COMPAT_GUID_WIN81, _WIN32_WINNT_WINBLUE },
1585         { &COMPAT_GUID_WIN8, _WIN32_WINNT_WIN8 },
1586         { &COMPAT_GUID_WIN7, _WIN32_WINNT_WIN7 },
1587         { &COMPAT_GUID_VISTA, _WIN32_WINNT_VISTA },
1588     };
1589 
1590     ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1591     ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1592     SIZE_T SizeRequired;
1593     NTSTATUS Status;
1594     DWORD n, cur;
1595     ReactOS_ShimData* pShimData = *pOldShimData;
1596 
1597     if (pShimData)
1598     {
1599         if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1600             pShimData->dwSize != sizeof(ReactOS_ShimData))
1601         {
1602             DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1603             return;
1604         }
1605         if (pShimData->dwRosProcessCompatVersion)
1606         {
1607             if (pShimData->dwRosProcessCompatVersion == REACTOS_COMPATVERSION_IGNOREMANIFEST)
1608             {
1609                 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion set to ignore manifest\n");
1610             }
1611             else
1612             {
1613                 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1614             }
1615             return;
1616         }
1617     }
1618 
1619     SizeRequired = sizeof(Buffer);
1620     Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1621                                                   pProcessActctx,
1622                                                   NULL,
1623                                                   CompatibilityInformationInActivationContext,
1624                                                   Buffer,
1625                                                   sizeof(Buffer),
1626                                                   &SizeRequired);
1627 
1628     if (!NT_SUCCESS(Status))
1629     {
1630         DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1631         return;
1632     }
1633 
1634     ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1635     /* No Compatibility elements present, bail out */
1636     if (ContextCompatInfo->ElementCount == 0)
1637         return;
1638 
1639     /* Search for known GUIDs, starting from oldest to newest.
1640        Note that on Windows it is somewhat reversed, starting from the latest known
1641        version, going down. But we are not Windows, trying to allow a lower version,
1642        we are ReactOS trying to fake a higher version. So we interpret what Windows
1643        does as "try the closest version to the actual version", so we start with the
1644        lowest version, which is closest to Windows 2003, which we mostly are. */
1645     for (cur = RTL_NUMBER_OF(KnownCompatGuids) - 1; cur != -1; --cur)
1646     {
1647         for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1648         {
1649             if (ContextCompatInfo->Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1650                 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, KnownCompatGuids[cur].Guid, sizeof(GUID)) == sizeof(GUID))
1651             {
1652                 if (LdrpDisableProcessCompatGuidDetection())
1653                 {
1654                     DPRINT1("LdrpInitializeProcessCompat: Not applying automatic fix for winver 0x%x due to policy\n", KnownCompatGuids[cur].Version);
1655                     return;
1656                 }
1657 
1658                 /* If this process did not need shim data before, allocate and store it */
1659                 if (pShimData == NULL)
1660                 {
1661                     PPEB Peb = NtCurrentPeb();
1662 
1663                     ASSERT(Peb->pShimData == NULL);
1664                     pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1665 
1666                     if (!pShimData)
1667                     {
1668                         DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1669                         return;
1670                     }
1671 
1672                     pShimData->dwSize = sizeof(*pShimData);
1673                     pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1674 
1675                     Peb->pShimData = pShimData;
1676                     *pOldShimData = pShimData;
1677                 }
1678 
1679                 /* Store the lowest found version, and bail out. */
1680                 pShimData->dwRosProcessCompatVersion = KnownCompatGuids[cur].Version;
1681                 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x in manifest from %wZ\n",
1682                         KnownCompatGuids[cur].Version,
1683                         &(NtCurrentPeb()->ProcessParameters->ImagePathName));
1684                 return;
1685             }
1686         }
1687     }
1688 }
1689 
1690 VOID
1691 NTAPI
1692 LdrpInitializeDotLocalSupport(PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
1693 {
1694     UNICODE_STRING ImagePathName = ProcessParameters->ImagePathName;
1695     WCHAR LocalBuffer[MAX_PATH];
1696     UNICODE_STRING DotLocal;
1697     NTSTATUS Status;
1698     ULONG RequiredSize;
1699 
1700     RequiredSize = ImagePathName.Length + LdrpDotLocal.Length + sizeof(UNICODE_NULL);
1701     if (RequiredSize <= sizeof(LocalBuffer))
1702     {
1703         RtlInitEmptyUnicodeString(&DotLocal, LocalBuffer, sizeof(LocalBuffer));
1704     }
1705     else if (RequiredSize <= UNICODE_STRING_MAX_BYTES)
1706     {
1707         DotLocal.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, RequiredSize);
1708         DotLocal.Length = 0;
1709         DotLocal.MaximumLength = RequiredSize;
1710         if (!DotLocal.Buffer)
1711             DPRINT1("LDR: Failed to allocate memory for .local check\n");
1712     }
1713     else
1714     {
1715         DotLocal.Buffer = NULL;
1716         DotLocal.Length = 0;
1717         DotLocal.MaximumLength = 0;
1718         DPRINT1("LDR: String too big for .local check\n");
1719     }
1720 
1721     if (DotLocal.Buffer)
1722     {
1723         Status = RtlAppendUnicodeStringToString(&DotLocal, &ImagePathName);
1724         ASSERT(NT_SUCCESS(Status));
1725         if (NT_SUCCESS(Status))
1726         {
1727             Status = RtlAppendUnicodeStringToString(&DotLocal, &LdrpDotLocal);
1728             ASSERT(NT_SUCCESS(Status));
1729         }
1730 
1731         if (NT_SUCCESS(Status))
1732         {
1733             if (RtlDoesFileExists_UStr(&DotLocal))
1734             {
1735                 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_PRIVATE_DLL_PATH;
1736             }
1737         }
1738         else
1739         {
1740             DPRINT1("LDR: Failed to append: 0x%lx\n", Status);
1741         }
1742 
1743         if (DotLocal.Buffer != LocalBuffer)
1744         {
1745             RtlFreeHeap(RtlGetProcessHeap(), 0, DotLocal.Buffer);
1746         }
1747     }
1748 }
1749 
1750 
1751 NTSTATUS
1752 NTAPI
1753 LdrpInitializeProcess(IN PCONTEXT Context,
1754                       IN PVOID SystemArgument1)
1755 {
1756     RTL_HEAP_PARAMETERS HeapParameters;
1757     ULONG ComSectionSize;
1758     ANSI_STRING BaseProcessInitPostImportName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");
1759     ANSI_STRING BaseQueryModuleDataName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1760     PVOID OldShimData;
1761     OBJECT_ATTRIBUTES ObjectAttributes;
1762     //UNICODE_STRING LocalFileName, FullImageName;
1763     HANDLE SymLinkHandle;
1764     //ULONG DebugHeapOnly;
1765     UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1766     PPEB Peb = NtCurrentPeb();
1767     BOOLEAN IsDotNetImage = FALSE;
1768     BOOLEAN FreeCurDir = FALSE;
1769     //HANDLE CompatKey;
1770     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1771     //LPWSTR ImagePathBuffer;
1772     ULONG ConfigSize;
1773     UNICODE_STRING CurrentDirectory;
1774     HANDLE OptionsKey;
1775     ULONG HeapFlags;
1776     PIMAGE_NT_HEADERS NtHeader;
1777     LPWSTR NtDllName = NULL;
1778     NTSTATUS Status, ImportStatus;
1779     NLSTABLEINFO NlsTable;
1780     PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1781     PTEB Teb = NtCurrentTeb();
1782     PLIST_ENTRY ListHead;
1783     PLIST_ENTRY NextEntry;
1784     ULONG i;
1785     PWSTR ImagePath;
1786     ULONG DebugProcessHeapOnly = 0;
1787     PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1788     PWCHAR Current;
1789     ULONG ExecuteOptions = 0;
1790     PVOID ViewBase;
1791 
1792     /* Set a NULL SEH Filter */
1793     RtlSetUnhandledExceptionFilter(NULL);
1794 
1795     /* Get the image path */
1796     ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1797 
1798     /* Check if it's not normalized */
1799     if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1800     {
1801         /* Normalize it*/
1802         ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1803     }
1804 
1805     /* Create a unicode string for the Image Path */
1806     ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1807     ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1808     ImagePathName.Buffer = ImagePath;
1809 
1810     /* Get the NT Headers */
1811     NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1812 
1813     /* Get the execution options */
1814     Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1815 
1816     /* Check if this is a .NET executable */
1817     if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1818                                      TRUE,
1819                                      IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1820                                      &ComSectionSize))
1821     {
1822         /* Remember this for later */
1823         IsDotNetImage = TRUE;
1824     }
1825 
1826     /* Save the NTDLL Base address */
1827     NtDllBase = SystemArgument1;
1828 
1829     /* If this is a Native Image */
1830     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1831     {
1832         /* Then do DLL Validation */
1833         LdrpDllValidation = TRUE;
1834     }
1835 
1836     /* Save the old Shim Data */
1837     OldShimData = Peb->pShimData;
1838 
1839     /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1840     //Peb->pShimData = NULL;
1841 
1842     /* Save the number of processors and CS Timeout */
1843     LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1844     RtlpTimeout = Peb->CriticalSectionTimeout;
1845 
1846     /* Normalize the parameters */
1847     ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1848     if (ProcessParameters)
1849     {
1850         /* Save the Image and Command Line Names */
1851         ImageFileName = ProcessParameters->ImagePathName;
1852         CommandLine = ProcessParameters->CommandLine;
1853     }
1854     else
1855     {
1856         /* It failed, initialize empty strings */
1857         RtlInitUnicodeString(&ImageFileName, NULL);
1858         RtlInitUnicodeString(&CommandLine, NULL);
1859     }
1860 
1861     /* Initialize NLS data */
1862     RtlInitNlsTables(Peb->AnsiCodePageData,
1863                      Peb->OemCodePageData,
1864                      Peb->UnicodeCaseTableData,
1865                      &NlsTable);
1866 
1867     /* Reset NLS Translations */
1868     RtlResetRtlTranslations(&NlsTable);
1869 
1870     /* Get the Image Config Directory */
1871     LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1872                                               TRUE,
1873                                               IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1874                                               &ConfigSize);
1875 
1876     /* Setup the Heap Parameters */
1877     RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
1878     HeapFlags = HEAP_GROWABLE;
1879     HeapParameters.Length = sizeof(HeapParameters);
1880 
1881     /* Check if we have Configuration Data */
1882 #define VALID_CONFIG_FIELD(Name) (ConfigSize >= (FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Name) + sizeof(LoadConfig->Name)))
1883     /* The 'original' load config ends after SecurityCookie */
1884     if ((LoadConfig) && ConfigSize && (VALID_CONFIG_FIELD(SecurityCookie) || ConfigSize == LoadConfig->Size))
1885     {
1886         if (ConfigSize != sizeof(IMAGE_LOAD_CONFIG_DIRECTORY))
1887             DPRINT1("WARN: Accepting different LOAD_CONFIG size!\n");
1888         else
1889             DPRINT1("Applying LOAD_CONFIG\n");
1890 
1891         if (VALID_CONFIG_FIELD(GlobalFlagsSet) && LoadConfig->GlobalFlagsSet)
1892             Peb->NtGlobalFlag |= LoadConfig->GlobalFlagsSet;
1893 
1894         if (VALID_CONFIG_FIELD(GlobalFlagsClear) && LoadConfig->GlobalFlagsClear)
1895             Peb->NtGlobalFlag &= ~LoadConfig->GlobalFlagsClear;
1896 
1897         if (VALID_CONFIG_FIELD(CriticalSectionDefaultTimeout) && LoadConfig->CriticalSectionDefaultTimeout)
1898             RtlpTimeout.QuadPart = Int32x32To64(LoadConfig->CriticalSectionDefaultTimeout, -10000000);
1899 
1900         if (VALID_CONFIG_FIELD(DeCommitFreeBlockThreshold) && LoadConfig->DeCommitFreeBlockThreshold)
1901             HeapParameters.DeCommitFreeBlockThreshold = LoadConfig->DeCommitFreeBlockThreshold;
1902 
1903         if (VALID_CONFIG_FIELD(DeCommitTotalFreeThreshold) && LoadConfig->DeCommitTotalFreeThreshold)
1904             HeapParameters.DeCommitTotalFreeThreshold = LoadConfig->DeCommitTotalFreeThreshold;
1905 
1906         if (VALID_CONFIG_FIELD(MaximumAllocationSize) && LoadConfig->MaximumAllocationSize)
1907             HeapParameters.MaximumAllocationSize = LoadConfig->MaximumAllocationSize;
1908 
1909         if (VALID_CONFIG_FIELD(VirtualMemoryThreshold) && LoadConfig->VirtualMemoryThreshold)
1910             HeapParameters.VirtualMemoryThreshold = LoadConfig->VirtualMemoryThreshold;
1911 
1912         if (VALID_CONFIG_FIELD(ProcessHeapFlags) && LoadConfig->ProcessHeapFlags)
1913             HeapFlags = LoadConfig->ProcessHeapFlags;
1914     }
1915 #undef VALID_CONFIG_FIELD
1916 
1917     /* Check for custom affinity mask */
1918     if (Peb->ImageProcessAffinityMask)
1919     {
1920         /* Set it */
1921         Status = NtSetInformationProcess(NtCurrentProcess(),
1922                                          ProcessAffinityMask,
1923                                          &Peb->ImageProcessAffinityMask,
1924                                          sizeof(Peb->ImageProcessAffinityMask));
1925     }
1926 
1927     /* Check if verbose debugging (ShowSnaps) was requested */
1928     ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1929 
1930     /* Start verbose debugging messages right now if they were requested */
1931     if (ShowSnaps)
1932     {
1933         DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1934                 Teb->ClientId.UniqueProcess,
1935                 &CommandLine);
1936     }
1937 
1938     /* If the timeout is too long */
1939     if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1940     {
1941         /* Then disable CS Timeout */
1942         RtlpTimeoutDisable = TRUE;
1943     }
1944 
1945     /* Initialize Critical Section Data */
1946     RtlpInitDeferedCriticalSection();
1947 
1948     /* Initialize VEH Call lists */
1949     RtlpInitializeVectoredExceptionHandling();
1950 
1951     /* Set TLS/FLS Bitmap data */
1952     Peb->FlsBitmap = &FlsBitMap;
1953     Peb->TlsBitmap = &TlsBitMap;
1954     Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1955 
1956     /* Initialize FLS Bitmap */
1957     RtlInitializeBitMap(&FlsBitMap,
1958                         Peb->FlsBitmapBits,
1959                         FLS_MAXIMUM_AVAILABLE);
1960     RtlSetBit(&FlsBitMap, 0);
1961     InitializeListHead(&Peb->FlsListHead);
1962 
1963     /* Initialize TLS Bitmap */
1964     RtlInitializeBitMap(&TlsBitMap,
1965                         Peb->TlsBitmapBits,
1966                         TLS_MINIMUM_AVAILABLE);
1967     RtlSetBit(&TlsBitMap, 0);
1968     RtlInitializeBitMap(&TlsExpansionBitMap,
1969                         Peb->TlsExpansionBitmapBits,
1970                         TLS_EXPANSION_SLOTS);
1971     RtlSetBit(&TlsExpansionBitMap, 0);
1972 
1973     /* Initialize the Hash Table */
1974     for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1975     {
1976         InitializeListHead(&LdrpHashTable[i]);
1977     }
1978 
1979     /* Initialize the Loader Lock */
1980     // FIXME: What's the point of initing it manually, if two lines lower
1981     //        a call to RtlInitializeCriticalSection() is being made anyway?
1982     //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1983     //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1984     RtlInitializeCriticalSection(&LdrpLoaderLock);
1985     LdrpLoaderLockInit = TRUE;
1986 
1987     /* Check if User Stack Trace Database support was requested */
1988     if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1989     {
1990         DPRINT1("We don't support user stack trace databases yet\n");
1991     }
1992 
1993     /* Setup Fast PEB Lock */
1994     RtlInitializeCriticalSection(&FastPebLock);
1995     Peb->FastPebLock = &FastPebLock;
1996     //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1997     //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1998 
1999     /* Setup Callout Lock and Notification list */
2000     //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
2001     InitializeListHead(&LdrpDllNotificationList);
2002 
2003     /* For old executables, use 16-byte aligned heap */
2004     if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
2005         (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
2006     {
2007         HeapFlags |= HEAP_CREATE_ALIGN_16;
2008     }
2009 
2010     /* Setup the Heap */
2011     RtlInitializeHeapManager();
2012     Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
2013                                      NULL,
2014                                      NtHeader->OptionalHeader.SizeOfHeapReserve,
2015                                      NtHeader->OptionalHeader.SizeOfHeapCommit,
2016                                      NULL,
2017                                      &HeapParameters);
2018 
2019     if (!Peb->ProcessHeap)
2020     {
2021         DPRINT1("Failed to create process heap\n");
2022         return STATUS_NO_MEMORY;
2023     }
2024 
2025     /* Allocate an Activation Context Stack */
2026     Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
2027     if (!NT_SUCCESS(Status)) return Status;
2028 
2029     RtlZeroMemory(&HeapParameters, sizeof(HeapParameters));
2030     HeapFlags = HEAP_GROWABLE | HEAP_CLASS_1;
2031     HeapParameters.Length = sizeof(HeapParameters);
2032     LdrpHeap = RtlCreateHeap(HeapFlags, 0, 0x10000, 0x6000, 0, &HeapParameters);
2033     if (!LdrpHeap)
2034     {
2035         DPRINT1("Failed to create loader private heap\n");
2036         return STATUS_NO_MEMORY;
2037     }
2038 
2039     /* Check for Debug Heap */
2040     if (OptionsKey)
2041     {
2042         /* Query the setting */
2043         Status = LdrQueryImageFileKeyOption(OptionsKey,
2044                                             L"DebugProcessHeapOnly",
2045                                             REG_DWORD,
2046                                             &DebugProcessHeapOnly,
2047                                             sizeof(ULONG),
2048                                             NULL);
2049 
2050         if (NT_SUCCESS(Status))
2051         {
2052             /* Reset DPH if requested */
2053             if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
2054             {
2055                 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
2056                 RtlpPageHeapEnabled = FALSE;
2057             }
2058         }
2059     }
2060 
2061     /* Build the NTDLL Path */
2062     FullPath.Buffer = StringBuffer;
2063     FullPath.Length = 0;
2064     FullPath.MaximumLength = sizeof(StringBuffer);
2065     RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
2066     RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
2067     RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
2068 
2069     /* Open the Known DLLs directory */
2070     RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
2071     InitializeObjectAttributes(&ObjectAttributes,
2072                                &KnownDllString,
2073                                OBJ_CASE_INSENSITIVE,
2074                                NULL,
2075                                NULL);
2076     Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
2077                                    DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
2078                                    &ObjectAttributes);
2079 
2080     /* Check if it exists */
2081     if (NT_SUCCESS(Status))
2082     {
2083         /* Open the Known DLLs Path */
2084         RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
2085         InitializeObjectAttributes(&ObjectAttributes,
2086                                    &KnownDllString,
2087                                    OBJ_CASE_INSENSITIVE,
2088                                    LdrpKnownDllObjectDirectory,
2089                                    NULL);
2090         Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
2091                                           SYMBOLIC_LINK_QUERY,
2092                                           &ObjectAttributes);
2093         if (NT_SUCCESS(Status))
2094         {
2095             /* Query the path */
2096             LdrpKnownDllPath.Length = 0;
2097             LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
2098             LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
2099             Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
2100             NtClose(SymLinkHandle);
2101             if (!NT_SUCCESS(Status))
2102             {
2103                 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
2104                 return Status;
2105             }
2106         }
2107     }
2108 
2109     /* Check if we failed */
2110     if (!NT_SUCCESS(Status))
2111     {
2112         /* Assume System32 */
2113         LdrpKnownDllObjectDirectory = NULL;
2114         RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
2115         LdrpKnownDllPath.Length -= sizeof(WCHAR);
2116     }
2117 
2118     /* If we have process parameters, get the default path and current path */
2119     if (ProcessParameters)
2120     {
2121         /* Check if we have a Dll Path */
2122         if (ProcessParameters->DllPath.Length)
2123         {
2124             /* Get the path */
2125             LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
2126         }
2127         else
2128         {
2129             /* We need a valid path */
2130             DPRINT1("No valid DllPath was given!\n");
2131             LdrpInitFailure(STATUS_INVALID_PARAMETER);
2132         }
2133 
2134         /* Set the current directory */
2135         CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
2136 
2137         /* Check if it's empty or invalid */
2138         if ((!CurrentDirectory.Buffer) ||
2139             (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
2140             (!CurrentDirectory.Length))
2141         {
2142             /* Allocate space for the buffer */
2143             CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
2144                                                       0,
2145                                                       3 * sizeof(WCHAR) +
2146                                                       sizeof(UNICODE_NULL));
2147             if (!CurrentDirectory.Buffer)
2148             {
2149                 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
2150                 // FIXME: And what?
2151             }
2152 
2153             /* Copy the drive of the system root */
2154             RtlMoveMemory(CurrentDirectory.Buffer,
2155                           SharedUserData->NtSystemRoot,
2156                           3 * sizeof(WCHAR));
2157             CurrentDirectory.Buffer[3] = UNICODE_NULL;
2158             CurrentDirectory.Length = 3 * sizeof(WCHAR);
2159             CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
2160 
2161             FreeCurDir = TRUE;
2162             DPRINT("Using dynamically allocd curdir\n");
2163         }
2164         else
2165         {
2166             /* Use the local buffer */
2167             DPRINT("Using local system root\n");
2168         }
2169     }
2170 
2171     /* Setup Loader Data */
2172     Peb->Ldr = &PebLdr;
2173     InitializeListHead(&PebLdr.InLoadOrderModuleList);
2174     InitializeListHead(&PebLdr.InMemoryOrderModuleList);
2175     InitializeListHead(&PebLdr.InInitializationOrderModuleList);
2176     PebLdr.Length = sizeof(PEB_LDR_DATA);
2177     PebLdr.Initialized = TRUE;
2178 
2179     /* Allocate a data entry for the Image */
2180     LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
2181 
2182     /* Set it up */
2183     LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
2184     LdrpImageEntry->LoadCount = -1;
2185     LdrpImageEntry->EntryPointActivationContext = 0;
2186     LdrpImageEntry->FullDllName = ImageFileName;
2187 
2188     if (IsDotNetImage)
2189         LdrpImageEntry->Flags = LDRP_COR_IMAGE;
2190     else
2191         LdrpImageEntry->Flags = 0;
2192 
2193     /* Check if the name is empty */
2194     if (!ImageFileName.Buffer[0])
2195     {
2196         /* Use the same Base name */
2197         LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2198     }
2199     else
2200     {
2201         /* Find the last slash */
2202         Current = ImageFileName.Buffer;
2203         while (*Current)
2204         {
2205             if (*Current++ == '\\')
2206             {
2207                 /* Set this path */
2208                 NtDllName = Current;
2209             }
2210         }
2211 
2212         /* Did we find anything? */
2213         if (!NtDllName)
2214         {
2215             /* Use the same Base name */
2216             LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2217         }
2218         else
2219         {
2220             /* Setup the name */
2221             LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
2222             LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
2223             LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
2224                                                      (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
2225         }
2226     }
2227 
2228     /* Processing done, insert it */
2229     LdrpInsertMemoryTableEntry(LdrpImageEntry);
2230     LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
2231 
2232     /* Now add an entry for NTDLL */
2233     NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
2234     NtLdrEntry->Flags = LDRP_IMAGE_DLL;
2235     NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
2236     NtLdrEntry->LoadCount = -1;
2237     NtLdrEntry->EntryPointActivationContext = 0;
2238 
2239     NtLdrEntry->FullDllName.Length = FullPath.Length;
2240     NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
2241     NtLdrEntry->FullDllName.Buffer = StringBuffer;
2242     RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
2243 
2244     NtLdrEntry->BaseDllName.Length = NtDllString.Length;
2245     NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
2246     NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
2247 
2248     /* Processing done, insert it */
2249     LdrpNtDllDataTableEntry = NtLdrEntry;
2250     LdrpInsertMemoryTableEntry(NtLdrEntry);
2251 
2252     /* Let the world know */
2253     if (ShowSnaps)
2254     {
2255         DPRINT1("LDR: NEW PROCESS\n");
2256         DPRINT1("     Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
2257         DPRINT1("     Current Directory: %wZ\n", &CurrentDirectory);
2258         DPRINT1("     Search Path: %wZ\n", &LdrpDefaultPath);
2259     }
2260 
2261     /* Link the Init Order List */
2262     InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2263                    &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2264 
2265     /* Initialize Wine's active context implementation for the current process */
2266     actctx_init(&OldShimData);
2267 
2268     /* Set the current directory */
2269     Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2270     if (!NT_SUCCESS(Status))
2271     {
2272         /* We failed, check if we should free it */
2273         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2274 
2275         /* Set it to the NT Root */
2276         CurrentDirectory = NtSystemRoot;
2277         RtlSetCurrentDirectory_U(&CurrentDirectory);
2278     }
2279     else
2280     {
2281         /* We're done with it, free it */
2282         if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2283     }
2284 
2285     /* Check if we should look for a .local file */
2286     if (ProcessParameters && !(ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH))
2287     {
2288         LdrpInitializeDotLocalSupport(ProcessParameters);
2289     }
2290 
2291     /* Check if the Application Verifier was enabled */
2292     if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2293     {
2294         Status = AVrfInitializeVerifier();
2295         if (!NT_SUCCESS(Status))
2296         {
2297             DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2298             return Status;
2299         }
2300 
2301     }
2302 
2303     if (IsDotNetImage)
2304     {
2305         /* FIXME */
2306         DPRINT1("We don't support .NET applications yet\n");
2307     }
2308 
2309     if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
2310         NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2311     {
2312         PVOID Kernel32BaseAddress;
2313         PVOID FunctionAddress;
2314 
2315         Status = LdrLoadDll(NULL, NULL, &Kernel32String, &Kernel32BaseAddress);
2316 
2317         if (!NT_SUCCESS(Status))
2318         {
2319             if (ShowSnaps)
2320                 DPRINT1("LDR: Unable to load %wZ, Status=0x%08lx\n", &Kernel32String, Status);
2321             return Status;
2322         }
2323 
2324         Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2325                                         &BaseProcessInitPostImportName,
2326                                         0,
2327                                         &FunctionAddress);
2328 
2329         if (!NT_SUCCESS(Status))
2330         {
2331             if (ShowSnaps)
2332                 DPRINT1("LDR: Unable to find post-import process init function, Status=0x%08lx\n", &Kernel32String, Status);
2333             return Status;
2334         }
2335         Kernel32ProcessInitPostImportFunction = FunctionAddress;
2336 
2337         Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2338                                         &BaseQueryModuleDataName,
2339                                         0,
2340                                         &FunctionAddress);
2341 
2342         if (!NT_SUCCESS(Status))
2343         {
2344             if (ShowSnaps)
2345                 DPRINT1("LDR: Unable to find BaseQueryModuleData, Status=0x%08lx\n", &Kernel32String, Status);
2346             return Status;
2347         }
2348         Kernel32BaseQueryModuleData = FunctionAddress;
2349     }
2350 
2351     /* Walk the IAT and load all the DLLs */
2352     ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2353 
2354     /* Check if relocation is needed */
2355     if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2356     {
2357         DPRINT1("LDR: Performing EXE relocation\n");
2358 
2359         /* Change the protection to prepare for relocation */
2360         ViewBase = Peb->ImageBaseAddress;
2361         Status = LdrpSetProtection(ViewBase, FALSE);
2362         if (!NT_SUCCESS(Status)) return Status;
2363 
2364         /* Do the relocation */
2365         Status = LdrRelocateImageWithBias(ViewBase,
2366                                           0LL,
2367                                           NULL,
2368                                           STATUS_SUCCESS,
2369                                           STATUS_CONFLICTING_ADDRESSES,
2370                                           STATUS_INVALID_IMAGE_FORMAT);
2371         if (!NT_SUCCESS(Status))
2372         {
2373             DPRINT1("LdrRelocateImageWithBias() failed\n");
2374             return Status;
2375         }
2376 
2377         /* Check if a start context was provided */
2378         if (Context)
2379         {
2380             DPRINT1("WARNING: Relocated EXE Context");
2381             UNIMPLEMENTED; // We should support this
2382             return STATUS_INVALID_IMAGE_FORMAT;
2383         }
2384 
2385         /* Restore the protection */
2386         Status = LdrpSetProtection(ViewBase, TRUE);
2387         if (!NT_SUCCESS(Status)) return Status;
2388     }
2389 
2390     /* Lock the DLLs */
2391     ListHead = &Peb->Ldr->InLoadOrderModuleList;
2392     NextEntry = ListHead->Flink;
2393     while (ListHead != NextEntry)
2394     {
2395         NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2396         NtLdrEntry->LoadCount = -1;
2397         NextEntry = NextEntry->Flink;
2398     }
2399 
2400     /* Phase 0 is done */
2401     LdrpLdrDatabaseIsSetup = TRUE;
2402 
2403     /* Check whether all static imports were properly loaded and return here */
2404     if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2405 
2406     /* Initialize TLS */
2407     Status = LdrpInitializeTls();
2408     if (!NT_SUCCESS(Status))
2409     {
2410         DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2411                 Status);
2412         return Status;
2413     }
2414 
2415     /* FIXME Mark the DLL Ranges for Stack Traces later */
2416 
2417     /* Notify the debugger now */
2418     if (Peb->BeingDebugged)
2419     {
2420         /* Break */
2421         DbgBreakPoint();
2422 
2423         /* Update show snaps again */
2424         ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2425     }
2426 
2427     /* Validate the Image for MP Usage */
2428     if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2429 
2430     /* Check NX Options */
2431     if (SharedUserData->NXSupportPolicy == 1)
2432     {
2433         ExecuteOptions = 0xD;
2434     }
2435     else if (!SharedUserData->NXSupportPolicy)
2436     {
2437         ExecuteOptions = 0xA;
2438     }
2439 
2440     /* Let Mm know */
2441     ZwSetInformationProcess(NtCurrentProcess(),
2442                             ProcessExecuteFlags,
2443                             &ExecuteOptions,
2444                             sizeof(ULONG));
2445 
2446     // FIXME: Should be done by Application Compatibility features,
2447     // by reading the registry, etc...
2448     // For now, this is the old code from ntdll!RtlGetVersion().
2449     RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2450     if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2451     {
2452         WCHAR szCSDVersion[128];
2453         LONG i;
2454         USHORT Length = (USHORT)ARRAYSIZE(szCSDVersion) - 1;
2455         i = _snwprintf(szCSDVersion, Length,
2456                        L"Service Pack %d",
2457                        ((Peb->OSCSDVersion >> 8) & 0xFF));
2458         if (i < 0)
2459         {
2460             /* Null-terminate if it was overflowed */
2461             szCSDVersion[Length] = UNICODE_NULL;
2462         }
2463 
2464         Length *= sizeof(WCHAR);
2465         Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2466                                                  0,
2467                                                  Length + sizeof(UNICODE_NULL));
2468         if (Peb->CSDVersion.Buffer)
2469         {
2470             Peb->CSDVersion.Length = Length;
2471             Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2472 
2473             RtlCopyMemory(Peb->CSDVersion.Buffer,
2474                           szCSDVersion,
2475                           Peb->CSDVersion.MaximumLength);
2476             Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2477         }
2478     }
2479 
2480     /* Check if we had Shim Data */
2481     if (OldShimData)
2482     {
2483         /* Load the Shim Engine */
2484         Peb->AppCompatInfo = NULL;
2485         LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2486     }
2487     else
2488     {
2489         /* Check for Application Compatibility Goo */
2490         //LdrQueryApplicationCompatibilityGoo(hKey);
2491         DPRINT("Querying app compat hacks is missing!\n");
2492     }
2493 
2494     /*
2495      * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2496      * incompatible images.
2497      */
2498 
2499     /* Now call the Init Routines */
2500     Status = LdrpRunInitializeRoutines(Context);
2501     if (!NT_SUCCESS(Status))
2502     {
2503         DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2504                 Status);
2505         return Status;
2506     }
2507 
2508     /* Notify Shim Engine */
2509     if (g_ShimsEnabled)
2510     {
2511         VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2512         SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2513         SE_InstallAfterInit(&ImagePathName, OldShimData);
2514     }
2515 
2516     /* Check if we have a user-defined Post Process Routine */
2517     if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2518     {
2519         /* Call it */
2520         Peb->PostProcessInitRoutine();
2521     }
2522 
2523     /* Close the key if we have one opened */
2524     if (OptionsKey) NtClose(OptionsKey);
2525 
2526     /* Return status */
2527     return Status;
2528 }
2529 
2530 VOID
2531 NTAPI
2532 LdrpInitFailure(NTSTATUS Status)
2533 {
2534     ULONG Response;
2535     PPEB Peb = NtCurrentPeb();
2536 
2537     /* Print a debug message */
2538     DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2539             &Peb->ProcessParameters->ImagePathName, Status);
2540 
2541     /* Raise a hard error */
2542     if (!LdrpFatalHardErrorCount)
2543     {
2544         ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2545     }
2546 }
2547 
2548 VOID
2549 NTAPI
2550 LdrpInit(PCONTEXT Context,
2551          PVOID SystemArgument1,
2552          PVOID SystemArgument2)
2553 {
2554     LARGE_INTEGER Timeout;
2555     PTEB Teb = NtCurrentTeb();
2556     NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2557     MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2558     PPEB Peb = NtCurrentPeb();
2559 
2560     DPRINT("LdrpInit() %p/%p\n",
2561         NtCurrentTeb()->RealClientId.UniqueProcess,
2562         NtCurrentTeb()->RealClientId.UniqueThread);
2563 
2564 #ifdef _WIN64
2565     /* Set the SList header usage */
2566     RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2567 #endif /* _WIN64 */
2568 
2569     /* Check if we have a deallocation stack */
2570     if (!Teb->DeallocationStack)
2571     {
2572         /* We don't, set one */
2573         Status = NtQueryVirtualMemory(NtCurrentProcess(),
2574                                       Teb->NtTib.StackLimit,
2575                                       MemoryBasicInformation,
2576                                       &MemoryBasicInfo,
2577                                       sizeof(MEMORY_BASIC_INFORMATION),
2578                                       NULL);
2579         if (!NT_SUCCESS(Status))
2580         {
2581             /* Fail */
2582             LdrpInitFailure(Status);
2583             RtlRaiseStatus(Status);
2584             return;
2585         }
2586 
2587         /* Set the stack */
2588         Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2589     }
2590 
2591     /* Now check if the process is already being initialized */
2592     while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2593                                       1,
2594                                       0) == 1)
2595     {
2596         /* Set the timeout to 30 milliseconds */
2597         Timeout.QuadPart = Int32x32To64(30, -10000);
2598 
2599         /* Make sure the status hasn't changed */
2600         while (LdrpProcessInitialized == 1)
2601         {
2602             /* Do the wait */
2603             ZwDelayExecution(FALSE, &Timeout);
2604         }
2605     }
2606 
2607     /* Check if we have already setup LDR data */
2608     if (!Peb->Ldr)
2609     {
2610         /* Setup the Loader Lock */
2611         Peb->LoaderLock = &LdrpLoaderLock;
2612 
2613         /* Let other code know we're initializing */
2614         LdrpInLdrInit = TRUE;
2615 
2616         /* Protect with SEH */
2617         _SEH2_TRY
2618         {
2619             /* Initialize the Process */
2620             LoaderStatus = LdrpInitializeProcess(Context,
2621                                                  SystemArgument1);
2622 
2623             /* Check for success and if MinimumStackCommit was requested */
2624             if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2625             {
2626                 /* Enforce the limit */
2627                 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2628                 UNIMPLEMENTED;
2629             }
2630         }
2631         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2632         {
2633             /* Fail with the SEH error */
2634             LoaderStatus = _SEH2_GetExceptionCode();
2635         }
2636         _SEH2_END;
2637 
2638         /* We're not initializing anymore */
2639         LdrpInLdrInit = FALSE;
2640 
2641         /* Check if init worked */
2642         if (NT_SUCCESS(LoaderStatus))
2643         {
2644             /* Set the process as Initialized */
2645             _InterlockedIncrement(&LdrpProcessInitialized);
2646         }
2647     }
2648     else
2649     {
2650         /* Loader data is there... is this a fork() ? */
2651         if(Peb->InheritedAddressSpace)
2652         {
2653             /* Handle the fork() */
2654             //LoaderStatus = LdrpForkProcess();
2655             LoaderStatus = STATUS_NOT_IMPLEMENTED;
2656             UNIMPLEMENTED;
2657         }
2658         else
2659         {
2660             /* This is a new thread initializing */
2661             LdrpInitializeThread(Context);
2662         }
2663     }
2664 
2665     /* All done, test alert the thread */
2666     NtTestAlert();
2667 
2668     /* Return */
2669     if (!NT_SUCCESS(LoaderStatus))
2670     {
2671         /* Fail */
2672         LdrpInitFailure(LoaderStatus);
2673         RtlRaiseStatus(LoaderStatus);
2674     }
2675 }
2676 
2677 /* EOF */
2678