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
;
85 extern ULONG RtlpDphGlobalFlags
;
87 ULONG RtlpDisableHeapLookaside
; // TODO: Move to heap.c
88 ULONG RtlpShutdownProcessFlags
; // TODO: Use it
90 NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
, PVOID ImageBase
);
93 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
95 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
98 /* FUNCTIONS *****************************************************************/
105 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey
,
107 OUT PHKEY NewKeyHandle
)
109 PHKEY RootKeyLocation
;
111 UNICODE_STRING SubKeyString
;
112 OBJECT_ATTRIBUTES ObjectAttributes
;
116 /* Check which root key to open */
118 RootKeyLocation
= &Wow64ExecOptionsKey
;
120 RootKeyLocation
= &ImageExecOptionsKey
;
122 /* Get the current key */
123 RootKey
= *RootKeyLocation
;
125 /* Setup the object attributes */
126 InitializeObjectAttributes(&ObjectAttributes
,
128 &Wow64OptionsString
: &ImageExecOptionsString
,
129 OBJ_CASE_INSENSITIVE
,
133 /* Open the root key */
134 Status
= ZwOpenKey(&RootKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
135 if (NT_SUCCESS(Status
))
137 /* Write the key handle */
138 if (_InterlockedCompareExchange((LONG
*)RootKeyLocation
, (LONG
)RootKey
, 0) != 0)
140 /* Someone already opened it, use it instead */
142 RootKey
= *RootKeyLocation
;
145 /* Extract the name */
146 SubKeyString
= *SubKey
;
147 p1
= (PWCHAR
)((ULONG_PTR
)SubKeyString
.Buffer
+ SubKeyString
.Length
);
148 while (SubKey
->Length
)
150 if (p1
[-1] == L
'\\') break;
152 SubKeyString
.Length
-= sizeof(*p1
);
154 SubKeyString
.Buffer
= p1
;
155 SubKeyString
.Length
= SubKeyString
.MaximumLength
- SubKeyString
.Length
- sizeof(WCHAR
);
157 /* Setup the object attributes */
158 InitializeObjectAttributes(&ObjectAttributes
,
160 OBJ_CASE_INSENSITIVE
,
164 /* Open the setting key */
165 Status
= ZwOpenKey((PHANDLE
)NewKeyHandle
, GENERIC_READ
, &ObjectAttributes
);
168 /* Return to caller */
177 LdrQueryImageFileKeyOption(IN HKEY KeyHandle
,
182 OUT PULONG ReturnedLength OPTIONAL
)
185 UNICODE_STRING ValueNameString
, IntegerString
;
186 ULONG KeyInfoSize
, ResultSize
;
187 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)&KeyInfo
;
188 BOOLEAN FreeHeap
= FALSE
;
191 /* Build a string for the value name */
192 Status
= RtlInitUnicodeStringEx(&ValueNameString
, ValueName
);
193 if (!NT_SUCCESS(Status
)) return Status
;
195 /* Query the value */
196 Status
= NtQueryValueKey(KeyHandle
,
198 KeyValuePartialInformation
,
202 if (Status
== STATUS_BUFFER_OVERFLOW
)
204 /* Our local buffer wasn't enough, allocate one */
205 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
206 KeyValueInformation
->DataLength
;
207 KeyValueInformation
= RtlAllocateHeap(RtlGetProcessHeap(),
212 /* Give up this time */
213 Status
= STATUS_NO_MEMORY
;
217 Status
= NtQueryValueKey(KeyHandle
,
219 KeyValuePartialInformation
,
226 /* Check for success */
227 if (NT_SUCCESS(Status
))
229 /* Handle binary data */
230 if (KeyValueInformation
->Type
== REG_BINARY
)
233 if ((Buffer
) && (KeyValueInformation
->DataLength
<= BufferSize
))
235 /* Copy into buffer */
236 RtlMoveMemory(Buffer
,
237 &KeyValueInformation
->Data
,
238 KeyValueInformation
->DataLength
);
242 Status
= STATUS_BUFFER_OVERFLOW
;
245 /* Copy the result length */
246 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
248 else if (KeyValueInformation
->Type
== REG_DWORD
)
250 /* Check for valid type */
251 if (KeyValueInformation
->Type
!= Type
)
254 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
260 (BufferSize
== sizeof(ULONG
)) &&
261 (KeyValueInformation
->DataLength
<= BufferSize
))
263 /* Copy into buffer */
264 RtlMoveMemory(Buffer
,
265 &KeyValueInformation
->Data
,
266 KeyValueInformation
->DataLength
);
270 Status
= STATUS_BUFFER_OVERFLOW
;
273 /* Copy the result length */
274 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
277 else if (KeyValueInformation
->Type
!= REG_SZ
)
279 /* We got something weird */
280 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
284 /* String, check what you requested */
285 if (Type
== REG_DWORD
)
288 if (BufferSize
!= sizeof(ULONG
))
292 Status
= STATUS_INFO_LENGTH_MISMATCH
;
296 /* OK, we know what you want... */
297 IntegerString
.Buffer
= (PWSTR
)KeyValueInformation
->Data
;
298 IntegerString
.Length
= KeyValueInformation
->DataLength
-
300 IntegerString
.MaximumLength
= KeyValueInformation
->DataLength
;
301 Status
= RtlUnicodeStringToInteger(&IntegerString
, 0, (PULONG
)Buffer
);
307 if (KeyValueInformation
->DataLength
> BufferSize
)
310 Status
= STATUS_BUFFER_OVERFLOW
;
315 BufferSize
= KeyValueInformation
->DataLength
;
318 /* Copy the string */
319 RtlMoveMemory(Buffer
, &KeyValueInformation
->Data
, BufferSize
);
322 /* Copy the result length */
323 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
327 /* Check if buffer was in heap */
328 if (FreeHeap
) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation
);
330 /* Close key and return */
340 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey
,
345 OUT PULONG ReturnedLength OPTIONAL
,
351 /* Open a handle to the key */
352 Status
= LdrOpenImageFileOptionsKey(SubKey
, Wow64
, &KeyHandle
);
354 /* Check for success */
355 if (NT_SUCCESS(Status
))
358 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
369 /* Return to caller */
378 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey
,
383 OUT PULONG ReturnedLength OPTIONAL
)
385 /* Call the newer function */
386 return LdrQueryImageFileExecutionOptionsEx(SubKey
,
397 LdrpEnsureLoaderLockIsHeld()
404 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress
, ULONG SizeOfImage
)
406 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir
;
410 /* Check NT header first */
411 if (!RtlImageNtHeader(BaseAddress
)) return NULL
;
413 /* Get the pointer to the config directory */
414 ConfigDir
= RtlImageDirectoryEntryToData(BaseAddress
,
416 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
419 /* Check for sanity */
421 (DirSize
!= 64 && ConfigDir
->Size
!= DirSize
) ||
422 (ConfigDir
->Size
< 0x48))
425 /* Now get the cookie */
426 Cookie
= (PVOID
)ConfigDir
->SecurityCookie
;
428 /* Check this cookie */
429 if ((PCHAR
)Cookie
<= (PCHAR
)BaseAddress
||
430 (PCHAR
)Cookie
>= (PCHAR
)BaseAddress
+ SizeOfImage
)
435 /* Return validated security cookie */
441 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry
)
444 LARGE_INTEGER Counter
;
447 /* Fetch address of the cookie */
448 Cookie
= LdrpFetchAddressOfSecurityCookie(LdrEntry
->DllBase
, LdrEntry
->SizeOfImage
);
452 /* Check if it's a default one */
453 if (*Cookie
== DEFAULT_SECURITY_COOKIE
||
456 /* We need to initialize it */
458 NtQueryPerformanceCounter(&Counter
, NULL
);
460 GetSystemTimeAsFileTime (&systime
.ft_struct
);
462 cookie
= systime
.ft_scalar
;
464 cookie
= systime
.ft_struct
.dwLowDateTime
;
465 cookie
^= systime
.ft_struct
.dwHighDateTime
;
468 cookie
^= GetCurrentProcessId ();
469 cookie
^= GetCurrentThreadId ();
470 cookie
^= GetTickCount ();
472 QueryPerformanceCounter (&perfctr
);
474 cookie
^= perfctr
.QuadPart
;
476 cookie
^= perfctr
.LowPart
;
477 cookie
^= perfctr
.HighPart
;
481 cookie
&= 0x0000ffffffffffffll
;
484 *Cookie
= Counter
.LowPart
;
495 LdrpInitializeThread(IN PCONTEXT Context
)
497 PPEB Peb
= NtCurrentPeb();
498 PLDR_DATA_TABLE_ENTRY LdrEntry
;
499 PLIST_ENTRY NextEntry
, ListHead
;
500 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
504 DPRINT("LdrpInitializeThread() called for %wZ\n",
505 &LdrpImageEntry
->BaseDllName
);
507 /* Allocate an Activation Context Stack */
508 /* FIXME: This is a hack for Wine's actctx stuff */
509 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
510 if (!(NtCurrentTeb()->ActivationContextStackPointer
))
512 Status
= RtlAllocateActivationContextStack((PVOID
*)&NtCurrentTeb()->ActivationContextStackPointer
);
513 if (NT_SUCCESS(Status
))
515 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
516 DPRINT("ActiveFrame %p\n", ((PACTIVATION_CONTEXT_STACK
)NtCurrentTeb()->ActivationContextStackPointer
)->ActiveFrame
);
517 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= NULL
;
520 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
523 /* Make sure we are not shutting down */
524 if (LdrpShutdownInProgress
) return;
529 /* Start at the beginning */
530 ListHead
= &Peb
->Ldr
->InMemoryOrderModuleList
;
531 NextEntry
= ListHead
->Flink
;
532 while (NextEntry
!= ListHead
)
534 /* Get the current entry */
535 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
537 /* Make sure it's not ourselves */
538 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
540 /* Check if we should call */
541 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
))
543 /* Get the entrypoint */
544 EntryPoint
= LdrEntry
->EntryPoint
;
546 /* Check if we are ready to call it */
548 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
549 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
551 /* Set up the Act Ctx */
552 ActCtx
.Size
= sizeof(ActCtx
);
554 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
556 /* Activate the ActCtx */
557 RtlActivateActivationContextUnsafeFast(&ActCtx
,
558 LdrEntry
->EntryPointActivationContext
);
560 /* Check if it has TLS */
561 if (LdrEntry
->TlsIndex
)
563 /* Make sure we're not shutting down */
564 if (!LdrpShutdownInProgress
)
567 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_ATTACH
);
571 /* Make sure we're not shutting down */
572 if (!LdrpShutdownInProgress
)
574 /* Call the Entrypoint */
575 DPRINT("%wZ - Calling entry point at %x for thread attaching\n",
576 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
577 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
583 /* Deactivate the ActCtx */
584 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
590 NextEntry
= NextEntry
->Flink
;
594 if (LdrpImageHasTls
&& !LdrpShutdownInProgress
)
596 /* Set up the Act Ctx */
597 ActCtx
.Size
= sizeof(ActCtx
);
599 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
601 /* Activate the ActCtx */
602 RtlActivateActivationContextUnsafeFast(&ActCtx
,
603 LdrpImageEntry
->EntryPointActivationContext
);
605 /* Do TLS callbacks */
606 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_ATTACH
);
608 /* Deactivate the ActCtx */
609 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
612 DPRINT("LdrpInitializeThread() done\n");
617 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL
)
619 PLDR_DATA_TABLE_ENTRY LocalArray
[16];
620 PLIST_ENTRY ListHead
;
621 PLIST_ENTRY NextEntry
;
622 PLDR_DATA_TABLE_ENTRY LdrEntry
, *LdrRootEntry
, OldInitializer
;
626 NTSTATUS Status
= STATUS_SUCCESS
;
627 PPEB Peb
= NtCurrentPeb();
628 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
629 ULONG BreakOnDllLoad
;
633 DPRINT("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
635 /* Check the Loader Lock */
636 LdrpEnsureLoaderLockIsHeld();
638 /* Get the number of entries to call */
639 if ((Count
= LdrpClearLoadInProgress()))
641 /* Check if we can use our local buffer */
644 /* Allocate space for all the entries */
645 LdrRootEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
647 Count
* sizeof(LdrRootEntry
));
648 if (!LdrRootEntry
) return STATUS_NO_MEMORY
;
652 /* Use our local array */
653 LdrRootEntry
= LocalArray
;
662 /* Show debug message */
665 DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n",
666 NtCurrentTeb()->RealClientId
.UniqueThread
,
667 NtCurrentTeb()->RealClientId
.UniqueProcess
,
668 &Peb
->ProcessParameters
->ImagePathName
);
672 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
673 NextEntry
= ListHead
->Flink
;
675 while (NextEntry
!= ListHead
)
677 /* Get the Data Entry */
678 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
680 /* Check if we have a Root Entry */
684 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
686 /* Setup the Cookie for the DLL */
687 LdrpInitSecurityCookie(LdrEntry
);
689 /* Check for valid entrypoint */
690 if (LdrEntry
->EntryPoint
)
693 LdrRootEntry
[i
] = LdrEntry
;
695 /* Display debug message */
698 DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
699 NtCurrentTeb()->RealClientId
.UniqueThread
,
700 NtCurrentTeb()->RealClientId
.UniqueProcess
,
701 &LdrEntry
->FullDllName
,
702 LdrEntry
->EntryPoint
);
710 LdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
711 NextEntry
= NextEntry
->Flink
;
714 /* If we got a context, then we have to call Kernel32 for TS support */
717 /* Check if we have one */
718 //if (Kernel32ProcessInitPostImportfunction)
721 //Kernel32ProcessInitPostImportfunction();
725 //Kernel32ProcessInitPostImportfunction = NULL;
729 /* No root entry? return */
730 if (!LdrRootEntry
) return STATUS_SUCCESS
;
732 /* Set the TLD TEB */
733 OldTldTeb
= LdrpTopLevelDllBeingLoadedTeb
;
734 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
741 LdrEntry
= LdrRootEntry
[i
];
743 /* FIXME: Verify NX Compat */
745 /* Move to next entry */
748 /* Get its entrypoint */
749 EntryPoint
= LdrEntry
->EntryPoint
;
751 /* Are we being debugged? */
753 if (Peb
->BeingDebugged
|| Peb
->ReadImageFileExecOptions
)
755 /* Check if we should break on load */
756 Status
= LdrQueryImageFileExecutionOptions(&LdrEntry
->BaseDllName
,
762 if (!NT_SUCCESS(Status
)) BreakOnDllLoad
= 0;
764 /* Reset status back to STATUS_SUCCESS */
765 Status
= STATUS_SUCCESS
;
771 /* Check if we should show a message */
774 DPRINT1("LDR: %wZ loaded.", &LdrEntry
->BaseDllName
);
775 DPRINT1(" - About to call init routine at %p\n", EntryPoint
);
778 /* Break in debugger */
782 /* Make sure we have an entrypoint */
785 /* Save the old Dll Initializer and write the current one */
786 OldInitializer
= LdrpCurrentDllInitializer
;
787 LdrpCurrentDllInitializer
= LdrEntry
;
789 /* Set up the Act Ctx */
790 ActCtx
.Size
= sizeof(ActCtx
);
792 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
794 /* Activate the ActCtx */
795 RtlActivateActivationContextUnsafeFast(&ActCtx
,
796 LdrEntry
->EntryPointActivationContext
);
798 /* Check if it has TLS */
799 if (LdrEntry
->TlsIndex
&& Context
)
802 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_ATTACH
);
805 /* Call the Entrypoint */
808 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
809 &LdrEntry
->BaseDllName
, EntryPoint
);
811 DllStatus
= LdrpCallInitRoutine(EntryPoint
,
816 /* Deactivate the ActCtx */
817 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
819 /* Save the Current DLL Initializer */
820 LdrpCurrentDllInitializer
= OldInitializer
;
822 /* Mark the entry as processed */
823 LdrEntry
->Flags
|= LDRP_PROCESS_ATTACH_CALLED
;
825 /* Fail if DLL init failed */
828 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
829 &LdrEntry
->BaseDllName
, EntryPoint
);
831 Status
= STATUS_DLL_INIT_FAILED
;
838 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
839 NextEntry
= NextEntry
->Flink
;
840 while (NextEntry
!= ListHead
)
842 /* Get the Data Entrry */
843 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
845 /* FIXME: Verify NX Compat */
846 // LdrpCheckNXCompatibility()
849 NextEntry
= NextEntry
->Flink
;
853 if (LdrpImageHasTls
&& Context
)
855 /* Set up the Act Ctx */
856 ActCtx
.Size
= sizeof(ActCtx
);
858 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
860 /* Activate the ActCtx */
861 RtlActivateActivationContextUnsafeFast(&ActCtx
,
862 LdrpImageEntry
->EntryPointActivationContext
);
864 /* Do TLS callbacks */
865 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_ATTACH
);
867 /* Deactivate the ActCtx */
868 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
872 /* Restore old TEB */
873 LdrpTopLevelDllBeingLoadedTeb
= OldTldTeb
;
875 /* Check if the array is in the heap */
876 if (LdrRootEntry
!= LocalArray
)
879 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry
);
882 /* Return to caller */
883 DPRINT("LdrpRunInitializeRoutines() done\n");
892 LdrShutdownProcess(VOID
)
894 PPEB Peb
= NtCurrentPeb();
895 PLDR_DATA_TABLE_ENTRY LdrEntry
;
896 PLIST_ENTRY NextEntry
, ListHead
;
897 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
900 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
901 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
903 /* Tell the Shim Engine */
915 /* Set the shutdown variables */
916 LdrpShutdownThreadId
= NtCurrentTeb()->RealClientId
.UniqueThread
;
917 LdrpShutdownInProgress
= TRUE
;
919 /* Enter the Loader Lock */
920 RtlEnterCriticalSection(&LdrpLoaderLock
);
922 /* Cleanup trace logging data (Etw) */
923 if (SharedUserData
->TraceLogging
)
926 DPRINT1("We don't support Etw yet.\n");
929 /* Start at the end */
930 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
931 NextEntry
= ListHead
->Blink
;
932 while (NextEntry
!= ListHead
)
934 /* Get the current entry */
935 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
936 NextEntry
= NextEntry
->Blink
;
938 /* Make sure it's not ourselves */
939 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
941 /* Get the entrypoint */
942 EntryPoint
= LdrEntry
->EntryPoint
;
944 /* Check if we are ready to call it */
946 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
949 /* Set up the Act Ctx */
950 ActCtx
.Size
= sizeof(ActCtx
);
952 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
954 /* Activate the ActCtx */
955 RtlActivateActivationContextUnsafeFast(&ActCtx
,
956 LdrEntry
->EntryPointActivationContext
);
958 /* Check if it has TLS */
959 if (LdrEntry
->TlsIndex
)
962 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_DETACH
);
965 /* Call the Entrypoint */
966 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
967 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
968 LdrpCallInitRoutine(EntryPoint
,
973 /* Deactivate the ActCtx */
974 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
982 /* Set up the Act Ctx */
983 ActCtx
.Size
= sizeof(ActCtx
);
985 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
987 /* Activate the ActCtx */
988 RtlActivateActivationContextUnsafeFast(&ActCtx
,
989 LdrpImageEntry
->EntryPointActivationContext
);
991 /* Do TLS callbacks */
992 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_DETACH
);
994 /* Deactivate the ActCtx */
995 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
998 /* FIXME: Do Heap detection and Etw final shutdown */
1000 /* Release the lock */
1001 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1002 DPRINT("LdrpShutdownProcess() done\n");
1004 return STATUS_SUCCESS
;
1012 LdrShutdownThread(VOID
)
1014 PPEB Peb
= NtCurrentPeb();
1015 PTEB Teb
= NtCurrentTeb();
1016 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1017 PLIST_ENTRY NextEntry
, ListHead
;
1018 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1021 DPRINT("LdrShutdownThread() called for %wZ\n",
1022 &LdrpImageEntry
->BaseDllName
);
1024 /* Cleanup trace logging data (Etw) */
1025 if (SharedUserData
->TraceLogging
)
1028 DPRINT1("We don't support Etw yet.\n");
1031 /* Get the Ldr Lock */
1032 RtlEnterCriticalSection(&LdrpLoaderLock
);
1034 /* Start at the end */
1035 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
1036 NextEntry
= ListHead
->Blink
;
1037 while (NextEntry
!= ListHead
)
1039 /* Get the current entry */
1040 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
1041 NextEntry
= NextEntry
->Blink
;
1043 /* Make sure it's not ourselves */
1044 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
1046 /* Check if we should call */
1047 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
) &&
1048 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
1049 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1051 /* Get the entrypoint */
1052 EntryPoint
= LdrEntry
->EntryPoint
;
1054 /* Check if we are ready to call it */
1057 /* Set up the Act Ctx */
1058 ActCtx
.Size
= sizeof(ActCtx
);
1060 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1062 /* Activate the ActCtx */
1063 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1064 LdrEntry
->EntryPointActivationContext
);
1066 /* Check if it has TLS */
1067 if (LdrEntry
->TlsIndex
)
1069 /* Make sure we're not shutting down */
1070 if (!LdrpShutdownInProgress
)
1073 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_DETACH
);
1077 /* Make sure we're not shutting down */
1078 if (!LdrpShutdownInProgress
)
1080 /* Call the Entrypoint */
1081 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
1082 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
1083 LdrpCallInitRoutine(EntryPoint
,
1089 /* Deactivate the ActCtx */
1090 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1097 if (LdrpImageHasTls
)
1099 /* Set up the Act Ctx */
1100 ActCtx
.Size
= sizeof(ActCtx
);
1102 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1104 /* Activate the ActCtx */
1105 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1106 LdrpImageEntry
->EntryPointActivationContext
);
1108 /* Do TLS callbacks */
1109 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_DETACH
);
1111 /* Deactivate the ActCtx */
1112 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1117 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1119 /* Check for expansion slots */
1120 if (Teb
->TlsExpansionSlots
)
1122 /* Free expansion slots */
1123 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->TlsExpansionSlots
);
1126 /* Check for FLS Data */
1130 DPRINT1("We don't support FLS Data yet\n");
1133 /* Check for Fiber data */
1134 if (Teb
->HasFiberData
)
1136 /* Free Fiber data*/
1137 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->NtTib
.FiberData
);
1138 Teb
->NtTib
.FiberData
= NULL
;
1141 /* Free the activation context stack */
1142 RtlFreeThreadActivationContextStack();
1143 DPRINT("LdrShutdownThread() done\n");
1145 return STATUS_SUCCESS
;
1150 LdrpInitializeTls(VOID
)
1152 PLIST_ENTRY NextEntry
, ListHead
;
1153 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1154 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1155 PLDRP_TLS_DATA TlsData
;
1158 /* Initialize the TLS List */
1159 InitializeListHead(&LdrpTlsList
);
1161 /* Loop all the modules */
1162 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1163 NextEntry
= ListHead
->Flink
;
1164 while (ListHead
!= NextEntry
)
1167 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1168 NextEntry
= NextEntry
->Flink
;
1170 /* Get the TLS directory */
1171 TlsDirectory
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1173 IMAGE_DIRECTORY_ENTRY_TLS
,
1176 /* Check if we have a directory */
1177 if (!TlsDirectory
) continue;
1179 /* Check if the image has TLS */
1180 if (!LdrpImageHasTls
) LdrpImageHasTls
= TRUE
;
1182 /* Show debug message */
1185 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1186 &LdrEntry
->BaseDllName
,
1190 /* Allocate an entry */
1191 TlsData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA
));
1192 if (!TlsData
) return STATUS_NO_MEMORY
;
1194 /* Lock the DLL and mark it for TLS Usage */
1195 LdrEntry
->LoadCount
= -1;
1196 LdrEntry
->TlsIndex
= -1;
1198 /* Save the cached TLS data */
1199 TlsData
->TlsDirectory
= *TlsDirectory
;
1200 InsertTailList(&LdrpTlsList
, &TlsData
->TlsLinks
);
1202 /* Update the index */
1203 *(PLONG
)TlsData
->TlsDirectory
.AddressOfIndex
= LdrpNumberOfTlsEntries
;
1204 TlsData
->TlsDirectory
.Characteristics
= LdrpNumberOfTlsEntries
++;
1207 /* Done setting up TLS, allocate entries */
1208 return LdrpAllocateTls();
1213 LdrpAllocateTls(VOID
)
1215 PTEB Teb
= NtCurrentTeb();
1216 PLIST_ENTRY NextEntry
, ListHead
;
1217 PLDRP_TLS_DATA TlsData
;
1221 /* Check if we have any entries */
1222 if (!LdrpNumberOfTlsEntries
)
1223 return STATUS_SUCCESS
;
1225 /* Allocate the vector array */
1226 TlsVector
= RtlAllocateHeap(RtlGetProcessHeap(),
1228 LdrpNumberOfTlsEntries
* sizeof(PVOID
));
1229 if (!TlsVector
) return STATUS_NO_MEMORY
;
1230 Teb
->ThreadLocalStoragePointer
= TlsVector
;
1232 /* Loop the TLS Array */
1233 ListHead
= &LdrpTlsList
;
1234 NextEntry
= ListHead
->Flink
;
1235 while (NextEntry
!= ListHead
)
1238 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1239 NextEntry
= NextEntry
->Flink
;
1241 /* Allocate this vector */
1242 TlsDataSize
= TlsData
->TlsDirectory
.EndAddressOfRawData
-
1243 TlsData
->TlsDirectory
.StartAddressOfRawData
;
1244 TlsVector
[TlsData
->TlsDirectory
.Characteristics
] = RtlAllocateHeap(RtlGetProcessHeap(),
1247 if (!TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1250 return STATUS_NO_MEMORY
;
1253 /* Show debug message */
1256 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
1258 TlsData
->TlsDirectory
.Characteristics
,
1259 &TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1260 TlsData
->TlsDirectory
.StartAddressOfRawData
,
1261 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1265 RtlCopyMemory(TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1266 (PVOID
)TlsData
->TlsDirectory
.StartAddressOfRawData
,
1271 return STATUS_SUCCESS
;
1278 PLIST_ENTRY ListHead
, NextEntry
;
1279 PLDRP_TLS_DATA TlsData
;
1281 PTEB Teb
= NtCurrentTeb();
1283 /* Get a pointer to the vector array */
1284 TlsVector
= Teb
->ThreadLocalStoragePointer
;
1285 if (!TlsVector
) return;
1287 /* Loop through it */
1288 ListHead
= &LdrpTlsList
;
1289 NextEntry
= ListHead
->Flink
;
1290 while (NextEntry
!= ListHead
)
1292 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1293 NextEntry
= NextEntry
->Flink
;
1295 /* Free each entry */
1296 if (TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1298 RtlFreeHeap(RtlGetProcessHeap(),
1300 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1304 /* Free the array itself */
1305 RtlFreeHeap(RtlGetProcessHeap(),
1312 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName
, PPEB Peb
, PHKEY OptionsKey
)
1316 ULONG ExecuteOptions
, MinimumStackCommit
= 0, GlobalFlag
;
1318 /* Return error if we were not provided a pointer where to save the options key handle */
1319 if (!OptionsKey
) return STATUS_INVALID_HANDLE
;
1321 /* Zero initialize the optinos key pointer */
1324 /* Open the options key */
1325 Status
= LdrOpenImageFileOptionsKey(ImagePathName
, 0, &KeyHandle
);
1327 /* Save it if it was opened successfully */
1328 if (NT_SUCCESS(Status
))
1329 *OptionsKey
= KeyHandle
;
1333 /* There are image specific options, read them starting with NXCOMPAT */
1334 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1338 sizeof(ExecuteOptions
),
1341 if (NT_SUCCESS(Status
))
1343 /* TODO: Set execution options for the process */
1345 if (ExecuteOptions == 0)
1349 ZwSetInformationProcess(NtCurrentProcess(),
1350 ProcessExecuteFlags,
1356 /* Check if this image uses large pages */
1357 if (Peb
->ImageUsesLargePages
)
1359 /* TODO: If it does, open large page key */
1363 /* Get various option values */
1364 LdrQueryImageFileKeyOption(KeyHandle
,
1365 L
"DisableHeapLookaside",
1367 &RtlpDisableHeapLookaside
,
1368 sizeof(RtlpDisableHeapLookaside
),
1371 LdrQueryImageFileKeyOption(KeyHandle
,
1374 &RtlpShutdownProcessFlags
,
1375 sizeof(RtlpShutdownProcessFlags
),
1378 LdrQueryImageFileKeyOption(KeyHandle
,
1379 L
"MinimumStackCommitInBytes",
1381 &MinimumStackCommit
,
1382 sizeof(MinimumStackCommit
),
1385 /* Update PEB's minimum stack commit if it's lower */
1386 if (Peb
->MinimumStackCommit
< MinimumStackCommit
)
1387 Peb
->MinimumStackCommit
= MinimumStackCommit
;
1389 /* Set the global flag */
1390 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1397 if (NT_SUCCESS(Status
))
1398 Peb
->NtGlobalFlag
= GlobalFlag
;
1404 /* There are no image-specific options, so perform global initialization */
1405 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1407 // TODO: Initialize app verifier package
1408 // Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, 1, FALSE);
1412 return STATUS_SUCCESS
;
1417 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
)
1424 LdrpInitializeProcess(IN PCONTEXT Context
,
1425 IN PVOID SystemArgument1
)
1427 RTL_HEAP_PARAMETERS HeapParameters
;
1428 ULONG ComSectionSize
;
1429 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1431 OBJECT_ATTRIBUTES ObjectAttributes
;
1432 //UNICODE_STRING LocalFileName, FullImageName;
1433 HANDLE SymLinkHandle
;
1434 //ULONG DebugHeapOnly;
1435 UNICODE_STRING CommandLine
, NtSystemRoot
, ImagePathName
, FullPath
, ImageFileName
, KnownDllString
;
1436 PPEB Peb
= NtCurrentPeb();
1437 BOOLEAN IsDotNetImage
= FALSE
;
1438 BOOLEAN FreeCurDir
= FALSE
;
1440 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
1441 //LPWSTR ImagePathBuffer;
1443 UNICODE_STRING CurrentDirectory
;
1446 PIMAGE_NT_HEADERS NtHeader
;
1447 LPWSTR NtDllName
= NULL
;
1449 NLSTABLEINFO NlsTable
;
1450 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig
;
1451 PTEB Teb
= NtCurrentTeb();
1452 PLIST_ENTRY ListHead
;
1453 PLIST_ENTRY NextEntry
;
1456 ULONG DebugProcessHeapOnly
= 0;
1457 PLDR_DATA_TABLE_ENTRY NtLdrEntry
;
1459 ULONG ExecuteOptions
= 0;
1462 /* Set a NULL SEH Filter */
1463 RtlSetUnhandledExceptionFilter(NULL
);
1465 /* Get the image path */
1466 ImagePath
= Peb
->ProcessParameters
->ImagePathName
.Buffer
;
1468 /* Check if it's normalized */
1469 if (Peb
->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_NORMALIZED
)
1472 ImagePath
= (PWSTR
)((ULONG_PTR
)ImagePath
+ (ULONG_PTR
)Peb
->ProcessParameters
);
1475 /* Create a unicode string for the Image Path */
1476 ImagePathName
.Length
= Peb
->ProcessParameters
->ImagePathName
.Length
;
1477 ImagePathName
.MaximumLength
= ImagePathName
.Length
+ sizeof(WCHAR
);
1478 ImagePathName
.Buffer
= ImagePath
;
1480 /* Get the NT Headers */
1481 NtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1483 /* Get the execution options */
1484 Status
= LdrpInitializeExecutionOptions(&ImagePathName
, Peb
, &OptionsKey
);
1486 /* Check if this is a .NET executable */
1487 if (RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1489 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1492 /* Remeber this for later */
1493 IsDotNetImage
= TRUE
;
1496 /* Save the NTDLL Base address */
1497 NtDllBase
= SystemArgument1
;
1499 /* If this is a Native Image */
1500 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
)
1502 /* Then do DLL Validation */
1503 LdrpDllValidation
= TRUE
;
1506 /* Save the old Shim Data */
1507 OldShimData
= Peb
->pShimData
;
1510 Peb
->pShimData
= NULL
;
1512 /* Save the number of processors and CS Timeout */
1513 LdrpNumberOfProcessors
= Peb
->NumberOfProcessors
;
1514 RtlpTimeout
= Peb
->CriticalSectionTimeout
;
1516 /* Normalize the parameters */
1517 ProcessParameters
= RtlNormalizeProcessParams(Peb
->ProcessParameters
);
1518 ProcessParameters
= Peb
->ProcessParameters
;
1519 if (ProcessParameters
)
1521 /* Save the Image and Command Line Names */
1522 ImageFileName
= ProcessParameters
->ImagePathName
;
1523 CommandLine
= ProcessParameters
->CommandLine
;
1527 /* It failed, initialize empty strings */
1528 RtlInitUnicodeString(&ImageFileName
, NULL
);
1529 RtlInitUnicodeString(&CommandLine
, NULL
);
1532 /* Initialize NLS data */
1533 RtlInitNlsTables(Peb
->AnsiCodePageData
,
1534 Peb
->OemCodePageData
,
1535 Peb
->UnicodeCaseTableData
,
1538 /* Reset NLS Translations */
1539 RtlResetRtlTranslations(&NlsTable
);
1541 /* Get the Image Config Directory */
1542 LoadConfig
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1544 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
1547 /* Setup the Heap Parameters */
1548 RtlZeroMemory(&HeapParameters
, sizeof(RTL_HEAP_PARAMETERS
));
1549 HeapFlags
= HEAP_GROWABLE
;
1550 HeapParameters
.Length
= sizeof(RTL_HEAP_PARAMETERS
);
1552 /* Check if we have Configuration Data */
1553 if ((LoadConfig
) && (ConfigSize
== sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
)))
1555 /* FIXME: Custom heap settings and misc. */
1556 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1559 /* Check for custom affinity mask */
1560 if (Peb
->ImageProcessAffinityMask
)
1563 Status
= NtSetInformationProcess(NtCurrentProcess(),
1564 ProcessAffinityMask
,
1565 &Peb
->ImageProcessAffinityMask
,
1566 sizeof(Peb
->ImageProcessAffinityMask
));
1569 /* Check if verbose debugging (ShowSnaps) was requested */
1570 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
1572 /* Start verbose debugging messages right now if they were requested */
1575 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1576 Teb
->ClientId
.UniqueProcess
,
1580 /* If the timeout is too long */
1581 if (RtlpTimeout
.QuadPart
< Int32x32To64(3600, -10000000))
1583 /* Then disable CS Timeout */
1584 RtlpTimeoutDisable
= TRUE
;
1587 /* Initialize Critical Section Data */
1588 RtlpInitDeferedCriticalSection();
1590 /* Initialize VEH Call lists */
1591 RtlpInitializeVectoredExceptionHandling();
1593 /* Set TLS/FLS Bitmap data */
1594 Peb
->FlsBitmap
= &FlsBitMap
;
1595 Peb
->TlsBitmap
= &TlsBitMap
;
1596 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
1598 /* Initialize FLS Bitmap */
1599 RtlInitializeBitMap(&FlsBitMap
,
1601 FLS_MAXIMUM_AVAILABLE
);
1602 RtlSetBit(&FlsBitMap
, 0);
1604 /* Initialize TLS Bitmap */
1605 RtlInitializeBitMap(&TlsBitMap
,
1607 TLS_MINIMUM_AVAILABLE
);
1608 RtlSetBit(&TlsBitMap
, 0);
1609 RtlInitializeBitMap(&TlsExpansionBitMap
,
1610 Peb
->TlsExpansionBitmapBits
,
1611 TLS_EXPANSION_SLOTS
);
1612 RtlSetBit(&TlsExpansionBitMap
, 0);
1614 /* Initialize the Hash Table */
1615 for (i
= 0; i
< LDR_HASH_TABLE_ENTRIES
; i
++)
1617 InitializeListHead(&LdrpHashTable
[i
]);
1620 /* Initialize the Loader Lock */
1621 // FIXME: What's the point of initing it manually, if two lines lower
1622 // a call to RtlInitializeCriticalSection() is being made anyway?
1623 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1624 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1625 RtlInitializeCriticalSection(&LdrpLoaderLock
);
1626 LdrpLoaderLockInit
= TRUE
;
1628 /* Check if User Stack Trace Database support was requested */
1629 if (Peb
->NtGlobalFlag
& FLG_USER_STACK_TRACE_DB
)
1631 DPRINT1("We don't support user stack trace databases yet\n");
1634 /* Setup Fast PEB Lock */
1635 RtlInitializeCriticalSection(&FastPebLock
);
1636 Peb
->FastPebLock
= &FastPebLock
;
1637 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1638 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1640 /* Setup Callout Lock and Notification list */
1641 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1642 InitializeListHead(&LdrpDllNotificationList
);
1644 /* For old executables, use 16-byte aligned heap */
1645 if ((NtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3) &&
1646 (NtHeader
->OptionalHeader
.MinorSubsystemVersion
< 51))
1648 HeapFlags
|= HEAP_CREATE_ALIGN_16
;
1651 /* Setup the Heap */
1652 RtlInitializeHeapManager();
1653 Peb
->ProcessHeap
= RtlCreateHeap(HeapFlags
,
1655 NtHeader
->OptionalHeader
.SizeOfHeapReserve
,
1656 NtHeader
->OptionalHeader
.SizeOfHeapCommit
,
1660 if (!Peb
->ProcessHeap
)
1662 DPRINT1("Failed to create process heap\n");
1663 return STATUS_NO_MEMORY
;
1666 // FIXME: Is it located properly?
1667 /* Initialize table of callbacks for the kernel. */
1668 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
1671 (USER32_CALLBACK_MAXIMUM
+ 1));
1672 if (!Peb
->KernelCallbackTable
)
1674 DPRINT1("Failed to create callback table\n");
1675 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
1678 /* Allocate an Activation Context Stack */
1679 Status
= RtlAllocateActivationContextStack((PVOID
*)&Teb
->ActivationContextStackPointer
);
1680 if (!NT_SUCCESS(Status
)) return Status
;
1682 // FIXME: Loader private heap is missing
1683 //DPRINT1("Loader private heap is missing\n");
1685 /* Check for Debug Heap */
1688 /* Query the setting */
1689 Status
= LdrQueryImageFileKeyOption(OptionsKey
,
1690 L
"DebugProcessHeapOnly",
1692 &DebugProcessHeapOnly
,
1696 if (NT_SUCCESS(Status
))
1698 /* Reset DPH if requested */
1699 if (RtlpPageHeapEnabled
&& DebugProcessHeapOnly
)
1701 RtlpDphGlobalFlags
&= ~0x40;
1702 RtlpPageHeapEnabled
= FALSE
;
1707 /* Build the NTDLL Path */
1708 FullPath
.Buffer
= StringBuffer
;
1709 FullPath
.Length
= 0;
1710 FullPath
.MaximumLength
= sizeof(StringBuffer
);
1711 RtlInitUnicodeString(&NtSystemRoot
, SharedUserData
->NtSystemRoot
);
1712 RtlAppendUnicodeStringToString(&FullPath
, &NtSystemRoot
);
1713 RtlAppendUnicodeToString(&FullPath
, L
"\\System32\\");
1715 /* Open the Known DLLs directory */
1716 RtlInitUnicodeString(&KnownDllString
, L
"\\KnownDlls");
1717 InitializeObjectAttributes(&ObjectAttributes
,
1719 OBJ_CASE_INSENSITIVE
,
1722 Status
= ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory
,
1723 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1726 /* Check if it exists */
1727 if (NT_SUCCESS(Status
))
1729 /* Open the Known DLLs Path */
1730 RtlInitUnicodeString(&KnownDllString
, L
"KnownDllPath");
1731 InitializeObjectAttributes(&ObjectAttributes
,
1733 OBJ_CASE_INSENSITIVE
,
1734 LdrpKnownDllObjectDirectory
,
1736 Status
= NtOpenSymbolicLinkObject(&SymLinkHandle
,
1737 SYMBOLIC_LINK_QUERY
,
1739 if (NT_SUCCESS(Status
))
1741 /* Query the path */
1742 LdrpKnownDllPath
.Length
= 0;
1743 LdrpKnownDllPath
.MaximumLength
= sizeof(LdrpKnownDllPathBuffer
);
1744 LdrpKnownDllPath
.Buffer
= LdrpKnownDllPathBuffer
;
1745 Status
= ZwQuerySymbolicLinkObject(SymLinkHandle
, &LdrpKnownDllPath
, NULL
);
1746 NtClose(SymLinkHandle
);
1747 if (!NT_SUCCESS(Status
))
1749 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status
);
1755 /* Check if we failed */
1756 if (!NT_SUCCESS(Status
))
1758 /* Aassume System32 */
1759 LdrpKnownDllObjectDirectory
= NULL
;
1760 RtlInitUnicodeString(&LdrpKnownDllPath
, StringBuffer
);
1761 LdrpKnownDllPath
.Length
-= sizeof(WCHAR
);
1764 /* If we have process parameters, get the default path and current path */
1765 if (ProcessParameters
)
1767 /* Check if we have a Dll Path */
1768 if (ProcessParameters
->DllPath
.Length
)
1771 LdrpDefaultPath
= *(PUNICODE_STRING
)&ProcessParameters
->DllPath
;
1775 /* We need a valid path */
1776 DPRINT1("No valid DllPath was given!\n");
1777 LdrpInitFailure(STATUS_INVALID_PARAMETER
);
1780 /* Set the current directory */
1781 CurrentDirectory
= ProcessParameters
->CurrentDirectory
.DosPath
;
1783 /* Check if it's empty or invalid */
1784 if ((!CurrentDirectory
.Buffer
) ||
1785 (CurrentDirectory
.Buffer
[0] == UNICODE_NULL
) ||
1786 (!CurrentDirectory
.Length
))
1788 /* Allocate space for the buffer */
1789 CurrentDirectory
.Buffer
= RtlAllocateHeap(Peb
->ProcessHeap
,
1792 sizeof(UNICODE_NULL
));
1793 if (!CurrentDirectory
.Buffer
)
1795 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1799 /* Copy the drive of the system root */
1800 RtlMoveMemory(CurrentDirectory
.Buffer
,
1801 SharedUserData
->NtSystemRoot
,
1803 CurrentDirectory
.Buffer
[3] = UNICODE_NULL
;
1804 CurrentDirectory
.Length
= 3 * sizeof(WCHAR
);
1805 CurrentDirectory
.MaximumLength
= CurrentDirectory
.Length
+ sizeof(WCHAR
);
1808 DPRINT("Using dynamically allocd curdir\n");
1812 /* Use the local buffer */
1813 DPRINT("Using local system root\n");
1817 /* Setup Loader Data */
1819 InitializeListHead(&PebLdr
.InLoadOrderModuleList
);
1820 InitializeListHead(&PebLdr
.InMemoryOrderModuleList
);
1821 InitializeListHead(&PebLdr
.InInitializationOrderModuleList
);
1822 PebLdr
.Length
= sizeof(PEB_LDR_DATA
);
1823 PebLdr
.Initialized
= TRUE
;
1825 /* Allocate a data entry for the Image */
1826 LdrpImageEntry
= NtLdrEntry
= LdrpAllocateDataTableEntry(Peb
->ImageBaseAddress
);
1829 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1830 NtLdrEntry
->LoadCount
= -1;
1831 NtLdrEntry
->EntryPointActivationContext
= 0;
1832 NtLdrEntry
->FullDllName
= ImageFileName
;
1835 NtLdrEntry
->Flags
= LDRP_COR_IMAGE
;
1837 NtLdrEntry
->Flags
= 0;
1839 /* Check if the name is empty */
1840 if (!ImageFileName
.Buffer
[0])
1842 /* Use the same Base name */
1843 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1847 /* Find the last slash */
1848 Current
= ImageFileName
.Buffer
;
1851 if (*Current
++ == '\\')
1854 NtDllName
= Current
;
1858 /* Did we find anything? */
1861 /* Use the same Base name */
1862 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1866 /* Setup the name */
1867 NtLdrEntry
->BaseDllName
.Length
= (USHORT
)((ULONG_PTR
)ImageFileName
.Buffer
+ ImageFileName
.Length
- (ULONG_PTR
)NtDllName
);
1868 NtLdrEntry
->BaseDllName
.MaximumLength
= NtLdrEntry
->BaseDllName
.Length
+ sizeof(WCHAR
);
1869 NtLdrEntry
->BaseDllName
.Buffer
= (PWSTR
)((ULONG_PTR
)ImageFileName
.Buffer
+
1870 (ImageFileName
.Length
- NtLdrEntry
->BaseDllName
.Length
));
1874 /* Processing done, insert it */
1875 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1876 NtLdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
1878 /* Now add an entry for NTDLL */
1879 NtLdrEntry
= LdrpAllocateDataTableEntry(SystemArgument1
);
1880 NtLdrEntry
->Flags
= LDRP_IMAGE_DLL
;
1881 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1882 NtLdrEntry
->LoadCount
= -1;
1883 NtLdrEntry
->EntryPointActivationContext
= 0;
1885 NtLdrEntry
->FullDllName
.Length
= FullPath
.Length
;
1886 NtLdrEntry
->FullDllName
.MaximumLength
= FullPath
.MaximumLength
;
1887 NtLdrEntry
->FullDllName
.Buffer
= StringBuffer
;
1888 RtlAppendUnicodeStringToString(&NtLdrEntry
->FullDllName
, &NtDllString
);
1890 NtLdrEntry
->BaseDllName
.Length
= NtDllString
.Length
;
1891 NtLdrEntry
->BaseDllName
.MaximumLength
= NtDllString
.MaximumLength
;
1892 NtLdrEntry
->BaseDllName
.Buffer
= NtDllString
.Buffer
;
1894 /* Processing done, insert it */
1895 LdrpNtDllDataTableEntry
= NtLdrEntry
;
1896 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1898 /* Let the world know */
1901 DPRINT1("LDR: NEW PROCESS\n");
1902 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry
->FullDllName
, &LdrpImageEntry
->BaseDllName
);
1903 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory
);
1904 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath
);
1907 /* Link the Init Order List */
1908 InsertHeadList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1909 &LdrpNtDllDataTableEntry
->InInitializationOrderModuleList
);
1911 /* Set the current directory */
1912 Status
= RtlSetCurrentDirectory_U(&CurrentDirectory
);
1913 if (!NT_SUCCESS(Status
))
1915 /* We failed, check if we should free it */
1916 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1918 /* Set it to the NT Root */
1919 CurrentDirectory
= NtSystemRoot
;
1920 RtlSetCurrentDirectory_U(&CurrentDirectory
);
1924 /* We're done with it, free it */
1925 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1928 /* Check if we should look for a .local file */
1929 if (ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
)
1932 DPRINT1("We don't support .local overrides yet\n");
1935 /* Check if the Application Verifier was enabled */
1936 if (Peb
->NtGlobalFlag
& FLG_POOL_ENABLE_TAIL_CHECK
)
1939 DPRINT1("We don't support Application Verifier yet\n");
1945 DPRINT1("We don't support .NET applications yet\n");
1948 /* FIXME: Load support for Terminal Services */
1949 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1951 /* Load kernel32 and call BasePostImportInit... */
1952 DPRINT1("Unimplemented codepath!\n");
1955 /* Walk the IAT and load all the DLLs */
1956 LdrpWalkImportDescriptor(LdrpDefaultPath
.Buffer
, LdrpImageEntry
);
1958 /* Check if relocation is needed */
1959 if (Peb
->ImageBaseAddress
!= (PVOID
)NtHeader
->OptionalHeader
.ImageBase
)
1961 DPRINT1("LDR: Performing EXE relocation\n");
1963 /* Change the protection to prepare for relocation */
1964 ViewBase
= Peb
->ImageBaseAddress
;
1965 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1966 if (!NT_SUCCESS(Status
)) return Status
;
1968 /* Do the relocation */
1969 Status
= LdrRelocateImageWithBias(ViewBase
,
1973 STATUS_CONFLICTING_ADDRESSES
,
1974 STATUS_INVALID_IMAGE_FORMAT
);
1975 if (!NT_SUCCESS(Status
))
1977 DPRINT1("LdrRelocateImageWithBias() failed\n");
1981 /* Check if a start context was provided */
1984 DPRINT1("WARNING: Relocated EXE Context");
1985 UNIMPLEMENTED
; // We should support this
1986 return STATUS_INVALID_IMAGE_FORMAT
;
1989 /* Restore the protection */
1990 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1991 if (!NT_SUCCESS(Status
)) return Status
;
1995 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1996 NextEntry
= ListHead
->Flink
;
1997 while (ListHead
!= NextEntry
)
1999 NtLdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2000 NtLdrEntry
->LoadCount
= -1;
2001 NextEntry
= NextEntry
->Flink
;
2004 /* Phase 0 is done */
2005 LdrpLdrDatabaseIsSetup
= TRUE
;
2007 /* Initialize TLS */
2008 Status
= LdrpInitializeTls();
2009 if (!NT_SUCCESS(Status
))
2011 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2016 /* FIXME Mark the DLL Ranges for Stack Traces later */
2018 /* Notify the debugger now */
2019 if (Peb
->BeingDebugged
)
2024 /* Update show snaps again */
2025 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
2028 /* Validate the Image for MP Usage */
2029 if (LdrpNumberOfProcessors
> 1) LdrpValidateImageForMp(LdrpImageEntry
);
2031 /* Check NX Options */
2032 if (SharedUserData
->NXSupportPolicy
== 1)
2034 ExecuteOptions
= 0xD;
2036 else if (!SharedUserData
->NXSupportPolicy
)
2038 ExecuteOptions
= 0xA;
2042 ZwSetInformationProcess(NtCurrentProcess(),
2043 ProcessExecuteFlags
,
2047 /* Check if we had Shim Data */
2050 /* Load the Shim Engine */
2051 Peb
->AppCompatInfo
= NULL
;
2052 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
2053 DPRINT1("We do not support shims yet\n");
2057 /* Check for Application Compatibility Goo */
2058 //LdrQueryApplicationCompatibilityGoo(hKey);
2059 DPRINT1("Querying app compat hacks is missing!\n");
2063 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2064 * incompatible images.
2067 /* Now call the Init Routines */
2068 Status
= LdrpRunInitializeRoutines(Context
);
2069 if (!NT_SUCCESS(Status
))
2071 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2076 /* FIXME: Unload the Shim Engine if it was loaded */
2078 /* Check if we have a user-defined Post Process Routine */
2079 if (NT_SUCCESS(Status
) && Peb
->PostProcessInitRoutine
)
2082 Peb
->PostProcessInitRoutine();
2085 ///* Close the key if we have one opened */
2086 if (OptionsKey
) NtClose(OptionsKey
);
2094 LdrpInitFailure(NTSTATUS Status
)
2097 PPEB Peb
= NtCurrentPeb();
2099 /* Print a debug message */
2100 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2101 &Peb
->ProcessParameters
->ImagePathName
, Status
);
2103 /* Raise a hard error */
2104 if (!LdrpFatalHardErrorCount
)
2106 ZwRaiseHardError(STATUS_APP_INIT_FAILURE
, 1, 0, (PULONG_PTR
)&Status
, OptionOk
, &Response
);
2112 LdrpInit(PCONTEXT Context
,
2113 PVOID SystemArgument1
,
2114 PVOID SystemArgument2
)
2116 LARGE_INTEGER Timeout
;
2117 PTEB Teb
= NtCurrentTeb();
2118 NTSTATUS Status
, LoaderStatus
= STATUS_SUCCESS
;
2119 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
2120 PPEB Peb
= NtCurrentPeb();
2122 DPRINT("LdrpInit()\n");
2124 /* Check if we have a deallocation stack */
2125 if (!Teb
->DeallocationStack
)
2127 /* We don't, set one */
2128 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
2129 Teb
->NtTib
.StackLimit
,
2130 MemoryBasicInformation
,
2132 sizeof(MEMORY_BASIC_INFORMATION
),
2134 if (!NT_SUCCESS(Status
))
2137 LdrpInitFailure(Status
);
2138 RtlRaiseStatus(Status
);
2143 Teb
->DeallocationStack
= MemoryBasicInfo
.AllocationBase
;
2146 /* Now check if the process is already being initialized */
2147 while (_InterlockedCompareExchange(&LdrpProcessInitialized
,
2151 /* Set the timeout to 30 seconds */
2152 Timeout
.QuadPart
= Int32x32To64(30, -10000);
2154 /* Make sure the status hasn't changed */
2155 while (!LdrpProcessInitialized
)
2158 ZwDelayExecution(FALSE
, &Timeout
);
2162 /* Check if we have already setup LDR data */
2165 /* Setup the Loader Lock */
2166 Peb
->LoaderLock
= &LdrpLoaderLock
;
2168 /* Let other code know we're initializing */
2169 LdrpInLdrInit
= TRUE
;
2171 /* Protect with SEH */
2174 /* Initialize the Process */
2175 LoaderStatus
= LdrpInitializeProcess(Context
,
2178 /* Check for success and if MinimumStackCommit was requested */
2179 if (NT_SUCCESS(LoaderStatus
) && Peb
->MinimumStackCommit
)
2181 /* Enforce the limit */
2182 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2188 /* Fail with the SEH error */
2189 LoaderStatus
= _SEH2_GetExceptionCode();
2193 /* We're not initializing anymore */
2194 LdrpInLdrInit
= FALSE
;
2196 /* Check if init worked */
2197 if (NT_SUCCESS(LoaderStatus
))
2199 /* Set the process as Initialized */
2200 _InterlockedIncrement(&LdrpProcessInitialized
);
2205 /* Loader data is there... is this a fork() ? */
2206 if(Peb
->InheritedAddressSpace
)
2208 /* Handle the fork() */
2209 //LoaderStatus = LdrpForkProcess();
2210 LoaderStatus
= STATUS_NOT_IMPLEMENTED
;
2215 /* This is a new thread initializing */
2216 LdrpInitializeThread(Context
);
2220 /* All done, test alert the thread */
2224 if (!NT_SUCCESS(LoaderStatus
))
2227 LdrpInitFailure(LoaderStatus
);
2228 RtlRaiseStatus(LoaderStatus
);