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