2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrinit.c
5 * PURPOSE: User-Mode Process/Thread Startup
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
13 #include <win32k/callback.h>
19 /* GLOBALS *******************************************************************/
21 HKEY ImageExecOptionsKey
;
22 HKEY Wow64ExecOptionsKey
;
23 UNICODE_STRING ImageExecOptionsString
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
24 UNICODE_STRING Wow64OptionsString
= RTL_CONSTANT_STRING(L
"");
25 UNICODE_STRING NtDllString
= RTL_CONSTANT_STRING(L
"ntdll.dll");
27 BOOLEAN LdrpInLdrInit
;
28 LONG LdrpProcessInitialized
;
29 BOOLEAN LdrpLoaderLockInit
;
30 BOOLEAN LdrpLdrDatabaseIsSetup
;
31 BOOLEAN LdrpShutdownInProgress
;
32 HANDLE LdrpShutdownThreadId
;
34 BOOLEAN LdrpDllValidation
;
36 PLDR_DATA_TABLE_ENTRY LdrpImageEntry
;
37 PUNICODE_STRING LdrpTopLevelDllBeingLoaded
;
38 WCHAR StringBuffer
[156];
39 extern PTEB LdrpTopLevelDllBeingLoadedTeb
; // defined in rtlsupp.c!
40 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer
;
41 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry
;
44 RTL_BITMAP TlsExpansionBitMap
;
46 BOOLEAN LdrpImageHasTls
;
47 LIST_ENTRY LdrpTlsList
;
48 ULONG LdrpNumberOfTlsEntries
;
49 ULONG LdrpNumberOfProcessors
;
51 LARGE_INTEGER RtlpTimeout
;
52 BOOLEAN RtlpTimeoutDisable
;
53 LIST_ENTRY LdrpHashTable
[LDR_HASH_TABLE_ENTRIES
];
54 LIST_ENTRY LdrpDllNotificationList
;
55 HANDLE LdrpKnownDllObjectDirectory
;
56 UNICODE_STRING LdrpKnownDllPath
;
57 WCHAR LdrpKnownDllPathBuffer
[128];
58 UNICODE_STRING LdrpDefaultPath
;
62 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug
;
63 RTL_CRITICAL_SECTION LdrpLoaderLock
=
72 RTL_CRITICAL_SECTION FastPebLock
;
76 ULONG LdrpFatalHardErrorCount
;
77 ULONG LdrpActiveUnloadCount
;
79 //extern LIST_ENTRY RtlCriticalSectionList;
81 VOID
RtlpInitializeVectoredExceptionHandling(VOID
);
82 VOID NTAPI
RtlpInitDeferedCriticalSection(VOID
);
83 VOID
RtlInitializeHeapManager(VOID
);
84 extern BOOLEAN RtlpPageHeapEnabled
;
86 ULONG RtlpDisableHeapLookaside
; // TODO: Move to heap.c
87 ULONG RtlpShutdownProcessFlags
; // TODO: Use it
89 NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders
, PVOID ImageBase
);
92 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
94 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
97 /* FUNCTIONS *****************************************************************/
104 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey
,
106 OUT PHKEY NewKeyHandle
)
108 PHKEY RootKeyLocation
;
110 UNICODE_STRING SubKeyString
;
111 OBJECT_ATTRIBUTES ObjectAttributes
;
115 /* Check which root key to open */
117 RootKeyLocation
= &Wow64ExecOptionsKey
;
119 RootKeyLocation
= &ImageExecOptionsKey
;
121 /* Get the current key */
122 RootKey
= *RootKeyLocation
;
124 /* Setup the object attributes */
125 InitializeObjectAttributes(&ObjectAttributes
,
127 &Wow64OptionsString
: &ImageExecOptionsString
,
128 OBJ_CASE_INSENSITIVE
,
132 /* Open the root key */
133 Status
= ZwOpenKey(&RootKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
134 if (NT_SUCCESS(Status
))
136 /* Write the key handle */
137 if (_InterlockedCompareExchange((LONG
*)RootKeyLocation
, (LONG
)RootKey
, 0) != 0)
139 /* Someone already opened it, use it instead */
141 RootKey
= *RootKeyLocation
;
144 /* Extract the name */
145 SubKeyString
= *SubKey
;
146 p1
= (PWCHAR
)((ULONG_PTR
)SubKeyString
.Buffer
+ SubKeyString
.Length
);
147 while (SubKeyString
.Length
)
149 if (p1
[-1] == L
'\\') break;
151 SubKeyString
.Length
-= sizeof(*p1
);
153 SubKeyString
.Buffer
= p1
;
154 SubKeyString
.Length
= SubKey
->Length
- SubKeyString
.Length
;
156 /* Setup the object attributes */
157 InitializeObjectAttributes(&ObjectAttributes
,
159 OBJ_CASE_INSENSITIVE
,
163 /* Open the setting key */
164 Status
= ZwOpenKey((PHANDLE
)NewKeyHandle
, GENERIC_READ
, &ObjectAttributes
);
167 /* Return to caller */
176 LdrQueryImageFileKeyOption(IN HKEY KeyHandle
,
181 OUT PULONG ReturnedLength OPTIONAL
)
184 UNICODE_STRING ValueNameString
, IntegerString
;
185 ULONG KeyInfoSize
, ResultSize
;
186 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)&KeyInfo
;
187 BOOLEAN FreeHeap
= FALSE
;
190 /* Build a string for the value name */
191 Status
= RtlInitUnicodeStringEx(&ValueNameString
, ValueName
);
192 if (!NT_SUCCESS(Status
)) return Status
;
194 /* Query the value */
195 Status
= ZwQueryValueKey(KeyHandle
,
197 KeyValuePartialInformation
,
201 if (Status
== STATUS_BUFFER_OVERFLOW
)
203 /* Our local buffer wasn't enough, allocate one */
204 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
205 KeyValueInformation
->DataLength
;
206 KeyValueInformation
= RtlAllocateHeap(RtlGetProcessHeap(),
211 /* Give up this time */
212 Status
= STATUS_NO_MEMORY
;
216 Status
= ZwQueryValueKey(KeyHandle
,
218 KeyValuePartialInformation
,
225 /* Check for success */
226 if (NT_SUCCESS(Status
))
228 /* Handle binary data */
229 if (KeyValueInformation
->Type
== REG_BINARY
)
232 if ((Buffer
) && (KeyValueInformation
->DataLength
<= BufferSize
))
234 /* Copy into buffer */
235 RtlMoveMemory(Buffer
,
236 &KeyValueInformation
->Data
,
237 KeyValueInformation
->DataLength
);
241 Status
= STATUS_BUFFER_OVERFLOW
;
244 /* Copy the result length */
245 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
247 else if (KeyValueInformation
->Type
== REG_DWORD
)
249 /* Check for valid type */
250 if (KeyValueInformation
->Type
!= Type
)
253 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
259 (BufferSize
== sizeof(ULONG
)) &&
260 (KeyValueInformation
->DataLength
<= BufferSize
))
262 /* Copy into buffer */
263 RtlMoveMemory(Buffer
,
264 &KeyValueInformation
->Data
,
265 KeyValueInformation
->DataLength
);
269 Status
= STATUS_BUFFER_OVERFLOW
;
272 /* Copy the result length */
273 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
276 else if (KeyValueInformation
->Type
!= REG_SZ
)
278 /* We got something weird */
279 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
283 /* String, check what you requested */
284 if (Type
== REG_DWORD
)
287 if (BufferSize
!= sizeof(ULONG
))
291 Status
= STATUS_INFO_LENGTH_MISMATCH
;
295 /* OK, we know what you want... */
296 IntegerString
.Buffer
= (PWSTR
)KeyValueInformation
->Data
;
297 IntegerString
.Length
= (USHORT
)KeyValueInformation
->DataLength
-
299 IntegerString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
300 Status
= RtlUnicodeStringToInteger(&IntegerString
, 0, (PULONG
)Buffer
);
306 if (KeyValueInformation
->DataLength
> BufferSize
)
309 Status
= STATUS_BUFFER_OVERFLOW
;
314 BufferSize
= KeyValueInformation
->DataLength
;
317 /* Copy the string */
318 RtlMoveMemory(Buffer
, &KeyValueInformation
->Data
, BufferSize
);
321 /* Copy the result length */
322 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
326 /* Check if buffer was in heap */
327 if (FreeHeap
) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation
);
338 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey
,
343 OUT PULONG ReturnedLength OPTIONAL
,
349 /* Open a handle to the key */
350 Status
= LdrOpenImageFileOptionsKey(SubKey
, Wow64
, &KeyHandle
);
352 /* Check for success */
353 if (NT_SUCCESS(Status
))
356 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
367 /* Return to caller */
376 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey
,
381 OUT PULONG ReturnedLength OPTIONAL
)
383 /* Call the newer function */
384 return LdrQueryImageFileExecutionOptionsEx(SubKey
,
395 LdrpEnsureLoaderLockIsHeld()
402 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress
, ULONG SizeOfImage
)
404 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir
;
408 /* Check NT header first */
409 if (!RtlImageNtHeader(BaseAddress
)) return NULL
;
411 /* Get the pointer to the config directory */
412 ConfigDir
= RtlImageDirectoryEntryToData(BaseAddress
,
414 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
417 /* Check for sanity */
419 (DirSize
!= 64 && ConfigDir
->Size
!= DirSize
) ||
420 (ConfigDir
->Size
< 0x48))
423 /* Now get the cookie */
424 Cookie
= (PVOID
)ConfigDir
->SecurityCookie
;
426 /* Check this cookie */
427 if ((PCHAR
)Cookie
<= (PCHAR
)BaseAddress
||
428 (PCHAR
)Cookie
>= (PCHAR
)BaseAddress
+ SizeOfImage
)
433 /* Return validated security cookie */
439 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry
)
442 LARGE_INTEGER Counter
;
445 /* Fetch address of the cookie */
446 Cookie
= LdrpFetchAddressOfSecurityCookie(LdrEntry
->DllBase
, LdrEntry
->SizeOfImage
);
450 /* Check if it's a default one */
451 if (*Cookie
== DEFAULT_SECURITY_COOKIE
||
454 /* We need to initialize it */
456 NtQueryPerformanceCounter(&Counter
, NULL
);
458 GetSystemTimeAsFileTime (&systime
.ft_struct
);
460 cookie
= systime
.ft_scalar
;
462 cookie
= systime
.ft_struct
.dwLowDateTime
;
463 cookie
^= systime
.ft_struct
.dwHighDateTime
;
466 cookie
^= GetCurrentProcessId ();
467 cookie
^= GetCurrentThreadId ();
468 cookie
^= GetTickCount ();
470 QueryPerformanceCounter (&perfctr
);
472 cookie
^= perfctr
.QuadPart
;
474 cookie
^= perfctr
.LowPart
;
475 cookie
^= perfctr
.HighPart
;
479 cookie
&= 0x0000ffffffffffffll
;
482 *Cookie
= Counter
.LowPart
;
493 LdrpInitializeThread(IN PCONTEXT Context
)
495 PPEB Peb
= NtCurrentPeb();
496 PLDR_DATA_TABLE_ENTRY LdrEntry
;
497 PLIST_ENTRY NextEntry
, ListHead
;
498 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
502 DPRINT("LdrpInitializeThread() called for %wZ (%lx/%lx)\n",
503 &LdrpImageEntry
->BaseDllName
,
504 NtCurrentTeb()->RealClientId
.UniqueProcess
,
505 NtCurrentTeb()->RealClientId
.UniqueThread
);
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 %p for thread attaching, %lx/%lx\n",
576 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
,
577 NtCurrentTeb()->RealClientId
.UniqueProcess
,
578 NtCurrentTeb()->RealClientId
.UniqueThread
);
579 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
585 /* Deactivate the ActCtx */
586 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
592 NextEntry
= NextEntry
->Flink
;
596 if (LdrpImageHasTls
&& !LdrpShutdownInProgress
)
598 /* Set up the Act Ctx */
599 ActCtx
.Size
= sizeof(ActCtx
);
601 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
603 /* Activate the ActCtx */
604 RtlActivateActivationContextUnsafeFast(&ActCtx
,
605 LdrpImageEntry
->EntryPointActivationContext
);
607 /* Do TLS callbacks */
608 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_ATTACH
);
610 /* Deactivate the ActCtx */
611 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
614 DPRINT("LdrpInitializeThread() done\n");
619 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL
)
621 PLDR_DATA_TABLE_ENTRY LocalArray
[16];
622 PLIST_ENTRY ListHead
;
623 PLIST_ENTRY NextEntry
;
624 PLDR_DATA_TABLE_ENTRY LdrEntry
, *LdrRootEntry
, OldInitializer
;
628 NTSTATUS Status
= STATUS_SUCCESS
;
629 PPEB Peb
= NtCurrentPeb();
630 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
631 ULONG BreakOnDllLoad
;
635 DPRINT("LdrpRunInitializeRoutines() called for %wZ (%lx/%lx)\n",
636 &LdrpImageEntry
->BaseDllName
,
637 NtCurrentTeb()->RealClientId
.UniqueProcess
,
638 NtCurrentTeb()->RealClientId
.UniqueThread
);
640 /* Check the Loader Lock */
641 LdrpEnsureLoaderLockIsHeld();
643 /* Get the number of entries to call */
644 if ((Count
= LdrpClearLoadInProgress()))
646 /* Check if we can use our local buffer */
649 /* Allocate space for all the entries */
650 LdrRootEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
652 Count
* sizeof(LdrRootEntry
));
653 if (!LdrRootEntry
) return STATUS_NO_MEMORY
;
657 /* Use our local array */
658 LdrRootEntry
= LocalArray
;
667 /* Show debug message */
670 DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ\n",
671 NtCurrentTeb()->RealClientId
.UniqueThread
,
672 NtCurrentTeb()->RealClientId
.UniqueProcess
,
673 &Peb
->ProcessParameters
->ImagePathName
);
677 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
678 NextEntry
= ListHead
->Flink
;
680 while (NextEntry
!= ListHead
)
682 /* Get the Data Entry */
683 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
685 /* Check if we have a Root Entry */
689 if (!(LdrEntry
->Flags
& LDRP_ENTRY_PROCESSED
))
691 /* Setup the Cookie for the DLL */
692 LdrpInitSecurityCookie(LdrEntry
);
694 /* Check for valid entrypoint */
695 if (LdrEntry
->EntryPoint
)
698 LdrRootEntry
[i
] = LdrEntry
;
700 /* Display debug message */
703 DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
704 NtCurrentTeb()->RealClientId
.UniqueThread
,
705 NtCurrentTeb()->RealClientId
.UniqueProcess
,
706 &LdrEntry
->FullDllName
,
707 LdrEntry
->EntryPoint
);
715 LdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
716 NextEntry
= NextEntry
->Flink
;
719 /* If we got a context, then we have to call Kernel32 for TS support */
722 /* Check if we have one */
723 //if (Kernel32ProcessInitPostImportfunction)
726 //Kernel32ProcessInitPostImportfunction();
730 //Kernel32ProcessInitPostImportfunction = NULL;
734 /* No root entry? return */
735 if (!LdrRootEntry
) return STATUS_SUCCESS
;
737 /* Set the TLD TEB */
738 OldTldTeb
= LdrpTopLevelDllBeingLoadedTeb
;
739 LdrpTopLevelDllBeingLoadedTeb
= NtCurrentTeb();
746 LdrEntry
= LdrRootEntry
[i
];
748 /* FIXME: Verify NX Compat */
750 /* Move to next entry */
753 /* Get its entrypoint */
754 EntryPoint
= LdrEntry
->EntryPoint
;
756 /* Are we being debugged? */
758 if (Peb
->BeingDebugged
|| Peb
->ReadImageFileExecOptions
)
760 /* Check if we should break on load */
761 Status
= LdrQueryImageFileExecutionOptions(&LdrEntry
->BaseDllName
,
767 if (!NT_SUCCESS(Status
)) BreakOnDllLoad
= 0;
769 /* Reset status back to STATUS_SUCCESS */
770 Status
= STATUS_SUCCESS
;
776 /* Check if we should show a message */
779 DPRINT1("LDR: %wZ loaded.", &LdrEntry
->BaseDllName
);
780 DPRINT1(" - About to call init routine at %p\n", EntryPoint
);
783 /* Break in debugger */
787 /* Make sure we have an entrypoint */
790 /* Save the old Dll Initializer and write the current one */
791 OldInitializer
= LdrpCurrentDllInitializer
;
792 LdrpCurrentDllInitializer
= LdrEntry
;
794 /* Set up the Act Ctx */
795 ActCtx
.Size
= sizeof(ActCtx
);
797 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
799 /* Activate the ActCtx */
800 RtlActivateActivationContextUnsafeFast(&ActCtx
,
801 LdrEntry
->EntryPointActivationContext
);
803 /* Check if it has TLS */
804 if (LdrEntry
->TlsIndex
&& Context
)
807 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_ATTACH
);
810 /* Call the Entrypoint */
813 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
814 &LdrEntry
->BaseDllName
, EntryPoint
);
816 DllStatus
= LdrpCallInitRoutine(EntryPoint
,
821 /* Deactivate the ActCtx */
822 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
824 /* Save the Current DLL Initializer */
825 LdrpCurrentDllInitializer
= OldInitializer
;
827 /* Mark the entry as processed */
828 LdrEntry
->Flags
|= LDRP_PROCESS_ATTACH_CALLED
;
830 /* Fail if DLL init failed */
833 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
834 &LdrEntry
->BaseDllName
, EntryPoint
);
836 Status
= STATUS_DLL_INIT_FAILED
;
843 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
844 NextEntry
= NextEntry
->Flink
;
845 while (NextEntry
!= ListHead
)
847 /* Get the Data Entrry */
848 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
850 /* FIXME: Verify NX Compat */
851 // LdrpCheckNXCompatibility()
854 NextEntry
= NextEntry
->Flink
;
858 if (LdrpImageHasTls
&& Context
)
860 /* Set up the Act Ctx */
861 ActCtx
.Size
= sizeof(ActCtx
);
863 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
865 /* Activate the ActCtx */
866 RtlActivateActivationContextUnsafeFast(&ActCtx
,
867 LdrpImageEntry
->EntryPointActivationContext
);
869 /* Do TLS callbacks */
870 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_ATTACH
);
872 /* Deactivate the ActCtx */
873 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
877 /* Restore old TEB */
878 LdrpTopLevelDllBeingLoadedTeb
= OldTldTeb
;
880 /* Check if the array is in the heap */
881 if (LdrRootEntry
!= LocalArray
)
884 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry
);
887 /* Return to caller */
888 DPRINT("LdrpRunInitializeRoutines() done\n");
897 LdrShutdownProcess(VOID
)
899 PPEB Peb
= NtCurrentPeb();
900 PLDR_DATA_TABLE_ENTRY LdrEntry
;
901 PLIST_ENTRY NextEntry
, ListHead
;
902 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
905 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry
->BaseDllName
);
906 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
908 /* Tell the Shim Engine */
920 /* Set the shutdown variables */
921 LdrpShutdownThreadId
= NtCurrentTeb()->RealClientId
.UniqueThread
;
922 LdrpShutdownInProgress
= TRUE
;
924 /* Enter the Loader Lock */
925 RtlEnterCriticalSection(&LdrpLoaderLock
);
927 /* Cleanup trace logging data (Etw) */
928 if (SharedUserData
->TraceLogging
)
931 DPRINT1("We don't support Etw yet.\n");
934 /* Start at the end */
935 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
936 NextEntry
= ListHead
->Blink
;
937 while (NextEntry
!= ListHead
)
939 /* Get the current entry */
940 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
941 NextEntry
= NextEntry
->Blink
;
943 /* Make sure it's not ourselves */
944 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
946 /* Get the entrypoint */
947 EntryPoint
= LdrEntry
->EntryPoint
;
949 /* Check if we are ready to call it */
951 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
954 /* Set up the Act Ctx */
955 ActCtx
.Size
= sizeof(ActCtx
);
957 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
959 /* Activate the ActCtx */
960 RtlActivateActivationContextUnsafeFast(&ActCtx
,
961 LdrEntry
->EntryPointActivationContext
);
963 /* Check if it has TLS */
964 if (LdrEntry
->TlsIndex
)
967 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_PROCESS_DETACH
);
970 /* Call the Entrypoint */
971 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
972 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
973 LdrpCallInitRoutine(EntryPoint
,
978 /* Deactivate the ActCtx */
979 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
987 /* Set up the Act Ctx */
988 ActCtx
.Size
= sizeof(ActCtx
);
990 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
992 /* Activate the ActCtx */
993 RtlActivateActivationContextUnsafeFast(&ActCtx
,
994 LdrpImageEntry
->EntryPointActivationContext
);
996 /* Do TLS callbacks */
997 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_PROCESS_DETACH
);
999 /* Deactivate the ActCtx */
1000 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1003 /* FIXME: Do Heap detection and Etw final shutdown */
1005 /* Release the lock */
1006 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1007 DPRINT("LdrpShutdownProcess() done\n");
1009 return STATUS_SUCCESS
;
1017 LdrShutdownThread(VOID
)
1019 PPEB Peb
= NtCurrentPeb();
1020 PTEB Teb
= NtCurrentTeb();
1021 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1022 PLIST_ENTRY NextEntry
, ListHead
;
1023 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1026 DPRINT("LdrShutdownThread() called for %wZ\n",
1027 &LdrpImageEntry
->BaseDllName
);
1029 /* Cleanup trace logging data (Etw) */
1030 if (SharedUserData
->TraceLogging
)
1033 DPRINT1("We don't support Etw yet.\n");
1036 /* Get the Ldr Lock */
1037 RtlEnterCriticalSection(&LdrpLoaderLock
);
1039 /* Start at the end */
1040 ListHead
= &Peb
->Ldr
->InInitializationOrderModuleList
;
1041 NextEntry
= ListHead
->Blink
;
1042 while (NextEntry
!= ListHead
)
1044 /* Get the current entry */
1045 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
1046 NextEntry
= NextEntry
->Blink
;
1048 /* Make sure it's not ourselves */
1049 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
1051 /* Check if we should call */
1052 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
) &&
1053 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
1054 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
1056 /* Get the entrypoint */
1057 EntryPoint
= LdrEntry
->EntryPoint
;
1059 /* Check if we are ready to call it */
1062 /* Set up the Act Ctx */
1063 ActCtx
.Size
= sizeof(ActCtx
);
1065 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1067 /* Activate the ActCtx */
1068 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1069 LdrEntry
->EntryPointActivationContext
);
1071 /* Check if it has TLS */
1072 if (LdrEntry
->TlsIndex
)
1074 /* Make sure we're not shutting down */
1075 if (!LdrpShutdownInProgress
)
1078 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_DETACH
);
1082 /* Make sure we're not shutting down */
1083 if (!LdrpShutdownInProgress
)
1085 /* Call the Entrypoint */
1086 DPRINT("%wZ - Calling entry point at %x for thread detaching\n",
1087 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
);
1088 LdrpCallInitRoutine(EntryPoint
,
1094 /* Deactivate the ActCtx */
1095 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1102 if (LdrpImageHasTls
)
1104 /* Set up the Act Ctx */
1105 ActCtx
.Size
= sizeof(ActCtx
);
1107 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1109 /* Activate the ActCtx */
1110 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1111 LdrpImageEntry
->EntryPointActivationContext
);
1113 /* Do TLS callbacks */
1114 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_DETACH
);
1116 /* Deactivate the ActCtx */
1117 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1122 RtlLeaveCriticalSection(&LdrpLoaderLock
);
1124 /* Check for expansion slots */
1125 if (Teb
->TlsExpansionSlots
)
1127 /* Free expansion slots */
1128 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->TlsExpansionSlots
);
1131 /* Check for FLS Data */
1135 DPRINT1("We don't support FLS Data yet\n");
1138 /* Check for Fiber data */
1139 if (Teb
->HasFiberData
)
1141 /* Free Fiber data*/
1142 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb
->NtTib
.FiberData
);
1143 Teb
->NtTib
.FiberData
= NULL
;
1146 /* Free the activation context stack */
1147 RtlFreeThreadActivationContextStack();
1148 DPRINT("LdrShutdownThread() done\n");
1150 return STATUS_SUCCESS
;
1155 LdrpInitializeTls(VOID
)
1157 PLIST_ENTRY NextEntry
, ListHead
;
1158 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1159 PIMAGE_TLS_DIRECTORY TlsDirectory
;
1160 PLDRP_TLS_DATA TlsData
;
1163 /* Initialize the TLS List */
1164 InitializeListHead(&LdrpTlsList
);
1166 /* Loop all the modules */
1167 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1168 NextEntry
= ListHead
->Flink
;
1169 while (ListHead
!= NextEntry
)
1172 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1173 NextEntry
= NextEntry
->Flink
;
1175 /* Get the TLS directory */
1176 TlsDirectory
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1178 IMAGE_DIRECTORY_ENTRY_TLS
,
1181 /* Check if we have a directory */
1182 if (!TlsDirectory
) continue;
1184 /* Check if the image has TLS */
1185 if (!LdrpImageHasTls
) LdrpImageHasTls
= TRUE
;
1187 /* Show debug message */
1190 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1191 &LdrEntry
->BaseDllName
,
1195 /* Allocate an entry */
1196 TlsData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA
));
1197 if (!TlsData
) return STATUS_NO_MEMORY
;
1199 /* Lock the DLL and mark it for TLS Usage */
1200 LdrEntry
->LoadCount
= -1;
1201 LdrEntry
->TlsIndex
= -1;
1203 /* Save the cached TLS data */
1204 TlsData
->TlsDirectory
= *TlsDirectory
;
1205 InsertTailList(&LdrpTlsList
, &TlsData
->TlsLinks
);
1207 /* Update the index */
1208 *(PLONG
)TlsData
->TlsDirectory
.AddressOfIndex
= LdrpNumberOfTlsEntries
;
1209 TlsData
->TlsDirectory
.Characteristics
= LdrpNumberOfTlsEntries
++;
1212 /* Done setting up TLS, allocate entries */
1213 return LdrpAllocateTls();
1218 LdrpAllocateTls(VOID
)
1220 PTEB Teb
= NtCurrentTeb();
1221 PLIST_ENTRY NextEntry
, ListHead
;
1222 PLDRP_TLS_DATA TlsData
;
1226 /* Check if we have any entries */
1227 if (!LdrpNumberOfTlsEntries
)
1228 return STATUS_SUCCESS
;
1230 /* Allocate the vector array */
1231 TlsVector
= RtlAllocateHeap(RtlGetProcessHeap(),
1233 LdrpNumberOfTlsEntries
* sizeof(PVOID
));
1234 if (!TlsVector
) return STATUS_NO_MEMORY
;
1235 Teb
->ThreadLocalStoragePointer
= TlsVector
;
1237 /* Loop the TLS Array */
1238 ListHead
= &LdrpTlsList
;
1239 NextEntry
= ListHead
->Flink
;
1240 while (NextEntry
!= ListHead
)
1243 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1244 NextEntry
= NextEntry
->Flink
;
1246 /* Allocate this vector */
1247 TlsDataSize
= TlsData
->TlsDirectory
.EndAddressOfRawData
-
1248 TlsData
->TlsDirectory
.StartAddressOfRawData
;
1249 TlsVector
[TlsData
->TlsDirectory
.Characteristics
] = RtlAllocateHeap(RtlGetProcessHeap(),
1252 if (!TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1255 return STATUS_NO_MEMORY
;
1258 /* Show debug message */
1261 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
1263 TlsData
->TlsDirectory
.Characteristics
,
1264 &TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1265 TlsData
->TlsDirectory
.StartAddressOfRawData
,
1266 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1270 RtlCopyMemory(TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
1271 (PVOID
)TlsData
->TlsDirectory
.StartAddressOfRawData
,
1276 return STATUS_SUCCESS
;
1283 PLIST_ENTRY ListHead
, NextEntry
;
1284 PLDRP_TLS_DATA TlsData
;
1286 PTEB Teb
= NtCurrentTeb();
1288 /* Get a pointer to the vector array */
1289 TlsVector
= Teb
->ThreadLocalStoragePointer
;
1290 if (!TlsVector
) return;
1292 /* Loop through it */
1293 ListHead
= &LdrpTlsList
;
1294 NextEntry
= ListHead
->Flink
;
1295 while (NextEntry
!= ListHead
)
1297 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
1298 NextEntry
= NextEntry
->Flink
;
1300 /* Free each entry */
1301 if (TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
1303 RtlFreeHeap(RtlGetProcessHeap(),
1305 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
1309 /* Free the array itself */
1310 RtlFreeHeap(RtlGetProcessHeap(),
1317 LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName
, PPEB Peb
, BOOLEAN SystemWide
, BOOLEAN ReadAdvancedOptions
)
1319 /* If global flags request DPH, perform some additional actions */
1320 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
1322 // TODO: Read advanced DPH flags from the registry if requested
1323 if (ReadAdvancedOptions
)
1328 /* Enable page heap */
1329 RtlpPageHeapEnabled
= TRUE
;
1332 return STATUS_SUCCESS
;
1337 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName
, PPEB Peb
, PHKEY OptionsKey
)
1341 ULONG ExecuteOptions
, MinimumStackCommit
= 0, GlobalFlag
;
1343 /* Return error if we were not provided a pointer where to save the options key handle */
1344 if (!OptionsKey
) return STATUS_INVALID_HANDLE
;
1346 /* Zero initialize the optinos key pointer */
1349 /* Open the options key */
1350 Status
= LdrOpenImageFileOptionsKey(ImagePathName
, 0, &KeyHandle
);
1352 /* Save it if it was opened successfully */
1353 if (NT_SUCCESS(Status
))
1354 *OptionsKey
= KeyHandle
;
1358 /* There are image specific options, read them starting with NXCOMPAT */
1359 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1363 sizeof(ExecuteOptions
),
1366 if (NT_SUCCESS(Status
))
1368 /* TODO: Set execution options for the process */
1370 if (ExecuteOptions == 0)
1374 ZwSetInformationProcess(NtCurrentProcess(),
1375 ProcessExecuteFlags,
1381 /* Check if this image uses large pages */
1382 if (Peb
->ImageUsesLargePages
)
1384 /* TODO: If it does, open large page key */
1388 /* Get various option values */
1389 LdrQueryImageFileKeyOption(KeyHandle
,
1390 L
"DisableHeapLookaside",
1392 &RtlpDisableHeapLookaside
,
1393 sizeof(RtlpDisableHeapLookaside
),
1396 LdrQueryImageFileKeyOption(KeyHandle
,
1399 &RtlpShutdownProcessFlags
,
1400 sizeof(RtlpShutdownProcessFlags
),
1403 LdrQueryImageFileKeyOption(KeyHandle
,
1404 L
"MinimumStackCommitInBytes",
1406 &MinimumStackCommit
,
1407 sizeof(MinimumStackCommit
),
1410 /* Update PEB's minimum stack commit if it's lower */
1411 if (Peb
->MinimumStackCommit
< MinimumStackCommit
)
1412 Peb
->MinimumStackCommit
= MinimumStackCommit
;
1414 /* Set the global flag */
1415 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1422 if (NT_SUCCESS(Status
))
1423 Peb
->NtGlobalFlag
= GlobalFlag
;
1427 /* Call AVRF if necessary */
1428 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1430 Status
= LdrpInitializeApplicationVerifierPackage(ImagePathName
, Peb
, TRUE
, FALSE
);
1431 if (!NT_SUCCESS(Status
))
1433 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status
);
1439 /* There are no image-specific options, so perform global initialization */
1440 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1442 /* Initialize app verifier package */
1443 Status
= LdrpInitializeApplicationVerifierPackage(ImagePathName
, Peb
, TRUE
, FALSE
);
1444 if (!NT_SUCCESS(Status
))
1446 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status
);
1451 return STATUS_SUCCESS
;
1456 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
)
1463 LdrpInitializeProcess(IN PCONTEXT Context
,
1464 IN PVOID SystemArgument1
)
1466 RTL_HEAP_PARAMETERS HeapParameters
;
1467 ULONG ComSectionSize
;
1468 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1470 OBJECT_ATTRIBUTES ObjectAttributes
;
1471 //UNICODE_STRING LocalFileName, FullImageName;
1472 HANDLE SymLinkHandle
;
1473 //ULONG DebugHeapOnly;
1474 UNICODE_STRING CommandLine
, NtSystemRoot
, ImagePathName
, FullPath
, ImageFileName
, KnownDllString
;
1475 PPEB Peb
= NtCurrentPeb();
1476 BOOLEAN IsDotNetImage
= FALSE
;
1477 BOOLEAN FreeCurDir
= FALSE
;
1479 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
1480 //LPWSTR ImagePathBuffer;
1482 UNICODE_STRING CurrentDirectory
;
1485 PIMAGE_NT_HEADERS NtHeader
;
1486 LPWSTR NtDllName
= NULL
;
1488 NLSTABLEINFO NlsTable
;
1489 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig
;
1490 PTEB Teb
= NtCurrentTeb();
1491 PLIST_ENTRY ListHead
;
1492 PLIST_ENTRY NextEntry
;
1495 ULONG DebugProcessHeapOnly
= 0;
1496 PLDR_DATA_TABLE_ENTRY NtLdrEntry
;
1498 ULONG ExecuteOptions
= 0;
1501 /* Set a NULL SEH Filter */
1502 RtlSetUnhandledExceptionFilter(NULL
);
1504 /* Get the image path */
1505 ImagePath
= Peb
->ProcessParameters
->ImagePathName
.Buffer
;
1507 /* Check if it's not normalized */
1508 if (!(Peb
->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_NORMALIZED
))
1511 ImagePath
= (PWSTR
)((ULONG_PTR
)ImagePath
+ (ULONG_PTR
)Peb
->ProcessParameters
);
1514 /* Create a unicode string for the Image Path */
1515 ImagePathName
.Length
= Peb
->ProcessParameters
->ImagePathName
.Length
;
1516 ImagePathName
.MaximumLength
= ImagePathName
.Length
+ sizeof(WCHAR
);
1517 ImagePathName
.Buffer
= ImagePath
;
1519 /* Get the NT Headers */
1520 NtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1522 /* Get the execution options */
1523 Status
= LdrpInitializeExecutionOptions(&ImagePathName
, Peb
, &OptionsKey
);
1525 /* Check if this is a .NET executable */
1526 if (RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1528 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1531 /* Remeber this for later */
1532 IsDotNetImage
= TRUE
;
1535 /* Save the NTDLL Base address */
1536 NtDllBase
= SystemArgument1
;
1538 /* If this is a Native Image */
1539 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
)
1541 /* Then do DLL Validation */
1542 LdrpDllValidation
= TRUE
;
1545 /* Save the old Shim Data */
1546 OldShimData
= Peb
->pShimData
;
1549 Peb
->pShimData
= NULL
;
1551 /* Save the number of processors and CS Timeout */
1552 LdrpNumberOfProcessors
= Peb
->NumberOfProcessors
;
1553 RtlpTimeout
= Peb
->CriticalSectionTimeout
;
1555 /* Normalize the parameters */
1556 ProcessParameters
= RtlNormalizeProcessParams(Peb
->ProcessParameters
);
1557 ProcessParameters
= Peb
->ProcessParameters
;
1558 if (ProcessParameters
)
1560 /* Save the Image and Command Line Names */
1561 ImageFileName
= ProcessParameters
->ImagePathName
;
1562 CommandLine
= ProcessParameters
->CommandLine
;
1566 /* It failed, initialize empty strings */
1567 RtlInitUnicodeString(&ImageFileName
, NULL
);
1568 RtlInitUnicodeString(&CommandLine
, NULL
);
1571 /* Initialize NLS data */
1572 RtlInitNlsTables(Peb
->AnsiCodePageData
,
1573 Peb
->OemCodePageData
,
1574 Peb
->UnicodeCaseTableData
,
1577 /* Reset NLS Translations */
1578 RtlResetRtlTranslations(&NlsTable
);
1580 /* Get the Image Config Directory */
1581 LoadConfig
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1583 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
1586 /* Setup the Heap Parameters */
1587 RtlZeroMemory(&HeapParameters
, sizeof(RTL_HEAP_PARAMETERS
));
1588 HeapFlags
= HEAP_GROWABLE
;
1589 HeapParameters
.Length
= sizeof(RTL_HEAP_PARAMETERS
);
1591 /* Check if we have Configuration Data */
1592 if ((LoadConfig
) && (ConfigSize
== sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
)))
1594 /* FIXME: Custom heap settings and misc. */
1595 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1598 /* Check for custom affinity mask */
1599 if (Peb
->ImageProcessAffinityMask
)
1602 Status
= NtSetInformationProcess(NtCurrentProcess(),
1603 ProcessAffinityMask
,
1604 &Peb
->ImageProcessAffinityMask
,
1605 sizeof(Peb
->ImageProcessAffinityMask
));
1608 /* Check if verbose debugging (ShowSnaps) was requested */
1609 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
1611 /* Start verbose debugging messages right now if they were requested */
1614 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1615 Teb
->ClientId
.UniqueProcess
,
1619 /* If the timeout is too long */
1620 if (RtlpTimeout
.QuadPart
< Int32x32To64(3600, -10000000))
1622 /* Then disable CS Timeout */
1623 RtlpTimeoutDisable
= TRUE
;
1626 /* Initialize Critical Section Data */
1627 RtlpInitDeferedCriticalSection();
1629 /* Initialize VEH Call lists */
1630 RtlpInitializeVectoredExceptionHandling();
1632 /* Set TLS/FLS Bitmap data */
1633 Peb
->FlsBitmap
= &FlsBitMap
;
1634 Peb
->TlsBitmap
= &TlsBitMap
;
1635 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
1637 /* Initialize FLS Bitmap */
1638 RtlInitializeBitMap(&FlsBitMap
,
1640 FLS_MAXIMUM_AVAILABLE
);
1641 RtlSetBit(&FlsBitMap
, 0);
1643 /* Initialize TLS Bitmap */
1644 RtlInitializeBitMap(&TlsBitMap
,
1646 TLS_MINIMUM_AVAILABLE
);
1647 RtlSetBit(&TlsBitMap
, 0);
1648 RtlInitializeBitMap(&TlsExpansionBitMap
,
1649 Peb
->TlsExpansionBitmapBits
,
1650 TLS_EXPANSION_SLOTS
);
1651 RtlSetBit(&TlsExpansionBitMap
, 0);
1653 /* Initialize the Hash Table */
1654 for (i
= 0; i
< LDR_HASH_TABLE_ENTRIES
; i
++)
1656 InitializeListHead(&LdrpHashTable
[i
]);
1659 /* Initialize the Loader Lock */
1660 // FIXME: What's the point of initing it manually, if two lines lower
1661 // a call to RtlInitializeCriticalSection() is being made anyway?
1662 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1663 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1664 RtlInitializeCriticalSection(&LdrpLoaderLock
);
1665 LdrpLoaderLockInit
= TRUE
;
1667 /* Check if User Stack Trace Database support was requested */
1668 if (Peb
->NtGlobalFlag
& FLG_USER_STACK_TRACE_DB
)
1670 DPRINT1("We don't support user stack trace databases yet\n");
1673 /* Setup Fast PEB Lock */
1674 RtlInitializeCriticalSection(&FastPebLock
);
1675 Peb
->FastPebLock
= &FastPebLock
;
1676 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1677 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1679 /* Setup Callout Lock and Notification list */
1680 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1681 InitializeListHead(&LdrpDllNotificationList
);
1683 /* For old executables, use 16-byte aligned heap */
1684 if ((NtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3) &&
1685 (NtHeader
->OptionalHeader
.MinorSubsystemVersion
< 51))
1687 HeapFlags
|= HEAP_CREATE_ALIGN_16
;
1690 /* Setup the Heap */
1691 RtlInitializeHeapManager();
1692 Peb
->ProcessHeap
= RtlCreateHeap(HeapFlags
,
1694 NtHeader
->OptionalHeader
.SizeOfHeapReserve
,
1695 NtHeader
->OptionalHeader
.SizeOfHeapCommit
,
1699 if (!Peb
->ProcessHeap
)
1701 DPRINT1("Failed to create process heap\n");
1702 return STATUS_NO_MEMORY
;
1705 // FIXME: Is it located properly?
1706 /* Initialize table of callbacks for the kernel. */
1707 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
1710 (USER32_CALLBACK_MAXIMUM
+ 1));
1711 if (!Peb
->KernelCallbackTable
)
1713 DPRINT1("Failed to create callback table\n");
1714 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
1717 /* Allocate an Activation Context Stack */
1718 Status
= RtlAllocateActivationContextStack((PVOID
*)&Teb
->ActivationContextStackPointer
);
1719 if (!NT_SUCCESS(Status
)) return Status
;
1721 // FIXME: Loader private heap is missing
1722 //DPRINT1("Loader private heap is missing\n");
1724 /* Check for Debug Heap */
1727 /* Query the setting */
1728 Status
= LdrQueryImageFileKeyOption(OptionsKey
,
1729 L
"DebugProcessHeapOnly",
1731 &DebugProcessHeapOnly
,
1735 if (NT_SUCCESS(Status
))
1737 /* Reset DPH if requested */
1738 if (RtlpPageHeapEnabled
&& DebugProcessHeapOnly
)
1740 RtlpDphGlobalFlags
&= ~DPH_FLAG_DLL_NOTIFY
;
1741 RtlpPageHeapEnabled
= FALSE
;
1746 /* Build the NTDLL Path */
1747 FullPath
.Buffer
= StringBuffer
;
1748 FullPath
.Length
= 0;
1749 FullPath
.MaximumLength
= sizeof(StringBuffer
);
1750 RtlInitUnicodeString(&NtSystemRoot
, SharedUserData
->NtSystemRoot
);
1751 RtlAppendUnicodeStringToString(&FullPath
, &NtSystemRoot
);
1752 RtlAppendUnicodeToString(&FullPath
, L
"\\System32\\");
1754 /* Open the Known DLLs directory */
1755 RtlInitUnicodeString(&KnownDllString
, L
"\\KnownDlls");
1756 InitializeObjectAttributes(&ObjectAttributes
,
1758 OBJ_CASE_INSENSITIVE
,
1761 Status
= ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory
,
1762 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1765 /* Check if it exists */
1766 if (NT_SUCCESS(Status
))
1768 /* Open the Known DLLs Path */
1769 RtlInitUnicodeString(&KnownDllString
, L
"KnownDllPath");
1770 InitializeObjectAttributes(&ObjectAttributes
,
1772 OBJ_CASE_INSENSITIVE
,
1773 LdrpKnownDllObjectDirectory
,
1775 Status
= NtOpenSymbolicLinkObject(&SymLinkHandle
,
1776 SYMBOLIC_LINK_QUERY
,
1778 if (NT_SUCCESS(Status
))
1780 /* Query the path */
1781 LdrpKnownDllPath
.Length
= 0;
1782 LdrpKnownDllPath
.MaximumLength
= sizeof(LdrpKnownDllPathBuffer
);
1783 LdrpKnownDllPath
.Buffer
= LdrpKnownDllPathBuffer
;
1784 Status
= ZwQuerySymbolicLinkObject(SymLinkHandle
, &LdrpKnownDllPath
, NULL
);
1785 NtClose(SymLinkHandle
);
1786 if (!NT_SUCCESS(Status
))
1788 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status
);
1794 /* Check if we failed */
1795 if (!NT_SUCCESS(Status
))
1797 /* Aassume System32 */
1798 LdrpKnownDllObjectDirectory
= NULL
;
1799 RtlInitUnicodeString(&LdrpKnownDllPath
, StringBuffer
);
1800 LdrpKnownDllPath
.Length
-= sizeof(WCHAR
);
1803 /* If we have process parameters, get the default path and current path */
1804 if (ProcessParameters
)
1806 /* Check if we have a Dll Path */
1807 if (ProcessParameters
->DllPath
.Length
)
1810 LdrpDefaultPath
= *(PUNICODE_STRING
)&ProcessParameters
->DllPath
;
1814 /* We need a valid path */
1815 DPRINT1("No valid DllPath was given!\n");
1816 LdrpInitFailure(STATUS_INVALID_PARAMETER
);
1819 /* Set the current directory */
1820 CurrentDirectory
= ProcessParameters
->CurrentDirectory
.DosPath
;
1822 /* Check if it's empty or invalid */
1823 if ((!CurrentDirectory
.Buffer
) ||
1824 (CurrentDirectory
.Buffer
[0] == UNICODE_NULL
) ||
1825 (!CurrentDirectory
.Length
))
1827 /* Allocate space for the buffer */
1828 CurrentDirectory
.Buffer
= RtlAllocateHeap(Peb
->ProcessHeap
,
1831 sizeof(UNICODE_NULL
));
1832 if (!CurrentDirectory
.Buffer
)
1834 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1838 /* Copy the drive of the system root */
1839 RtlMoveMemory(CurrentDirectory
.Buffer
,
1840 SharedUserData
->NtSystemRoot
,
1842 CurrentDirectory
.Buffer
[3] = UNICODE_NULL
;
1843 CurrentDirectory
.Length
= 3 * sizeof(WCHAR
);
1844 CurrentDirectory
.MaximumLength
= CurrentDirectory
.Length
+ sizeof(WCHAR
);
1847 DPRINT("Using dynamically allocd curdir\n");
1851 /* Use the local buffer */
1852 DPRINT("Using local system root\n");
1856 /* Setup Loader Data */
1858 InitializeListHead(&PebLdr
.InLoadOrderModuleList
);
1859 InitializeListHead(&PebLdr
.InMemoryOrderModuleList
);
1860 InitializeListHead(&PebLdr
.InInitializationOrderModuleList
);
1861 PebLdr
.Length
= sizeof(PEB_LDR_DATA
);
1862 PebLdr
.Initialized
= TRUE
;
1864 /* Allocate a data entry for the Image */
1865 LdrpImageEntry
= NtLdrEntry
= LdrpAllocateDataTableEntry(Peb
->ImageBaseAddress
);
1868 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1869 NtLdrEntry
->LoadCount
= -1;
1870 NtLdrEntry
->EntryPointActivationContext
= 0;
1871 NtLdrEntry
->FullDllName
= ImageFileName
;
1874 NtLdrEntry
->Flags
= LDRP_COR_IMAGE
;
1876 NtLdrEntry
->Flags
= 0;
1878 /* Check if the name is empty */
1879 if (!ImageFileName
.Buffer
[0])
1881 /* Use the same Base name */
1882 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1886 /* Find the last slash */
1887 Current
= ImageFileName
.Buffer
;
1890 if (*Current
++ == '\\')
1893 NtDllName
= Current
;
1897 /* Did we find anything? */
1900 /* Use the same Base name */
1901 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1905 /* Setup the name */
1906 NtLdrEntry
->BaseDllName
.Length
= (USHORT
)((ULONG_PTR
)ImageFileName
.Buffer
+ ImageFileName
.Length
- (ULONG_PTR
)NtDllName
);
1907 NtLdrEntry
->BaseDllName
.MaximumLength
= NtLdrEntry
->BaseDllName
.Length
+ sizeof(WCHAR
);
1908 NtLdrEntry
->BaseDllName
.Buffer
= (PWSTR
)((ULONG_PTR
)ImageFileName
.Buffer
+
1909 (ImageFileName
.Length
- NtLdrEntry
->BaseDllName
.Length
));
1913 /* Processing done, insert it */
1914 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1915 NtLdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
1917 /* Now add an entry for NTDLL */
1918 NtLdrEntry
= LdrpAllocateDataTableEntry(SystemArgument1
);
1919 NtLdrEntry
->Flags
= LDRP_IMAGE_DLL
;
1920 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1921 NtLdrEntry
->LoadCount
= -1;
1922 NtLdrEntry
->EntryPointActivationContext
= 0;
1924 NtLdrEntry
->FullDllName
.Length
= FullPath
.Length
;
1925 NtLdrEntry
->FullDllName
.MaximumLength
= FullPath
.MaximumLength
;
1926 NtLdrEntry
->FullDllName
.Buffer
= StringBuffer
;
1927 RtlAppendUnicodeStringToString(&NtLdrEntry
->FullDllName
, &NtDllString
);
1929 NtLdrEntry
->BaseDllName
.Length
= NtDllString
.Length
;
1930 NtLdrEntry
->BaseDllName
.MaximumLength
= NtDllString
.MaximumLength
;
1931 NtLdrEntry
->BaseDllName
.Buffer
= NtDllString
.Buffer
;
1933 /* Processing done, insert it */
1934 LdrpNtDllDataTableEntry
= NtLdrEntry
;
1935 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1937 /* Let the world know */
1940 DPRINT1("LDR: NEW PROCESS\n");
1941 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry
->FullDllName
, &LdrpImageEntry
->BaseDllName
);
1942 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory
);
1943 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath
);
1946 /* Link the Init Order List */
1947 InsertHeadList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1948 &LdrpNtDllDataTableEntry
->InInitializationOrderModuleList
);
1950 /* Set the current directory */
1951 Status
= RtlSetCurrentDirectory_U(&CurrentDirectory
);
1952 if (!NT_SUCCESS(Status
))
1954 /* We failed, check if we should free it */
1955 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1957 /* Set it to the NT Root */
1958 CurrentDirectory
= NtSystemRoot
;
1959 RtlSetCurrentDirectory_U(&CurrentDirectory
);
1963 /* We're done with it, free it */
1964 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1967 /* Check if we should look for a .local file */
1968 if (ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
)
1971 DPRINT1("We don't support .local overrides yet\n");
1974 /* Check if the Application Verifier was enabled */
1975 if (Peb
->NtGlobalFlag
& FLG_POOL_ENABLE_TAIL_CHECK
)
1978 DPRINT1("We don't support Application Verifier yet\n");
1984 DPRINT1("We don't support .NET applications yet\n");
1987 /* FIXME: Load support for Terminal Services */
1988 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1990 /* Load kernel32 and call BasePostImportInit... */
1991 DPRINT("Unimplemented codepath!\n");
1994 /* Walk the IAT and load all the DLLs */
1995 LdrpWalkImportDescriptor(LdrpDefaultPath
.Buffer
, LdrpImageEntry
);
1997 /* Check if relocation is needed */
1998 if (Peb
->ImageBaseAddress
!= (PVOID
)NtHeader
->OptionalHeader
.ImageBase
)
2000 DPRINT1("LDR: Performing EXE relocation\n");
2002 /* Change the protection to prepare for relocation */
2003 ViewBase
= Peb
->ImageBaseAddress
;
2004 Status
= LdrpSetProtection(ViewBase
, FALSE
);
2005 if (!NT_SUCCESS(Status
)) return Status
;
2007 /* Do the relocation */
2008 Status
= LdrRelocateImageWithBias(ViewBase
,
2012 STATUS_CONFLICTING_ADDRESSES
,
2013 STATUS_INVALID_IMAGE_FORMAT
);
2014 if (!NT_SUCCESS(Status
))
2016 DPRINT1("LdrRelocateImageWithBias() failed\n");
2020 /* Check if a start context was provided */
2023 DPRINT1("WARNING: Relocated EXE Context");
2024 UNIMPLEMENTED
; // We should support this
2025 return STATUS_INVALID_IMAGE_FORMAT
;
2028 /* Restore the protection */
2029 Status
= LdrpSetProtection(ViewBase
, TRUE
);
2030 if (!NT_SUCCESS(Status
)) return Status
;
2034 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
2035 NextEntry
= ListHead
->Flink
;
2036 while (ListHead
!= NextEntry
)
2038 NtLdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2039 NtLdrEntry
->LoadCount
= -1;
2040 NextEntry
= NextEntry
->Flink
;
2043 /* Phase 0 is done */
2044 LdrpLdrDatabaseIsSetup
= TRUE
;
2046 /* Initialize TLS */
2047 Status
= LdrpInitializeTls();
2048 if (!NT_SUCCESS(Status
))
2050 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2055 /* FIXME Mark the DLL Ranges for Stack Traces later */
2057 /* Notify the debugger now */
2058 if (Peb
->BeingDebugged
)
2063 /* Update show snaps again */
2064 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
2067 /* Validate the Image for MP Usage */
2068 if (LdrpNumberOfProcessors
> 1) LdrpValidateImageForMp(LdrpImageEntry
);
2070 /* Check NX Options */
2071 if (SharedUserData
->NXSupportPolicy
== 1)
2073 ExecuteOptions
= 0xD;
2075 else if (!SharedUserData
->NXSupportPolicy
)
2077 ExecuteOptions
= 0xA;
2081 ZwSetInformationProcess(NtCurrentProcess(),
2082 ProcessExecuteFlags
,
2086 /* Check if we had Shim Data */
2089 /* Load the Shim Engine */
2090 Peb
->AppCompatInfo
= NULL
;
2091 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
2092 DPRINT1("We do not support shims yet\n");
2096 /* Check for Application Compatibility Goo */
2097 //LdrQueryApplicationCompatibilityGoo(hKey);
2098 DPRINT("Querying app compat hacks is missing!\n");
2102 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2103 * incompatible images.
2106 /* Now call the Init Routines */
2107 Status
= LdrpRunInitializeRoutines(Context
);
2108 if (!NT_SUCCESS(Status
))
2110 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2115 /* FIXME: Unload the Shim Engine if it was loaded */
2117 /* Check if we have a user-defined Post Process Routine */
2118 if (NT_SUCCESS(Status
) && Peb
->PostProcessInitRoutine
)
2121 Peb
->PostProcessInitRoutine();
2124 /* Close the key if we have one opened */
2125 if (OptionsKey
) NtClose(OptionsKey
);
2133 LdrpInitFailure(NTSTATUS Status
)
2136 PPEB Peb
= NtCurrentPeb();
2138 /* Print a debug message */
2139 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2140 &Peb
->ProcessParameters
->ImagePathName
, Status
);
2142 /* Raise a hard error */
2143 if (!LdrpFatalHardErrorCount
)
2145 ZwRaiseHardError(STATUS_APP_INIT_FAILURE
, 1, 0, (PULONG_PTR
)&Status
, OptionOk
, &Response
);
2151 LdrpInit(PCONTEXT Context
,
2152 PVOID SystemArgument1
,
2153 PVOID SystemArgument2
)
2155 LARGE_INTEGER Timeout
;
2156 PTEB Teb
= NtCurrentTeb();
2157 NTSTATUS Status
, LoaderStatus
= STATUS_SUCCESS
;
2158 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
2159 PPEB Peb
= NtCurrentPeb();
2161 DPRINT("LdrpInit() %lx/%lx\n",
2162 NtCurrentTeb()->RealClientId
.UniqueProcess
,
2163 NtCurrentTeb()->RealClientId
.UniqueThread
);
2165 /* Check if we have a deallocation stack */
2166 if (!Teb
->DeallocationStack
)
2168 /* We don't, set one */
2169 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
2170 Teb
->NtTib
.StackLimit
,
2171 MemoryBasicInformation
,
2173 sizeof(MEMORY_BASIC_INFORMATION
),
2175 if (!NT_SUCCESS(Status
))
2178 LdrpInitFailure(Status
);
2179 RtlRaiseStatus(Status
);
2184 Teb
->DeallocationStack
= MemoryBasicInfo
.AllocationBase
;
2187 /* Now check if the process is already being initialized */
2188 while (_InterlockedCompareExchange(&LdrpProcessInitialized
,
2192 /* Set the timeout to 30 seconds */
2193 Timeout
.QuadPart
= Int32x32To64(30, -10000);
2195 /* Make sure the status hasn't changed */
2196 while (!LdrpProcessInitialized
)
2199 ZwDelayExecution(FALSE
, &Timeout
);
2203 /* Check if we have already setup LDR data */
2206 /* Setup the Loader Lock */
2207 Peb
->LoaderLock
= &LdrpLoaderLock
;
2209 /* Let other code know we're initializing */
2210 LdrpInLdrInit
= TRUE
;
2212 /* Protect with SEH */
2215 /* Initialize the Process */
2216 LoaderStatus
= LdrpInitializeProcess(Context
,
2219 /* Check for success and if MinimumStackCommit was requested */
2220 if (NT_SUCCESS(LoaderStatus
) && Peb
->MinimumStackCommit
)
2222 /* Enforce the limit */
2223 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2229 /* Fail with the SEH error */
2230 LoaderStatus
= _SEH2_GetExceptionCode();
2234 /* We're not initializing anymore */
2235 LdrpInLdrInit
= FALSE
;
2237 /* Check if init worked */
2238 if (NT_SUCCESS(LoaderStatus
))
2240 /* Set the process as Initialized */
2241 _InterlockedIncrement(&LdrpProcessInitialized
);
2246 /* Loader data is there... is this a fork() ? */
2247 if(Peb
->InheritedAddressSpace
)
2249 /* Handle the fork() */
2250 //LoaderStatus = LdrpForkProcess();
2251 LoaderStatus
= STATUS_NOT_IMPLEMENTED
;
2256 /* This is a new thread initializing */
2257 LdrpInitializeThread(Context
);
2261 /* All done, test alert the thread */
2265 if (!NT_SUCCESS(LoaderStatus
))
2268 LdrpInitFailure(LoaderStatus
);
2269 RtlRaiseStatus(LoaderStatus
);