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