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 NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
, PVOID ImageBase
);
90 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
92 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
95 /* FUNCTIONS *****************************************************************/
102 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey
,
104 OUT PHKEY NewKeyHandle
)
106 PHKEY RootKeyLocation
;
108 UNICODE_STRING SubKeyString
;
109 OBJECT_ATTRIBUTES ObjectAttributes
;
113 /* Check which root key to open */
115 RootKeyLocation
= &Wow64ExecOptionsKey
;
117 RootKeyLocation
= &ImageExecOptionsKey
;
119 /* Get the current key */
120 RootKey
= *RootKeyLocation
;
122 /* Setup the object attributes */
123 InitializeObjectAttributes(&ObjectAttributes
,
125 &Wow64OptionsString
: &ImageExecOptionsString
,
126 OBJ_CASE_INSENSITIVE
,
130 /* Open the root key */
131 Status
= ZwOpenKey(&RootKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
132 if (NT_SUCCESS(Status
))
134 /* Write the key handle */
135 if (_InterlockedCompareExchange((LONG
*)RootKeyLocation
, (LONG
)RootKey
, 0) != 0)
137 /* Someone already opened it, use it instead */
139 RootKey
= *RootKeyLocation
;
142 /* Extract the name */
143 SubKeyString
= *SubKey
;
144 p1
= (PWCHAR
)((ULONG_PTR
)SubKeyString
.Buffer
+ SubKeyString
.Length
);
145 while (SubKey
->Length
)
147 if (p1
[-1] == L
'\\') break;
149 SubKeyString
.Length
-= sizeof(*p1
);
151 SubKeyString
.Buffer
= p1
;
152 SubKeyString
.Length
= SubKeyString
.MaximumLength
- SubKeyString
.Length
- sizeof(WCHAR
);
154 /* Setup the object attributes */
155 InitializeObjectAttributes(&ObjectAttributes
,
157 OBJ_CASE_INSENSITIVE
,
161 /* Open the setting key */
162 Status
= ZwOpenKey((PHANDLE
)NewKeyHandle
, GENERIC_READ
, &ObjectAttributes
);
165 /* Return to caller */
174 LdrQueryImageFileKeyOption(IN HKEY KeyHandle
,
179 OUT PULONG ReturnedLength OPTIONAL
)
182 UNICODE_STRING ValueNameString
, IntegerString
;
183 ULONG KeyInfoSize
, ResultSize
;
184 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)&KeyInfo
;
185 BOOLEAN FreeHeap
= FALSE
;
188 /* Build a string for the value name */
189 Status
= RtlInitUnicodeStringEx(&ValueNameString
, ValueName
);
190 if (!NT_SUCCESS(Status
)) return Status
;
192 /* Query the value */
193 Status
= NtQueryValueKey(KeyHandle
,
195 KeyValuePartialInformation
,
199 if (Status
== STATUS_BUFFER_OVERFLOW
)
201 /* Our local buffer wasn't enough, allocate one */
202 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
203 KeyValueInformation
->DataLength
;
204 KeyValueInformation
= RtlAllocateHeap(RtlGetProcessHeap(),
209 /* Give up this time */
210 Status
= STATUS_NO_MEMORY
;
214 Status
= NtQueryValueKey(KeyHandle
,
216 KeyValuePartialInformation
,
223 /* Check for success */
224 if (NT_SUCCESS(Status
))
226 /* Handle binary data */
227 if (KeyValueInformation
->Type
== REG_BINARY
)
230 if ((Buffer
) && (KeyValueInformation
->DataLength
<= BufferSize
))
232 /* Copy into buffer */
233 RtlMoveMemory(Buffer
,
234 &KeyValueInformation
->Data
,
235 KeyValueInformation
->DataLength
);
239 Status
= STATUS_BUFFER_OVERFLOW
;
242 /* Copy the result length */
243 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
245 else if (KeyValueInformation
->Type
== REG_DWORD
)
247 /* Check for valid type */
248 if (KeyValueInformation
->Type
!= Type
)
251 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
257 (BufferSize
== sizeof(ULONG
)) &&
258 (KeyValueInformation
->DataLength
<= BufferSize
))
260 /* Copy into buffer */
261 RtlMoveMemory(Buffer
,
262 &KeyValueInformation
->Data
,
263 KeyValueInformation
->DataLength
);
267 Status
= STATUS_BUFFER_OVERFLOW
;
270 /* Copy the result length */
271 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
274 else if (KeyValueInformation
->Type
!= REG_SZ
)
276 /* We got something weird */
277 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
281 /* String, check what you requested */
282 if (Type
== REG_DWORD
)
285 if (BufferSize
!= sizeof(ULONG
))
289 Status
= STATUS_INFO_LENGTH_MISMATCH
;
293 /* OK, we know what you want... */
294 IntegerString
.Buffer
= (PWSTR
)KeyValueInformation
->Data
;
295 IntegerString
.Length
= KeyValueInformation
->DataLength
-
297 IntegerString
.MaximumLength
= KeyValueInformation
->DataLength
;
298 Status
= RtlUnicodeStringToInteger(&IntegerString
, 0, (PULONG
)Buffer
);
304 if (KeyValueInformation
->DataLength
> BufferSize
)
307 Status
= STATUS_BUFFER_OVERFLOW
;
312 BufferSize
= KeyValueInformation
->DataLength
;
315 /* Copy the string */
316 RtlMoveMemory(Buffer
, &KeyValueInformation
->Data
, BufferSize
);
319 /* Copy the result length */
320 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
324 /* Check if buffer was in heap */
325 if (FreeHeap
) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation
);
327 /* Close key and return */
337 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey
,
342 OUT PULONG ReturnedLength OPTIONAL
,
348 /* Open a handle to the key */
349 Status
= LdrOpenImageFileOptionsKey(SubKey
, Wow64
, &KeyHandle
);
351 /* Check for success */
352 if (NT_SUCCESS(Status
))
355 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
366 /* Return to caller */
375 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey
,
380 OUT PULONG ReturnedLength OPTIONAL
)
382 /* Call the newer function */
383 return LdrQueryImageFileExecutionOptionsEx(SubKey
,
394 LdrpEnsureLoaderLockIsHeld()
401 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress
, ULONG SizeOfImage
)
403 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir
;
407 /* Check NT header first */
408 if (!RtlImageNtHeader(BaseAddress
)) return NULL
;
410 /* Get the pointer to the config directory */
411 ConfigDir
= RtlImageDirectoryEntryToData(BaseAddress
,
413 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
416 /* Check for sanity */
418 (DirSize
!= 64 && ConfigDir
->Size
!= DirSize
) ||
419 (ConfigDir
->Size
< 0x48))
422 /* Now get the cookie */
423 Cookie
= (PVOID
)ConfigDir
->SecurityCookie
;
425 /* Check this cookie */
426 if ((PCHAR
)Cookie
<= (PCHAR
)BaseAddress
||
427 (PCHAR
)Cookie
>= (PCHAR
)BaseAddress
+ SizeOfImage
)
432 /* Return validated security cookie */
438 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry
)
441 LARGE_INTEGER Counter
;
444 /* Fetch address of the cookie */
445 Cookie
= LdrpFetchAddressOfSecurityCookie(LdrEntry
->DllBase
, LdrEntry
->SizeOfImage
);
449 /* Check if it's a default one */
450 if (*Cookie
== DEFAULT_SECURITY_COOKIE
||
453 /* We need to initialize it */
455 NtQueryPerformanceCounter(&Counter
, NULL
);
457 GetSystemTimeAsFileTime (&systime
.ft_struct
);
459 cookie
= systime
.ft_scalar
;
461 cookie
= systime
.ft_struct
.dwLowDateTime
;
462 cookie
^= systime
.ft_struct
.dwHighDateTime
;
465 cookie
^= GetCurrentProcessId ();
466 cookie
^= GetCurrentThreadId ();
467 cookie
^= GetTickCount ();
469 QueryPerformanceCounter (&perfctr
);
471 cookie
^= perfctr
.QuadPart
;
473 cookie
^= perfctr
.LowPart
;
474 cookie
^= perfctr
.HighPart
;
478 cookie
&= 0x0000ffffffffffffll
;
481 *Cookie
= Counter
.LowPart
;
492 LdrpInitializeThread(IN PCONTEXT Context
)
494 PPEB Peb
= NtCurrentPeb();
495 PLDR_DATA_TABLE_ENTRY LdrEntry
;
496 PLIST_ENTRY NextEntry
, ListHead
;
497 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
501 DPRINT("LdrpInitializeThread() called for %wZ\n",
502 &LdrpImageEntry
->BaseDllName
);
504 /* Allocate an Activation Context Stack */
505 /* FIXME: This is a hack for Wine's actctx stuff */
506 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
507 if (!(NtCurrentTeb()->ActivationContextStackPointer
))
509 Status
= RtlAllocateActivationContextStack((PVOID
*)&NtCurrentTeb()->ActivationContextStackPointer
);
510 if (NT_SUCCESS(Status
))
512 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
513 DPRINT("ActiveFrame %p\n", ((PACTIVATION_CONTEXT_STACK
)NtCurrentTeb()->ActivationContextStackPointer
)->ActiveFrame
);
514 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= NULL
;
517 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
520 /* Make sure we are not shutting down */
521 if (LdrpShutdownInProgress
) return;
526 /* Start at the beginning */
527 ListHead
= &Peb
->Ldr
->InMemoryOrderModuleList
;
528 NextEntry
= ListHead
->Flink
;
529 while (NextEntry
!= ListHead
)
531 /* Get the current entry */
532 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
534 /* Make sure it's not ourselves */
535 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
537 /* Check if we should call */
538 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
))
540 /* Get the entrypoint */
541 EntryPoint
= LdrEntry
->EntryPoint
;
543 /* Check if we are ready to call it */
545 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
546 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
548 /* Set up the Act Ctx */
549 ActCtx
.Size
= sizeof(ActCtx
);
551 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
553 /* Activate the ActCtx */
554 RtlActivateActivationContextUnsafeFast(&ActCtx
,
555 LdrEntry
->EntryPointActivationContext
);
557 /* Check if it has TLS */
558 if (LdrEntry
->TlsIndex
)
560 /* Make sure we're not shutting down */
561 if (!LdrpShutdownInProgress
)
564 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_ATTACH
);
568 /* Make sure we're not shutting down */
569 if (!LdrpShutdownInProgress
)
571 /* Call the Entrypoint */
572 DPRINT("%wZ - Calling entry point at %x for thread attaching\n",
573 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
574 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
580 /* Deactivate the ActCtx */
581 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
587 NextEntry
= NextEntry
->Flink
;
591 if (LdrpImageHasTls
&& !LdrpShutdownInProgress
)
593 /* Set up the Act Ctx */
594 ActCtx
.Size
= sizeof(ActCtx
);
596 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
598 /* Activate the ActCtx */
599 RtlActivateActivationContextUnsafeFast(&ActCtx
,
600 LdrpImageEntry
->EntryPointActivationContext
);
602 /* Do TLS callbacks */
603 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_ATTACH
);
605 /* Deactivate the ActCtx */
606 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
609 DPRINT("LdrpInitializeThread() done\n");
614 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL
)
616 PLDR_DATA_TABLE_ENTRY LocalArray
[16];
617 PLIST_ENTRY ListHead
;
618 PLIST_ENTRY NextEntry
;
619 PLDR_DATA_TABLE_ENTRY LdrEntry
, *LdrRootEntry
, OldInitializer
;
623 NTSTATUS Status
= STATUS_SUCCESS
;
624 PPEB Peb
= NtCurrentPeb();
625 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
626 ULONG BreakOnDllLoad
;
630 DPRINT("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
632 /* Check the Loader Lock */
633 LdrpEnsureLoaderLockIsHeld();
635 /* Get the number of entries to call */
636 if ((Count
= LdrpClearLoadInProgress()))
638 /* Check if we can use our local buffer */
641 /* Allocate space for all the entries */
642 LdrRootEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
644 Count
* sizeof(LdrRootEntry
));
645 if (!LdrRootEntry
) return STATUS_NO_MEMORY
;
649 /* Use our local array */
650 LdrRootEntry
= LocalArray
;
659 /* Show debug message */
662 DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n",
663 NtCurrentTeb()->RealClientId
.UniqueThread
,
664 NtCurrentTeb()->RealClientId
.UniqueProcess
,
665 &Peb
->ProcessParameters
->ImagePathName
);
669 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
670 NextEntry
= ListHead
->Flink
;
672 while (NextEntry
!= ListHead
)
674 /* Get the Data Entry */
675 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
677 /* Check if we have a Root Entry */
681 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
683 /* Setup the Cookie for the DLL */
684 LdrpInitSecurityCookie(LdrEntry
);
686 /* Check for valid entrypoint */
687 if (LdrEntry
->EntryPoint
)
690 LdrRootEntry
[i
] = LdrEntry
;
692 /* Display debug message */
695 DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
696 NtCurrentTeb()->RealClientId
.UniqueThread
,
697 NtCurrentTeb()->RealClientId
.UniqueProcess
,
698 &LdrEntry
->FullDllName
,
699 LdrEntry
->EntryPoint
);
707 LdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
708 NextEntry
= NextEntry
->Flink
;
711 /* If we got a context, then we have to call Kernel32 for TS support */
714 /* Check if we have one */
715 //if (Kernel32ProcessInitPostImportfunction)
718 //Kernel32ProcessInitPostImportfunction();
722 //Kernel32ProcessInitPostImportfunction = NULL;
726 /* No root entry? return */
727 if (!LdrRootEntry
) return STATUS_SUCCESS
;
729 /* Set the TLD TEB */
730 OldTldTeb
= LdrpTopLevelDllBeingLoadedTeb
;
731 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
738 LdrEntry
= LdrRootEntry
[i
];
740 /* FIXME: Verify NX Compat */
742 /* Move to next entry */
745 /* Get its entrypoint */
746 EntryPoint
= LdrEntry
->EntryPoint
;
748 /* Are we being debugged? */
750 if (Peb
->BeingDebugged
|| Peb
->ReadImageFileExecOptions
)
752 /* Check if we should break on load */
753 Status
= LdrQueryImageFileExecutionOptions(&LdrEntry
->BaseDllName
,
759 if (!NT_SUCCESS(Status
)) BreakOnDllLoad
= 0;
761 /* Reset status back to STATUS_SUCCESS */
762 Status
= STATUS_SUCCESS
;
768 /* Check if we should show a message */
771 DPRINT1("LDR: %wZ loaded.", &LdrEntry
->BaseDllName
);
772 DPRINT1(" - About to call init routine at %p\n", EntryPoint
);
775 /* Break in debugger */
779 /* Make sure we have an entrypoint */
782 /* Save the old Dll Initializer and write the current one */
783 OldInitializer
= LdrpCurrentDllInitializer
;
784 LdrpCurrentDllInitializer
= LdrEntry
;
786 /* Set up the Act Ctx */
787 ActCtx
.Size
= sizeof(ActCtx
);
789 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
791 /* Activate the ActCtx */
792 RtlActivateActivationContextUnsafeFast(&ActCtx
,
793 LdrEntry
->EntryPointActivationContext
);
795 /* Check if it has TLS */
796 if (LdrEntry
->TlsIndex
&& Context
)
799 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_ATTACH
);
802 /* Call the Entrypoint */
805 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
806 &LdrEntry
->BaseDllName
, EntryPoint
);
808 DllStatus
= LdrpCallInitRoutine(EntryPoint
,
813 /* Deactivate the ActCtx */
814 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
816 /* Save the Current DLL Initializer */
817 LdrpCurrentDllInitializer
= OldInitializer
;
819 /* Mark the entry as processed */
820 LdrEntry
->Flags
|= LDRP_PROCESS_ATTACH_CALLED
;
822 /* Fail if DLL init failed */
825 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
826 &LdrEntry
->BaseDllName
, EntryPoint
);
828 Status
= STATUS_DLL_INIT_FAILED
;
835 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
836 NextEntry
= NextEntry
->Flink
;
837 while (NextEntry
!= ListHead
)
839 /* Get the Data Entrry */
840 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
842 /* FIXME: Verify NX Compat */
843 // LdrpCheckNXCompatibility()
846 NextEntry
= NextEntry
->Flink
;
850 if (LdrpImageHasTls
&& Context
)
852 /* Set up the Act Ctx */
853 ActCtx
.Size
= sizeof(ActCtx
);
855 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
857 /* Activate the ActCtx */
858 RtlActivateActivationContextUnsafeFast(&ActCtx
,
859 LdrpImageEntry
->EntryPointActivationContext
);
861 /* Do TLS callbacks */
862 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_ATTACH
);
864 /* Deactivate the ActCtx */
865 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
869 /* Restore old TEB */
870 LdrpTopLevelDllBeingLoadedTeb
= OldTldTeb
;
872 /* Check if the array is in the heap */
873 if (LdrRootEntry
!= LocalArray
)
876 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry
);
879 /* Return to caller */
880 DPRINT("LdrpRunInitializeRoutines() done\n");
889 LdrShutdownProcess(VOID
)
891 PPEB Peb
= NtCurrentPeb();
892 PLDR_DATA_TABLE_ENTRY LdrEntry
;
893 PLIST_ENTRY NextEntry
, ListHead
;
894 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
897 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
898 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
900 /* Tell the Shim Engine */
912 /* Set the shutdown variables */
913 LdrpShutdownThreadId
= NtCurrentTeb()->RealClientId
.UniqueThread
;
914 LdrpShutdownInProgress
= TRUE
;
916 /* Enter the Loader Lock */
917 RtlEnterCriticalSection(&LdrpLoaderLock
);
919 /* Cleanup trace logging data (Etw) */
920 if (SharedUserData
->TraceLogging
)
923 DPRINT1("We don't support Etw yet.\n");
926 /* Start at the end */
927 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
928 NextEntry
= ListHead
->Blink
;
929 while (NextEntry
!= ListHead
)
931 /* Get the current entry */
932 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
933 NextEntry
= NextEntry
->Blink
;
935 /* Make sure it's not ourselves */
936 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
938 /* Get the entrypoint */
939 EntryPoint
= LdrEntry
->EntryPoint
;
941 /* Check if we are ready to call it */
943 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
946 /* Set up the Act Ctx */
947 ActCtx
.Size
= sizeof(ActCtx
);
949 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
951 /* Activate the ActCtx */
952 RtlActivateActivationContextUnsafeFast(&ActCtx
,
953 LdrEntry
->EntryPointActivationContext
);
955 /* Check if it has TLS */
956 if (LdrEntry
->TlsIndex
)
959 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_DETACH
);
962 /* Call the Entrypoint */
963 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
964 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
965 LdrpCallInitRoutine(EntryPoint
,
970 /* Deactivate the ActCtx */
971 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
979 /* Set up the Act Ctx */
980 ActCtx
.Size
= sizeof(ActCtx
);
982 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
984 /* Activate the ActCtx */
985 RtlActivateActivationContextUnsafeFast(&ActCtx
,
986 LdrpImageEntry
->EntryPointActivationContext
);
988 /* Do TLS callbacks */
989 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_DETACH
);
991 /* Deactivate the ActCtx */
992 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
995 /* FIXME: Do Heap detection and Etw final shutdown */
997 /* Release the lock */
998 RtlLeaveCriticalSection(&LdrpLoaderLock
);
999 DPRINT("LdrpShutdownProcess() done\n");
1001 return STATUS_SUCCESS
;
1009 LdrShutdownThread(VOID
)
1011 PPEB Peb
= NtCurrentPeb();
1012 PTEB Teb
= NtCurrentTeb();
1013 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1014 PLIST_ENTRY NextEntry
, ListHead
;
1015 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1018 DPRINT("LdrShutdownThread() called for %wZ\n",
1019 &LdrpImageEntry
->BaseDllName
);
1021 /* Cleanup trace logging data (Etw) */
1022 if (SharedUserData
->TraceLogging
)
1025 DPRINT1("We don't support Etw yet.\n");
1028 /* Get the Ldr Lock */
1029 RtlEnterCriticalSection(&LdrpLoaderLock
);
1031 /* Start at the end */
1032 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
1033 NextEntry
= ListHead
->Blink
;
1034 while (NextEntry
!= ListHead
)
1036 /* Get the current entry */
1037 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
1038 NextEntry
= NextEntry
->Blink
;
1040 /* Make sure it's not ourselves */
1041 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
1043 /* Check if we should call */
1044 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
) &&
1045 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
1046 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1048 /* Get the entrypoint */
1049 EntryPoint
= LdrEntry
->EntryPoint
;
1051 /* Check if we are ready to call it */
1054 /* Set up the Act Ctx */
1055 ActCtx
.Size
= sizeof(ActCtx
);
1057 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1059 /* Activate the ActCtx */
1060 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1061 LdrEntry
->EntryPointActivationContext
);
1063 /* Check if it has TLS */
1064 if (LdrEntry
->TlsIndex
)
1066 /* Make sure we're not shutting down */
1067 if (!LdrpShutdownInProgress
)
1070 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_DETACH
);
1074 /* Make sure we're not shutting down */
1075 if (!LdrpShutdownInProgress
)
1077 /* Call the Entrypoint */
1078 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
1079 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
1080 LdrpCallInitRoutine(EntryPoint
,
1086 /* Deactivate the ActCtx */
1087 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1094 if (LdrpImageHasTls
)
1096 /* Set up the Act Ctx */
1097 ActCtx
.Size
= sizeof(ActCtx
);
1099 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1101 /* Activate the ActCtx */
1102 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1103 LdrpImageEntry
->EntryPointActivationContext
);
1105 /* Do TLS callbacks */
1106 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_DETACH
);
1108 /* Deactivate the ActCtx */
1109 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1114 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1116 /* Check for expansion slots */
1117 if (Teb
->TlsExpansionSlots
)
1119 /* Free expansion slots */
1120 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->TlsExpansionSlots
);
1123 /* Check for FLS Data */
1127 DPRINT1("We don't support FLS Data yet\n");
1130 /* Check for Fiber data */
1131 if (Teb
->HasFiberData
)
1133 /* Free Fiber data*/
1134 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->NtTib
.FiberData
);
1135 Teb
->NtTib
.FiberData
= NULL
;
1138 /* Free the activation context stack */
1139 RtlFreeThreadActivationContextStack();
1140 DPRINT("LdrShutdownThread() done\n");
1142 return STATUS_SUCCESS
;
1147 LdrpInitializeTls(VOID
)
1149 PLIST_ENTRY NextEntry
, ListHead
;
1150 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1151 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1152 PLDRP_TLS_DATA TlsData
;
1155 /* Initialize the TLS List */
1156 InitializeListHead(&LdrpTlsList
);
1158 /* Loop all the modules */
1159 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1160 NextEntry
= ListHead
->Flink
;
1161 while (ListHead
!= NextEntry
)
1164 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1165 NextEntry
= NextEntry
->Flink
;
1167 /* Get the TLS directory */
1168 TlsDirectory
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1170 IMAGE_DIRECTORY_ENTRY_TLS
,
1173 /* Check if we have a directory */
1174 if (!TlsDirectory
) continue;
1176 /* Check if the image has TLS */
1177 if (!LdrpImageHasTls
) LdrpImageHasTls
= TRUE
;
1179 /* Show debug message */
1182 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1183 &LdrEntry
->BaseDllName
,
1187 /* Allocate an entry */
1188 TlsData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA
));
1189 if (!TlsData
) return STATUS_NO_MEMORY
;
1191 /* Lock the DLL and mark it for TLS Usage */
1192 LdrEntry
->LoadCount
= -1;
1193 LdrEntry
->TlsIndex
= -1;
1195 /* Save the cached TLS data */
1196 TlsData
->TlsDirectory
= *TlsDirectory
;
1197 InsertTailList(&LdrpTlsList
, &TlsData
->TlsLinks
);
1199 /* Update the index */
1200 *(PLONG
)TlsData
->TlsDirectory
.AddressOfIndex
= LdrpNumberOfTlsEntries
;
1201 TlsData
->TlsDirectory
.Characteristics
= LdrpNumberOfTlsEntries
++;
1204 /* Done setting up TLS, allocate entries */
1205 return LdrpAllocateTls();
1210 LdrpAllocateTls(VOID
)
1212 PTEB Teb
= NtCurrentTeb();
1213 PLIST_ENTRY NextEntry
, ListHead
;
1214 PLDRP_TLS_DATA TlsData
;
1218 /* Check if we have any entries */
1219 if (!LdrpNumberOfTlsEntries
)
1220 return STATUS_SUCCESS
;
1222 /* Allocate the vector array */
1223 TlsVector
= RtlAllocateHeap(RtlGetProcessHeap(),
1225 LdrpNumberOfTlsEntries
* sizeof(PVOID
));
1226 if (!TlsVector
) return STATUS_NO_MEMORY
;
1227 Teb
->ThreadLocalStoragePointer
= TlsVector
;
1229 /* Loop the TLS Array */
1230 ListHead
= &LdrpTlsList
;
1231 NextEntry
= ListHead
->Flink
;
1232 while (NextEntry
!= ListHead
)
1235 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1236 NextEntry
= NextEntry
->Flink
;
1238 /* Allocate this vector */
1239 TlsDataSize
= TlsData
->TlsDirectory
.EndAddressOfRawData
-
1240 TlsData
->TlsDirectory
.StartAddressOfRawData
;
1241 TlsVector
[TlsData
->TlsDirectory
.Characteristics
] = RtlAllocateHeap(RtlGetProcessHeap(),
1244 if (!TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1247 return STATUS_NO_MEMORY
;
1250 /* Show debug message */
1253 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
1255 TlsData
->TlsDirectory
.Characteristics
,
1256 &TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1257 TlsData
->TlsDirectory
.StartAddressOfRawData
,
1258 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1262 RtlCopyMemory(TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1263 (PVOID
)TlsData
->TlsDirectory
.StartAddressOfRawData
,
1268 return STATUS_SUCCESS
;
1275 PLIST_ENTRY ListHead
, NextEntry
;
1276 PLDRP_TLS_DATA TlsData
;
1278 PTEB Teb
= NtCurrentTeb();
1280 /* Get a pointer to the vector array */
1281 TlsVector
= Teb
->ThreadLocalStoragePointer
;
1282 if (!TlsVector
) return;
1284 /* Loop through it */
1285 ListHead
= &LdrpTlsList
;
1286 NextEntry
= ListHead
->Flink
;
1287 while (NextEntry
!= ListHead
)
1289 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1290 NextEntry
= NextEntry
->Flink
;
1292 /* Free each entry */
1293 if (TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1295 RtlFreeHeap(RtlGetProcessHeap(),
1297 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1301 /* Free the array itself */
1302 RtlFreeHeap(RtlGetProcessHeap(),
1309 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName
, PPEB Peb
, PHKEY OptionsKey
)
1313 return STATUS_SUCCESS
;
1318 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
)
1325 LdrpInitializeProcess(IN PCONTEXT Context
,
1326 IN PVOID SystemArgument1
)
1328 RTL_HEAP_PARAMETERS HeapParameters
;
1329 ULONG ComSectionSize
;
1330 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1332 OBJECT_ATTRIBUTES ObjectAttributes
;
1333 //UNICODE_STRING LocalFileName, FullImageName;
1334 HANDLE SymLinkHandle
;
1335 //ULONG DebugHeapOnly;
1336 UNICODE_STRING CommandLine
, NtSystemRoot
, ImagePathName
, FullPath
, ImageFileName
, KnownDllString
;
1337 PPEB Peb
= NtCurrentPeb();
1338 BOOLEAN IsDotNetImage
= FALSE
;
1339 BOOLEAN FreeCurDir
= FALSE
;
1341 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
1342 //LPWSTR ImagePathBuffer;
1344 UNICODE_STRING CurrentDirectory
;
1347 PIMAGE_NT_HEADERS NtHeader
;
1348 LPWSTR NtDllName
= NULL
;
1350 NLSTABLEINFO NlsTable
;
1351 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig
;
1352 PTEB Teb
= NtCurrentTeb();
1353 PLIST_ENTRY ListHead
;
1354 PLIST_ENTRY NextEntry
;
1357 ULONG DebugProcessHeapOnly
= 0;
1358 PLDR_DATA_TABLE_ENTRY NtLdrEntry
;
1360 ULONG ExecuteOptions
= 0;
1363 /* Set a NULL SEH Filter */
1364 RtlSetUnhandledExceptionFilter(NULL
);
1366 /* Get the image path */
1367 ImagePath
= Peb
->ProcessParameters
->ImagePathName
.Buffer
;
1369 /* Check if it's normalized */
1370 if (Peb
->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_NORMALIZED
)
1373 ImagePath
= (PWSTR
)((ULONG_PTR
)ImagePath
+ (ULONG_PTR
)Peb
->ProcessParameters
);
1376 /* Create a unicode string for the Image Path */
1377 ImagePathName
.Length
= Peb
->ProcessParameters
->ImagePathName
.Length
;
1378 ImagePathName
.MaximumLength
= ImagePathName
.Length
+ sizeof(WCHAR
);
1379 ImagePathName
.Buffer
= ImagePath
;
1381 /* Get the NT Headers */
1382 NtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1384 /* Get the execution options */
1385 Status
= LdrpInitializeExecutionOptions(&ImagePathName
, Peb
, &OptionsKey
);
1387 /* Check if this is a .NET executable */
1388 if (RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1390 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1393 /* Remeber this for later */
1394 IsDotNetImage
= TRUE
;
1397 /* Save the NTDLL Base address */
1398 NtDllBase
= SystemArgument1
;
1400 /* If this is a Native Image */
1401 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
)
1403 /* Then do DLL Validation */
1404 LdrpDllValidation
= TRUE
;
1407 /* Save the old Shim Data */
1408 OldShimData
= Peb
->pShimData
;
1411 Peb
->pShimData
= NULL
;
1413 /* Save the number of processors and CS Timeout */
1414 LdrpNumberOfProcessors
= Peb
->NumberOfProcessors
;
1415 RtlpTimeout
= Peb
->CriticalSectionTimeout
;
1417 /* Normalize the parameters */
1418 ProcessParameters
= RtlNormalizeProcessParams(Peb
->ProcessParameters
);
1419 ProcessParameters
= Peb
->ProcessParameters
;
1420 if (ProcessParameters
)
1422 /* Save the Image and Command Line Names */
1423 ImageFileName
= ProcessParameters
->ImagePathName
;
1424 CommandLine
= ProcessParameters
->CommandLine
;
1428 /* It failed, initialize empty strings */
1429 RtlInitUnicodeString(&ImageFileName
, NULL
);
1430 RtlInitUnicodeString(&CommandLine
, NULL
);
1433 /* Initialize NLS data */
1434 RtlInitNlsTables(Peb
->AnsiCodePageData
,
1435 Peb
->OemCodePageData
,
1436 Peb
->UnicodeCaseTableData
,
1439 /* Reset NLS Translations */
1440 RtlResetRtlTranslations(&NlsTable
);
1442 /* Get the Image Config Directory */
1443 LoadConfig
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1445 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
1448 /* Setup the Heap Parameters */
1449 RtlZeroMemory(&HeapParameters
, sizeof(RTL_HEAP_PARAMETERS
));
1450 HeapFlags
= HEAP_GROWABLE
;
1451 HeapParameters
.Length
= sizeof(RTL_HEAP_PARAMETERS
);
1453 /* Check if we have Configuration Data */
1454 if ((LoadConfig
) && (ConfigSize
== sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
)))
1456 /* FIXME: Custom heap settings and misc. */
1457 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1460 /* Check for custom affinity mask */
1461 if (Peb
->ImageProcessAffinityMask
)
1464 Status
= NtSetInformationProcess(NtCurrentProcess(),
1465 ProcessAffinityMask
,
1466 &Peb
->ImageProcessAffinityMask
,
1467 sizeof(Peb
->ImageProcessAffinityMask
));
1470 /* Check if verbose debugging (ShowSnaps) was requested */
1471 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
1473 /* Start verbose debugging messages right now if they were requested */
1476 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1477 Teb
->ClientId
.UniqueProcess
,
1481 /* If the timeout is too long */
1482 if (RtlpTimeout
.QuadPart
< Int32x32To64(3600, -10000000))
1484 /* Then disable CS Timeout */
1485 RtlpTimeoutDisable
= TRUE
;
1488 /* Initialize Critical Section Data */
1489 RtlpInitDeferedCriticalSection();
1491 /* Initialize VEH Call lists */
1492 RtlpInitializeVectoredExceptionHandling();
1494 /* Set TLS/FLS Bitmap data */
1495 Peb
->FlsBitmap
= &FlsBitMap
;
1496 Peb
->TlsBitmap
= &TlsBitMap
;
1497 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
1499 /* Initialize FLS Bitmap */
1500 RtlInitializeBitMap(&FlsBitMap
,
1502 FLS_MAXIMUM_AVAILABLE
);
1503 RtlSetBit(&FlsBitMap
, 0);
1505 /* Initialize TLS Bitmap */
1506 RtlInitializeBitMap(&TlsBitMap
,
1508 TLS_MINIMUM_AVAILABLE
);
1509 RtlSetBit(&TlsBitMap
, 0);
1510 RtlInitializeBitMap(&TlsExpansionBitMap
,
1511 Peb
->TlsExpansionBitmapBits
,
1512 TLS_EXPANSION_SLOTS
);
1513 RtlSetBit(&TlsExpansionBitMap
, 0);
1515 /* Initialize the Hash Table */
1516 for (i
= 0; i
< LDR_HASH_TABLE_ENTRIES
; i
++)
1518 InitializeListHead(&LdrpHashTable
[i
]);
1521 /* Initialize the Loader Lock */
1522 // FIXME: What's the point of initing it manually, if two lines lower
1523 // a call to RtlInitializeCriticalSection() is being made anyway?
1524 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1525 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1526 RtlInitializeCriticalSection(&LdrpLoaderLock
);
1527 LdrpLoaderLockInit
= TRUE
;
1529 /* Check if User Stack Trace Database support was requested */
1530 if (Peb
->NtGlobalFlag
& FLG_USER_STACK_TRACE_DB
)
1532 DPRINT1("We don't support user stack trace databases yet\n");
1535 /* Setup Fast PEB Lock */
1536 RtlInitializeCriticalSection(&FastPebLock
);
1537 Peb
->FastPebLock
= &FastPebLock
;
1538 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1539 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1541 /* Setup Callout Lock and Notification list */
1542 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1543 InitializeListHead(&LdrpDllNotificationList
);
1545 /* For old executables, use 16-byte aligned heap */
1546 if ((NtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3) &&
1547 (NtHeader
->OptionalHeader
.MinorSubsystemVersion
< 51))
1549 HeapFlags
|= HEAP_CREATE_ALIGN_16
;
1552 /* Setup the Heap */
1553 RtlInitializeHeapManager();
1554 Peb
->ProcessHeap
= RtlCreateHeap(HeapFlags
,
1556 NtHeader
->OptionalHeader
.SizeOfHeapReserve
,
1557 NtHeader
->OptionalHeader
.SizeOfHeapCommit
,
1561 if (!Peb
->ProcessHeap
)
1563 DPRINT1("Failed to create process heap\n");
1564 return STATUS_NO_MEMORY
;
1567 // FIXME: Is it located properly?
1568 /* Initialize table of callbacks for the kernel. */
1569 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
1572 (USER32_CALLBACK_MAXIMUM
+ 1));
1573 if (!Peb
->KernelCallbackTable
)
1575 DPRINT1("Failed to create callback table\n");
1576 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
1579 /* Allocate an Activation Context Stack */
1580 Status
= RtlAllocateActivationContextStack((PVOID
*)&Teb
->ActivationContextStackPointer
);
1581 if (!NT_SUCCESS(Status
)) return Status
;
1583 // FIXME: Loader private heap is missing
1584 //DPRINT1("Loader private heap is missing\n");
1586 /* Check for Debug Heap */
1589 /* Query the setting */
1590 Status
= LdrQueryImageFileKeyOption(OptionsKey
,
1591 L
"DebugProcessHeapOnly",
1593 &DebugProcessHeapOnly
,
1597 if (NT_SUCCESS(Status
))
1599 /* Reset DPH if requested */
1600 if (RtlpPageHeapEnabled
&& DebugProcessHeapOnly
)
1602 RtlpDphGlobalFlags
&= ~0x40;
1603 RtlpPageHeapEnabled
= FALSE
;
1608 /* Build the NTDLL Path */
1609 FullPath
.Buffer
= StringBuffer
;
1610 FullPath
.Length
= 0;
1611 FullPath
.MaximumLength
= sizeof(StringBuffer
);
1612 RtlInitUnicodeString(&NtSystemRoot
, SharedUserData
->NtSystemRoot
);
1613 RtlAppendUnicodeStringToString(&FullPath
, &NtSystemRoot
);
1614 RtlAppendUnicodeToString(&FullPath
, L
"\\System32\\");
1616 /* Open the Known DLLs directory */
1617 RtlInitUnicodeString(&KnownDllString
, L
"\\KnownDlls");
1618 InitializeObjectAttributes(&ObjectAttributes
,
1620 OBJ_CASE_INSENSITIVE
,
1623 Status
= ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory
,
1624 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1627 /* Check if it exists */
1628 if (NT_SUCCESS(Status
))
1630 /* Open the Known DLLs Path */
1631 RtlInitUnicodeString(&KnownDllString
, L
"KnownDllPath");
1632 InitializeObjectAttributes(&ObjectAttributes
,
1634 OBJ_CASE_INSENSITIVE
,
1635 LdrpKnownDllObjectDirectory
,
1637 Status
= NtOpenSymbolicLinkObject(&SymLinkHandle
,
1638 SYMBOLIC_LINK_QUERY
,
1640 if (NT_SUCCESS(Status
))
1642 /* Query the path */
1643 LdrpKnownDllPath
.Length
= 0;
1644 LdrpKnownDllPath
.MaximumLength
= sizeof(LdrpKnownDllPathBuffer
);
1645 LdrpKnownDllPath
.Buffer
= LdrpKnownDllPathBuffer
;
1646 Status
= ZwQuerySymbolicLinkObject(SymLinkHandle
, &LdrpKnownDllPath
, NULL
);
1647 NtClose(SymLinkHandle
);
1648 if (!NT_SUCCESS(Status
))
1650 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status
);
1656 /* Check if we failed */
1657 if (!NT_SUCCESS(Status
))
1659 /* Aassume System32 */
1660 LdrpKnownDllObjectDirectory
= NULL
;
1661 RtlInitUnicodeString(&LdrpKnownDllPath
, StringBuffer
);
1662 LdrpKnownDllPath
.Length
-= sizeof(WCHAR
);
1665 /* If we have process parameters, get the default path and current path */
1666 if (ProcessParameters
)
1668 /* Check if we have a Dll Path */
1669 if (ProcessParameters
->DllPath
.Length
)
1672 LdrpDefaultPath
= *(PUNICODE_STRING
)&ProcessParameters
->DllPath
;
1676 /* We need a valid path */
1677 DPRINT1("No valid DllPath was given!\n");
1678 LdrpInitFailure(STATUS_INVALID_PARAMETER
);
1681 /* Set the current directory */
1682 CurrentDirectory
= ProcessParameters
->CurrentDirectory
.DosPath
;
1684 /* Check if it's empty or invalid */
1685 if ((!CurrentDirectory
.Buffer
) ||
1686 (CurrentDirectory
.Buffer
[0] == UNICODE_NULL
) ||
1687 (!CurrentDirectory
.Length
))
1689 /* Allocate space for the buffer */
1690 CurrentDirectory
.Buffer
= RtlAllocateHeap(Peb
->ProcessHeap
,
1693 sizeof(UNICODE_NULL
));
1694 if (!CurrentDirectory
.Buffer
)
1696 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1700 /* Copy the drive of the system root */
1701 RtlMoveMemory(CurrentDirectory
.Buffer
,
1702 SharedUserData
->NtSystemRoot
,
1704 CurrentDirectory
.Buffer
[3] = UNICODE_NULL
;
1705 CurrentDirectory
.Length
= 3 * sizeof(WCHAR
);
1706 CurrentDirectory
.MaximumLength
= CurrentDirectory
.Length
+ sizeof(WCHAR
);
1709 DPRINT("Using dynamically allocd curdir\n");
1713 /* Use the local buffer */
1714 DPRINT("Using local system root\n");
1718 /* Setup Loader Data */
1720 InitializeListHead(&PebLdr
.InLoadOrderModuleList
);
1721 InitializeListHead(&PebLdr
.InMemoryOrderModuleList
);
1722 InitializeListHead(&PebLdr
.InInitializationOrderModuleList
);
1723 PebLdr
.Length
= sizeof(PEB_LDR_DATA
);
1724 PebLdr
.Initialized
= TRUE
;
1726 /* Allocate a data entry for the Image */
1727 LdrpImageEntry
= NtLdrEntry
= LdrpAllocateDataTableEntry(Peb
->ImageBaseAddress
);
1730 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1731 NtLdrEntry
->LoadCount
= -1;
1732 NtLdrEntry
->EntryPointActivationContext
= 0;
1733 NtLdrEntry
->FullDllName
= ImageFileName
;
1736 NtLdrEntry
->Flags
= LDRP_COR_IMAGE
;
1738 NtLdrEntry
->Flags
= 0;
1740 /* Check if the name is empty */
1741 if (!ImageFileName
.Buffer
[0])
1743 /* Use the same Base name */
1744 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1748 /* Find the last slash */
1749 Current
= ImageFileName
.Buffer
;
1752 if (*Current
++ == '\\')
1755 NtDllName
= Current
;
1759 /* Did we find anything? */
1762 /* Use the same Base name */
1763 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1767 /* Setup the name */
1768 NtLdrEntry
->BaseDllName
.Length
= (USHORT
)((ULONG_PTR
)ImageFileName
.Buffer
+ ImageFileName
.Length
- (ULONG_PTR
)NtDllName
);
1769 NtLdrEntry
->BaseDllName
.MaximumLength
= NtLdrEntry
->BaseDllName
.Length
+ sizeof(WCHAR
);
1770 NtLdrEntry
->BaseDllName
.Buffer
= (PWSTR
)((ULONG_PTR
)ImageFileName
.Buffer
+
1771 (ImageFileName
.Length
- NtLdrEntry
->BaseDllName
.Length
));
1775 /* Processing done, insert it */
1776 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1777 NtLdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
1779 /* Now add an entry for NTDLL */
1780 NtLdrEntry
= LdrpAllocateDataTableEntry(SystemArgument1
);
1781 NtLdrEntry
->Flags
= LDRP_IMAGE_DLL
;
1782 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1783 NtLdrEntry
->LoadCount
= -1;
1784 NtLdrEntry
->EntryPointActivationContext
= 0;
1786 NtLdrEntry
->FullDllName
.Length
= FullPath
.Length
;
1787 NtLdrEntry
->FullDllName
.MaximumLength
= FullPath
.MaximumLength
;
1788 NtLdrEntry
->FullDllName
.Buffer
= StringBuffer
;
1789 RtlAppendUnicodeStringToString(&NtLdrEntry
->FullDllName
, &NtDllString
);
1791 NtLdrEntry
->BaseDllName
.Length
= NtDllString
.Length
;
1792 NtLdrEntry
->BaseDllName
.MaximumLength
= NtDllString
.MaximumLength
;
1793 NtLdrEntry
->BaseDllName
.Buffer
= NtDllString
.Buffer
;
1795 /* Processing done, insert it */
1796 LdrpNtDllDataTableEntry
= NtLdrEntry
;
1797 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1799 /* Let the world know */
1802 DPRINT1("LDR: NEW PROCESS\n");
1803 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry
->FullDllName
, &LdrpImageEntry
->BaseDllName
);
1804 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory
);
1805 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath
);
1808 /* Link the Init Order List */
1809 InsertHeadList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1810 &LdrpNtDllDataTableEntry
->InInitializationOrderModuleList
);
1812 /* Set the current directory */
1813 Status
= RtlSetCurrentDirectory_U(&CurrentDirectory
);
1814 if (!NT_SUCCESS(Status
))
1816 /* We failed, check if we should free it */
1817 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1819 /* Set it to the NT Root */
1820 CurrentDirectory
= NtSystemRoot
;
1821 RtlSetCurrentDirectory_U(&CurrentDirectory
);
1825 /* We're done with it, free it */
1826 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1829 /* Check if we should look for a .local file */
1830 if (ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
)
1833 DPRINT1("We don't support .local overrides yet\n");
1836 /* Check if the Application Verifier was enabled */
1837 if (Peb
->NtGlobalFlag
& FLG_POOL_ENABLE_TAIL_CHECK
)
1840 DPRINT1("We don't support Application Verifier yet\n");
1846 DPRINT1("We don't support .NET applications yet\n");
1849 /* FIXME: Load support for Terminal Services */
1850 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1852 /* Load kernel32 and call BasePostImportInit... */
1853 DPRINT1("Unimplemented codepath!\n");
1856 /* Walk the IAT and load all the DLLs */
1857 LdrpWalkImportDescriptor(LdrpDefaultPath
.Buffer
, LdrpImageEntry
);
1859 /* Check if relocation is needed */
1860 if (Peb
->ImageBaseAddress
!= (PVOID
)NtHeader
->OptionalHeader
.ImageBase
)
1862 DPRINT1("LDR: Performing EXE relocation\n");
1864 /* Change the protection to prepare for relocation */
1865 ViewBase
= Peb
->ImageBaseAddress
;
1866 Status
= LdrpSetProtection(ViewBase
, FALSE
);
1867 if (!NT_SUCCESS(Status
)) return Status
;
1869 /* Do the relocation */
1870 Status
= LdrRelocateImageWithBias(ViewBase
,
1874 STATUS_CONFLICTING_ADDRESSES
,
1875 STATUS_INVALID_IMAGE_FORMAT
);
1876 if (!NT_SUCCESS(Status
))
1878 DPRINT1("LdrRelocateImageWithBias() failed\n");
1882 /* Check if a start context was provided */
1885 DPRINT1("WARNING: Relocated EXE Context");
1886 UNIMPLEMENTED
; // We should support this
1887 return STATUS_INVALID_IMAGE_FORMAT
;
1890 /* Restore the protection */
1891 Status
= LdrpSetProtection(ViewBase
, TRUE
);
1892 if (!NT_SUCCESS(Status
)) return Status
;
1896 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
1897 NextEntry
= ListHead
->Flink
;
1898 while (ListHead
!= NextEntry
)
1900 NtLdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1901 NtLdrEntry
->LoadCount
= -1;
1902 NextEntry
= NextEntry
->Flink
;
1905 /* Phase 0 is done */
1906 LdrpLdrDatabaseIsSetup
= TRUE
;
1908 /* Initialize TLS */
1909 Status
= LdrpInitializeTls();
1910 if (!NT_SUCCESS(Status
))
1912 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
1917 /* FIXME Mark the DLL Ranges for Stack Traces later */
1919 /* Notify the debugger now */
1920 if (Peb
->BeingDebugged
)
1925 /* Update show snaps again */
1926 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
1929 /* Validate the Image for MP Usage */
1930 if (LdrpNumberOfProcessors
> 1) LdrpValidateImageForMp(LdrpImageEntry
);
1932 /* Check NX Options */
1933 if (SharedUserData
->NXSupportPolicy
== 1)
1935 ExecuteOptions
= 0xD;
1937 else if (!SharedUserData
->NXSupportPolicy
)
1939 ExecuteOptions
= 0xA;
1943 ZwSetInformationProcess(NtCurrentProcess(),
1944 ProcessExecuteFlags
,
1948 /* Check if we had Shim Data */
1951 /* Load the Shim Engine */
1952 Peb
->AppCompatInfo
= NULL
;
1953 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
1954 DPRINT1("We do not support shims yet\n");
1958 /* Check for Application Compatibility Goo */
1959 //LdrQueryApplicationCompatibilityGoo(hKey);
1960 DPRINT1("Querying app compat hacks is missing!\n");
1964 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
1965 * incompatible images.
1968 /* Now call the Init Routines */
1969 Status
= LdrpRunInitializeRoutines(Context
);
1970 if (!NT_SUCCESS(Status
))
1972 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
1977 /* FIXME: Unload the Shim Engine if it was loaded */
1979 /* Check if we have a user-defined Post Process Routine */
1980 if (NT_SUCCESS(Status
) && Peb
->PostProcessInitRoutine
)
1984 Peb
->PostProcessInitRoutine();
1987 ///* Close the key if we have one opened */
1988 //if (hKey) NtClose(hKey);
1996 LdrpInitFailure(NTSTATUS Status
)
2000 /* Print a debug message */
2001 DPRINT1("LDR: Process initialization failure; NTSTATUS = %08lx\n", Status
);
2003 /* Raise a hard error */
2004 if (!LdrpFatalHardErrorCount
)
2006 ZwRaiseHardError(STATUS_APP_INIT_FAILURE
, 1, 0, (PULONG_PTR
)&Status
, OptionOk
, &Response
);
2012 LdrpInit(PCONTEXT Context
,
2013 PVOID SystemArgument1
,
2014 PVOID SystemArgument2
)
2016 LARGE_INTEGER Timeout
;
2017 PTEB Teb
= NtCurrentTeb();
2018 NTSTATUS Status
, LoaderStatus
= STATUS_SUCCESS
;
2019 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
2020 PPEB Peb
= NtCurrentPeb();
2022 DPRINT("LdrpInit()\n");
2024 /* Check if we have a deallocation stack */
2025 if (!Teb
->DeallocationStack
)
2027 /* We don't, set one */
2028 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
2029 Teb
->NtTib
.StackLimit
,
2030 MemoryBasicInformation
,
2032 sizeof(MEMORY_BASIC_INFORMATION
),
2034 if (!NT_SUCCESS(Status
))
2037 LdrpInitFailure(Status
);
2038 RtlRaiseStatus(Status
);
2043 Teb
->DeallocationStack
= MemoryBasicInfo
.AllocationBase
;
2046 /* Now check if the process is already being initialized */
2047 while (_InterlockedCompareExchange(&LdrpProcessInitialized
,
2051 /* Set the timeout to 30 seconds */
2052 Timeout
.QuadPart
= Int32x32To64(30, -10000);
2054 /* Make sure the status hasn't changed */
2055 while (!LdrpProcessInitialized
)
2058 ZwDelayExecution(FALSE
, &Timeout
);
2062 /* Check if we have already setup LDR data */
2065 /* Setup the Loader Lock */
2066 Peb
->LoaderLock
= &LdrpLoaderLock
;
2068 /* Let other code know we're initializing */
2069 LdrpInLdrInit
= TRUE
;
2071 /* Protect with SEH */
2074 /* Initialize the Process */
2075 LoaderStatus
= LdrpInitializeProcess(Context
,
2078 /* Check for success and if MinimumStackCommit was requested */
2079 if (NT_SUCCESS(LoaderStatus
) && Peb
->MinimumStackCommit
)
2081 /* Enforce the limit */
2082 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2086 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2088 /* Fail with the SEH error */
2089 LoaderStatus
= _SEH2_GetExceptionCode();
2093 /* We're not initializing anymore */
2094 LdrpInLdrInit
= FALSE
;
2096 /* Check if init worked */
2097 if (NT_SUCCESS(LoaderStatus
))
2099 /* Set the process as Initialized */
2100 _InterlockedIncrement(&LdrpProcessInitialized
);
2105 /* Loader data is there... is this a fork() ? */
2106 if(Peb
->InheritedAddressSpace
)
2108 /* Handle the fork() */
2109 //LoaderStatus = LdrpForkProcess();
2110 LoaderStatus
= STATUS_NOT_IMPLEMENTED
;
2115 /* This is a new thread initializing */
2116 LdrpInitializeThread(Context
);
2120 /* All done, test alert the thread */
2124 if (!NT_SUCCESS(LoaderStatus
))
2127 LdrpInitFailure(LoaderStatus
);
2128 RtlRaiseStatus(LoaderStatus
);