[NTDLL/LDR]
[reactos.git] / reactos / dll / ntdll / ldr / startup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: dll/ntdll/ldr/startup.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15 #include <win32k/callback.h>
16
17 VOID RtlInitializeHeapManager(VOID);
18 VOID LdrpInitLoader(VOID);
19 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
20 NTSTATUS LdrpAttachThread(VOID);
21 VOID RtlpInitializeVectoredExceptionHandling(VOID);
22 extern PTEB LdrpTopLevelDllBeingLoadedTeb;
23
24 /* GLOBALS *******************************************************************/
25
26 PLDR_DATA_TABLE_ENTRY ExeModule;
27 static RTL_CRITICAL_SECTION PebLock;
28 static RTL_BITMAP TlsBitMap;
29 static RTL_BITMAP TlsExpansionBitMap;
30 static volatile BOOLEAN LdrpInitialized = FALSE;
31 static LONG LdrpInitLock = 0;
32
33 #define VALUE_BUFFER_SIZE 256
34
35 /* FUNCTIONS *****************************************************************/
36
37 BOOLEAN
38 FASTCALL
39 ReadCompatibilitySetting(HANDLE Key,
40 LPWSTR Value,
41 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo,
42 DWORD * Buffer)
43 {
44 UNICODE_STRING ValueName;
45 NTSTATUS Status;
46 ULONG Length;
47
48 RtlInitUnicodeString(&ValueName, Value);
49 Status = NtQueryValueKey(Key,
50 &ValueName,
51 KeyValuePartialInformation,
52 ValueInfo,
53 VALUE_BUFFER_SIZE,
54 &Length);
55
56 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
57 {
58 RtlFreeUnicodeString(&ValueName);
59 return FALSE;
60 }
61
62 RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
63 RtlFreeUnicodeString(&ValueName);
64 return TRUE;
65 }
66
67 VOID
68 FASTCALL
69 LoadImageFileExecutionOptions(PPEB Peb)
70 {
71 NTSTATUS Status = STATUS_SUCCESS;
72 ULONG Value = 0;
73 UNICODE_STRING ImageName;
74 UNICODE_STRING ImagePathName;
75 ULONG ValueSize;
76 extern ULONG RtlpDphGlobalFlags, RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
77 extern ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
78 extern WCHAR RtlpDphTargetDlls[512];
79 extern BOOLEAN RtlpPageHeapEnabled;
80
81 if (Peb->ProcessParameters &&
82 Peb->ProcessParameters->ImagePathName.Length > 0)
83 {
84 DPRINT("%wZ\n", &Peb->ProcessParameters->ImagePathName);
85
86 ImagePathName = Peb->ProcessParameters->ImagePathName;
87 ImageName.Buffer = ImagePathName.Buffer + ImagePathName.Length / sizeof(WCHAR);
88 ImageName.Length = 0;
89
90 while (ImagePathName.Buffer < ImageName.Buffer)
91 {
92 ImageName.Buffer--;
93 if (*ImageName.Buffer == L'\\')
94 {
95 ImageName.Buffer++;
96 break;
97 }
98 }
99
100 ImageName.Length = ImagePathName.Length -
101 (ImageName.Buffer - ImagePathName.Buffer) * sizeof(WCHAR);
102 ImageName.MaximumLength = ImageName.Length +
103 ImagePathName.MaximumLength - ImagePathName.Length;
104
105 DPRINT("%wZ\n", &ImageName);
106
107 /* global flag */
108 Status = LdrQueryImageFileExecutionOptions(&ImageName,
109 L"GlobalFlag",
110 REG_DWORD,
111 (PVOID)&Value,
112 sizeof(Value),
113 &ValueSize);
114 if (NT_SUCCESS(Status))
115 {
116 Peb->NtGlobalFlag = Value;
117 DPRINT("GlobalFlag: Value=0x%lx\n", Value);
118 }
119 else
120 {
121 /* Add debugging flags if there is no GlobalFlags override */
122 if (Peb->BeingDebugged)
123 {
124 Peb->NtGlobalFlag |= FLG_HEAP_VALIDATE_PARAMETERS |
125 FLG_HEAP_ENABLE_FREE_CHECK |
126 FLG_HEAP_ENABLE_TAIL_CHECK;
127 }
128 }
129
130 /* Handle the case when page heap is enabled */
131 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
132 {
133 /* Disable all heap debugging flags so that no heap call goes via page heap branch */
134 Peb->NtGlobalFlag &= ~(FLG_HEAP_VALIDATE_PARAMETERS |
135 FLG_HEAP_VALIDATE_ALL |
136 FLG_HEAP_ENABLE_FREE_CHECK |
137 FLG_HEAP_ENABLE_TAIL_CHECK |
138 FLG_USER_STACK_TRACE_DB |
139 FLG_HEAP_ENABLE_TAGGING |
140 FLG_HEAP_ENABLE_TAG_BY_DLL);
141
142 /* Get page heap flags without checking return value */
143 LdrQueryImageFileExecutionOptions(&ImageName,
144 L"PageHeapFlags",
145 REG_DWORD,
146 (PVOID)&RtlpDphGlobalFlags,
147 sizeof(RtlpDphGlobalFlags),
148 &ValueSize);
149
150 LdrQueryImageFileExecutionOptions(&ImageName,
151 L"PageHeapSizeRangeStart",
152 REG_DWORD,
153 (PVOID)&RtlpPageHeapSizeRangeStart,
154 sizeof(RtlpPageHeapSizeRangeStart),
155 &ValueSize);
156
157 LdrQueryImageFileExecutionOptions(&ImageName,
158 L"PageHeapSizeRangeEnd",
159 REG_DWORD,
160 (PVOID)&RtlpPageHeapSizeRangeEnd,
161 sizeof(RtlpPageHeapSizeRangeEnd),
162 &ValueSize);
163
164 LdrQueryImageFileExecutionOptions(&ImageName,
165 L"PageHeapDllRangeStart",
166 REG_DWORD,
167 (PVOID)&RtlpPageHeapDllRangeStart,
168 sizeof(RtlpPageHeapDllRangeStart),
169 &ValueSize);
170
171 LdrQueryImageFileExecutionOptions(&ImageName,
172 L"PageHeapDllRangeEnd",
173 REG_DWORD,
174 (PVOID)&RtlpPageHeapDllRangeEnd,
175 sizeof(RtlpPageHeapDllRangeEnd),
176 &ValueSize);
177
178 LdrQueryImageFileExecutionOptions(&ImageName,
179 L"PageHeapTargetDlls",
180 REG_SZ,
181 (PVOID)RtlpDphTargetDlls,
182 sizeof(RtlpDphTargetDlls),
183 &ValueSize);
184
185 /* Now when all parameters are read, enable page heap */
186 RtlpPageHeapEnabled = TRUE;
187 }
188 }
189 }
190
191 BOOLEAN
192 FASTCALL
193 LoadCompatibilitySettings(PPEB Peb)
194 {
195 NTSTATUS Status;
196 HANDLE UserKey = NULL;
197 HANDLE KeyHandle;
198 HANDLE SubKeyHandle;
199 OBJECT_ATTRIBUTES ObjectAttributes;
200 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(
201 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
202 UNICODE_STRING ValueName;
203 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
204 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
205 ULONG Length;
206 DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
207 SPMajorVersion, SPMinorVersion = 0;
208
209 if (Peb->ProcessParameters &&
210 (Peb->ProcessParameters->ImagePathName.Length > 0))
211 {
212 Status = RtlOpenCurrentUser(KEY_READ, &UserKey);
213 if (!NT_SUCCESS(Status))
214 {
215 return FALSE;
216 }
217
218 InitializeObjectAttributes(&ObjectAttributes,
219 &KeyName,
220 OBJ_CASE_INSENSITIVE,
221 UserKey,
222 NULL);
223
224 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
225
226 if (!NT_SUCCESS(Status))
227 {
228 if (UserKey)
229 NtClose(UserKey);
230 return FALSE;
231 }
232
233 /* query version name for application */
234 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer;
235 Status = NtQueryValueKey(KeyHandle,
236 &Peb->ProcessParameters->ImagePathName,
237 KeyValuePartialInformation,
238 ValueBuffer,
239 VALUE_BUFFER_SIZE,
240 &Length);
241
242 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
243 {
244 NtClose(KeyHandle);
245 if (UserKey)
246 NtClose(UserKey);
247 return FALSE;
248 }
249
250 ValueName.Length = ValueInfo->DataLength;
251 ValueName.MaximumLength = ValueInfo->DataLength;
252 ValueName.Buffer = (PWSTR) ValueInfo->Data;
253
254 /* load version info */
255 InitializeObjectAttributes(&ObjectAttributes,
256 &ValueName,
257 OBJ_CASE_INSENSITIVE,
258 KeyHandle,
259 NULL);
260
261 Status = NtOpenKey(&SubKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
262
263 if (!NT_SUCCESS(Status))
264 {
265 NtClose(KeyHandle);
266 if (UserKey)
267 NtClose(UserKey);
268 return FALSE;
269 }
270
271 DPRINT("Loading version information for: %wZ\n", &ValueName);
272
273 /* read settings from registry */
274 if (!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
275 goto finish;
276 if (!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
277 goto finish;
278 if (!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
279 goto finish;
280 if (!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
281 goto finish;
282
283 /* now assign the settings */
284 Peb->OSMajorVersion = (ULONG) MajorVersion;
285 Peb->OSMinorVersion = (ULONG) MinorVersion;
286 Peb->OSBuildNumber = (USHORT) BuildNumber;
287 Peb->OSPlatformId = (ULONG) PlatformId;
288
289 /* optional service pack version numbers */
290 if (ReadCompatibilitySetting(SubKeyHandle,
291 L"SPMajorVersion",
292 ValueInfo,
293 &SPMajorVersion) &&
294 ReadCompatibilitySetting(SubKeyHandle,
295 L"SPMinorVersion",
296 ValueInfo,
297 &SPMinorVersion))
298 {
299 Peb->OSCSDVersion = ((SPMajorVersion & 0xFF) << 8) |
300 (SPMinorVersion & 0xFF);
301 }
302
303 finish:
304 /* we're finished */
305 NtClose(SubKeyHandle);
306 NtClose(KeyHandle);
307 if (UserKey)
308 NtClose(UserKey);
309 return TRUE;
310 }
311
312 return FALSE;
313 }
314
315 static
316 VOID
317 LdrpInit2(PCONTEXT Context,
318 PVOID SystemArgument1,
319 PVOID SystemArgument2)
320 {
321 PIMAGE_NT_HEADERS NTHeaders;
322 PEPFUNC EntryPoint;
323 PIMAGE_DOS_HEADER PEDosHeader;
324 PVOID ImageBase;
325 PPEB Peb = NtCurrentPeb();
326 PLDR_DATA_TABLE_ENTRY NtModule; // ntdll
327 NLSTABLEINFO NlsTable;
328 WCHAR FullNtDllPath[MAX_PATH];
329 SYSTEM_BASIC_INFORMATION SystemInformation;
330 NTSTATUS Status;
331 PVOID BaseAddress = SystemArgument1;
332
333 DPRINT("LdrpInit()\n");
334 DPRINT("Peb %p\n", Peb);
335 ImageBase = Peb->ImageBaseAddress;
336 DPRINT("ImageBase %p\n", ImageBase);
337
338 if (ImageBase <= (PVOID) 0x1000)
339 {
340 DPRINT("ImageBase is null\n");
341 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
342 }
343
344 /* If MZ header exists */
345 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
346 NTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)ImageBase + PEDosHeader->e_lfanew);
347 DPRINT("PEDosHeader %p\n", PEDosHeader);
348
349 if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE ||
350 PEDosHeader->e_lfanew == 0L ||
351 NTHeaders->Signature != IMAGE_NT_SIGNATURE)
352 {
353 DPRINT1("Image has bad header\n");
354 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
355 }
356
357 /* normalize process parameters */
358 RtlNormalizeProcessParams(Peb->ProcessParameters);
359
360 /* Initialize NLS data */
361 RtlInitNlsTables(Peb->AnsiCodePageData,
362 Peb->OemCodePageData,
363 Peb->UnicodeCaseTableData,
364 &NlsTable);
365 RtlResetRtlTranslations(&NlsTable);
366
367 /* Get number of processors */
368 DPRINT("Here\n");
369 Status = ZwQuerySystemInformation(SystemBasicInformation,
370 &SystemInformation,
371 sizeof(SYSTEM_BASIC_INFORMATION),
372 NULL);
373 DPRINT("Here2\n");
374 if (!NT_SUCCESS(Status))
375 {
376 ZwTerminateProcess(NtCurrentProcess(), Status);
377 }
378
379 Peb->NumberOfProcessors = SystemInformation.NumberOfProcessors;
380
381 /* Initialize Critical Section Data */
382 RtlpInitDeferedCriticalSection();
383
384 /* Load execution options */
385 LoadImageFileExecutionOptions(Peb);
386
387 /* create process heap */
388 RtlInitializeHeapManager();
389 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
390 NULL,
391 NTHeaders->OptionalHeader.SizeOfHeapReserve,
392 NTHeaders->OptionalHeader.SizeOfHeapCommit,
393 NULL,
394 NULL);
395 if (Peb->ProcessHeap == 0)
396 {
397 DPRINT1("Failed to create process heap\n");
398 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
399 }
400
401 /* Check for correct machine type */
402 if (NTHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE)
403 {
404 ULONG_PTR HardErrorParameters[1];
405 UNICODE_STRING ImageNameU;
406 ANSI_STRING ImageNameA;
407 WCHAR *Ptr;
408 ULONG ErrorResponse;
409
410 DPRINT1("Image %wZ is for a foreign architecture (0x%x).\n",
411 &Peb->ProcessParameters->ImagePathName, NTHeaders->FileHeader.Machine);
412
413 /* Get the full image path name */
414 ImageNameU = Peb->ProcessParameters->ImagePathName;
415
416 /* Get the file name */
417 Ptr = Peb->ProcessParameters->ImagePathName.Buffer +
418 (Peb->ProcessParameters->ImagePathName.Length / sizeof(WCHAR)) -1;
419 while ((Ptr >= Peb->ProcessParameters->ImagePathName.Buffer) &&
420 (*Ptr != L'\\')) Ptr--;
421 ImageNameU.Buffer = Ptr + 1;
422 ImageNameU.Length = Peb->ProcessParameters->ImagePathName.Length -
423 (ImageNameU.Buffer - Peb->ProcessParameters->ImagePathName.Buffer) * sizeof(WCHAR);
424 ImageNameU.MaximumLength = ImageNameU.Length;
425
426 /*`Convert to ANSI, harderror message needs that */
427 RtlUnicodeStringToAnsiString(&ImageNameA, &ImageNameU, TRUE);
428
429 /* Raise harderror */
430 HardErrorParameters[0] = (ULONG_PTR)&ImageNameA;
431 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE,
432 1,
433 1,
434 HardErrorParameters,
435 OptionOk,
436 &ErrorResponse);
437
438 RtlFreeAnsiString(&ImageNameA);
439 ZwTerminateProcess(NtCurrentProcess(), STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE);
440 }
441
442 /* initialized vectored exception handling */
443 RtlpInitializeVectoredExceptionHandling();
444
445 /* initalize peb lock support */
446 RtlInitializeCriticalSection(&PebLock);
447 Peb->FastPebLock = &PebLock;
448
449 /* initialize tls bitmaps */
450 RtlInitializeBitMap(&TlsBitMap, Peb->TlsBitmapBits, TLS_MINIMUM_AVAILABLE);
451 RtlInitializeBitMap(&TlsExpansionBitMap, Peb->TlsExpansionBitmapBits, TLS_EXPANSION_SLOTS);
452
453 Peb->TlsBitmap = &TlsBitMap;
454 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
455 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
456
457 /* Initialize table of callbacks for the kernel. */
458 Peb->KernelCallbackTable = RtlAllocateHeap(RtlGetProcessHeap(),
459 0,
460 sizeof(PVOID) *
461 (USER32_CALLBACK_MAXIMUM + 1));
462 if (Peb->KernelCallbackTable == NULL)
463 {
464 DPRINT1("Failed to create callback table\n");
465 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
466 }
467
468 /* initalize loader lock */
469 RtlInitializeCriticalSection(&LdrpLoaderLock);
470 Peb->LoaderLock = &LdrpLoaderLock;
471
472 /* create loader information */
473 Peb->Ldr = (PPEB_LDR_DATA) RtlAllocateHeap(Peb->ProcessHeap,
474 0,
475 sizeof(PEB_LDR_DATA));
476 if (Peb->Ldr == NULL)
477 {
478 DPRINT1("Failed to create loader data\n");
479 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
480 }
481
482 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
483 Peb->Ldr->Initialized = FALSE;
484 Peb->Ldr->SsHandle = NULL;
485 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
486 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
487 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
488
489 /* Load compatibility settings */
490 LoadCompatibilitySettings(Peb);
491
492 /* build full ntdll path */
493 wcscpy(FullNtDllPath, SharedUserData->NtSystemRoot);
494 wcscat(FullNtDllPath, L"\\system32\\ntdll.dll");
495
496 /* add entry for ntdll */
497 NtModule = (PLDR_DATA_TABLE_ENTRY)
498 RtlAllocateHeap(Peb->ProcessHeap,
499 0,
500 sizeof(LDR_DATA_TABLE_ENTRY));
501 if (NtModule == NULL)
502 {
503 DPRINT1("Failed to create loader module entry (NTDLL)\n");
504 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
505 }
506 memset(NtModule, 0, sizeof(LDR_DATA_TABLE_ENTRY));
507
508 NtModule->DllBase = BaseAddress;
509 NtModule->EntryPoint = 0; /* no entry point */
510 RtlCreateUnicodeString(&NtModule->FullDllName, FullNtDllPath);
511 RtlCreateUnicodeString(&NtModule->BaseDllName, L"ntdll.dll");
512 NtModule->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
513
514 NtModule->LoadCount = -1; /* don't unload */
515 NtModule->TlsIndex = -1;
516 NtModule->SectionPointer = NULL;
517 NtModule->CheckSum = 0;
518
519 NTHeaders = RtlImageNtHeader(NtModule->DllBase);
520 NtModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
521 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
522
523 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
524 &NtModule->InLoadOrderLinks);
525 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
526 &NtModule->InInitializationOrderModuleList);
527
528 /* add entry for executable (becomes first list entry) */
529 ExeModule = (PLDR_DATA_TABLE_ENTRY)
530 RtlAllocateHeap(Peb->ProcessHeap,
531 HEAP_ZERO_MEMORY,
532 sizeof(LDR_DATA_TABLE_ENTRY));
533 if (ExeModule == NULL)
534 {
535 DPRINT1("Failed to create loader module infomation\n");
536 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
537 }
538
539 ExeModule->DllBase = Peb->ImageBaseAddress;
540
541 if ((Peb->ProcessParameters == NULL) ||
542 (Peb->ProcessParameters->ImagePathName.Length == 0))
543 {
544 DPRINT1("Failed to access the process parameter block\n");
545 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
546 }
547
548 RtlCreateUnicodeString(&ExeModule->FullDllName,
549 Peb->ProcessParameters->ImagePathName.Buffer);
550 RtlCreateUnicodeString(&ExeModule->BaseDllName,
551 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
552
553 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule->BaseDllName, &ExeModule->FullDllName);
554
555 ExeModule->Flags = LDRP_ENTRY_PROCESSED;
556 ExeModule->LoadCount = -1; /* don't unload */
557 ExeModule->TlsIndex = -1;
558 ExeModule->SectionPointer = NULL;
559 ExeModule->CheckSum = 0;
560
561 NTHeaders = RtlImageNtHeader(ExeModule->DllBase);
562 ExeModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
563 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
564
565 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
566
567 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
568 &ExeModule->InLoadOrderLinks);
569
570 LdrpInitLoader();
571
572 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
573 ExeModule->EntryPoint = EntryPoint;
574
575 /* all required dlls are loaded now */
576 Peb->Ldr->Initialized = TRUE;
577
578 /* Check before returning that we can run the image safely. */
579 if (EntryPoint == NULL)
580 {
581 DPRINT1("Failed to initialize image\n");
582 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
583 }
584
585 /* Break into debugger */
586 if (Peb->BeingDebugged)
587 DbgBreakPoint();
588 }
589
590 VOID
591 NTAPI
592 LdrpInit(PCONTEXT Context,
593 PVOID SystemArgument1,
594 PVOID SystemArgument2)
595 {
596 if (!LdrpInitialized)
597 {
598 if (!_InterlockedExchange(&LdrpInitLock, 1))
599 {
600 LdrpInit2(Context, SystemArgument1, SystemArgument2);
601 LdrpInitialized = TRUE;
602 }
603 else
604 {
605 LARGE_INTEGER Interval = {{-200000, -1}};
606
607 do
608 {
609 NtDelayExecution(FALSE, &Interval);
610 }
611 while (!LdrpInitialized);
612 }
613 }
614
615 /* attach the thread */
616 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
617 LdrpAttachThread();
618 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
619 }
620
621 /* EOF */