Fixed LdrShutdownProcess() to only detach static dlls, any dynamically loaded ones...
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.45 2001/07/02 20:27:41 phreak Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /*
12 * TODO:
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
22 #include <windows.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27 #include <napi/shared_data.h>
28
29
30 #ifdef DBG_NTDLL_LDR_UTILS
31 #define NDEBUG
32 #endif
33 #include <ntdll/ntdll.h>
34
35 /* PROTOTYPES ****************************************************************/
36
37
38 /* Type for a DLL's entry point */
39 typedef
40 WINBOOL
41 STDCALL
42 (* PDLLMAIN_FUNC) (
43 HANDLE hInst,
44 ULONG ul_reason_for_call,
45 LPVOID lpReserved
46 );
47
48 static NTSTATUS LdrFindDll(PLDR_MODULE *Dll,PUNICODE_STRING Name);
49 static PVOID LdrFixupForward(PCHAR ForwardName);
50 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
51
52
53 /* FUNCTIONS *****************************************************************/
54
55
56 #ifdef KDBG
57
58 VOID LdrLoadModuleSymbols(PLDR_MODULE ModuleObject)
59 {
60 NtSystemDebugControl(
61 0xffffffff,
62 (PVOID)ModuleObject,
63 0,
64 NULL,
65 0,
66 NULL);
67 }
68
69 #endif /* KDBG */
70
71
72 /***************************************************************************
73 * NAME LOCAL
74 * LdrAdjustDllName
75 *
76 * DESCRIPTION
77 * Adjusts the name of a dll to a fully qualified name.
78 *
79 * ARGUMENTS
80 * FullDllName: Pointer to caller supplied storage for the fully
81 * qualified dll name.
82 * DllName: Pointer to the dll name.
83 * BaseName: TRUE: Only the file name is passed to FullDllName
84 * FALSE: The full path is preserved in FullDllName
85 *
86 * RETURN VALUE
87 * None
88 *
89 * REVISIONS
90 *
91 * NOTE
92 * A given path is not affected by the adjustment, but the file
93 * name only:
94 * ntdll --> ntdll.dll
95 * ntdll. --> ntdll
96 * ntdll.xyz --> ntdll.xyz
97 */
98
99 static VOID
100 LdrAdjustDllName (PUNICODE_STRING FullDllName,
101 PUNICODE_STRING DllName,
102 BOOLEAN BaseName)
103 {
104 WCHAR Buffer[MAX_PATH];
105 ULONG Length;
106 PWCHAR Extension;
107 PWCHAR Pointer;
108
109 Length = DllName->Length / sizeof(WCHAR);
110
111 if (BaseName == TRUE)
112 {
113 /* get the base dll name */
114 Pointer = DllName->Buffer + Length;
115 Extension = Pointer;
116
117 do
118 {
119 --Pointer;
120 }
121 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
122
123 Pointer++;
124 Length = Extension - Pointer;
125 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
126 }
127 else
128 {
129 /* get the full dll name */
130 memmove (Buffer, DllName->Buffer, DllName->Length);
131 }
132
133 /* Build the DLL's absolute name */
134 Extension = wcsrchr (Buffer, L'.');
135 if ((Extension != NULL) && (*Extension == L'.'))
136 {
137 /* with extension - remove dot if it's the last character */
138 if (Buffer[Length - 1] == L'.')
139 Length--;
140 Buffer[Length] = 0;
141 }
142 else
143 {
144 /* name without extension - assume that it is .dll */
145 memmove (Buffer + Length, L".dll", 10);
146 }
147
148 RtlCreateUnicodeString (FullDllName,
149 Buffer);
150 }
151
152
153 /***************************************************************************
154 * NAME EXPORTED
155 * LdrLoadDll
156 *
157 * DESCRIPTION
158 *
159 * ARGUMENTS
160 *
161 * RETURN VALUE
162 *
163 * REVISIONS
164 *
165 * NOTE
166 *
167 */
168
169 NTSTATUS STDCALL
170 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
171 IN ULONG LoadFlags,
172 IN PUNICODE_STRING Name,
173 OUT PVOID *BaseAddress OPTIONAL)
174 {
175 WCHAR SearchPathBuffer[MAX_PATH];
176 WCHAR FullDosName[MAX_PATH];
177 UNICODE_STRING AdjustedName;
178 UNICODE_STRING FullNtFileName;
179 OBJECT_ATTRIBUTES FileObjectAttributes;
180 char BlockBuffer [1024];
181 PIMAGE_DOS_HEADER DosHeader;
182 NTSTATUS Status;
183 PIMAGE_NT_HEADERS NTHeaders;
184 ULONG ImageSize;
185 ULONG InitialViewSize;
186 PVOID ImageBase;
187 HANDLE FileHandle;
188 HANDLE SectionHandle;
189 PDLLMAIN_FUNC Entrypoint = NULL;
190 PLDR_MODULE Module;
191
192 if (Name == NULL)
193 {
194 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
195 return STATUS_SUCCESS;
196 }
197
198 *BaseAddress = NULL;
199
200 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
201 Name, BaseAddress);
202
203 /* adjust the full dll name */
204 LdrAdjustDllName (&AdjustedName,
205 Name,
206 FALSE);
207 DPRINT("AdjustedName: %wZ\n", &AdjustedName);
208
209 /*
210 * Test if dll is already loaded.
211 */
212 if (LdrFindDll(&Module, &AdjustedName) == STATUS_SUCCESS)
213 {
214 DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
215 if (Module->LoadCount != -1)
216 Module->LoadCount++;
217 *BaseAddress = Module->BaseAddress;
218 return STATUS_SUCCESS;
219 }
220 DPRINT("Loading \"%wZ\"\n", Name);
221
222 if (SearchPath == NULL)
223 {
224 PKUSER_SHARED_DATA SharedUserData =
225 (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
226
227 SearchPath = SearchPathBuffer;
228 wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
229 wcscat (SearchPathBuffer, L"\\system32;");
230 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
231 }
232
233 DPRINT("SearchPath %S\n", SearchPath);
234
235 if (RtlDosSearchPath_U (SearchPath,
236 AdjustedName.Buffer,
237 NULL,
238 MAX_PATH,
239 FullDosName,
240 NULL) == 0)
241 return STATUS_DLL_NOT_FOUND;
242
243 DPRINT("FullDosName %S\n", FullDosName);
244
245 RtlFreeUnicodeString (&AdjustedName);
246
247 if (!RtlDosPathNameToNtPathName_U (FullDosName,
248 &FullNtFileName,
249 NULL,
250 NULL))
251 return STATUS_DLL_NOT_FOUND;
252
253 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
254
255 InitializeObjectAttributes(&FileObjectAttributes,
256 &FullNtFileName,
257 0,
258 NULL,
259 NULL);
260
261 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
262
263 Status = ZwOpenFile(&FileHandle,
264 FILE_ALL_ACCESS,
265 &FileObjectAttributes,
266 NULL,
267 0,
268 0);
269 if (!NT_SUCCESS(Status))
270 {
271 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
272 &FullNtFileName, Status);
273 RtlFreeUnicodeString (&FullNtFileName);
274 return Status;
275 }
276 RtlFreeUnicodeString (&FullNtFileName);
277
278 Status = ZwReadFile(FileHandle,
279 0,
280 0,
281 0,
282 0,
283 BlockBuffer,
284 sizeof(BlockBuffer),
285 0,
286 0);
287 if (!NT_SUCCESS(Status))
288 {
289 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
290 ZwClose(FileHandle);
291 return Status;
292 }
293 /*
294 * Overlay DOS and NT headers structures to the
295 * buffer with DLL's header raw data.
296 */
297 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
298 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
299 /*
300 * Check it is a PE image file.
301 */
302 if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
303 || (DosHeader->e_lfanew == 0L)
304 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
305 {
306 DPRINT("NTDLL format invalid\n");
307 ZwClose(FileHandle);
308
309 return STATUS_UNSUCCESSFUL;
310 }
311
312 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
313 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
314
315 DPRINT("ImageBase 0x%08x\n", ImageBase);
316
317 /*
318 * Create a section for dll.
319 */
320 Status = ZwCreateSection(&SectionHandle,
321 SECTION_ALL_ACCESS,
322 NULL,
323 NULL,
324 PAGE_READWRITE,
325 SEC_COMMIT | SEC_IMAGE,
326 FileHandle);
327 if (!NT_SUCCESS(Status))
328 {
329 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
330 ZwClose(FileHandle);
331 return Status;
332 }
333
334 /*
335 * Map the dll into the process.
336 */
337 InitialViewSize = 0;
338 ImageBase = 0;
339 Status = ZwMapViewOfSection(SectionHandle,
340 NtCurrentProcess(),
341 &ImageBase,
342 0,
343 InitialViewSize,
344 NULL,
345 &InitialViewSize,
346 0,
347 MEM_COMMIT,
348 PAGE_READWRITE);
349 if (!NT_SUCCESS(Status))
350 {
351 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
352 Status);
353 ZwClose(FileHandle);
354 return(Status);
355 }
356 ZwClose(FileHandle);
357
358 /* relocate dll and fixup import table */
359 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
360 IMAGE_FILE_DLL)
361 {
362 Entrypoint =
363 (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle);
364 }
365
366 /* build module entry */
367 Module = RtlAllocateHeap(RtlGetProcessHeap(),
368 0,
369 sizeof (LDR_MODULE));
370 Module->BaseAddress = (PVOID)ImageBase;
371 Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
372 if (Module->EntryPoint != 0)
373 Module->EntryPoint += (ULONG)Module->BaseAddress;
374 Module->SizeOfImage = ImageSize;
375 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
376 {
377 /* loading while app is running */
378 Module->LoadCount = 1;
379 }
380 else
381 {
382 /*
383 * loading while app is initializing
384 * dll must not be unloaded
385 */
386 Module->LoadCount = -1;
387 }
388
389 Module->TlsIndex = 0;
390 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
391 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
392
393 RtlCreateUnicodeString (&Module->FullDllName,
394 FullDosName);
395 RtlCreateUnicodeString (&Module->BaseDllName,
396 wcsrchr(FullDosName, L'\\') + 1);
397 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
398
399 /* FIXME: aquire loader lock */
400 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
401 &Module->InLoadOrderModuleList);
402 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
403 &Module->InInitializationOrderModuleList);
404 /* FIXME: release loader lock */
405
406 #ifdef KDBG
407 LdrLoadModuleSymbols(Module);
408 #endif /* KDBG */
409
410 /* initialize dll */
411 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
412 IMAGE_FILE_DLL)
413 {
414 if (Module->EntryPoint != 0)
415 {
416 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
417
418 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
419 if (FALSE == Entrypoint(Module->BaseAddress,
420 DLL_PROCESS_ATTACH,
421 NULL))
422 {
423 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
424 &Module->BaseDllName);
425 /* FIXME: should clean up and fail */
426 }
427 else
428 {
429 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
430 &Module->BaseDllName);
431 }
432 }
433 else
434 {
435 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
436 &Module->BaseDllName);
437 }
438 }
439
440 *BaseAddress = Module->BaseAddress;
441 return STATUS_SUCCESS;
442 }
443
444
445 /***************************************************************************
446 * NAME LOCAL
447 * LdrFindDll
448 *
449 * DESCRIPTION
450 *
451 * ARGUMENTS
452 *
453 * RETURN VALUE
454 *
455 * REVISIONS
456 *
457 * NOTE
458 *
459 */
460 static NTSTATUS LdrFindDll(PLDR_MODULE *Dll, PUNICODE_STRING Name)
461 {
462 PLIST_ENTRY ModuleListHead;
463 PLIST_ENTRY Entry;
464 PLDR_MODULE Module;
465
466 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name);
467
468 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
469 Entry = ModuleListHead->Flink;
470
471 // NULL is the current process
472 if ( Name == NULL )
473 {
474 *Dll = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
475 return STATUS_SUCCESS;
476 }
477
478 while (Entry != ModuleListHead)
479 {
480 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
481
482 DPRINT("Scanning %wZ %wZ\n", &Module->BaseDllName, Name);
483
484 if (RtlCompareUnicodeString(&Module->BaseDllName, Name, TRUE) == 0)
485 {
486 *Dll = Module;
487 return STATUS_SUCCESS;
488 }
489
490 Entry = Entry->Flink;
491 }
492
493 DPRINT("Failed to find dll %wZ\n", Name);
494
495 return STATUS_UNSUCCESSFUL;
496 }
497
498 /**********************************************************************
499 * NAME LOCAL
500 * LdrFixupForward
501 *
502 * DESCRIPTION
503 *
504 * ARGUMENTS
505 *
506 * RETURN VALUE
507 *
508 * REVISIONS
509 *
510 * NOTE
511 *
512 */
513 static PVOID
514 LdrFixupForward(PCHAR ForwardName)
515 {
516 CHAR NameBuffer[128];
517 UNICODE_STRING DllName;
518 UNICODE_STRING FunctionName;
519 NTSTATUS Status;
520 PCHAR p;
521 PVOID BaseAddress;
522
523 strcpy(NameBuffer, ForwardName);
524 p = strchr(NameBuffer, '.');
525 if (p != NULL)
526 {
527 *p = 0;
528
529 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
530 RtlCreateUnicodeStringFromAsciiz (&DllName,
531 NameBuffer);
532
533 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
534 if (!NT_SUCCESS(Status))
535 {
536 Status = LdrLoadDll(NULL,
537 0,
538 &DllName,
539 &BaseAddress);
540 if (!NT_SUCCESS(Status))
541 {
542 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
543 RtlFreeUnicodeString (&DllName);
544 return NULL;
545 }
546 }
547
548 RtlFreeUnicodeString (&DllName);
549 DPRINT("BaseAddress: %p\n", BaseAddress);
550
551 return LdrGetExportByName(BaseAddress, p+1, -1);
552 }
553
554 return NULL;
555 }
556
557
558 /**********************************************************************
559 * NAME LOCAL
560 * LdrGetExportByOrdinal
561 *
562 * DESCRIPTION
563 *
564 * ARGUMENTS
565 *
566 * RETURN VALUE
567 *
568 * REVISIONS
569 *
570 * NOTE
571 *
572 */
573 static PVOID
574 LdrGetExportByOrdinal (
575 PVOID BaseAddress,
576 ULONG Ordinal
577 )
578 {
579 PIMAGE_EXPORT_DIRECTORY ExportDir;
580 PDWORD * ExFunctions;
581 USHORT * ExOrdinals;
582
583 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
584 RtlImageDirectoryEntryToData (BaseAddress,
585 TRUE,
586 IMAGE_DIRECTORY_ENTRY_EXPORT,
587 NULL);
588
589
590 ExOrdinals = (USHORT *)
591 RVA(
592 BaseAddress,
593 ExportDir->AddressOfNameOrdinals
594 );
595 ExFunctions = (PDWORD *)
596 RVA(
597 BaseAddress,
598 ExportDir->AddressOfFunctions
599 );
600 DbgPrint(
601 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
602 Ordinal,
603 ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
604 );
605 return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
606 }
607
608
609 /**********************************************************************
610 * NAME LOCAL
611 * LdrGetExportByName
612 *
613 * DESCRIPTION
614 *
615 * ARGUMENTS
616 *
617 * RETURN VALUE
618 *
619 * REVISIONS
620 *
621 * NOTE
622 *
623 */
624 static PVOID
625 LdrGetExportByName(PVOID BaseAddress,
626 PUCHAR SymbolName,
627 WORD Hint)
628 {
629 PIMAGE_EXPORT_DIRECTORY ExportDir;
630 PDWORD * ExFunctions;
631 PDWORD * ExNames;
632 USHORT * ExOrdinals;
633 ULONG i;
634 PVOID ExName;
635 ULONG Ordinal;
636 PVOID Function;
637 ULONG minn, maxn;
638 ULONG ExportDirSize;
639
640 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
641
642 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
643 RtlImageDirectoryEntryToData(BaseAddress,
644 TRUE,
645 IMAGE_DIRECTORY_ENTRY_EXPORT,
646 &ExportDirSize);
647 if (ExportDir == NULL)
648 {
649 DbgPrint("LdrGetExportByName(): no export directory!\n");
650 return NULL;
651 }
652
653 /*
654 * Get header pointers
655 */
656 ExNames = (PDWORD *)RVA(BaseAddress,
657 ExportDir->AddressOfNames);
658 ExOrdinals = (USHORT *)RVA(BaseAddress,
659 ExportDir->AddressOfNameOrdinals);
660 ExFunctions = (PDWORD *)RVA(BaseAddress,
661 ExportDir->AddressOfFunctions);
662
663 /*
664 * Check the hint first
665 */
666 if (Hint < ExportDir->NumberOfFunctions)
667 {
668 ExName = RVA(BaseAddress, ExNames[Hint]);
669 if (strcmp(ExName, SymbolName) == 0)
670 {
671 Ordinal = ExOrdinals[Hint];
672 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
673 if (((ULONG)Function >= (ULONG)ExportDir) &&
674 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
675 {
676 DPRINT("Forward: %s\n", (PCHAR)Function);
677 Function = LdrFixupForward((PCHAR)Function);
678 }
679 if (Function != NULL)
680 return Function;
681 }
682 }
683
684 /*
685 * Try a binary search first
686 */
687 minn = 0;
688 maxn = ExportDir->NumberOfFunctions;
689 while (minn <= maxn)
690 {
691 ULONG mid;
692 LONG res;
693
694 mid = (minn + maxn) / 2;
695
696 ExName = RVA(BaseAddress, ExNames[mid]);
697 res = strcmp(ExName, SymbolName);
698 if (res == 0)
699 {
700 Ordinal = ExOrdinals[mid];
701 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
702 if (((ULONG)Function >= (ULONG)ExportDir) &&
703 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
704 {
705 DPRINT("Forward: %s\n", (PCHAR)Function);
706 Function = LdrFixupForward((PCHAR)Function);
707 }
708 if (Function != NULL)
709 return Function;
710 }
711 else if (minn == maxn)
712 {
713 DPRINT("LdrGetExportByName(): binary search failed\n");
714 break;
715 }
716 else if (res > 0)
717 {
718 maxn = mid - 1;
719 }
720 else
721 {
722 minn = mid + 1;
723 }
724 }
725
726 /*
727 * Fall back on a linear search
728 */
729 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
730 for (i = 0; i < ExportDir->NumberOfFunctions; i++)
731 {
732 ExName = RVA(BaseAddress, ExNames[i]);
733 if (strcmp(ExName,SymbolName) == 0)
734 {
735 Ordinal = ExOrdinals[i];
736 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
737 DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
738 if (((ULONG)Function >= (ULONG)ExportDir) &&
739 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
740 {
741 DPRINT("Forward: %s\n", (PCHAR)Function);
742 Function = LdrFixupForward((PCHAR)Function);
743 }
744 return Function;
745 }
746 }
747 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
748 return NULL;
749 }
750
751
752 /**********************************************************************
753 * NAME LOCAL
754 * LdrPerformRelocations
755 *
756 * DESCRIPTION
757 * Relocate a DLL's memory image.
758 *
759 * ARGUMENTS
760 *
761 * RETURN VALUE
762 *
763 * REVISIONS
764 *
765 * NOTE
766 *
767 */
768 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
769 PVOID ImageBase)
770 {
771 USHORT NumberOfEntries;
772 PUSHORT pValue16;
773 ULONG RelocationRVA;
774 ULONG Delta32;
775 ULONG Offset;
776 PULONG pValue32;
777 PRELOCATION_DIRECTORY RelocationDir;
778 PRELOCATION_ENTRY RelocationBlock;
779 int i;
780
781
782 RelocationRVA = NTHeaders->OptionalHeader
783 .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
784 .VirtualAddress;
785
786 if (RelocationRVA)
787 {
788 RelocationDir = (PRELOCATION_DIRECTORY)
789 ((PCHAR)ImageBase + RelocationRVA);
790
791 while (RelocationDir->SizeOfBlock)
792 {
793 Delta32 = (ULONG)(ImageBase -
794 NTHeaders->OptionalHeader.ImageBase);
795 RelocationBlock = (PRELOCATION_ENTRY) (
796 RelocationRVA
797 + ImageBase
798 + sizeof (RELOCATION_DIRECTORY)
799 );
800 NumberOfEntries = (
801 RelocationDir->SizeOfBlock
802 - sizeof (RELOCATION_DIRECTORY)
803 )
804 / sizeof (RELOCATION_ENTRY);
805
806 for ( i = 0;
807 (i < NumberOfEntries);
808 i++
809 )
810 {
811 Offset = (
812 RelocationBlock[i].TypeOffset
813 & 0xfff
814 )
815 + RelocationDir->VirtualAddress;
816 /*
817 * What kind of relocations should we perform
818 * for the current entry?
819 */
820 switch (RelocationBlock[i].TypeOffset >> 12)
821 {
822 case TYPE_RELOC_ABSOLUTE:
823 break;
824
825 case TYPE_RELOC_HIGH:
826 pValue16 = (PUSHORT) (ImageBase + Offset);
827 *pValue16 += Delta32 >> 16;
828 break;
829
830 case TYPE_RELOC_LOW:
831 pValue16 = (PUSHORT)(ImageBase + Offset);
832 *pValue16 += Delta32 & 0xffff;
833 break;
834
835 case TYPE_RELOC_HIGHLOW:
836 pValue32 = (PULONG) (ImageBase + Offset);
837 *pValue32 += Delta32;
838 break;
839
840 case TYPE_RELOC_HIGHADJ:
841 /* FIXME: do the highadjust fixup */
842 DPRINT(
843 "TYPE_RELOC_HIGHADJ fixup not implemented"
844 ", sorry\n"
845 );
846 return(STATUS_UNSUCCESSFUL);
847
848 default:
849 DPRINT("unexpected fixup type\n");
850 return STATUS_UNSUCCESSFUL;
851 }
852 }
853 RelocationRVA += RelocationDir->SizeOfBlock;
854 RelocationDir = (PRELOCATION_DIRECTORY) (
855 ImageBase
856 + RelocationRVA
857 );
858 }
859 }
860 return STATUS_SUCCESS;
861 }
862
863
864 /**********************************************************************
865 * NAME LOCAL
866 * LdrFixupImports
867 *
868 * DESCRIPTION
869 * Compute the entry point for every symbol the DLL imports
870 * from other modules.
871 *
872 * ARGUMENTS
873 *
874 * RETURN VALUE
875 *
876 * REVISIONS
877 *
878 * NOTE
879 *
880 */
881 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
882 PVOID ImageBase)
883 {
884 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
885 ULONG Ordinal;
886 PVOID BaseAddress;
887 NTSTATUS Status;
888
889 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
890 ImageBase);
891
892 /*
893 * Process each import module.
894 */
895 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
896 ImageBase + NTHeaders->OptionalHeader
897 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
898 .VirtualAddress);
899 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
900
901 while (ImportModuleDirectory->dwRVAModuleName)
902 {
903 PVOID * ImportAddressList;
904 PULONG FunctionNameList;
905 UNICODE_STRING DllName;
906 DWORD pName;
907 WORD pHint;
908
909 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
910 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
911
912 RtlCreateUnicodeStringFromAsciiz (&DllName,
913 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
914
915 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
916 if (!NT_SUCCESS(Status))
917 {
918 Status = LdrLoadDll(NULL,
919 0,
920 &DllName,
921 &BaseAddress);
922 RtlFreeUnicodeString (&DllName);
923 if (!NT_SUCCESS(Status))
924 {
925 DbgPrint("LdrFixupImports:failed to load %s\n"
926 ,(PCHAR)(ImageBase
927 + ImportModuleDirectory->dwRVAModuleName));
928
929 return Status;
930 }
931 }
932
933 /*
934 * Get the import address list.
935 */
936 ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
937 + ImportModuleDirectory->dwRVAFunctionAddressList);
938
939 /*
940 * Get the list of functions to import.
941 */
942 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
943 {
944 FunctionNameList = (PULONG) (
945 ImageBase
946 + ImportModuleDirectory->dwRVAFunctionNameList
947 );
948 }
949 else
950 {
951 FunctionNameList =
952 (PULONG)(ImageBase
953 + ImportModuleDirectory->dwRVAFunctionAddressList);
954 }
955 /*
956 * Walk through function list and fixup addresses.
957 */
958 while (*FunctionNameList != 0L)
959 {
960 if ((*FunctionNameList) & 0x80000000)
961 {
962 Ordinal = (*FunctionNameList) & 0x7fffffff;
963 *ImportAddressList =
964 LdrGetExportByOrdinal(BaseAddress,
965 Ordinal);
966 }
967 else
968 {
969 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
970 pHint = *(PWORD)(ImageBase + *FunctionNameList);
971
972 *ImportAddressList =
973 LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
974 if ((*ImportAddressList) == NULL)
975 {
976 DbgPrint("Failed to import %s\n", pName);
977 return STATUS_UNSUCCESSFUL;
978 }
979 }
980 ImportAddressList++;
981 FunctionNameList++;
982 }
983 ImportModuleDirectory++;
984 }
985 return STATUS_SUCCESS;
986 }
987
988
989 /**********************************************************************
990 * NAME
991 * LdrPEStartup
992 *
993 * DESCRIPTION
994 * 1. Map the DLL's sections into memory.
995 * 2. Relocate, if needed the DLL.
996 * 3. Fixup any imported symbol.
997 * 4. Compute the DLL's entry point.
998 *
999 * ARGUMENTS
1000 * ImageBase
1001 * Address at which the DLL's image
1002 * is loaded.
1003 *
1004 * SectionHandle
1005 * Handle of the section that contains
1006 * the DLL's image.
1007 *
1008 * RETURN VALUE
1009 * NULL on error; otherwise the entry point
1010 * to call for initializing the DLL.
1011 *
1012 * REVISIONS
1013 *
1014 * NOTE
1015 *
1016 */
1017 PEPFUNC LdrPEStartup (PVOID ImageBase,
1018 HANDLE SectionHandle)
1019 {
1020 NTSTATUS Status;
1021 PEPFUNC EntryPoint = NULL;
1022 PIMAGE_DOS_HEADER DosHeader;
1023 PIMAGE_NT_HEADERS NTHeaders;
1024
1025 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1026 ImageBase, (ULONG)SectionHandle);
1027
1028 /*
1029 * Overlay DOS and WNT headers structures
1030 * to the DLL's image.
1031 */
1032 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1033 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1034
1035 /*
1036 * If the base address is different from the
1037 * one the DLL is actually loaded, perform any
1038 * relocation.
1039 */
1040 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1041 {
1042 DbgPrint("LDR: Performing relocations\n");
1043 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1044 if (!NT_SUCCESS(Status))
1045 {
1046 DbgPrint("LdrPerformRelocations() failed\n");
1047 return NULL;
1048 }
1049 }
1050
1051 /*
1052 * If the DLL's imports symbols from other
1053 * modules, fixup the imported calls entry points.
1054 */
1055 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1056 .VirtualAddress != 0)
1057 {
1058 DPRINT("About to fixup imports\n");
1059 Status = LdrFixupImports(NTHeaders, ImageBase);
1060 if (!NT_SUCCESS(Status))
1061 {
1062 DbgPrint("LdrFixupImports() failed\n");
1063 return NULL;
1064 }
1065 DPRINT("Fixup done\n");
1066 }
1067
1068 /*
1069 * Compute the DLL's entry point's address.
1070 */
1071 DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1072 DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1073 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1074 {
1075 EntryPoint = (PEPFUNC) (ImageBase
1076 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1077 }
1078 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1079 return EntryPoint;
1080 }
1081
1082
1083 NTSTATUS STDCALL
1084 LdrUnloadDll (IN PVOID BaseAddress)
1085 {
1086 PIMAGE_NT_HEADERS NtHeaders;
1087 PDLLMAIN_FUNC Entrypoint;
1088 PLIST_ENTRY ModuleListHead;
1089 PLIST_ENTRY Entry;
1090 PLDR_MODULE Module;
1091 NTSTATUS Status;
1092
1093 if (BaseAddress == NULL)
1094 return STATUS_SUCCESS;
1095
1096 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1097 Entry = ModuleListHead->Flink;
1098
1099 while (Entry != ModuleListHead);
1100 {
1101 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1102 if (Module->BaseAddress == BaseAddress)
1103 {
1104 if (Module->LoadCount == -1)
1105 {
1106 /* never unload this dll */
1107 return STATUS_SUCCESS;
1108 }
1109 else if (Module->LoadCount > 1)
1110 {
1111 Module->LoadCount--;
1112 return STATUS_SUCCESS;
1113 }
1114
1115 NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1116 if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1117 {
1118 if (Module->EntryPoint != 0)
1119 {
1120 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1121 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1122 Entrypoint(Module->BaseAddress,
1123 DLL_PROCESS_DETACH,
1124 NULL);
1125 }
1126 else
1127 {
1128 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1129 }
1130 }
1131 Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1132 Module->BaseAddress);
1133 ZwClose (Module->SectionHandle);
1134
1135 /* remove the module entry from the list */
1136 RtlFreeUnicodeString (&Module->FullDllName);
1137 RtlFreeUnicodeString (&Module->BaseDllName);
1138 RemoveEntryList (Entry);
1139 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1140
1141 return Status;
1142 }
1143
1144 Entry = Entry->Flink;
1145 }
1146
1147 DPRINT("NTDLL.LDR: Dll not found\n")
1148
1149 return STATUS_UNSUCCESSFUL;
1150 }
1151
1152
1153 NTSTATUS STDCALL
1154 LdrFindResource_U(PVOID BaseAddress,
1155 PLDR_RESOURCE_INFO ResourceInfo,
1156 ULONG Level,
1157 PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
1158 {
1159 PIMAGE_RESOURCE_DIRECTORY ResDir;
1160 PIMAGE_RESOURCE_DIRECTORY ResBase;
1161 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1162 NTSTATUS Status = STATUS_SUCCESS;
1163 ULONG EntryCount;
1164 PWCHAR ws;
1165 ULONG i;
1166 ULONG Id;
1167
1168 DPRINT ("LdrFindResource_U()\n");
1169
1170 /* Get the pointer to the resource directory */
1171 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1172 RtlImageDirectoryEntryToData (BaseAddress,
1173 TRUE,
1174 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1175 &i);
1176 if (ResDir == NULL)
1177 {
1178 return STATUS_RESOURCE_DATA_NOT_FOUND;
1179 }
1180
1181 DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
1182
1183 ResBase = ResDir;
1184
1185 /* Let's go into resource tree */
1186 for (i = 0; i < Level; i++)
1187 {
1188 DPRINT("ResDir: %x\n", (ULONG)ResDir);
1189 Id = ((PULONG)ResourceInfo)[i];
1190 EntryCount = ResDir->NumberOfNamedEntries;
1191 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1192 DPRINT("ResEntry %x\n", (ULONG)ResEntry);
1193 if (Id & 0xFFFF0000)
1194 {
1195 /* Resource name is a unicode string */
1196 for (; EntryCount--; ResEntry++)
1197 {
1198 /* Scan entries for equal name */
1199 if (ResEntry->Name & 0x80000000)
1200 {
1201 ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1202 if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
1203 wcslen((PWCHAR)Id) == (int)*ws )
1204 {
1205 goto found;
1206 }
1207 }
1208 }
1209 }
1210 else
1211 {
1212 /* We use ID number instead of string */
1213 ResEntry += EntryCount;
1214 EntryCount = ResDir->NumberOfIdEntries;
1215 for (; EntryCount--; ResEntry++)
1216 {
1217 /* Scan entries for equal name */
1218 if (ResEntry->Name == Id)
1219 {
1220 DPRINT("ID entry found %x\n", Id);
1221 goto found;
1222 }
1223 }
1224 }
1225 DPRINT("Error %lu\n", i);
1226
1227 switch (i)
1228 {
1229 case 0:
1230 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1231
1232 case 1:
1233 return STATUS_RESOURCE_NAME_NOT_FOUND;
1234
1235 case 2:
1236 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1237 {
1238 /* Use the first available language */
1239 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1240 break;
1241 }
1242 return STATUS_RESOURCE_LANG_NOT_FOUND;
1243
1244 case 3:
1245 return STATUS_RESOURCE_DATA_NOT_FOUND;
1246
1247 default:
1248 return STATUS_INVALID_PARAMETER;
1249 }
1250 found:;
1251 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
1252 (ResEntry->OffsetToData & 0x7FFFFFFF));
1253 }
1254 DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
1255
1256 if (ResourceDataEntry)
1257 {
1258 *ResourceDataEntry = (PVOID)ResDir;
1259 }
1260
1261 return Status;
1262 }
1263
1264
1265 NTSTATUS STDCALL
1266 LdrAccessResource(IN PVOID BaseAddress,
1267 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
1268 OUT PVOID *Resource OPTIONAL,
1269 OUT PULONG Size OPTIONAL)
1270 {
1271 PIMAGE_SECTION_HEADER Section;
1272 PIMAGE_NT_HEADERS NtHeader;
1273 ULONG SectionRva;
1274 ULONG SectionVa;
1275 ULONG DataSize;
1276 ULONG Offset = 0;
1277 ULONG Data;
1278
1279 Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
1280 TRUE,
1281 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1282 &DataSize);
1283 if (Data == 0)
1284 return STATUS_RESOURCE_DATA_NOT_FOUND;
1285
1286 if ((ULONG)BaseAddress & 1)
1287 {
1288 /* loaded as ordinary file */
1289 NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
1290 Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
1291 Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
1292 if (Section == NULL)
1293 {
1294 return STATUS_RESOURCE_DATA_NOT_FOUND;
1295 }
1296
1297 if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
1298 {
1299 SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
1300 SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
1301 Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
1302 }
1303 }
1304
1305 if (Resource)
1306 {
1307 *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
1308 }
1309
1310 if (Size)
1311 {
1312 *Size = ResourceDataEntry->Size;
1313 }
1314
1315 return STATUS_SUCCESS;
1316 }
1317
1318
1319 NTSTATUS STDCALL
1320 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress)
1321 {
1322 PLIST_ENTRY ModuleListHead;
1323 PLIST_ENTRY Entry;
1324 PLDR_MODULE Module;
1325 NTSTATUS Status;
1326
1327 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1328 BaseAddress);
1329
1330 Status = STATUS_DLL_NOT_FOUND;
1331
1332 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1333 Entry = ModuleListHead->Flink;
1334
1335 while (Entry != ModuleListHead)
1336 {
1337 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1338
1339 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1340 &Module->BaseDllName,
1341 Module->BaseAddress);
1342
1343 if (Module->BaseAddress == BaseAddress)
1344 {
1345 if (Module->TlsIndex == 0)
1346 {
1347 Module->Flags |= 0x00040000;
1348 Status = STATUS_SUCCESS;
1349 }
1350 return Status;
1351 }
1352
1353 Entry = Entry->Flink;
1354 }
1355
1356 return Status;
1357 }
1358
1359
1360 NTSTATUS STDCALL
1361 LdrFindResourceDirectory_U (IN PVOID BaseAddress,
1362 WCHAR **name,
1363 DWORD level,
1364 OUT PVOID *addr)
1365 {
1366 PIMAGE_RESOURCE_DIRECTORY ResDir;
1367 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1368 ULONG EntryCount;
1369 ULONG i;
1370 NTSTATUS Status = STATUS_SUCCESS;
1371 WCHAR *ws;
1372
1373 /* Get the pointer to the resource directory */
1374 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1375 RtlImageDirectoryEntryToData (BaseAddress,
1376 TRUE,
1377 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1378 &i);
1379 if (ResDir == NULL)
1380 {
1381 return STATUS_RESOURCE_DATA_NOT_FOUND;
1382 }
1383
1384 /* Let's go into resource tree */
1385 for (i = 0; i < level; i++, name++)
1386 {
1387 EntryCount = ResDir->NumberOfNamedEntries;
1388 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1389 if ((ULONG)(*name) & 0xFFFF0000)
1390 {
1391 /* Resource name is a unicode string */
1392 for (; EntryCount--; ResEntry++)
1393 {
1394 /* Scan entries for equal name */
1395 if (ResEntry->Name & 0x80000000)
1396 {
1397 ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1398 if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
1399 {
1400 goto found;
1401 }
1402 }
1403 }
1404 }
1405 else
1406 {
1407 /* We use ID number instead of string */
1408 ResEntry += EntryCount;
1409 EntryCount = ResDir->NumberOfIdEntries;
1410 for (; EntryCount--; ResEntry++)
1411 {
1412 /* Scan entries for equal name */
1413 if (ResEntry->Name == (ULONG)(*name))
1414 goto found;
1415 }
1416 }
1417
1418 switch (i)
1419 {
1420 case 0:
1421 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1422
1423 case 1:
1424 return STATUS_RESOURCE_NAME_NOT_FOUND;
1425
1426 case 2:
1427 Status = STATUS_RESOURCE_LANG_NOT_FOUND;
1428 /* Just use first language entry */
1429 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1430 {
1431 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1432 break;
1433 }
1434 return Status;
1435
1436 case 3:
1437 return STATUS_RESOURCE_DATA_NOT_FOUND;
1438
1439 default:
1440 return STATUS_INVALID_PARAMETER;
1441 }
1442 found:;
1443 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
1444 }
1445
1446 if (addr)
1447 {
1448 *addr = (PVOID)ResDir;
1449 }
1450
1451 return Status;
1452 }
1453
1454
1455 NTSTATUS STDCALL
1456 LdrGetDllHandle (IN ULONG Unknown1,
1457 IN ULONG Unknown2,
1458 IN PUNICODE_STRING DllName,
1459 OUT PVOID *BaseAddress)
1460 {
1461 UNICODE_STRING FullDllName;
1462 PLIST_ENTRY ModuleListHead;
1463 PLIST_ENTRY Entry;
1464 PLDR_MODULE Module;
1465
1466 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1467 Unknown1, Unknown2, DllName, BaseAddress);
1468
1469 /* NULL is the current executable */
1470 if ( DllName == NULL )
1471 {
1472 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1473 DPRINT("BaseAddress %x\n", *BaseAddress);
1474 return STATUS_SUCCESS;
1475 }
1476
1477 LdrAdjustDllName (&FullDllName,
1478 DllName,
1479 TRUE);
1480
1481 DPRINT("FullDllName %wZ\n",
1482 &FullDllName);
1483
1484 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1485 Entry = ModuleListHead->Flink;
1486
1487 while (Entry != ModuleListHead)
1488 {
1489 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1490
1491 DPRINT("EntryPoint %x\n", Module->EntryPoint);
1492 DPRINT("Comparing %wZ and %wZ\n",
1493 &Module->BaseDllName,
1494 &FullDllName);
1495
1496 if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE))
1497 {
1498 RtlFreeUnicodeString (&FullDllName);
1499 *BaseAddress = Module->BaseAddress;
1500 DPRINT("BaseAddress %x\n", *BaseAddress);
1501 return STATUS_SUCCESS;
1502 }
1503
1504 Entry = Entry->Flink;
1505 }
1506
1507 DPRINT("Failed to find dll %wZ\n", &FullDllName);
1508 RtlFreeUnicodeString (&FullDllName);
1509 *BaseAddress = NULL;
1510 return STATUS_DLL_NOT_FOUND;
1511 }
1512
1513
1514 NTSTATUS STDCALL
1515 LdrGetProcedureAddress (IN PVOID BaseAddress,
1516 IN PANSI_STRING Name,
1517 IN ULONG Ordinal,
1518 OUT PVOID *ProcedureAddress)
1519 {
1520 PIMAGE_EXPORT_DIRECTORY ExportDir;
1521 PUSHORT OrdinalPtr;
1522 PULONG NamePtr;
1523 PULONG AddressPtr;
1524 ULONG i = 0;
1525
1526 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1527 BaseAddress, Name, Ordinal, ProcedureAddress);
1528
1529 /* Get the pointer to the export directory */
1530 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1531 RtlImageDirectoryEntryToData (BaseAddress,
1532 TRUE,
1533 IMAGE_DIRECTORY_ENTRY_EXPORT,
1534 &i);
1535
1536 DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1537
1538 if (!ExportDir || !i || !ProcedureAddress)
1539 {
1540 return STATUS_INVALID_PARAMETER;
1541 }
1542
1543 AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1544 if (Name && Name->Length)
1545 {
1546 /* by name */
1547 OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
1548 NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
1549 for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
1550 {
1551 if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1552 {
1553 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1554 return STATUS_SUCCESS;
1555 }
1556 }
1557 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1558 }
1559 else
1560 {
1561 /* by ordinal */
1562 Ordinal &= 0x0000FFFF;
1563 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1564 {
1565 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1566 return STATUS_SUCCESS;
1567 }
1568 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1569 }
1570
1571 return STATUS_PROCEDURE_NOT_FOUND;
1572 }
1573
1574
1575 NTSTATUS STDCALL
1576 LdrShutdownProcess (VOID)
1577 {
1578 PLIST_ENTRY ModuleListHead;
1579 PLIST_ENTRY Entry;
1580 PLDR_MODULE Module;
1581
1582 DPRINT("LdrShutdownProcess() called\n");
1583
1584 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1585
1586 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1587 Entry = ModuleListHead->Blink;
1588
1589 while (Entry != ModuleListHead)
1590 {
1591 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1592
1593 DPRINT(" Unloading %S\n",
1594 &Module->BaseDllName);
1595 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1596 // they loaded dynamically, and when the last reference is gone, that lib will
1597 // be detached.
1598 if (Module->EntryPoint != 0 && Module->LoadCount == -1)
1599 {
1600 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1601
1602 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1603 Entrypoint (Module->BaseAddress,
1604 DLL_PROCESS_DETACH,
1605 NULL);
1606 }
1607
1608 Entry = Entry->Blink;
1609 }
1610
1611 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1612
1613 DPRINT("LdrShutdownProcess() done\n");
1614
1615 return STATUS_SUCCESS;
1616 }
1617
1618
1619 NTSTATUS STDCALL
1620 LdrShutdownThread (VOID)
1621 {
1622 PLIST_ENTRY ModuleListHead;
1623 PLIST_ENTRY Entry;
1624 PLDR_MODULE Module;
1625
1626 DPRINT("LdrShutdownThread() called\n");
1627
1628 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1629
1630 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1631 Entry = ModuleListHead->Blink;
1632
1633 while (Entry != ModuleListHead)
1634 {
1635 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1636
1637 DPRINT(" Unloading %wZ\n",
1638 &Module->BaseDllName);
1639
1640 if (Module->EntryPoint != 0)
1641 {
1642 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1643
1644 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1645 Entrypoint (Module->BaseAddress,
1646 DLL_THREAD_DETACH,
1647 NULL);
1648 }
1649
1650 Entry = Entry->Blink;
1651 }
1652
1653 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1654
1655 DPRINT("LdrShutdownThread() done\n");
1656
1657 return STATUS_SUCCESS;
1658 }
1659
1660 /* EOF */