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 HANDLE ImageExecOptionsKey
;
22 HANDLE 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
);
90 void actctx_init(void);
93 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
95 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
98 /* FUNCTIONS *****************************************************************/
105 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey
,
107 OUT PHANDLE NewKeyHandle
)
109 PHANDLE RootKeyLocation
;
111 UNICODE_STRING SubKeyString
;
112 OBJECT_ATTRIBUTES ObjectAttributes
;
116 /* Check which root key to open */
118 RootKeyLocation
= &Wow64ExecOptionsKey
;
120 RootKeyLocation
= &ImageExecOptionsKey
;
122 /* Get the current key */
123 RootKey
= *RootKeyLocation
;
125 /* Setup the object attributes */
126 InitializeObjectAttributes(&ObjectAttributes
,
128 &Wow64OptionsString
: &ImageExecOptionsString
,
129 OBJ_CASE_INSENSITIVE
,
133 /* Open the root key */
134 Status
= ZwOpenKey(&RootKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
135 if (NT_SUCCESS(Status
))
137 /* Write the key handle */
138 if (_InterlockedCompareExchange((LONG
*)RootKeyLocation
, (LONG
)RootKey
, 0) != 0)
140 /* Someone already opened it, use it instead */
142 RootKey
= *RootKeyLocation
;
145 /* Extract the name */
146 SubKeyString
= *SubKey
;
147 p1
= (PWCHAR
)((ULONG_PTR
)SubKeyString
.Buffer
+ SubKeyString
.Length
);
148 while (SubKeyString
.Length
)
150 if (p1
[-1] == L
'\\') break;
152 SubKeyString
.Length
-= sizeof(*p1
);
154 SubKeyString
.Buffer
= p1
;
155 SubKeyString
.Length
= SubKey
->Length
- SubKeyString
.Length
;
157 /* Setup the object attributes */
158 InitializeObjectAttributes(&ObjectAttributes
,
160 OBJ_CASE_INSENSITIVE
,
164 /* Open the setting key */
165 Status
= ZwOpenKey((PHANDLE
)NewKeyHandle
, GENERIC_READ
, &ObjectAttributes
);
168 /* Return to caller */
177 LdrQueryImageFileKeyOption(IN HANDLE KeyHandle
,
182 OUT PULONG ReturnedLength OPTIONAL
)
185 UNICODE_STRING ValueNameString
, IntegerString
;
186 ULONG KeyInfoSize
, ResultSize
;
187 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)&KeyInfo
;
188 BOOLEAN FreeHeap
= FALSE
;
191 /* Build a string for the value name */
192 Status
= RtlInitUnicodeStringEx(&ValueNameString
, ValueName
);
193 if (!NT_SUCCESS(Status
)) return Status
;
195 /* Query the value */
196 Status
= ZwQueryValueKey(KeyHandle
,
198 KeyValuePartialInformation
,
202 if (Status
== STATUS_BUFFER_OVERFLOW
)
204 /* Our local buffer wasn't enough, allocate one */
205 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
206 KeyValueInformation
->DataLength
;
207 KeyValueInformation
= RtlAllocateHeap(RtlGetProcessHeap(),
210 if (KeyValueInformation
== NULL
)
212 /* Give up this time */
213 Status
= STATUS_NO_MEMORY
;
217 Status
= ZwQueryValueKey(KeyHandle
,
219 KeyValuePartialInformation
,
226 /* Check for success */
227 if (NT_SUCCESS(Status
))
229 /* Handle binary data */
230 if (KeyValueInformation
->Type
== REG_BINARY
)
233 if ((Buffer
) && (KeyValueInformation
->DataLength
<= BufferSize
))
235 /* Copy into buffer */
236 RtlMoveMemory(Buffer
,
237 &KeyValueInformation
->Data
,
238 KeyValueInformation
->DataLength
);
242 Status
= STATUS_BUFFER_OVERFLOW
;
245 /* Copy the result length */
246 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
248 else if (KeyValueInformation
->Type
== REG_DWORD
)
250 /* Check for valid type */
251 if (KeyValueInformation
->Type
!= Type
)
254 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
260 (BufferSize
== sizeof(ULONG
)) &&
261 (KeyValueInformation
->DataLength
<= BufferSize
))
263 /* Copy into buffer */
264 RtlMoveMemory(Buffer
,
265 &KeyValueInformation
->Data
,
266 KeyValueInformation
->DataLength
);
270 Status
= STATUS_BUFFER_OVERFLOW
;
273 /* Copy the result length */
274 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
277 else if (KeyValueInformation
->Type
!= REG_SZ
)
279 /* We got something weird */
280 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
284 /* String, check what you requested */
285 if (Type
== REG_DWORD
)
288 if (BufferSize
!= sizeof(ULONG
))
292 Status
= STATUS_INFO_LENGTH_MISMATCH
;
296 /* OK, we know what you want... */
297 IntegerString
.Buffer
= (PWSTR
)KeyValueInformation
->Data
;
298 IntegerString
.Length
= (USHORT
)KeyValueInformation
->DataLength
-
300 IntegerString
.MaximumLength
= (USHORT
)KeyValueInformation
->DataLength
;
301 Status
= RtlUnicodeStringToInteger(&IntegerString
, 0, (PULONG
)Buffer
);
307 if (KeyValueInformation
->DataLength
> BufferSize
)
310 Status
= STATUS_BUFFER_OVERFLOW
;
315 BufferSize
= KeyValueInformation
->DataLength
;
318 /* Copy the string */
319 RtlMoveMemory(Buffer
, &KeyValueInformation
->Data
, BufferSize
);
322 /* Copy the result length */
323 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
327 /* Check if buffer was in heap */
328 if (FreeHeap
) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation
);
339 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey
,
344 OUT PULONG ReturnedLength OPTIONAL
,
350 /* Open a handle to the key */
351 Status
= LdrOpenImageFileOptionsKey(SubKey
, Wow64
, &KeyHandle
);
353 /* Check for success */
354 if (NT_SUCCESS(Status
))
357 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
368 /* Return to caller */
377 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey
,
382 OUT PULONG ReturnedLength OPTIONAL
)
384 /* Call the newer function */
385 return LdrQueryImageFileExecutionOptionsEx(SubKey
,
396 LdrpEnsureLoaderLockIsHeld()
403 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress
, ULONG SizeOfImage
)
405 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir
;
409 /* Check NT header first */
410 if (!RtlImageNtHeader(BaseAddress
)) return NULL
;
412 /* Get the pointer to the config directory */
413 ConfigDir
= RtlImageDirectoryEntryToData(BaseAddress
,
415 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
418 /* Check for sanity */
420 (DirSize
!= 64 && ConfigDir
->Size
!= DirSize
) ||
421 (ConfigDir
->Size
< 0x48))
424 /* Now get the cookie */
425 Cookie
= (PVOID
)ConfigDir
->SecurityCookie
;
427 /* Check this cookie */
428 if ((PCHAR
)Cookie
<= (PCHAR
)BaseAddress
||
429 (PCHAR
)Cookie
>= (PCHAR
)BaseAddress
+ SizeOfImage
)
434 /* Return validated security cookie */
440 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry
)
443 LARGE_INTEGER Counter
;
446 /* Fetch address of the cookie */
447 Cookie
= LdrpFetchAddressOfSecurityCookie(LdrEntry
->DllBase
, LdrEntry
->SizeOfImage
);
451 /* Check if it's a default one */
452 if ((*Cookie
== DEFAULT_SECURITY_COOKIE
) ||
455 /* Make up a cookie from a bunch of values which may uniquely represent
456 current moment of time, environment, etc */
457 NtQueryPerformanceCounter(&Counter
, NULL
);
459 NewCookie
= Counter
.LowPart
^ Counter
.HighPart
;
460 NewCookie
^= (ULONG
)NtCurrentTeb()->ClientId
.UniqueProcess
;
461 NewCookie
^= (ULONG
)NtCurrentTeb()->ClientId
.UniqueThread
;
463 /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
464 while (SharedUserData
->SystemTime
.High1Time
!= SharedUserData
->SystemTime
.High2Time
)
469 /* Calculate the milliseconds value and xor it to the cookie */
470 NewCookie
^= Int64ShrlMod32(UInt32x32To64(SharedUserData
->TickCountMultiplier
, SharedUserData
->TickCount
.LowPart
), 24) +
471 (SharedUserData
->TickCountMultiplier
* (SharedUserData
->TickCount
.High1Time
<< 8));
473 /* Make the cookie 16bit if necessary */
474 if (*Cookie
== 0xBB40) NewCookie
&= 0xFFFF;
476 /* If the result is 0 or the same as we got, just subtract one from the existing value
478 if ((NewCookie
== 0) || (NewCookie
== *Cookie
))
480 NewCookie
= *Cookie
- 1;
483 /* Set the new cookie value */
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 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer
);
509 Status
= RtlAllocateActivationContextStack((PVOID
*)&NtCurrentTeb()->ActivationContextStackPointer
);
510 if (!NT_SUCCESS(Status
))
512 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
515 /* Make sure we are not shutting down */
516 if (LdrpShutdownInProgress
) return;
521 /* Start at the beginning */
522 ListHead
= &Peb
->Ldr
->InMemoryOrderModuleList
;
523 NextEntry
= ListHead
->Flink
;
524 while (NextEntry
!= ListHead
)
526 /* Get the current entry */
527 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
529 /* Make sure it's not ourselves */
530 if (Peb
->ImageBaseAddress
!= LdrEntry
->DllBase
)
532 /* Check if we should call */
533 if (!(LdrEntry
->Flags
& LDRP_DONT_CALL_FOR_THREADS
))
535 /* Get the entrypoint */
536 EntryPoint
= LdrEntry
->EntryPoint
;
538 /* Check if we are ready to call it */
540 (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
) &&
541 (LdrEntry
->Flags
& LDRP_IMAGE_DLL
))
543 /* Set up the Act Ctx */
544 ActCtx
.Size
= sizeof(ActCtx
);
546 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
548 /* Activate the ActCtx */
549 RtlActivateActivationContextUnsafeFast(&ActCtx
,
550 LdrEntry
->EntryPointActivationContext
);
552 /* Check if it has TLS */
553 if (LdrEntry
->TlsIndex
)
555 /* Make sure we're not shutting down */
556 if (!LdrpShutdownInProgress
)
559 LdrpCallTlsInitializers(LdrEntry
->DllBase
, DLL_THREAD_ATTACH
);
563 /* Make sure we're not shutting down */
564 if (!LdrpShutdownInProgress
)
566 /* Call the Entrypoint */
567 DPRINT("%wZ - Calling entry point at %p for thread attaching, %lx/%lx\n",
568 &LdrEntry
->BaseDllName
, LdrEntry
->EntryPoint
,
569 NtCurrentTeb()->RealClientId
.UniqueProcess
,
570 NtCurrentTeb()->RealClientId
.UniqueThread
);
571 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
577 /* Deactivate the ActCtx */
578 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
584 NextEntry
= NextEntry
->Flink
;
588 if (LdrpImageHasTls
&& !LdrpShutdownInProgress
)
590 /* Set up the Act Ctx */
591 ActCtx
.Size
= sizeof(ActCtx
);
593 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
595 /* Activate the ActCtx */
596 RtlActivateActivationContextUnsafeFast(&ActCtx
,
597 LdrpImageEntry
->EntryPointActivationContext
);
599 /* Do TLS callbacks */
600 LdrpCallTlsInitializers(Peb
->ImageBaseAddress
, DLL_THREAD_ATTACH
);
602 /* Deactivate the ActCtx */
603 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
606 DPRINT("LdrpInitializeThread() done\n");
611 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL
)
613 PLDR_DATA_TABLE_ENTRY LocalArray
[16];
614 PLIST_ENTRY ListHead
;
615 PLIST_ENTRY NextEntry
;
616 PLDR_DATA_TABLE_ENTRY LdrEntry
, *LdrRootEntry
, OldInitializer
;
620 NTSTATUS Status
= STATUS_SUCCESS
;
621 PPEB Peb
= NtCurrentPeb();
622 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
623 ULONG BreakOnDllLoad
;
627 DPRINT("LdrpRunInitializeRoutines() called for %wZ (%lx/%lx)\n",
628 &LdrpImageEntry
->BaseDllName
,
629 NtCurrentTeb()->RealClientId
.UniqueProcess
,
630 NtCurrentTeb()->RealClientId
.UniqueThread
);
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 LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName
, PPEB Peb
, BOOLEAN SystemWide
, BOOLEAN ReadAdvancedOptions
)
1311 /* If global flags request DPH, perform some additional actions */
1312 if (Peb
->NtGlobalFlag
& FLG_HEAP_PAGE_ALLOCS
)
1314 // TODO: Read advanced DPH flags from the registry if requested
1315 if (ReadAdvancedOptions
)
1320 /* Enable page heap */
1321 RtlpPageHeapEnabled
= TRUE
;
1324 return STATUS_SUCCESS
;
1329 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName
, PPEB Peb
, PHANDLE OptionsKey
)
1333 ULONG ExecuteOptions
, MinimumStackCommit
= 0, GlobalFlag
;
1335 /* Return error if we were not provided a pointer where to save the options key handle */
1336 if (!OptionsKey
) return STATUS_INVALID_HANDLE
;
1338 /* Zero initialize the optinos key pointer */
1341 /* Open the options key */
1342 Status
= LdrOpenImageFileOptionsKey(ImagePathName
, 0, &KeyHandle
);
1344 /* Save it if it was opened successfully */
1345 if (NT_SUCCESS(Status
))
1346 *OptionsKey
= KeyHandle
;
1350 /* There are image specific options, read them starting with NXCOMPAT */
1351 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1355 sizeof(ExecuteOptions
),
1358 if (NT_SUCCESS(Status
))
1360 /* TODO: Set execution options for the process */
1362 if (ExecuteOptions == 0)
1366 ZwSetInformationProcess(NtCurrentProcess(),
1367 ProcessExecuteFlags,
1373 /* Check if this image uses large pages */
1374 if (Peb
->ImageUsesLargePages
)
1376 /* TODO: If it does, open large page key */
1380 /* Get various option values */
1381 LdrQueryImageFileKeyOption(KeyHandle
,
1382 L
"DisableHeapLookaside",
1384 &RtlpDisableHeapLookaside
,
1385 sizeof(RtlpDisableHeapLookaside
),
1388 LdrQueryImageFileKeyOption(KeyHandle
,
1391 &RtlpShutdownProcessFlags
,
1392 sizeof(RtlpShutdownProcessFlags
),
1395 LdrQueryImageFileKeyOption(KeyHandle
,
1396 L
"MinimumStackCommitInBytes",
1398 &MinimumStackCommit
,
1399 sizeof(MinimumStackCommit
),
1402 /* Update PEB's minimum stack commit if it's lower */
1403 if (Peb
->MinimumStackCommit
< MinimumStackCommit
)
1404 Peb
->MinimumStackCommit
= MinimumStackCommit
;
1406 /* Set the global flag */
1407 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
1414 if (NT_SUCCESS(Status
))
1415 Peb
->NtGlobalFlag
= GlobalFlag
;
1419 /* Call AVRF if necessary */
1420 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1422 Status
= LdrpInitializeApplicationVerifierPackage(ImagePathName
, Peb
, TRUE
, FALSE
);
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status
);
1431 /* There are no image-specific options, so perform global initialization */
1432 if (Peb
->NtGlobalFlag
& (FLG_POOL_ENABLE_TAIL_CHECK
| FLG_HEAP_PAGE_ALLOCS
))
1434 /* Initialize app verifier package */
1435 Status
= LdrpInitializeApplicationVerifierPackage(ImagePathName
, Peb
, TRUE
, FALSE
);
1436 if (!NT_SUCCESS(Status
))
1438 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status
);
1443 return STATUS_SUCCESS
;
1448 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
)
1455 LdrpInitializeProcess(IN PCONTEXT Context
,
1456 IN PVOID SystemArgument1
)
1458 RTL_HEAP_PARAMETERS HeapParameters
;
1459 ULONG ComSectionSize
;
1460 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1462 OBJECT_ATTRIBUTES ObjectAttributes
;
1463 //UNICODE_STRING LocalFileName, FullImageName;
1464 HANDLE SymLinkHandle
;
1465 //ULONG DebugHeapOnly;
1466 UNICODE_STRING CommandLine
, NtSystemRoot
, ImagePathName
, FullPath
, ImageFileName
, KnownDllString
;
1467 PPEB Peb
= NtCurrentPeb();
1468 BOOLEAN IsDotNetImage
= FALSE
;
1469 BOOLEAN FreeCurDir
= FALSE
;
1471 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
1472 //LPWSTR ImagePathBuffer;
1474 UNICODE_STRING CurrentDirectory
;
1477 PIMAGE_NT_HEADERS NtHeader
;
1478 LPWSTR NtDllName
= NULL
;
1480 NLSTABLEINFO NlsTable
;
1481 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig
;
1482 PTEB Teb
= NtCurrentTeb();
1483 PLIST_ENTRY ListHead
;
1484 PLIST_ENTRY NextEntry
;
1487 ULONG DebugProcessHeapOnly
= 0;
1488 PLDR_DATA_TABLE_ENTRY NtLdrEntry
;
1490 ULONG ExecuteOptions
= 0;
1493 /* Set a NULL SEH Filter */
1494 RtlSetUnhandledExceptionFilter(NULL
);
1496 /* Get the image path */
1497 ImagePath
= Peb
->ProcessParameters
->ImagePathName
.Buffer
;
1499 /* Check if it's not normalized */
1500 if (!(Peb
->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_NORMALIZED
))
1503 ImagePath
= (PWSTR
)((ULONG_PTR
)ImagePath
+ (ULONG_PTR
)Peb
->ProcessParameters
);
1506 /* Create a unicode string for the Image Path */
1507 ImagePathName
.Length
= Peb
->ProcessParameters
->ImagePathName
.Length
;
1508 ImagePathName
.MaximumLength
= ImagePathName
.Length
+ sizeof(WCHAR
);
1509 ImagePathName
.Buffer
= ImagePath
;
1511 /* Get the NT Headers */
1512 NtHeader
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
1514 /* Get the execution options */
1515 Status
= LdrpInitializeExecutionOptions(&ImagePathName
, Peb
, &OptionsKey
);
1517 /* Check if this is a .NET executable */
1518 if (RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1520 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1523 /* Remeber this for later */
1524 IsDotNetImage
= TRUE
;
1527 /* Save the NTDLL Base address */
1528 NtDllBase
= SystemArgument1
;
1530 /* If this is a Native Image */
1531 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
)
1533 /* Then do DLL Validation */
1534 LdrpDllValidation
= TRUE
;
1537 /* Save the old Shim Data */
1538 OldShimData
= Peb
->pShimData
;
1541 Peb
->pShimData
= NULL
;
1543 /* Save the number of processors and CS Timeout */
1544 LdrpNumberOfProcessors
= Peb
->NumberOfProcessors
;
1545 RtlpTimeout
= Peb
->CriticalSectionTimeout
;
1547 /* Normalize the parameters */
1548 ProcessParameters
= RtlNormalizeProcessParams(Peb
->ProcessParameters
);
1549 ProcessParameters
= Peb
->ProcessParameters
;
1550 if (ProcessParameters
)
1552 /* Save the Image and Command Line Names */
1553 ImageFileName
= ProcessParameters
->ImagePathName
;
1554 CommandLine
= ProcessParameters
->CommandLine
;
1558 /* It failed, initialize empty strings */
1559 RtlInitUnicodeString(&ImageFileName
, NULL
);
1560 RtlInitUnicodeString(&CommandLine
, NULL
);
1563 /* Initialize NLS data */
1564 RtlInitNlsTables(Peb
->AnsiCodePageData
,
1565 Peb
->OemCodePageData
,
1566 Peb
->UnicodeCaseTableData
,
1569 /* Reset NLS Translations */
1570 RtlResetRtlTranslations(&NlsTable
);
1572 /* Get the Image Config Directory */
1573 LoadConfig
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
1575 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
1578 /* Setup the Heap Parameters */
1579 RtlZeroMemory(&HeapParameters
, sizeof(RTL_HEAP_PARAMETERS
));
1580 HeapFlags
= HEAP_GROWABLE
;
1581 HeapParameters
.Length
= sizeof(RTL_HEAP_PARAMETERS
);
1583 /* Check if we have Configuration Data */
1584 if ((LoadConfig
) && (ConfigSize
== sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
)))
1586 /* FIXME: Custom heap settings and misc. */
1587 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1590 /* Check for custom affinity mask */
1591 if (Peb
->ImageProcessAffinityMask
)
1594 Status
= NtSetInformationProcess(NtCurrentProcess(),
1595 ProcessAffinityMask
,
1596 &Peb
->ImageProcessAffinityMask
,
1597 sizeof(Peb
->ImageProcessAffinityMask
));
1600 /* Check if verbose debugging (ShowSnaps) was requested */
1601 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
1603 /* Start verbose debugging messages right now if they were requested */
1606 DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
1607 Teb
->ClientId
.UniqueProcess
,
1611 /* If the timeout is too long */
1612 if (RtlpTimeout
.QuadPart
< Int32x32To64(3600, -10000000))
1614 /* Then disable CS Timeout */
1615 RtlpTimeoutDisable
= TRUE
;
1618 /* Initialize Critical Section Data */
1619 RtlpInitDeferedCriticalSection();
1621 /* Initialize VEH Call lists */
1622 RtlpInitializeVectoredExceptionHandling();
1624 /* Set TLS/FLS Bitmap data */
1625 Peb
->FlsBitmap
= &FlsBitMap
;
1626 Peb
->TlsBitmap
= &TlsBitMap
;
1627 Peb
->TlsExpansionBitmap
= &TlsExpansionBitMap
;
1629 /* Initialize FLS Bitmap */
1630 RtlInitializeBitMap(&FlsBitMap
,
1632 FLS_MAXIMUM_AVAILABLE
);
1633 RtlSetBit(&FlsBitMap
, 0);
1635 /* Initialize TLS Bitmap */
1636 RtlInitializeBitMap(&TlsBitMap
,
1638 TLS_MINIMUM_AVAILABLE
);
1639 RtlSetBit(&TlsBitMap
, 0);
1640 RtlInitializeBitMap(&TlsExpansionBitMap
,
1641 Peb
->TlsExpansionBitmapBits
,
1642 TLS_EXPANSION_SLOTS
);
1643 RtlSetBit(&TlsExpansionBitMap
, 0);
1645 /* Initialize the Hash Table */
1646 for (i
= 0; i
< LDR_HASH_TABLE_ENTRIES
; i
++)
1648 InitializeListHead(&LdrpHashTable
[i
]);
1651 /* Initialize the Loader Lock */
1652 // FIXME: What's the point of initing it manually, if two lines lower
1653 // a call to RtlInitializeCriticalSection() is being made anyway?
1654 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1655 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1656 RtlInitializeCriticalSection(&LdrpLoaderLock
);
1657 LdrpLoaderLockInit
= TRUE
;
1659 /* Check if User Stack Trace Database support was requested */
1660 if (Peb
->NtGlobalFlag
& FLG_USER_STACK_TRACE_DB
)
1662 DPRINT1("We don't support user stack trace databases yet\n");
1665 /* Setup Fast PEB Lock */
1666 RtlInitializeCriticalSection(&FastPebLock
);
1667 Peb
->FastPebLock
= &FastPebLock
;
1668 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1669 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1671 /* Setup Callout Lock and Notification list */
1672 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1673 InitializeListHead(&LdrpDllNotificationList
);
1675 /* For old executables, use 16-byte aligned heap */
1676 if ((NtHeader
->OptionalHeader
.MajorSubsystemVersion
<= 3) &&
1677 (NtHeader
->OptionalHeader
.MinorSubsystemVersion
< 51))
1679 HeapFlags
|= HEAP_CREATE_ALIGN_16
;
1682 /* Setup the Heap */
1683 RtlInitializeHeapManager();
1684 Peb
->ProcessHeap
= RtlCreateHeap(HeapFlags
,
1686 NtHeader
->OptionalHeader
.SizeOfHeapReserve
,
1687 NtHeader
->OptionalHeader
.SizeOfHeapCommit
,
1691 if (!Peb
->ProcessHeap
)
1693 DPRINT1("Failed to create process heap\n");
1694 return STATUS_NO_MEMORY
;
1697 // FIXME: Is it located properly?
1698 /* Initialize table of callbacks for the kernel. */
1699 Peb
->KernelCallbackTable
= RtlAllocateHeap(RtlGetProcessHeap(),
1702 (USER32_CALLBACK_MAXIMUM
+ 1));
1703 if (!Peb
->KernelCallbackTable
)
1705 DPRINT1("Failed to create callback table\n");
1706 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
1709 /* Allocate an Activation Context Stack */
1710 Status
= RtlAllocateActivationContextStack((PVOID
*)&Teb
->ActivationContextStackPointer
);
1711 if (!NT_SUCCESS(Status
)) return Status
;
1713 // FIXME: Loader private heap is missing
1714 //DPRINT1("Loader private heap is missing\n");
1716 /* Check for Debug Heap */
1719 /* Query the setting */
1720 Status
= LdrQueryImageFileKeyOption(OptionsKey
,
1721 L
"DebugProcessHeapOnly",
1723 &DebugProcessHeapOnly
,
1727 if (NT_SUCCESS(Status
))
1729 /* Reset DPH if requested */
1730 if (RtlpPageHeapEnabled
&& DebugProcessHeapOnly
)
1732 RtlpDphGlobalFlags
&= ~DPH_FLAG_DLL_NOTIFY
;
1733 RtlpPageHeapEnabled
= FALSE
;
1738 /* Build the NTDLL Path */
1739 FullPath
.Buffer
= StringBuffer
;
1740 FullPath
.Length
= 0;
1741 FullPath
.MaximumLength
= sizeof(StringBuffer
);
1742 RtlInitUnicodeString(&NtSystemRoot
, SharedUserData
->NtSystemRoot
);
1743 RtlAppendUnicodeStringToString(&FullPath
, &NtSystemRoot
);
1744 RtlAppendUnicodeToString(&FullPath
, L
"\\System32\\");
1746 /* Open the Known DLLs directory */
1747 RtlInitUnicodeString(&KnownDllString
, L
"\\KnownDlls");
1748 InitializeObjectAttributes(&ObjectAttributes
,
1750 OBJ_CASE_INSENSITIVE
,
1753 Status
= ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory
,
1754 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1757 /* Check if it exists */
1758 if (NT_SUCCESS(Status
))
1760 /* Open the Known DLLs Path */
1761 RtlInitUnicodeString(&KnownDllString
, L
"KnownDllPath");
1762 InitializeObjectAttributes(&ObjectAttributes
,
1764 OBJ_CASE_INSENSITIVE
,
1765 LdrpKnownDllObjectDirectory
,
1767 Status
= NtOpenSymbolicLinkObject(&SymLinkHandle
,
1768 SYMBOLIC_LINK_QUERY
,
1770 if (NT_SUCCESS(Status
))
1772 /* Query the path */
1773 LdrpKnownDllPath
.Length
= 0;
1774 LdrpKnownDllPath
.MaximumLength
= sizeof(LdrpKnownDllPathBuffer
);
1775 LdrpKnownDllPath
.Buffer
= LdrpKnownDllPathBuffer
;
1776 Status
= ZwQuerySymbolicLinkObject(SymLinkHandle
, &LdrpKnownDllPath
, NULL
);
1777 NtClose(SymLinkHandle
);
1778 if (!NT_SUCCESS(Status
))
1780 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status
);
1786 /* Check if we failed */
1787 if (!NT_SUCCESS(Status
))
1789 /* Aassume System32 */
1790 LdrpKnownDllObjectDirectory
= NULL
;
1791 RtlInitUnicodeString(&LdrpKnownDllPath
, StringBuffer
);
1792 LdrpKnownDllPath
.Length
-= sizeof(WCHAR
);
1795 /* If we have process parameters, get the default path and current path */
1796 if (ProcessParameters
)
1798 /* Check if we have a Dll Path */
1799 if (ProcessParameters
->DllPath
.Length
)
1802 LdrpDefaultPath
= *(PUNICODE_STRING
)&ProcessParameters
->DllPath
;
1806 /* We need a valid path */
1807 DPRINT1("No valid DllPath was given!\n");
1808 LdrpInitFailure(STATUS_INVALID_PARAMETER
);
1811 /* Set the current directory */
1812 CurrentDirectory
= ProcessParameters
->CurrentDirectory
.DosPath
;
1814 /* Check if it's empty or invalid */
1815 if ((!CurrentDirectory
.Buffer
) ||
1816 (CurrentDirectory
.Buffer
[0] == UNICODE_NULL
) ||
1817 (!CurrentDirectory
.Length
))
1819 /* Allocate space for the buffer */
1820 CurrentDirectory
.Buffer
= RtlAllocateHeap(Peb
->ProcessHeap
,
1823 sizeof(UNICODE_NULL
));
1824 if (!CurrentDirectory
.Buffer
)
1826 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1830 /* Copy the drive of the system root */
1831 RtlMoveMemory(CurrentDirectory
.Buffer
,
1832 SharedUserData
->NtSystemRoot
,
1834 CurrentDirectory
.Buffer
[3] = UNICODE_NULL
;
1835 CurrentDirectory
.Length
= 3 * sizeof(WCHAR
);
1836 CurrentDirectory
.MaximumLength
= CurrentDirectory
.Length
+ sizeof(WCHAR
);
1839 DPRINT("Using dynamically allocd curdir\n");
1843 /* Use the local buffer */
1844 DPRINT("Using local system root\n");
1848 /* Setup Loader Data */
1850 InitializeListHead(&PebLdr
.InLoadOrderModuleList
);
1851 InitializeListHead(&PebLdr
.InMemoryOrderModuleList
);
1852 InitializeListHead(&PebLdr
.InInitializationOrderModuleList
);
1853 PebLdr
.Length
= sizeof(PEB_LDR_DATA
);
1854 PebLdr
.Initialized
= TRUE
;
1856 /* Allocate a data entry for the Image */
1857 LdrpImageEntry
= NtLdrEntry
= LdrpAllocateDataTableEntry(Peb
->ImageBaseAddress
);
1860 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1861 NtLdrEntry
->LoadCount
= -1;
1862 NtLdrEntry
->EntryPointActivationContext
= 0;
1863 NtLdrEntry
->FullDllName
= ImageFileName
;
1866 NtLdrEntry
->Flags
= LDRP_COR_IMAGE
;
1868 NtLdrEntry
->Flags
= 0;
1870 /* Check if the name is empty */
1871 if (!ImageFileName
.Buffer
[0])
1873 /* Use the same Base name */
1874 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1878 /* Find the last slash */
1879 Current
= ImageFileName
.Buffer
;
1882 if (*Current
++ == '\\')
1885 NtDllName
= Current
;
1889 /* Did we find anything? */
1892 /* Use the same Base name */
1893 NtLdrEntry
->BaseDllName
= NtLdrEntry
->FullDllName
;
1897 /* Setup the name */
1898 NtLdrEntry
->BaseDllName
.Length
= (USHORT
)((ULONG_PTR
)ImageFileName
.Buffer
+ ImageFileName
.Length
- (ULONG_PTR
)NtDllName
);
1899 NtLdrEntry
->BaseDllName
.MaximumLength
= NtLdrEntry
->BaseDllName
.Length
+ sizeof(WCHAR
);
1900 NtLdrEntry
->BaseDllName
.Buffer
= (PWSTR
)((ULONG_PTR
)ImageFileName
.Buffer
+
1901 (ImageFileName
.Length
- NtLdrEntry
->BaseDllName
.Length
));
1905 /* Processing done, insert it */
1906 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1907 NtLdrEntry
->Flags
|= LDRP_ENTRY_PROCESSED
;
1909 /* Now add an entry for NTDLL */
1910 NtLdrEntry
= LdrpAllocateDataTableEntry(SystemArgument1
);
1911 NtLdrEntry
->Flags
= LDRP_IMAGE_DLL
;
1912 NtLdrEntry
->EntryPoint
= LdrpFetchAddressOfEntryPoint(NtLdrEntry
->DllBase
);
1913 NtLdrEntry
->LoadCount
= -1;
1914 NtLdrEntry
->EntryPointActivationContext
= 0;
1916 NtLdrEntry
->FullDllName
.Length
= FullPath
.Length
;
1917 NtLdrEntry
->FullDllName
.MaximumLength
= FullPath
.MaximumLength
;
1918 NtLdrEntry
->FullDllName
.Buffer
= StringBuffer
;
1919 RtlAppendUnicodeStringToString(&NtLdrEntry
->FullDllName
, &NtDllString
);
1921 NtLdrEntry
->BaseDllName
.Length
= NtDllString
.Length
;
1922 NtLdrEntry
->BaseDllName
.MaximumLength
= NtDllString
.MaximumLength
;
1923 NtLdrEntry
->BaseDllName
.Buffer
= NtDllString
.Buffer
;
1925 /* Processing done, insert it */
1926 LdrpNtDllDataTableEntry
= NtLdrEntry
;
1927 LdrpInsertMemoryTableEntry(NtLdrEntry
);
1929 /* Let the world know */
1932 DPRINT1("LDR: NEW PROCESS\n");
1933 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry
->FullDllName
, &LdrpImageEntry
->BaseDllName
);
1934 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory
);
1935 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath
);
1938 /* Link the Init Order List */
1939 InsertHeadList(&Peb
->Ldr
->InInitializationOrderModuleList
,
1940 &LdrpNtDllDataTableEntry
->InInitializationOrderModuleList
);
1942 /* Initialize Wine's active context implementation for the current process */
1945 /* Set the current directory */
1946 Status
= RtlSetCurrentDirectory_U(&CurrentDirectory
);
1947 if (!NT_SUCCESS(Status
))
1949 /* We failed, check if we should free it */
1950 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1952 /* Set it to the NT Root */
1953 CurrentDirectory
= NtSystemRoot
;
1954 RtlSetCurrentDirectory_U(&CurrentDirectory
);
1958 /* We're done with it, free it */
1959 if (FreeCurDir
) RtlFreeUnicodeString(&CurrentDirectory
);
1962 /* Check if we should look for a .local file */
1963 if (ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
)
1966 DPRINT1("We don't support .local overrides yet\n");
1969 /* Check if the Application Verifier was enabled */
1970 if (Peb
->NtGlobalFlag
& FLG_POOL_ENABLE_TAIL_CHECK
)
1973 DPRINT1("We don't support Application Verifier yet\n");
1979 DPRINT1("We don't support .NET applications yet\n");
1982 /* FIXME: Load support for Terminal Services */
1983 if (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_GUI
)
1985 /* Load kernel32 and call BasePostImportInit... */
1986 DPRINT("Unimplemented codepath!\n");
1989 /* Walk the IAT and load all the DLLs */
1990 LdrpWalkImportDescriptor(LdrpDefaultPath
.Buffer
, LdrpImageEntry
);
1992 /* Check if relocation is needed */
1993 if (Peb
->ImageBaseAddress
!= (PVOID
)NtHeader
->OptionalHeader
.ImageBase
)
1995 DPRINT1("LDR: Performing EXE relocation\n");
1997 /* Change the protection to prepare for relocation */
1998 ViewBase
= Peb
->ImageBaseAddress
;
1999 Status
= LdrpSetProtection(ViewBase
, FALSE
);
2000 if (!NT_SUCCESS(Status
)) return Status
;
2002 /* Do the relocation */
2003 Status
= LdrRelocateImageWithBias(ViewBase
,
2007 STATUS_CONFLICTING_ADDRESSES
,
2008 STATUS_INVALID_IMAGE_FORMAT
);
2009 if (!NT_SUCCESS(Status
))
2011 DPRINT1("LdrRelocateImageWithBias() failed\n");
2015 /* Check if a start context was provided */
2018 DPRINT1("WARNING: Relocated EXE Context");
2019 UNIMPLEMENTED
; // We should support this
2020 return STATUS_INVALID_IMAGE_FORMAT
;
2023 /* Restore the protection */
2024 Status
= LdrpSetProtection(ViewBase
, TRUE
);
2025 if (!NT_SUCCESS(Status
)) return Status
;
2029 ListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
2030 NextEntry
= ListHead
->Flink
;
2031 while (ListHead
!= NextEntry
)
2033 NtLdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
2034 NtLdrEntry
->LoadCount
= -1;
2035 NextEntry
= NextEntry
->Flink
;
2038 /* Phase 0 is done */
2039 LdrpLdrDatabaseIsSetup
= TRUE
;
2041 /* Initialize TLS */
2042 Status
= LdrpInitializeTls();
2043 if (!NT_SUCCESS(Status
))
2045 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2050 /* FIXME Mark the DLL Ranges for Stack Traces later */
2052 /* Notify the debugger now */
2053 if (Peb
->BeingDebugged
)
2058 /* Update show snaps again */
2059 ShowSnaps
= Peb
->NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
;
2062 /* Validate the Image for MP Usage */
2063 if (LdrpNumberOfProcessors
> 1) LdrpValidateImageForMp(LdrpImageEntry
);
2065 /* Check NX Options */
2066 if (SharedUserData
->NXSupportPolicy
== 1)
2068 ExecuteOptions
= 0xD;
2070 else if (!SharedUserData
->NXSupportPolicy
)
2072 ExecuteOptions
= 0xA;
2076 ZwSetInformationProcess(NtCurrentProcess(),
2077 ProcessExecuteFlags
,
2081 /* Check if we had Shim Data */
2084 /* Load the Shim Engine */
2085 Peb
->AppCompatInfo
= NULL
;
2086 //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
2087 DPRINT1("We do not support shims yet\n");
2091 /* Check for Application Compatibility Goo */
2092 //LdrQueryApplicationCompatibilityGoo(hKey);
2093 DPRINT("Querying app compat hacks is missing!\n");
2097 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2098 * incompatible images.
2101 /* Now call the Init Routines */
2102 Status
= LdrpRunInitializeRoutines(Context
);
2103 if (!NT_SUCCESS(Status
))
2105 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2110 /* FIXME: Unload the Shim Engine if it was loaded */
2112 /* Check if we have a user-defined Post Process Routine */
2113 if (NT_SUCCESS(Status
) && Peb
->PostProcessInitRoutine
)
2116 Peb
->PostProcessInitRoutine();
2119 /* Close the key if we have one opened */
2120 if (OptionsKey
) NtClose(OptionsKey
);
2128 LdrpInitFailure(NTSTATUS Status
)
2131 PPEB Peb
= NtCurrentPeb();
2133 /* Print a debug message */
2134 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2135 &Peb
->ProcessParameters
->ImagePathName
, Status
);
2137 /* Raise a hard error */
2138 if (!LdrpFatalHardErrorCount
)
2140 ZwRaiseHardError(STATUS_APP_INIT_FAILURE
, 1, 0, (PULONG_PTR
)&Status
, OptionOk
, &Response
);
2146 LdrpInit(PCONTEXT Context
,
2147 PVOID SystemArgument1
,
2148 PVOID SystemArgument2
)
2150 LARGE_INTEGER Timeout
;
2151 PTEB Teb
= NtCurrentTeb();
2152 NTSTATUS Status
, LoaderStatus
= STATUS_SUCCESS
;
2153 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
2154 PPEB Peb
= NtCurrentPeb();
2156 DPRINT("LdrpInit() %lx/%lx\n",
2157 NtCurrentTeb()->RealClientId
.UniqueProcess
,
2158 NtCurrentTeb()->RealClientId
.UniqueThread
);
2160 /* Check if we have a deallocation stack */
2161 if (!Teb
->DeallocationStack
)
2163 /* We don't, set one */
2164 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
2165 Teb
->NtTib
.StackLimit
,
2166 MemoryBasicInformation
,
2168 sizeof(MEMORY_BASIC_INFORMATION
),
2170 if (!NT_SUCCESS(Status
))
2173 LdrpInitFailure(Status
);
2174 RtlRaiseStatus(Status
);
2179 Teb
->DeallocationStack
= MemoryBasicInfo
.AllocationBase
;
2182 /* Now check if the process is already being initialized */
2183 while (_InterlockedCompareExchange(&LdrpProcessInitialized
,
2187 /* Set the timeout to 30 seconds */
2188 Timeout
.QuadPart
= Int32x32To64(30, -10000);
2190 /* Make sure the status hasn't changed */
2191 while (!LdrpProcessInitialized
)
2194 ZwDelayExecution(FALSE
, &Timeout
);
2198 /* Check if we have already setup LDR data */
2201 /* Setup the Loader Lock */
2202 Peb
->LoaderLock
= &LdrpLoaderLock
;
2204 /* Let other code know we're initializing */
2205 LdrpInLdrInit
= TRUE
;
2207 /* Protect with SEH */
2210 /* Initialize the Process */
2211 LoaderStatus
= LdrpInitializeProcess(Context
,
2214 /* Check for success and if MinimumStackCommit was requested */
2215 if (NT_SUCCESS(LoaderStatus
) && Peb
->MinimumStackCommit
)
2217 /* Enforce the limit */
2218 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2222 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2224 /* Fail with the SEH error */
2225 LoaderStatus
= _SEH2_GetExceptionCode();
2229 /* We're not initializing anymore */
2230 LdrpInLdrInit
= FALSE
;
2232 /* Check if init worked */
2233 if (NT_SUCCESS(LoaderStatus
))
2235 /* Set the process as Initialized */
2236 _InterlockedIncrement(&LdrpProcessInitialized
);
2241 /* Loader data is there... is this a fork() ? */
2242 if(Peb
->InheritedAddressSpace
)
2244 /* Handle the fork() */
2245 //LoaderStatus = LdrpForkProcess();
2246 LoaderStatus
= STATUS_NOT_IMPLEMENTED
;
2251 /* This is a new thread initializing */
2252 LdrpInitializeThread(Context
);
2256 /* All done, test alert the thread */
2260 if (!NT_SUCCESS(LoaderStatus
))
2263 LdrpInitFailure(LoaderStatus
);
2264 RtlRaiseStatus(LoaderStatus
);