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)
10 /* INCLUDES *****************************************************************/
13 #include <win32k/callback.h>
19 /* GLOBALS *******************************************************************/
21 HKEY ImageExecOptionsKey
;
22 HKEY Wow64ExecOptionsKey
;
23 UNICODE_STRING ImageExecOptionsString
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
24 UNICODE_STRING Wow64OptionsString
= RTL_CONSTANT_STRING(L
"");
25 UNICODE_STRING NtDllString
= RTL_CONSTANT_STRING(L
"ntdll.dll");
27 BOOLEAN LdrpInLdrInit
;
28 LONG LdrpProcessInitialized
;
29 BOOLEAN LdrpLoaderLockInit
;
30 BOOLEAN LdrpLdrDatabaseIsSetup
;
31 BOOLEAN LdrpShutdownInProgress
;
32 HANDLE LdrpShutdownThreadId
;
34 BOOLEAN LdrpDllValidation
;
36 PLDR_DATA_TABLE_ENTRY LdrpImageEntry
;
37 PUNICODE_STRING LdrpTopLevelDllBeingLoaded
;
38 WCHAR StringBuffer
[156];
39 extern PTEB LdrpTopLevelDllBeingLoadedTeb
; // defined in rtlsupp.c!
40 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer
;
41 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry
;
44 RTL_BITMAP TlsExpansionBitMap
;
46 BOOLEAN LdrpImageHasTls
;
47 LIST_ENTRY LdrpTlsList
;
48 ULONG LdrpNumberOfTlsEntries
;
49 ULONG LdrpNumberOfProcessors
;
51 LARGE_INTEGER RtlpTimeout
;
52 BOOLEAN RtlpTimeoutDisable
;
53 LIST_ENTRY LdrpHashTable
[LDR_HASH_TABLE_ENTRIES
];
54 LIST_ENTRY LdrpDllNotificationList
;
55 HANDLE LdrpKnownDllObjectDirectory
;
56 UNICODE_STRING LdrpKnownDllPath
;
57 WCHAR LdrpKnownDllPathBuffer
[128];
58 UNICODE_STRING LdrpDefaultPath
;
62 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug
;
63 RTL_CRITICAL_SECTION LdrpLoaderLock
=
72 RTL_CRITICAL_SECTION FastPebLock
;
76 ULONG LdrpFatalHardErrorCount
;
77 ULONG LdrpActiveUnloadCount
;
79 //extern LIST_ENTRY RtlCriticalSectionList;
81 VOID
RtlpInitializeVectoredExceptionHandling(VOID
);
82 VOID NTAPI
RtlpInitDeferedCriticalSection(VOID
);
83 VOID
RtlInitializeHeapManager(VOID
);
84 extern BOOLEAN RtlpPageHeapEnabled
;
86 ULONG RtlpDisableHeapLookaside
; // TODO: Move to heap.c
87 ULONG RtlpShutdownProcessFlags
; // TODO: Use it
89 NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
, PVOID ImageBase
);
92 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
94 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
97 /* FUNCTIONS *****************************************************************/
104 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey
,
106 OUT PHKEY NewKeyHandle
)
108 PHKEY RootKeyLocation
;
110 UNICODE_STRING SubKeyString
;
111 OBJECT_ATTRIBUTES ObjectAttributes
;
115 /* Check which root key to open */
117 RootKeyLocation
= &Wow64ExecOptionsKey
;
119 RootKeyLocation
= &ImageExecOptionsKey
;
121 /* Get the current key */
122 RootKey
= *RootKeyLocation
;
124 /* Setup the object attributes */
125 InitializeObjectAttributes(&ObjectAttributes
,
127 &Wow64OptionsString
: &ImageExecOptionsString
,
128 OBJ_CASE_INSENSITIVE
,
132 /* Open the root key */
133 Status
= ZwOpenKey(&RootKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
134 if (NT_SUCCESS(Status
))
136 /* Write the key handle */
137 if (_InterlockedCompareExchange((LONG
*)RootKeyLocation
, (LONG
)RootKey
, 0) != 0)
139 /* Someone already opened it, use it instead */
141 RootKey
= *RootKeyLocation
;
144 /* Extract the name */
145 SubKeyString
= *SubKey
;
146 p1
= (PWCHAR
)((ULONG_PTR
)SubKeyString
.Buffer
+ SubKeyString
.Length
);
147 while (SubKeyString
.Length
)
149 if (p1
[-1] == L
'\\') break;
151 SubKeyString
.Length
-= sizeof(*p1
);
153 SubKeyString
.Buffer
= p1
;
154 SubKeyString
.Length
= SubKey
->Length
- SubKeyString
.Length
;
156 /* Setup the object attributes */
157 InitializeObjectAttributes(&ObjectAttributes
,
159 OBJ_CASE_INSENSITIVE
,
163 /* Open the setting key */
164 Status
= ZwOpenKey((PHANDLE
)NewKeyHandle
, GENERIC_READ
, &ObjectAttributes
);
167 /* Return to caller */
176 LdrQueryImageFileKeyOption(IN HKEY KeyHandle
,
181 OUT PULONG ReturnedLength OPTIONAL
)
184 UNICODE_STRING ValueNameString
, IntegerString
;
185 ULONG KeyInfoSize
, ResultSize
;
186 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)&KeyInfo
;
187 BOOLEAN FreeHeap
= FALSE
;
190 /* Build a string for the value name */
191 Status
= RtlInitUnicodeStringEx(&ValueNameString
, ValueName
);
192 if (!NT_SUCCESS(Status
)) return Status
;
194 /* Query the value */
195 Status
= ZwQueryValueKey(KeyHandle
,
197 KeyValuePartialInformation
,
201 if (Status
== STATUS_BUFFER_OVERFLOW
)
203 /* Our local buffer wasn't enough, allocate one */
204 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
205 KeyValueInformation
->DataLength
;
206 KeyValueInformation
= RtlAllocateHeap(RtlGetProcessHeap(),
211 /* Give up this time */
212 Status
= STATUS_NO_MEMORY
;
216 Status
= ZwQueryValueKey(KeyHandle
,
218 KeyValuePartialInformation
,
225 /* Check for success */
226 if (NT_SUCCESS(Status
))
228 /* Handle binary data */
229 if (KeyValueInformation
->Type
== REG_BINARY
)
232 if ((Buffer
) && (KeyValueInformation
->DataLength
<= BufferSize
))
234 /* Copy into buffer */
235 RtlMoveMemory(Buffer
,
236 &KeyValueInformation
->Data
,
237 KeyValueInformation
->DataLength
);
241 Status
= STATUS_BUFFER_OVERFLOW
;
244 /* Copy the result length */
245 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
247 else if (KeyValueInformation
->Type
== REG_DWORD
)
249 /* Check for valid type */
250 if (KeyValueInformation
->Type
!= Type
)
253 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
259 (BufferSize
== sizeof(ULONG
)) &&
260 (KeyValueInformation
->DataLength
<= BufferSize
))
262 /* Copy into buffer */
263 RtlMoveMemory(Buffer
,
264 &KeyValueInformation
->Data
,
265 KeyValueInformation
->DataLength
);
269 Status
= STATUS_BUFFER_OVERFLOW
;
272 /* Copy the result length */
273 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
276 else if (KeyValueInformation
->Type
!= REG_SZ
)
278 /* We got something weird */
279 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
283 /* String, check what you requested */
284 if (Type
== REG_DWORD
)
287 if (BufferSize
!= sizeof(ULONG
))
291 Status
= STATUS_INFO_LENGTH_MISMATCH
;
295 /* OK, we know what you want... */
296 IntegerString
.Buffer
= (PWSTR
)KeyValueInformation
->Data
;
297 IntegerString
.Length
= KeyValueInformation
->DataLength
-
299 IntegerString
.MaximumLength
= KeyValueInformation
->DataLength
;
300 Status
= RtlUnicodeStringToInteger(&IntegerString
, 0, (PULONG
)Buffer
);
306 if (KeyValueInformation
->DataLength
> BufferSize
)
309 Status
= STATUS_BUFFER_OVERFLOW
;
314 BufferSize
= KeyValueInformation
->DataLength
;
317 /* Copy the string */
318 RtlMoveMemory(Buffer
, &KeyValueInformation
->Data
, BufferSize
);
321 /* Copy the result length */
322 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
326 /* Check if buffer was in heap */
327 if (FreeHeap
) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation
);
338 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey
,
343 OUT PULONG ReturnedLength OPTIONAL
,
349 /* Open a handle to the key */
350 Status
= LdrOpenImageFileOptionsKey(SubKey
, Wow64
, &KeyHandle
);
352 /* Check for success */
353 if (NT_SUCCESS(Status
))
356 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
367 /* Return to caller */
376 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey
,
381 OUT PULONG ReturnedLength OPTIONAL
)
383 /* Call the newer function */
384 return LdrQueryImageFileExecutionOptionsEx(SubKey
,
395 LdrpEnsureLoaderLockIsHeld()
402 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress
, ULONG SizeOfImage
)
404 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir
;
408 /* Check NT header first */
409 if (!RtlImageNtHeader(BaseAddress
)) return NULL
;
411 /* Get the pointer to the config directory */
412 ConfigDir
= RtlImageDirectoryEntryToData(BaseAddress
,
414 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
417 /* Check for sanity */
419 (DirSize
!= 64 && ConfigDir
->Size
!= DirSize
) ||
420 (ConfigDir
->Size
< 0x48))
423 /* Now get the cookie */
424 Cookie
= (PVOID
)ConfigDir
->SecurityCookie
;
426 /* Check this cookie */
427 if ((PCHAR
)Cookie
<= (PCHAR
)BaseAddress
||
428 (PCHAR
)Cookie
>= (PCHAR
)BaseAddress
+ SizeOfImage
)
433 /* Return validated security cookie */
439 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry
)
442 LARGE_INTEGER Counter
;
445 /* Fetch address of the cookie */
446 Cookie
= LdrpFetchAddressOfSecurityCookie(LdrEntry
->DllBase
, LdrEntry
->SizeOfImage
);
450 /* Check if it's a default one */
451 if (*Cookie
== DEFAULT_SECURITY_COOKIE
||
454 /* We need to initialize it */
456 NtQueryPerformanceCounter(&Counter
, NULL
);
458 GetSystemTimeAsFileTime (&systime
.ft_struct
);
460 cookie
= systime
.ft_scalar
;
462 cookie
= systime
.ft_struct
.dwLowDateTime
;
463 cookie
^= systime
.ft_struct
.dwHighDateTime
;
466 cookie
^= GetCurrentProcessId ();
467 cookie
^= GetCurrentThreadId ();
468 cookie
^= GetTickCount ();
470 QueryPerformanceCounter (&perfctr
);
472 cookie
^= perfctr
.QuadPart
;
474 cookie
^= perfctr
.LowPart
;
475 cookie
^= perfctr
.HighPart
;
479 cookie
&= 0x0000ffffffffffffll
;
482 *Cookie
= Counter
.LowPart
;
493 LdrpInitializeThread(IN PCONTEXT Context
)
495 PPEB Peb
= NtCurrentPeb();
496 PLDR_DATA_TABLE_ENTRY LdrEntry
;
497 PLIST_ENTRY NextEntry
, ListHead
;
498 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
502 DPRINT("LdrpInitializeThread() called for %wZ\n",
503 &LdrpImageEntry
->BaseDllName
);
505 /* Allocate an Activation Context Stack */
506 /* FIXME: This is a hack for Wine's actctx stuff */
507 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
508 if (!(NtCurrentTeb()->ActivationContextStackPointer
))
510 Status
= RtlAllocateActivationContextStack((PVOID
*)&NtCurrentTeb()->ActivationContextStackPointer
);
511 if (NT_SUCCESS(Status
))
513 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
514 DPRINT("ActiveFrame %p\n", ((PACTIVATION_CONTEXT_STACK
)NtCurrentTeb()->ActivationContextStackPointer
)->ActiveFrame
);
515 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= NULL
;
518 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
521 /* Make sure we are not shutting down */
522 if (LdrpShutdownInProgress
) return;
527 /* Start at the beginning */
528 ListHead
= &Peb
->Ldr
->InMemoryOrderModuleList
;
529 NextEntry
= ListHead
->Flink
;
530 while (NextEntry
!= ListHead
)
532 /* Get the current entry */
533 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
535 /* Make sure it's not ourselves */
536 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
538 /* Check if we should call */
539 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
))
541 /* Get the entrypoint */
542 EntryPoint
= LdrEntry
->EntryPoint
;
544 /* Check if we are ready to call it */
546 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
547 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
549 /* Set up the Act Ctx */
550 ActCtx
.Size
= sizeof(ActCtx
);
552 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
554 /* Activate the ActCtx */
555 RtlActivateActivationContextUnsafeFast(&ActCtx
,
556 LdrEntry
->EntryPointActivationContext
);
558 /* Check if it has TLS */
559 if (LdrEntry
->TlsIndex
)
561 /* Make sure we're not shutting down */
562 if (!LdrpShutdownInProgress
)
565 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_ATTACH
);
569 /* Make sure we're not shutting down */
570 if (!LdrpShutdownInProgress
)
572 /* Call the Entrypoint */
573 DPRINT("%wZ - Calling entry point at %x for thread attaching\n",
574 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
575 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
581 /* Deactivate the ActCtx */
582 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
588 NextEntry
= NextEntry
->Flink
;
592 if (LdrpImageHasTls
&& !LdrpShutdownInProgress
)
594 /* Set up the Act Ctx */
595 ActCtx
.Size
= sizeof(ActCtx
);
597 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
599 /* Activate the ActCtx */
600 RtlActivateActivationContextUnsafeFast(&ActCtx
,
601 LdrpImageEntry
->EntryPointActivationContext
);
603 /* Do TLS callbacks */
604 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_ATTACH
);
606 /* Deactivate the ActCtx */
607 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
610 DPRINT("LdrpInitializeThread() done\n");
615 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL
)
617 PLDR_DATA_TABLE_ENTRY LocalArray
[16];
618 PLIST_ENTRY ListHead
;
619 PLIST_ENTRY NextEntry
;
620 PLDR_DATA_TABLE_ENTRY LdrEntry
, *LdrRootEntry
, OldInitializer
;
624 NTSTATUS Status
= STATUS_SUCCESS
;
625 PPEB Peb
= NtCurrentPeb();
626 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
627 ULONG BreakOnDllLoad
;
631 DPRINT("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
633 /* Check the Loader Lock */
634 LdrpEnsureLoaderLockIsHeld();
636 /* Get the number of entries to call */
637 if ((Count
= LdrpClearLoadInProgress()))
639 /* Check if we can use our local buffer */
642 /* Allocate space for all the entries */
643 LdrRootEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
645 Count
* sizeof(LdrRootEntry
));
646 if (!LdrRootEntry
) return STATUS_NO_MEMORY
;
650 /* Use our local array */
651 LdrRootEntry
= LocalArray
;
660 /* Show debug message */
663 DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n",
664 NtCurrentTeb()->RealClientId
.UniqueThread
,
665 NtCurrentTeb()->RealClientId
.UniqueProcess
,
666 &Peb
->ProcessParameters
->ImagePathName
);
670 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
671 NextEntry
= ListHead
->Flink
;
673 while (NextEntry
!= ListHead
)
675 /* Get the Data Entry */
676 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
678 /* Check if we have a Root Entry */
682 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
684 /* Setup the Cookie for the DLL */
685 LdrpInitSecurityCookie(LdrEntry
);
687 /* Check for valid entrypoint */
688 if (LdrEntry
->EntryPoint
)
691 LdrRootEntry
[i
] = LdrEntry
;
693 /* Display debug message */
696 DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
697 NtCurrentTeb()->RealClientId
.UniqueThread
,
698 NtCurrentTeb()->RealClientId
.UniqueProcess
,
699 &LdrEntry
->FullDllName
,
700 LdrEntry
->EntryPoint
);
708 LdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
709 NextEntry
= NextEntry
->Flink
;
712 /* If we got a context, then we have to call Kernel32 for TS support */
715 /* Check if we have one */
716 //if (Kernel32ProcessInitPostImportfunction)
719 //Kernel32ProcessInitPostImportfunction();
723 //Kernel32ProcessInitPostImportfunction = NULL;
727 /* No root entry? return */
728 if (!LdrRootEntry
) return STATUS_SUCCESS
;
730 /* Set the TLD TEB */
731 OldTldTeb
= LdrpTopLevelDllBeingLoadedTeb
;
732 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
739 LdrEntry
= LdrRootEntry
[i
];
741 /* FIXME: Verify NX Compat */
743 /* Move to next entry */
746 /* Get its entrypoint */
747 EntryPoint
= LdrEntry
->EntryPoint
;
749 /* Are we being debugged? */
751 if (Peb
->BeingDebugged
|| Peb
->ReadImageFileExecOptions
)
753 /* Check if we should break on load */
754 Status
= LdrQueryImageFileExecutionOptions(&LdrEntry
->BaseDllName
,
760 if (!NT_SUCCESS(Status
)) BreakOnDllLoad
= 0;
762 /* Reset status back to STATUS_SUCCESS */
763 Status
= STATUS_SUCCESS
;
769 /* Check if we should show a message */
772 DPRINT1("LDR: %wZ loaded.", &LdrEntry
->BaseDllName
);
773 DPRINT1(" - About to call init routine at %p\n", EntryPoint
);
776 /* Break in debugger */
780 /* Make sure we have an entrypoint */
783 /* Save the old Dll Initializer and write the current one */
784 OldInitializer
= LdrpCurrentDllInitializer
;
785 LdrpCurrentDllInitializer
= LdrEntry
;
787 /* Set up the Act Ctx */
788 ActCtx
.Size
= sizeof(ActCtx
);
790 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
792 /* Activate the ActCtx */
793 RtlActivateActivationContextUnsafeFast(&ActCtx
,
794 LdrEntry
->EntryPointActivationContext
);
796 /* Check if it has TLS */
797 if (LdrEntry
->TlsIndex
&& Context
)
800 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_ATTACH
);
803 /* Call the Entrypoint */
806 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
807 &LdrEntry
->BaseDllName
, EntryPoint
);
809 DllStatus
= LdrpCallInitRoutine(EntryPoint
,
814 /* Deactivate the ActCtx */
815 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
817 /* Save the Current DLL Initializer */
818 LdrpCurrentDllInitializer
= OldInitializer
;
820 /* Mark the entry as processed */
821 LdrEntry
->Flags
|= LDRP_PROCESS_ATTACH_CALLED
;
823 /* Fail if DLL init failed */
826 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
827 &LdrEntry
->BaseDllName
, EntryPoint
);
829 Status
= STATUS_DLL_INIT_FAILED
;
836 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
837 NextEntry
= NextEntry
->Flink
;
838 while (NextEntry
!= ListHead
)
840 /* Get the Data Entrry */
841 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
843 /* FIXME: Verify NX Compat */
844 // LdrpCheckNXCompatibility()
847 NextEntry
= NextEntry
->Flink
;
851 if (LdrpImageHasTls
&& Context
)
853 /* Set up the Act Ctx */
854 ActCtx
.Size
= sizeof(ActCtx
);
856 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
858 /* Activate the ActCtx */
859 RtlActivateActivationContextUnsafeFast(&ActCtx
,
860 LdrpImageEntry
->EntryPointActivationContext
);
862 /* Do TLS callbacks */
863 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_ATTACH
);
865 /* Deactivate the ActCtx */
866 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
870 /* Restore old TEB */
871 LdrpTopLevelDllBeingLoadedTeb
= OldTldTeb
;
873 /* Check if the array is in the heap */
874 if (LdrRootEntry
!= LocalArray
)
877 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry
);
880 /* Return to caller */
881 DPRINT("LdrpRunInitializeRoutines() done\n");
890 LdrShutdownProcess(VOID
)
892 PPEB Peb
= NtCurrentPeb();
893 PLDR_DATA_TABLE_ENTRY LdrEntry
;
894 PLIST_ENTRY NextEntry
, ListHead
;
895 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
898 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
899 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
901 /* Tell the Shim Engine */
913 /* Set the shutdown variables */
914 LdrpShutdownThreadId
= NtCurrentTeb()->RealClientId
.UniqueThread
;
915 LdrpShutdownInProgress
= TRUE
;
917 /* Enter the Loader Lock */
918 RtlEnterCriticalSection(&LdrpLoaderLock
);
920 /* Cleanup trace logging data (Etw) */
921 if (SharedUserData
->TraceLogging
)
924 DPRINT1("We don't support Etw yet.\n");
927 /* Start at the end */
928 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
929 NextEntry
= ListHead
->Blink
;
930 while (NextEntry
!= ListHead
)
932 /* Get the current entry */
933 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
934 NextEntry
= NextEntry
->Blink
;
936 /* Make sure it's not ourselves */
937 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
939 /* Get the entrypoint */
940 EntryPoint
= LdrEntry
->EntryPoint
;
942 /* Check if we are ready to call it */
944 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
947 /* Set up the Act Ctx */
948 ActCtx
.Size
= sizeof(ActCtx
);
950 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
952 /* Activate the ActCtx */
953 RtlActivateActivationContextUnsafeFast(&ActCtx
,
954 LdrEntry
->EntryPointActivationContext
);
956 /* Check if it has TLS */
957 if (LdrEntry
->TlsIndex
)
960 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_DETACH
);
963 /* Call the Entrypoint */
964 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
965 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
966 LdrpCallInitRoutine(EntryPoint
,
971 /* Deactivate the ActCtx */
972 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
980 /* Set up the Act Ctx */
981 ActCtx
.Size
= sizeof(ActCtx
);
983 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
985 /* Activate the ActCtx */
986 RtlActivateActivationContextUnsafeFast(&ActCtx
,
987 LdrpImageEntry
->EntryPointActivationContext
);
989 /* Do TLS callbacks */
990 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_DETACH
);
992 /* Deactivate the ActCtx */
993 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
996 /* FIXME: Do Heap detection and Etw final shutdown */
998 /* Release the lock */
999 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1000 DPRINT("LdrpShutdownProcess() done\n");
1002 return STATUS_SUCCESS
;
1010 LdrShutdownThread(VOID
)
1012 PPEB Peb
= NtCurrentPeb();
1013 PTEB Teb
= NtCurrentTeb();
1014 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1015 PLIST_ENTRY NextEntry
, ListHead
;
1016 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1019 DPRINT("LdrShutdownThread() called for %wZ\n",
1020 &LdrpImageEntry
->BaseDllName
);
1022 /* Cleanup trace logging data (Etw) */
1023 if (SharedUserData
->TraceLogging
)
1026 DPRINT1("We don't support Etw yet.\n");
1029 /* Get the Ldr Lock */
1030 RtlEnterCriticalSection(&LdrpLoaderLock
);
1032 /* Start at the end */
1033 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
1034 NextEntry
= ListHead
->Blink
;
1035 while (NextEntry
!= ListHead
)
1037 /* Get the current entry */
1038 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
1039 NextEntry
= NextEntry
->Blink
;
1041 /* Make sure it's not ourselves */
1042 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
1044 /* Check if we should call */
1045 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
) &&
1046 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
1047 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1049 /* Get the entrypoint */
1050 EntryPoint
= LdrEntry
->EntryPoint
;
1052 /* Check if we are ready to call it */
1055 /* Set up the Act Ctx */
1056 ActCtx
.Size
= sizeof(ActCtx
);
1058 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1060 /* Activate the ActCtx */
1061 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1062 LdrEntry
->EntryPointActivationContext
);
1064 /* Check if it has TLS */
1065 if (LdrEntry
->TlsIndex
)
1067 /* Make sure we're not shutting down */
1068 if (!LdrpShutdownInProgress
)
1071 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_DETACH
);
1075 /* Make sure we're not shutting down */
1076 if (!LdrpShutdownInProgress
)
1078 /* Call the Entrypoint */
1079 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
1080 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
1081 LdrpCallInitRoutine(EntryPoint
,
1087 /* Deactivate the ActCtx */
1088 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1095 if (LdrpImageHasTls
)
1097 /* Set up the Act Ctx */
1098 ActCtx
.Size
= sizeof(ActCtx
);
1100 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1102 /* Activate the ActCtx */
1103 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1104 LdrpImageEntry
->EntryPointActivationContext
);
1106 /* Do TLS callbacks */
1107 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_DETACH
);
1109 /* Deactivate the ActCtx */
1110 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1115 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1117 /* Check for expansion slots */
1118 if (Teb
->TlsExpansionSlots
)
1120 /* Free expansion slots */
1121 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->TlsExpansionSlots
);
1124 /* Check for FLS Data */
1128 DPRINT1("We don't support FLS Data yet\n");
1131 /* Check for Fiber data */
1132 if (Teb
->HasFiberData
)
1134 /* Free Fiber data*/
1135 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->NtTib
.FiberData
);
1136 Teb
->NtTib
.FiberData
= NULL
;
1139 /* Free the activation context stack */
1140 RtlFreeThreadActivationContextStack();
1141 DPRINT("LdrShutdownThread() done\n");
1143 return STATUS_SUCCESS
;
1148 LdrpInitializeTls(VOID
)
1150 PLIST_ENTRY NextEntry
, ListHead
;
1151 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1152 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1153 PLDRP_TLS_DATA TlsData
;
1156 /* Initialize the TLS List */
1157 InitializeListHead(&LdrpTlsList
);
1159 /* Loop all the modules */
1160 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1161 NextEntry
= ListHead
->Flink
;
1162 while (ListHead
!= NextEntry
)
1165 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1166 NextEntry
= NextEntry
->Flink
;
1168 /* Get the TLS directory */
1169 TlsDirectory
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1171 IMAGE_DIRECTORY_ENTRY_TLS
,
1174 /* Check if we have a directory */
1175 if (!TlsDirectory
) continue;
1177 /* Check if the image has TLS */
1178 if (!LdrpImageHasTls
) LdrpImageHasTls
= TRUE
;
1180 /* Show debug message */
1183 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1184 &LdrEntry
->BaseDllName
,
1188 /* Allocate an entry */
1189 TlsData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA
));
1190 if (!TlsData
) return STATUS_NO_MEMORY
;
1192 /* Lock the DLL and mark it for TLS Usage */
1193 LdrEntry
->LoadCount
= -1;
1194 LdrEntry
->TlsIndex
= -1;
1196 /* Save the cached TLS data */
1197 TlsData
->TlsDirectory
= *TlsDirectory
;
1198 InsertTailList(&LdrpTlsList
, &TlsData
->TlsLinks
);
1200 /* Update the index */
1201 *(PLONG
)TlsData
->TlsDirectory
.AddressOfIndex
= LdrpNumberOfTlsEntries
;
1202 TlsData
->TlsDirectory
.Characteristics
= LdrpNumberOfTlsEntries
++;
1205 /* Done setting up TLS, allocate entries */
1206 return LdrpAllocateTls();
1211 LdrpAllocateTls(VOID
)
1213 PTEB Teb
= NtCurrentTeb();
1214 PLIST_ENTRY NextEntry
, ListHead
;
1215 PLDRP_TLS_DATA TlsData
;
1219 /* Check if we have any entries */
1220 if (!LdrpNumberOfTlsEntries
)
1221 return STATUS_SUCCESS
;
1223 /* Allocate the vector array */
1224 TlsVector
= RtlAllocateHeap(RtlGetProcessHeap(),
1226 LdrpNumberOfTlsEntries
* sizeof(PVOID
));
1227 if (!TlsVector
) return STATUS_NO_MEMORY
;
1228 Teb
->ThreadLocalStoragePointer
= TlsVector
;
1230 /* Loop the TLS Array */
1231 ListHead
= &LdrpTlsList
;
1232 NextEntry
= ListHead
->Flink
;
1233 while (NextEntry
!= ListHead
)
1236 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1237 NextEntry
= NextEntry
->Flink
;
1239 /* Allocate this vector */
1240 TlsDataSize
= TlsData
->TlsDirectory
.EndAddressOfRawData
-
1241 TlsData
->TlsDirectory
.StartAddressOfRawData
;
1242 TlsVector
[TlsData
->TlsDirectory
.Characteristics
] = RtlAllocateHeap(RtlGetProcessHeap(),
1245 if (!TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1248 return STATUS_NO_MEMORY
;
1251 /* Show debug message */
1254 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
1256 TlsData
->TlsDirectory
.Characteristics
,
1257 &TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1258 TlsData
->TlsDirectory
.StartAddressOfRawData
,
1259 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1263 RtlCopyMemory(TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1264 (PVOID
)TlsData
->TlsDirectory
.StartAddressOfRawData
,
1269 return STATUS_SUCCESS
;
1276 PLIST_ENTRY ListHead
, NextEntry
;
1277 PLDRP_TLS_DATA TlsData
;
1279 PTEB Teb
= NtCurrentTeb();
1281 /* Get a pointer to the vector array */
1282 TlsVector
= Teb
->ThreadLocalStoragePointer
;
1283 if (!TlsVector
) return;
1285 /* Loop through it */
1286 ListHead
= &LdrpTlsList
;
1287 NextEntry
= ListHead
->Flink
;
1288 while (NextEntry
!= ListHead
)
1290 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1291 NextEntry
= NextEntry
->Flink
;
1293 /* Free each entry */
1294 if (TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1296 RtlFreeHeap(RtlGetProcessHeap(),
1298 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1302 /* Free the array itself */
1303 RtlFreeHeap(RtlGetProcessHeap(),
1310 LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName
, PPEB Peb
, BOOLEAN SystemWide
, BOOLEAN ReadAdvancedOptions
)
1312 /* If global flags request DPH, perform some additional actions */
1313 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
1315 // TODO: Read advanced DPH flags from the registry if requested
1316 if (ReadAdvancedOptions
)
1321 /* Enable page heap */
1322 RtlpPageHeapEnabled
= TRUE
;
1325 return STATUS_SUCCESS
;
1330 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName
, PPEB Peb
, PHKEY OptionsKey
)
1334 ULONG ExecuteOptions
, MinimumStackCommit
= 0, GlobalFlag
;
1336 /* Return error if we were not provided a pointer where to save the options key handle */
1337 if (!OptionsKey
) return STATUS_INVALID_HANDLE
;
1339 /* Zero initialize the optinos key pointer */
1342 /* Open the options key */
1343 Status
= LdrOpenImageFileOptionsKey(ImagePathName
, 0, &KeyHandle
);
1345 /* Save it if it was opened successfully */
1346 if (NT_SUCCESS(Status
))
1347 *OptionsKey
= KeyHandle
;
1351 /* There are image specific options, read them starting with NXCOMPAT */
1352 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1356 sizeof(ExecuteOptions
),
1359 if (NT_SUCCESS(Status
))
1361 /* TODO: Set execution options for the process */
1363 if (ExecuteOptions == 0)
1367 ZwSetInformationProcess(NtCurrentProcess(),
1368 ProcessExecuteFlags,
1374 /* Check if this image uses large pages */
1375 if (Peb
->ImageUsesLargePages
)
1377 /* TODO: If it does, open large page key */
1381 /* Get various option values */
1382 LdrQueryImageFileKeyOption(KeyHandle
,
1383 L
"DisableHeapLookaside",
1385 &RtlpDisableHeapLookaside
,
1386 sizeof(RtlpDisableHeapLookaside
),
1389 LdrQueryImageFileKeyOption(KeyHandle
,
1392 &RtlpShutdownProcessFlags
,
1393 sizeof(RtlpShutdownProcessFlags
),
1396 LdrQueryImageFileKeyOption(KeyHandle
,
1397 L
"MinimumStackCommitInBytes",
1399 &MinimumStackCommit
,
1400 sizeof(MinimumStackCommit
),
1403 /* Update PEB's minimum stack commit if it's lower */
1404 if (Peb
->MinimumStackCommit
< MinimumStackCommit
)
1405 Peb
->MinimumStackCommit
= MinimumStackCommit
;
1407 /* Set the global flag */
1408 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1415 if (NT_SUCCESS(Status
))
1416 Peb
->NtGlobalFlag
= GlobalFlag
;
1420 /* Call AVRF if necessary */
1421 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1423 Status
= LdrpInitializeApplicationVerifierPackage(ImagePathName
, Peb
, TRUE
, FALSE
);
1424 if (!NT_SUCCESS(Status
))
1426 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status
);
1432 /* There are no image-specific options, so perform global initialization */
1433 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1435 /* Initialize app verifier package */
1436 Status
= LdrpInitializeApplicationVerifierPackage(ImagePathName
, Peb
, TRUE
, FALSE
);
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status
);
1444 return STATUS_SUCCESS
;
1449 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
)
1456 LdrpInitializeProcess(IN PCONTEXT Context
,
1457 IN PVOID SystemArgument1
)
1459 RTL_HEAP_PARAMETERS HeapParameters
;
1460 ULONG ComSectionSize
;
1461 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1463 OBJECT_ATTRIBUTES ObjectAttributes
;
1464 //UNICODE_STRING LocalFileName, FullImageName;
1465 HANDLE SymLinkHandle
;
1466 //ULONG DebugHeapOnly;
1467 UNICODE_STRING CommandLine
, NtSystemRoot
, ImagePathName
, FullPath
, ImageFileName
, KnownDllString
;
1468 PPEB Peb
= NtCurrentPeb();
1469 BOOLEAN IsDotNetImage
= FALSE
;
1470 BOOLEAN FreeCurDir
= FALSE
;
1472 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
1473 //LPWSTR ImagePathBuffer;
1475 UNICODE_STRING CurrentDirectory
;
1478 PIMAGE_NT_HEADERS NtHeader
;
1479 LPWSTR NtDllName
= NULL
;
1481 NLSTABLEINFO NlsTable
;
1482 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig
;
1483 PTEB Teb
= NtCurrentTeb();
1484 PLIST_ENTRY ListHead
;
1485 PLIST_ENTRY NextEntry
;
1488 ULONG DebugProcessHeapOnly
= 0;
1489 PLDR_DATA_TABLE_ENTRY NtLdrEntry
;
1491 ULONG ExecuteOptions
= 0;
1494 /* Set a NULL SEH Filter */
1495 RtlSetUnhandledExceptionFilter(NULL
);
1497 /* Get the image path */
1498 ImagePath
= Peb
->ProcessParameters
->ImagePathName
.Buffer
;
1500 /* Check if it's not normalized */
1501 if (!(Peb
->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_NORMALIZED
))
1504 ImagePath
= (PWSTR
)((ULONG_PTR
)ImagePath
+ (ULONG_PTR
)Peb
->ProcessParameters
);
1507 /* Create a unicode string for the Image Path */
1508 ImagePathName
.Length
= Peb
->ProcessParameters
->ImagePathName
.Length
;
1509 ImagePathName
.MaximumLength
= ImagePathName
.Length
+ sizeof(WCHAR
);
1510 ImagePathName
.Buffer
= ImagePath
;
1512 /* Get the NT Headers */
1513 NtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1515 /* Get the execution options */
1516 Status
= LdrpInitializeExecutionOptions(&ImagePathName
, Peb
, &OptionsKey
);
1518 /* Check if this is a .NET executable */
1519 if (RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1521 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1524 /* Remeber this for later */
1525 IsDotNetImage
= TRUE
;
1528 /* Save the NTDLL Base address */
1529 NtDllBase
= SystemArgument1
;
1531 /* If this is a Native Image */
1532 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
)
1534 /* Then do DLL Validation */
1535 LdrpDllValidation
= TRUE
;
1538 /* Save the old Shim Data */
1539 OldShimData
= Peb
->pShimData
;
1542 Peb
->pShimData
= NULL
;
1544 /* Save the number of processors and CS Timeout */
1545 LdrpNumberOfProcessors
= Peb
->NumberOfProcessors
;
1546 RtlpTimeout
= Peb
->CriticalSectionTimeout
;
1548 /* Normalize the parameters */
1549 ProcessParameters
= RtlNormalizeProcessParams(Peb
->ProcessParameters
);
1550 ProcessParameters
= Peb
->ProcessParameters
;
1551 if (ProcessParameters
)
1553 /* Save the Image and Command Line Names */
1554 ImageFileName
= ProcessParameters
->ImagePathName
;
1555 CommandLine
= ProcessParameters
->CommandLine
;
1559 /* It failed, initialize empty strings */
1560 RtlInitUnicodeString(&ImageFileName
, NULL
);
1561 RtlInitUnicodeString(&CommandLine
, NULL
);
1564 /* Initialize NLS data */
1565 RtlInitNlsTables(Peb
->AnsiCodePageData
,
1566 Peb
->OemCodePageData
,
1567 Peb
->UnicodeCaseTableData
,
1570 /* Reset NLS Translations */
1571 RtlResetRtlTranslations(&NlsTable
);
1573 /* Get the Image Config Directory */
1574 LoadConfig
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1576 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
1579 /* Setup the Heap Parameters */
1580 RtlZeroMemory(&HeapParameters
, sizeof(RTL_HEAP_PARAMETERS
));
1581 HeapFlags
= HEAP_GROWABLE
;
1582 HeapParameters
.Length
= sizeof(RTL_HEAP_PARAMETERS
);
1584 /* Check if we have Configuration Data */
1585 if ((LoadConfig
) && (ConfigSize
== sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
)))
1587 /* FIXME: Custom heap settings and misc. */
1588 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1591 /* Check for custom affinity mask */
1592 if (Peb
->ImageProcessAffinityMask
)
1595 Status
= NtSetInformationProcess(NtCurrentProcess(),
1596 ProcessAffinityMask
,
1597 &Peb
->ImageProcessAffinityMask
,
1598 sizeof(Peb
->ImageProcessAffinityMask
));
1601 /* Check if verbose debugging (ShowSnaps) was requested */
1602 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
1604 /* Start verbose debugging messages right now if they were requested */
1607 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1608 Teb
->ClientId
.UniqueProcess
,
1612 /* If the timeout is too long */
1613 if (RtlpTimeout
.QuadPart
< Int32x32To64(3600, -10000000))
1615 /* Then disable CS Timeout */
1616 RtlpTimeoutDisable
= TRUE
;
1619 /* Initialize Critical Section Data */
1620 RtlpInitDeferedCriticalSection();
1622 /* Initialize VEH Call lists */
1623 RtlpInitializeVectoredExceptionHandling();
1625 /* Set TLS/FLS Bitmap data */
1626 Peb
->FlsBitmap
= &FlsBitMap
;
1627 Peb
->TlsBitmap
= &TlsBitMap
;
1628 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
1630 /* Initialize FLS Bitmap */
1631 RtlInitializeBitMap(&FlsBitMap
,
1633 FLS_MAXIMUM_AVAILABLE
);
1634 RtlSetBit(&FlsBitMap
, 0);
1636 /* Initialize TLS Bitmap */
1637 RtlInitializeBitMap(&TlsBitMap
,
1639 TLS_MINIMUM_AVAILABLE
);
1640 RtlSetBit(&TlsBitMap
, 0);
1641 RtlInitializeBitMap(&TlsExpansionBitMap
,
1642 Peb
->TlsExpansionBitmapBits
,
1643 TLS_EXPANSION_SLOTS
);
1644 RtlSetBit(&TlsExpansionBitMap
, 0);
1646 /* Initialize the Hash Table */
1647 for (i
= 0; i
< LDR_HASH_TABLE_ENTRIES
; i
++)
1649 InitializeListHead(&LdrpHashTable
[i
]);
1652 /* Initialize the Loader Lock */
1653 // FIXME: What's the point of initing it manually, if two lines lower
1654 // a call to RtlInitializeCriticalSection() is being made anyway?
1655 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1656 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1657 RtlInitializeCriticalSection(&LdrpLoaderLock
);
1658 LdrpLoaderLockInit
= TRUE
;
1660 /* Check if User Stack Trace Database support was requested */
1661 if (Peb
->NtGlobalFlag
& FLG_USER_STACK_TRACE_DB
)
1663 DPRINT1("We don't support user stack trace databases yet\n");
1666 /* Setup Fast PEB Lock */
1667 RtlInitializeCriticalSection(&FastPebLock
);
1668 Peb
->FastPebLock
= &FastPebLock
;
1669 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1670 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1672 /* Setup Callout Lock and Notification list */
1673 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1674 InitializeListHead(&LdrpDllNotificationList
);
1676 /* For old executables, use 16-byte aligned heap */
1677 if ((NtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3) &&
1678 (NtHeader
->OptionalHeader
.MinorSubsystemVersion
< 51))
1680 HeapFlags
|= HEAP_CREATE_ALIGN_16
;
1683 /* Setup the Heap */
1684 RtlInitializeHeapManager();
1685 Peb
->ProcessHeap
= RtlCreateHeap(HeapFlags
,
1687 NtHeader
->OptionalHeader
.SizeOfHeapReserve
,
1688 NtHeader
->OptionalHeader
.SizeOfHeapCommit
,
1692 if (!Peb
->ProcessHeap
)
1694 DPRINT1("Failed to create process heap\n");
1695 return STATUS_NO_MEMORY
;
1698 // FIXME: Is it located properly?
1699 /* Initialize table of callbacks for the kernel. */
1700 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
1703 (USER32_CALLBACK_MAXIMUM
+ 1));
1704 if (!Peb
->KernelCallbackTable
)
1706 DPRINT1("Failed to create callback table\n");
1707 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
1710 /* Allocate an Activation Context Stack */
1711 Status
= RtlAllocateActivationContextStack((PVOID
*)&Teb
->ActivationContextStackPointer
);
1712 if (!NT_SUCCESS(Status
)) return Status
;
1714 // FIXME: Loader private heap is missing
1715 //DPRINT1("Loader private heap is missing\n");
1717 /* Check for Debug Heap */
1720 /* Query the setting */
1721 Status
= LdrQueryImageFileKeyOption(OptionsKey
,
1722 L
"DebugProcessHeapOnly",
1724 &DebugProcessHeapOnly
,
1728 if (NT_SUCCESS(Status
))
1730 /* Reset DPH if requested */
1731 if (RtlpPageHeapEnabled
&& DebugProcessHeapOnly
)
1733 RtlpDphGlobalFlags
&= ~DPH_FLAG_DLL_NOTIFY
;
1734 RtlpPageHeapEnabled
= FALSE
;
1739 /* Build the NTDLL Path */
1740 FullPath
.Buffer
= StringBuffer
;
1741 FullPath
.Length
= 0;
1742 FullPath
.MaximumLength
= sizeof(StringBuffer
);
1743 RtlInitUnicodeString(&NtSystemRoot
, SharedUserData
->NtSystemRoot
);
1744 RtlAppendUnicodeStringToString(&FullPath
, &NtSystemRoot
);
1745 RtlAppendUnicodeToString(&FullPath
, L
"\\System32\\");
1747 /* Open the Known DLLs directory */
1748 RtlInitUnicodeString(&KnownDllString
, L
"\\KnownDlls");
1749 InitializeObjectAttributes(&ObjectAttributes
,
1751 OBJ_CASE_INSENSITIVE
,
1754 Status
= ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory
,
1755 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1758 /* Check if it exists */
1759 if (NT_SUCCESS(Status
))
1761 /* Open the Known DLLs Path */
1762 RtlInitUnicodeString(&KnownDllString
, L
"KnownDllPath");
1763 InitializeObjectAttributes(&ObjectAttributes
,
1765 OBJ_CASE_INSENSITIVE
,
1766 LdrpKnownDllObjectDirectory
,
1768 Status
= NtOpenSymbolicLinkObject(&SymLinkHandle
,
1769 SYMBOLIC_LINK_QUERY
,
1771 if (NT_SUCCESS(Status
))
1773 /* Query the path */
1774 LdrpKnownDllPath
.Length
= 0;
1775 LdrpKnownDllPath
.MaximumLength
= sizeof(LdrpKnownDllPathBuffer
);
1776 LdrpKnownDllPath
.Buffer
= LdrpKnownDllPathBuffer
;
1777 Status
= ZwQuerySymbolicLinkObject(SymLinkHandle
, &LdrpKnownDllPath
, NULL
);
1778 NtClose(SymLinkHandle
);
1779 if (!NT_SUCCESS(Status
))
1781 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status
);
1787 /* Check if we failed */
1788 if (!NT_SUCCESS(Status
))
1790 /* Aassume System32 */
1791 LdrpKnownDllObjectDirectory
= NULL
;
1792 RtlInitUnicodeString(&LdrpKnownDllPath
, StringBuffer
);
1793 LdrpKnownDllPath
.Length
-= sizeof(WCHAR
);
1796 /* If we have process parameters, get the default path and current path */
1797 if (ProcessParameters
)
1799 /* Check if we have a Dll Path */
1800 if (ProcessParameters
->DllPath
.Length
)
1803 LdrpDefaultPath
= *(PUNICODE_STRING
)&ProcessParameters
->DllPath
;
1807 /* We need a valid path */
1808 DPRINT1("No valid DllPath was given!\n");
1809 LdrpInitFailure(STATUS_INVALID_PARAMETER
);
1812 /* Set the current directory */
1813 CurrentDirectory
= ProcessParameters
->CurrentDirectory
.DosPath
;
1815 /* Check if it's empty or invalid */
1816 if ((!CurrentDirectory
.Buffer
) ||
1817 (CurrentDirectory
.Buffer
[0] == UNICODE_NULL
) ||
1818 (!CurrentDirectory
.Length
))
1820 /* Allocate space for the buffer */
1821 CurrentDirectory
.Buffer
= RtlAllocateHeap(Peb
->ProcessHeap
,
1824 sizeof(UNICODE_NULL
));
1825 if (!CurrentDirectory
.Buffer
)
1827 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1831 /* Copy the drive of the system root */
1832 RtlMoveMemory(CurrentDirectory
.Buffer
,
1833 SharedUserData
->NtSystemRoot
,
1835 CurrentDirectory
.Buffer
[3] = UNICODE_NULL
;
1836 CurrentDirectory
.Length
= 3 * sizeof(WCHAR
);
1837 CurrentDirectory
.MaximumLength
= CurrentDirectory
.Length
+ sizeof(WCHAR
);
1840 DPRINT("Using dynamically allocd curdir\n");
1844 /* Use the local buffer */
1845 DPRINT("Using local system root\n");
1849 /* Setup Loader Data */
1851 InitializeListHead(&PebLdr
.InLoadOrderModuleList
);
1852 InitializeListHead(&PebLdr
.InMemoryOrderModuleList
);
1853 InitializeListHead(&PebLdr
.InInitializationOrderModuleList
);
1854 PebLdr
.Length
= sizeof(PEB_LDR_DATA
);
1855 PebLdr
.Initialized
= TRUE
;
1857 /* Allocate a data entry for the Image */
1858 LdrpImageEntry
= NtLdrEntry
= LdrpAllocateDataTableEntry(Peb
->ImageBaseAddress
);
1861 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1862 NtLdrEntry
->LoadCount
= -1;
1863 NtLdrEntry
->EntryPointActivationContext
= 0;
1864 NtLdrEntry
->FullDllName
= ImageFileName
;
1867 NtLdrEntry
->Flags
= LDRP_COR_IMAGE
;
1869 NtLdrEntry
->Flags
= 0;
1871 /* Check if the name is empty */
1872 if (!ImageFileName
.Buffer
[0])
1874 /* Use the same Base name */
1875 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1879 /* Find the last slash */
1880 Current
= ImageFileName
.Buffer
;
1883 if (*Current
++ == '\\')
1886 NtDllName
= Current
;
1890 /* Did we find anything? */
1893 /* Use the same Base name */
1894 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1898 /* Setup the name */
1899 NtLdrEntry
->BaseDllName
.Length
= (USHORT
)((ULONG_PTR
)ImageFileName
.Buffer
+ ImageFileName
.Length
- (ULONG_PTR
)NtDllName
);
1900 NtLdrEntry
->BaseDllName
.MaximumLength
= NtLdrEntry
->BaseDllName
.Length
+ sizeof(WCHAR
);
1901 NtLdrEntry
->BaseDllName
.Buffer
= (PWSTR
)((ULONG_PTR
)ImageFileName
.Buffer
+
1902 (ImageFileName
.Length
- NtLdrEntry
->BaseDllName
.Length
));
1906 /* Processing done, insert it */
1907 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1908 NtLdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
1910 /* Now add an entry for NTDLL */
1911 NtLdrEntry
= LdrpAllocateDataTableEntry(SystemArgument1
);
1912 NtLdrEntry
->Flags
= LDRP_IMAGE_DLL
;
1913 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1914 NtLdrEntry
->LoadCount
= -1;
1915 NtLdrEntry
->EntryPointActivationContext
= 0;
1917 NtLdrEntry
->FullDllName
.Length
= FullPath
.Length
;
1918 NtLdrEntry
->FullDllName
.MaximumLength
= FullPath
.MaximumLength
;
1919 NtLdrEntry
->FullDllName
.Buffer
= StringBuffer
;
1920 RtlAppendUnicodeStringToString(&NtLdrEntry
->FullDllName
, &NtDllString
);
1922 NtLdrEntry
->BaseDllName
.Length
= NtDllString
.Length
;
1923 NtLdrEntry
->BaseDllName
.MaximumLength
= NtDllString
.MaximumLength
;
1924 NtLdrEntry
->BaseDllName
.Buffer
= NtDllString
.Buffer
;
1926 /* Processing done, insert it */
1927 LdrpNtDllDataTableEntry
= NtLdrEntry
;
1928 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1930 /* Let the world know */
1933 DPRINT1("LDR: NEW PROCESS\n");
1934 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry
->FullDllName
, &LdrpImageEntry
->BaseDllName
);
1935 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory
);
1936 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath
);
1939 /* Link the Init Order List */
1940 InsertHeadList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1941 &LdrpNtDllDataTableEntry
->InInitializationOrderModuleList
);
1943 /* Set the current directory */
1944 Status
= RtlSetCurrentDirectory_U(&CurrentDirectory
);
1945 if (!NT_SUCCESS(Status
))
1947 /* We failed, check if we should free it */
1948 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1950 /* Set it to the NT Root */
1951 CurrentDirectory
= NtSystemRoot
;
1952 RtlSetCurrentDirectory_U(&CurrentDirectory
);
1956 /* We're done with it, free it */
1957 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1960 /* Check if we should look for a .local file */
1961 if (ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
)
1964 DPRINT1("We don't support .local overrides yet\n");
1967 /* Check if the Application Verifier was enabled */
1968 if (Peb
->NtGlobalFlag
& FLG_POOL_ENABLE_TAIL_CHECK
)
1971 DPRINT1("We don't support Application Verifier yet\n");
1977 DPRINT1("We don't support .NET applications yet\n");
1980 /* FIXME: Load support for Terminal Services */
1981 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1983 /* Load kernel32 and call BasePostImportInit... */
1984 DPRINT1("Unimplemented codepath!\n");
1987 /* Walk the IAT and load all the DLLs */
1988 LdrpWalkImportDescriptor(LdrpDefaultPath
.Buffer
, LdrpImageEntry
);
1990 /* Check if relocation is needed */
1991 if (Peb
->ImageBaseAddress
!= (PVOID
)NtHeader
->OptionalHeader
.ImageBase
)
1993 DPRINT1("LDR: Performing EXE relocation\n");
1995 /* Change the protection to prepare for relocation */
1996 ViewBase
= Peb
->ImageBaseAddress
;
1997 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1998 if (!NT_SUCCESS(Status
)) return Status
;
2000 /* Do the relocation */
2001 Status
= LdrRelocateImageWithBias(ViewBase
,
2005 STATUS_CONFLICTING_ADDRESSES
,
2006 STATUS_INVALID_IMAGE_FORMAT
);
2007 if (!NT_SUCCESS(Status
))
2009 DPRINT1("LdrRelocateImageWithBias() failed\n");
2013 /* Check if a start context was provided */
2016 DPRINT1("WARNING: Relocated EXE Context");
2017 UNIMPLEMENTED
; // We should support this
2018 return STATUS_INVALID_IMAGE_FORMAT
;
2021 /* Restore the protection */
2022 Status
= LdrpSetProtection(ViewBase
, TRUE
);
2023 if (!NT_SUCCESS(Status
)) return Status
;
2027 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
2028 NextEntry
= ListHead
->Flink
;
2029 while (ListHead
!= NextEntry
)
2031 NtLdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2032 NtLdrEntry
->LoadCount
= -1;
2033 NextEntry
= NextEntry
->Flink
;
2036 /* Phase 0 is done */
2037 LdrpLdrDatabaseIsSetup
= TRUE
;
2039 /* Initialize TLS */
2040 Status
= LdrpInitializeTls();
2041 if (!NT_SUCCESS(Status
))
2043 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2048 /* FIXME Mark the DLL Ranges for Stack Traces later */
2050 /* Notify the debugger now */
2051 if (Peb
->BeingDebugged
)
2056 /* Update show snaps again */
2057 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
2060 /* Validate the Image for MP Usage */
2061 if (LdrpNumberOfProcessors
> 1) LdrpValidateImageForMp(LdrpImageEntry
);
2063 /* Check NX Options */
2064 if (SharedUserData
->NXSupportPolicy
== 1)
2066 ExecuteOptions
= 0xD;
2068 else if (!SharedUserData
->NXSupportPolicy
)
2070 ExecuteOptions
= 0xA;
2074 ZwSetInformationProcess(NtCurrentProcess(),
2075 ProcessExecuteFlags
,
2079 /* Check if we had Shim Data */
2082 /* Load the Shim Engine */
2083 Peb
->AppCompatInfo
= NULL
;
2084 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
2085 DPRINT1("We do not support shims yet\n");
2089 /* Check for Application Compatibility Goo */
2090 //LdrQueryApplicationCompatibilityGoo(hKey);
2091 DPRINT1("Querying app compat hacks is missing!\n");
2095 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2096 * incompatible images.
2099 /* Now call the Init Routines */
2100 Status
= LdrpRunInitializeRoutines(Context
);
2101 if (!NT_SUCCESS(Status
))
2103 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2108 /* FIXME: Unload the Shim Engine if it was loaded */
2110 /* Check if we have a user-defined Post Process Routine */
2111 if (NT_SUCCESS(Status
) && Peb
->PostProcessInitRoutine
)
2114 Peb
->PostProcessInitRoutine();
2117 /* Close the key if we have one opened */
2118 if (OptionsKey
) NtClose(OptionsKey
);
2126 LdrpInitFailure(NTSTATUS Status
)
2129 PPEB Peb
= NtCurrentPeb();
2131 /* Print a debug message */
2132 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2133 &Peb
->ProcessParameters
->ImagePathName
, Status
);
2135 /* Raise a hard error */
2136 if (!LdrpFatalHardErrorCount
)
2138 ZwRaiseHardError(STATUS_APP_INIT_FAILURE
, 1, 0, (PULONG_PTR
)&Status
, OptionOk
, &Response
);
2144 LdrpInit(PCONTEXT Context
,
2145 PVOID SystemArgument1
,
2146 PVOID SystemArgument2
)
2148 LARGE_INTEGER Timeout
;
2149 PTEB Teb
= NtCurrentTeb();
2150 NTSTATUS Status
, LoaderStatus
= STATUS_SUCCESS
;
2151 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
2152 PPEB Peb
= NtCurrentPeb();
2154 DPRINT("LdrpInit()\n");
2156 /* Check if we have a deallocation stack */
2157 if (!Teb
->DeallocationStack
)
2159 /* We don't, set one */
2160 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
2161 Teb
->NtTib
.StackLimit
,
2162 MemoryBasicInformation
,
2164 sizeof(MEMORY_BASIC_INFORMATION
),
2166 if (!NT_SUCCESS(Status
))
2169 LdrpInitFailure(Status
);
2170 RtlRaiseStatus(Status
);
2175 Teb
->DeallocationStack
= MemoryBasicInfo
.AllocationBase
;
2178 /* Now check if the process is already being initialized */
2179 while (_InterlockedCompareExchange(&LdrpProcessInitialized
,
2183 /* Set the timeout to 30 seconds */
2184 Timeout
.QuadPart
= Int32x32To64(30, -10000);
2186 /* Make sure the status hasn't changed */
2187 while (!LdrpProcessInitialized
)
2190 ZwDelayExecution(FALSE
, &Timeout
);
2194 /* Check if we have already setup LDR data */
2197 /* Setup the Loader Lock */
2198 Peb
->LoaderLock
= &LdrpLoaderLock
;
2200 /* Let other code know we're initializing */
2201 LdrpInLdrInit
= TRUE
;
2203 /* Protect with SEH */
2206 /* Initialize the Process */
2207 LoaderStatus
= LdrpInitializeProcess(Context
,
2210 /* Check for success and if MinimumStackCommit was requested */
2211 if (NT_SUCCESS(LoaderStatus
) && Peb
->MinimumStackCommit
)
2213 /* Enforce the limit */
2214 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2218 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2220 /* Fail with the SEH error */
2221 LoaderStatus
= _SEH2_GetExceptionCode();
2225 /* We're not initializing anymore */
2226 LdrpInLdrInit
= FALSE
;
2228 /* Check if init worked */
2229 if (NT_SUCCESS(LoaderStatus
))
2231 /* Set the process as Initialized */
2232 _InterlockedIncrement(&LdrpProcessInitialized
);
2237 /* Loader data is there... is this a fork() ? */
2238 if(Peb
->InheritedAddressSpace
)
2240 /* Handle the fork() */
2241 //LoaderStatus = LdrpForkProcess();
2242 LoaderStatus
= STATUS_NOT_IMPLEMENTED
;
2247 /* This is a new thread initializing */
2248 LdrpInitializeThread(Context
);
2252 /* All done, test alert the thread */
2256 if (!NT_SUCCESS(LoaderStatus
))
2259 LdrpInitFailure(LoaderStatus
);
2260 RtlRaiseStatus(LoaderStatus
);