Put in updated version of bitops header
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.19 1999/12/11 21:14:47 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 /* INCLUDES *****************************************************************/
12
13 #include <reactos/config.h>
14 #define WIN32_NO_STATUS
15 #define WIN32_NO_PEHDR
16 #include <windows.h>
17 #include <ddk/ntddk.h>
18 #include <pe.h>
19 #include <string.h>
20 #include <internal/string.h>
21 #include <wchar.h>
22 #include <ntdll/ldr.h>
23
24 #ifdef DBG_NTDLL_LDR_UTILS
25 #define NDEBUG
26 #endif
27 #include <ntdll/ntdll.h>
28
29 /* FUNCTIONS *****************************************************************/
30
31
32 /* Type for a DLL's entry point */
33 typedef
34 WINBOOL
35 STDCALL
36 (* PDLLMAIN_FUNC) (
37 HANDLE hInst,
38 ULONG ul_reason_for_call,
39 LPVOID lpReserved
40 );
41
42 static
43 NTSTATUS
44 LdrFindDll (PDLL* Dll,PCHAR Name);
45
46 /**********************************************************************
47 * NAME
48 * LdrLoadDll
49 *
50 * DESCRIPTION
51 *
52 * ARGUMENTS
53 *
54 * RETURN VALUE
55 *
56 * REVISIONS
57 *
58 * NOTE
59 *
60 */
61
62 NTSTATUS LdrLoadDll (PDLL* Dll,
63 PCHAR Name)
64 {
65 char fqname [255] = "\\??\\C:\\reactos\\system32\\";
66 ANSI_STRING AnsiString;
67 UNICODE_STRING UnicodeString;
68 OBJECT_ATTRIBUTES FileObjectAttributes;
69 char BlockBuffer [1024];
70 PIMAGE_DOS_HEADER DosHeader;
71 NTSTATUS Status;
72 PIMAGE_NT_HEADERS NTHeaders;
73 PEPFUNC DllStartupAddr;
74 ULONG ImageSize;
75 ULONG InitialViewSize;
76 PVOID ImageBase;
77 HANDLE FileHandle;
78 HANDLE SectionHandle;
79 PDLLMAIN_FUNC Entrypoint;
80
81 if ( Dll == NULL )
82 return -1;
83
84 if ( Name == NULL ) {
85 *Dll = &LdrDllListHead;
86 return STATUS_SUCCESS;
87 }
88
89 DPRINT("LdrLoadDll(Base %x, Name \"%s\")\n", Dll, Name);
90
91 /*
92 * Build the DLL's absolute name
93 */
94
95 if ( strncmp(Name,"\\??\\",3) != 0 ) {
96
97 strcat(fqname, Name);
98 }
99 else
100 strncpy(fqname, Name, 256);
101
102 DPRINT("fqname \"%s\"\n", fqname);
103 /*
104 * Open the DLL's image file.
105 */
106
107 if (LdrFindDll(Dll, Name) == STATUS_SUCCESS)
108 return STATUS_SUCCESS;
109
110
111 RtlInitAnsiString(
112 & AnsiString,
113 fqname
114 );
115 RtlAnsiStringToUnicodeString(
116 & UnicodeString,
117 & AnsiString,
118 TRUE
119 );
120
121 InitializeObjectAttributes(
122 & FileObjectAttributes,
123 & UnicodeString,
124 0,
125 NULL,
126 NULL
127 );
128
129 DPRINT("Opening dll \"%s\"\n", fqname);
130
131 Status = ZwOpenFile(
132 & FileHandle,
133 FILE_ALL_ACCESS,
134 & FileObjectAttributes,
135 NULL,
136 0,
137 0
138 );
139 if (!NT_SUCCESS(Status))
140 {
141 dprintf("Dll open of %s failed: Status = 0x%08x\n",
142 fqname, Status);
143 return Status;
144 }
145 Status = ZwReadFile(
146 FileHandle,
147 0,
148 0,
149 0,
150 0,
151 BlockBuffer,
152 sizeof BlockBuffer,
153 0,
154 0
155 );
156 if (!NT_SUCCESS(Status))
157 {
158 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
159 ZwClose(FileHandle);
160 return Status;
161 }
162 /*
163 * Overlay DOS and NT headers structures to the
164 * buffer with DLL's header raw data.
165 */
166 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
167 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
168 /*
169 * Check it is a PE image file.
170 */
171 if ( (DosHeader->e_magic != IMAGE_DOS_MAGIC)
172 || (DosHeader->e_lfanew == 0L)
173 // || (*(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
174 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC)
175 )
176 {
177 DPRINT("NTDLL format invalid\n");
178 ZwClose(FileHandle);
179
180 return STATUS_UNSUCCESSFUL;
181 }
182
183 // NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
184 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
185 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
186
187 DPRINT("ImageBase 0x%08x\n", ImageBase);
188
189 DllStartupAddr =
190 (PEPFUNC) (
191 ImageBase
192 + NTHeaders->OptionalHeader.AddressOfEntryPoint
193 );
194 /*
195 * Create a section for NTDLL.
196 */
197 Status = ZwCreateSection(
198 & SectionHandle,
199 SECTION_ALL_ACCESS,
200 NULL,
201 NULL,
202 PAGE_READWRITE,
203 MEM_COMMIT,
204 FileHandle
205 );
206 if (!NT_SUCCESS(Status))
207 {
208 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
209 ZwClose(FileHandle);
210 return Status;
211 }
212 /*
213 * Map the NTDLL into the process.
214 */
215 InitialViewSize =
216 DosHeader->e_lfanew
217 + sizeof (IMAGE_NT_HEADERS)
218 + sizeof (IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
219 Status = ZwMapViewOfSection(
220 SectionHandle,
221 NtCurrentProcess(),
222 (PVOID*)&ImageBase,
223 0,
224 InitialViewSize,
225 NULL,
226 &InitialViewSize,
227 0,
228 MEM_COMMIT,
229 PAGE_READWRITE
230 );
231 if (!NT_SUCCESS(Status))
232 {
233 dprintf("NTDLL.LDR: map view of section failed (Status %x)\n",
234 Status);
235 ZwClose(FileHandle);
236 return(Status);
237 }
238 ZwClose(FileHandle);
239
240 (*Dll) = RtlAllocateHeap(
241 RtlGetProcessHeap(),
242 0,
243 sizeof (DLL)
244 );
245 (*Dll)->Headers = NTHeaders;
246 (*Dll)->BaseAddress = (PVOID)ImageBase;
247 (*Dll)->Next = LdrDllListHead.Next;
248 (*Dll)->Prev = & LdrDllListHead;
249 (*Dll)->ReferenceCount = 1;
250 LdrDllListHead.Next->Prev = (*Dll);
251 LdrDllListHead.Next = (*Dll);
252
253
254 if (((*Dll)->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
255 IMAGE_FILE_DLL)
256 {
257
258 Entrypoint =
259 (PDLLMAIN_FUNC) LdrPEStartup(
260 ImageBase,
261 SectionHandle
262 );
263 if (Entrypoint != NULL)
264 {
265 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
266 if (FALSE == Entrypoint(
267 Dll,
268 DLL_PROCESS_ATTACH,
269 NULL
270 ))
271 {
272 DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname);
273 /* FIXME: should clean up and fail */
274 }
275 else
276 {
277 DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname);
278 }
279 }
280 else
281 {
282 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname);
283 }
284 }
285 return STATUS_SUCCESS;
286 }
287
288
289 /**********************************************************************
290 * NAME LOCAL
291 * LdrFindDll
292 *
293 * DESCRIPTION
294 *
295 * ARGUMENTS
296 *
297 * RETURN VALUE
298 *
299 * REVISIONS
300 *
301 * NOTE
302 *
303 */
304 static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
305 {
306 PIMAGE_EXPORT_DIRECTORY ExportDir;
307 DLL * current;
308 PIMAGE_OPTIONAL_HEADER OptionalHeader;
309
310
311 DPRINT("NTDLL.LdrFindDll(Name %s)\n", Name);
312
313 current = & LdrDllListHead;
314
315 // NULL is the current process
316
317 if ( Name == NULL )
318 {
319 *Dll = current;
320 return STATUS_SUCCESS;
321 }
322
323 do
324 {
325 OptionalHeader = & current->Headers->OptionalHeader;
326 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
327 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
328 .VirtualAddress;
329 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
330 ((ULONG)ExportDir + (ULONG)current->BaseAddress);
331
332 DPRINT("Scanning %x %x %x\n",ExportDir->Name,
333 current->BaseAddress,
334 (ExportDir->Name + current->BaseAddress));
335 DPRINT("Scanning %s %s\n",
336 ExportDir->Name + current->BaseAddress, Name);
337
338 if (_stricmp(ExportDir->Name + current->BaseAddress, Name) == 0)
339 {
340 *Dll = current;
341 current->ReferenceCount++;
342 return STATUS_SUCCESS;
343 }
344
345 current = current->Next;
346
347 } while (current != & LdrDllListHead);
348
349 DPRINT("Failed to find dll %s\n",Name);
350
351 return -1;
352 }
353
354
355 /**********************************************************************
356 * NAME
357 * LdrMapSections
358 *
359 * DESCRIPTION
360 *
361 * ARGUMENTS
362 *
363 * RETURN VALUE
364 *
365 * REVISIONS
366 *
367 * NOTE
368 *
369 */
370 NTSTATUS LdrMapSections(HANDLE ProcessHandle,
371 PVOID ImageBase,
372 HANDLE SectionHandle,
373 PIMAGE_NT_HEADERS NTHeaders)
374 {
375 ULONG i;
376 NTSTATUS Status;
377
378
379 for (i = 0; (i < NTHeaders->FileHeader.NumberOfSections); i++)
380 {
381 PIMAGE_SECTION_HEADER Sections;
382 LARGE_INTEGER Offset;
383 ULONG Base;
384 ULONG Size;
385
386 Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(ImageBase);
387 Base = (ULONG) (Sections[i].VirtualAddress + ImageBase);
388 Offset.u.LowPart = Sections[i].PointerToRawData;
389 Offset.u.HighPart = 0;
390
391 Size = max(Sections[i].Misc.VirtualSize, Sections[i].SizeOfRawData);
392
393 DPRINT("Mapping section %d offset %x base %x size %x\n",
394 i, Offset.u.LowPart, Base, Sections[i].Misc.VirtualSize);
395 DPRINT("Size %x\n", Sections[i].SizeOfRawData);
396
397 Status = ZwMapViewOfSection(SectionHandle,
398 ProcessHandle,
399 (PVOID*)&Base,
400 0,
401 Size,
402 &Offset,
403 (PULONG)&Size,
404 0,
405 MEM_COMMIT,
406 PAGE_READWRITE);
407 if (!NT_SUCCESS(Status))
408 {
409 DPRINT("Failed to map section");
410 return(Status);
411 }
412 }
413 return STATUS_SUCCESS;
414 }
415
416
417 /**********************************************************************
418 * NAME LOCAL
419 * LdrGetExportByOrdinal
420 *
421 * DESCRIPTION
422 *
423 * ARGUMENTS
424 *
425 * RETURN VALUE
426 *
427 * REVISIONS
428 *
429 * NOTE
430 *
431 */
432
433 PVOID
434 LdrGetExportByOrdinal (
435 PDLL Module,
436 ULONG Ordinal
437 )
438 {
439 PIMAGE_EXPORT_DIRECTORY ExportDir;
440 PDWORD * ExFunctions;
441 USHORT * ExOrdinals;
442
443 ExportDir = (
444 Module->BaseAddress
445 + (Module->Headers->OptionalHeader
446 .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
447 .VirtualAddress
448 )
449 );
450
451 ExOrdinals = (USHORT *)
452 RVA(
453 Module->BaseAddress,
454 ExportDir->AddressOfNameOrdinals
455 );
456 ExFunctions = (PDWORD *)
457 RVA(
458 Module->BaseAddress,
459 ExportDir->AddressOfFunctions
460 );
461 dprintf(
462 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
463 Ordinal,
464 ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
465 );
466 return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
467 }
468
469
470 /**********************************************************************
471 * NAME LOCAL
472 * LdrGetExportByName
473 *
474 * DESCRIPTION
475 *
476 * ARGUMENTS
477 *
478 * RETURN VALUE
479 *
480 * REVISIONS
481 *
482 * NOTE
483 *
484 */
485
486 PVOID
487 LdrGetExportByName (
488 PDLL Module,
489 PUCHAR SymbolName
490 )
491 {
492 PIMAGE_EXPORT_DIRECTORY ExportDir;
493 PDWORD * ExFunctions;
494 PDWORD * ExNames;
495 USHORT * ExOrdinals;
496 ULONG i;
497 PVOID ExName;
498 ULONG Ordinal;
499
500 // DPRINT(
501 // "LdrFindExport(Module %x, SymbolName %s)\n",
502 // Module,
503 // SymbolName
504 // );
505
506 ExportDir = (
507 Module->BaseAddress
508 + (Module->Headers->OptionalHeader
509 .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
510 .VirtualAddress
511 )
512 );
513 /*
514 * Get header pointers
515 */
516 ExNames = (PDWORD *)
517 RVA(
518 Module->BaseAddress,
519 ExportDir->AddressOfNames
520 );
521 ExOrdinals = (USHORT *)
522 RVA(
523 Module->BaseAddress,
524 ExportDir->AddressOfNameOrdinals
525 );
526 ExFunctions = (PDWORD *)
527 RVA(
528 Module->BaseAddress,
529 ExportDir->AddressOfFunctions
530 );
531 for ( i = 0;
532 ( i < ExportDir->NumberOfFunctions);
533 i++
534 )
535 {
536 ExName = RVA(
537 Module->BaseAddress,
538 ExNames[i]
539 );
540 // DPRINT(
541 // "Comparing '%s' '%s'\n",
542 // ExName,
543 // SymbolName
544 // );
545 if (strcmp(ExName,SymbolName) == 0)
546 {
547 Ordinal = ExOrdinals[i];
548 return(RVA(Module->BaseAddress, ExFunctions[Ordinal]));
549 }
550 }
551
552 dprintf("LdrGetExportByName() = failed to find %s\n",SymbolName);
553
554 return NULL;
555 }
556
557
558 /**********************************************************************
559 * NAME LOCAL
560 * LdrPerformRelocations
561 *
562 * DESCRIPTION
563 * Relocate a DLL's memory image.
564 *
565 * ARGUMENTS
566 *
567 * RETURN VALUE
568 *
569 * REVISIONS
570 *
571 * NOTE
572 *
573 */
574 static
575 NTSTATUS
576 LdrPerformRelocations (
577 PIMAGE_NT_HEADERS NTHeaders,
578 PVOID ImageBase
579 )
580 {
581 USHORT NumberOfEntries;
582 PUSHORT pValue16;
583 ULONG RelocationRVA;
584 ULONG Delta32;
585 ULONG Offset;
586 PULONG pValue32;
587 PRELOCATION_DIRECTORY RelocationDir;
588 PRELOCATION_ENTRY RelocationBlock;
589 int i;
590
591
592 RelocationRVA =
593 NTHeaders->OptionalHeader
594 .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
595 .VirtualAddress;
596 if (RelocationRVA)
597 {
598 RelocationDir = (PRELOCATION_DIRECTORY)
599 ((PCHAR)ImageBase + RelocationRVA);
600
601 while (RelocationDir->SizeOfBlock)
602 {
603 Delta32 = (unsigned long) (
604 ImageBase
605 - NTHeaders->OptionalHeader.ImageBase
606 );
607 RelocationBlock = (PRELOCATION_ENTRY) (
608 RelocationRVA
609 + ImageBase
610 + sizeof (RELOCATION_DIRECTORY)
611 );
612 NumberOfEntries = (
613 RelocationDir->SizeOfBlock
614 - sizeof (RELOCATION_DIRECTORY)
615 )
616 / sizeof (RELOCATION_ENTRY);
617
618 for ( i = 0;
619 (i < NumberOfEntries);
620 i++
621 )
622 {
623 Offset = (
624 RelocationBlock[i].TypeOffset
625 & 0xfff
626 )
627 + RelocationDir->VirtualAddress;
628 /*
629 * What kind of relocations should we perform
630 * for the current entry?
631 */
632 switch (RelocationBlock[i].TypeOffset >> 12)
633 {
634 case TYPE_RELOC_ABSOLUTE:
635 break;
636
637 case TYPE_RELOC_HIGH:
638 pValue16 = (PUSHORT) (ImageBase + Offset);
639 *pValue16 += Delta32 >> 16;
640 break;
641
642 case TYPE_RELOC_LOW:
643 pValue16 = (PUSHORT)(ImageBase + Offset);
644 *pValue16 += Delta32 & 0xffff;
645 break;
646
647 case TYPE_RELOC_HIGHLOW:
648 pValue32 = (PULONG) (ImageBase + Offset);
649 *pValue32 += Delta32;
650 break;
651
652 case TYPE_RELOC_HIGHADJ:
653 /* FIXME: do the highadjust fixup */
654 DPRINT(
655 "TYPE_RELOC_HIGHADJ fixup not implemented"
656 ", sorry\n"
657 );
658 return(STATUS_UNSUCCESSFUL);
659
660 default:
661 DPRINT("unexpected fixup type\n");
662 return STATUS_UNSUCCESSFUL;
663 }
664 }
665 RelocationRVA += RelocationDir->SizeOfBlock;
666 RelocationDir = (PRELOCATION_DIRECTORY) (
667 ImageBase
668 + RelocationRVA
669 );
670 }
671 }
672 return STATUS_SUCCESS;
673 }
674
675
676 /**********************************************************************
677 * NAME LOCAL
678 * LdrFixupImports
679 *
680 * DESCRIPTION
681 * Compute the entry point for every symbol the DLL imports
682 * from other modules.
683 *
684 * ARGUMENTS
685 *
686 * RETURN VALUE
687 *
688 * REVISIONS
689 *
690 * NOTE
691 *
692 */
693 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
694 PVOID ImageBase)
695 {
696 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
697 ULONG Ordinal;
698 PDLL Module;
699 NTSTATUS Status;
700
701 DPRINT1("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
702 ImageBase);
703
704 /*
705 * Process each import module.
706 */
707 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
708 ImageBase + NTHeaders->OptionalHeader
709 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
710 .VirtualAddress);
711 DPRINT1("ImportModuleDirectory %x\n", ImportModuleDirectory);
712
713 while (ImportModuleDirectory->dwRVAModuleName)
714 {
715 PVOID * ImportAddressList;
716 PULONG FunctionNameList;
717 DWORD pName;
718 PWORD pHint;
719
720 DPRINT1("ImportModule->Directory->dwRVAModuleName %s\n",
721 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
722
723 Status = LdrLoadDll(&Module,
724 (PCHAR)(ImageBase
725 +ImportModuleDirectory->dwRVAModuleName));
726 if (!NT_SUCCESS(Status))
727 {
728 return Status;
729 }
730 /*
731 * Get the import address list.
732 */
733 ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
734 + ImportModuleDirectory->dwRVAFunctionAddressList);
735
736 /*
737 * Get the list of functions to import.
738 */
739 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
740 {
741 FunctionNameList = (PULONG) (
742 ImageBase
743 + ImportModuleDirectory->dwRVAFunctionNameList
744 );
745 }
746 else
747 {
748 FunctionNameList = (PULONG) (
749 ImageBase
750 + ImportModuleDirectory->dwRVAFunctionAddressList
751 );
752 }
753 /*
754 * Walk through function list and fixup addresses.
755 */
756 while (*FunctionNameList != 0L)
757 {
758 if ((*FunctionNameList) & 0x80000000)
759 {
760 Ordinal = (*FunctionNameList) & 0x7fffffff;
761 *ImportAddressList =
762 LdrGetExportByOrdinal(
763 Module,
764 Ordinal
765 );
766 }
767 else
768 {
769 pName = (DWORD) (
770 ImageBase
771 + *FunctionNameList
772 + 2
773 );
774 pHint = (PWORD) (
775 ImageBase
776 + *FunctionNameList
777 );
778
779 *ImportAddressList =
780 LdrGetExportByName(
781 Module,
782 (PUCHAR) pName
783 );
784 if ((*ImportAddressList) == NULL)
785 {
786 dprintf("Failed to import %s\n", pName);
787 return STATUS_UNSUCCESSFUL;
788 }
789 }
790 ImportAddressList++;
791 FunctionNameList++;
792 }
793 ImportModuleDirectory++;
794 }
795 return STATUS_SUCCESS;
796 }
797
798
799 /**********************************************************************
800 * NAME
801 * LdrPEStartup
802 *
803 * DESCRIPTION
804 * 1. Map the DLL's sections into memory.
805 * 2. Relocate, if needed the DLL.
806 * 3. Fixup any imported symbol.
807 * 4. Compute the DLL's entry point.
808 *
809 * ARGUMENTS
810 * ImageBase
811 * Address at which the DLL's image
812 * is loaded.
813 *
814 * SectionHandle
815 * Handle of the section that contains
816 * the DLL's image.
817 *
818 * RETURN VALUE
819 * NULL on error; otherwise the entry point
820 * to call for initializing the DLL.
821 *
822 * REVISIONS
823 *
824 * NOTE
825 *
826 */
827 PEPFUNC LdrPEStartup (PVOID ImageBase,
828 HANDLE SectionHandle)
829 {
830 NTSTATUS Status;
831 PEPFUNC EntryPoint;
832 PIMAGE_DOS_HEADER DosHeader;
833 PIMAGE_NT_HEADERS NTHeaders;
834
835
836 /*
837 * Overlay DOS and WNT headers structures
838 * to the DLL's image.
839 */
840 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
841 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
842
843 /*
844 * Initialize image sections.
845 */
846 LdrMapSections(NtCurrentProcess(),
847 ImageBase,
848 SectionHandle,
849 NTHeaders);
850
851 /*
852 * If the base address is different from the
853 * one the DLL is actually loaded, perform any
854 * relocation.
855 */
856 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
857 {
858 Status = LdrPerformRelocations(NTHeaders, ImageBase);
859 if (!NT_SUCCESS(Status))
860 {
861 dprintf("LdrPerformRelocations() failed\n");
862 return NULL;
863 }
864 }
865
866 /*
867 * If the DLL's imports symbols from other
868 * modules, fixup the imported calls entry points.
869 */
870 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
871 .VirtualAddress != 0)
872 {
873 DPRINT("About to fixup imports\n");
874 Status = LdrFixupImports(NTHeaders, ImageBase);
875 if (!NT_SUCCESS(Status))
876 {
877 dprintf("LdrFixupImports() failed\n");
878 return NULL;
879 }
880 }
881
882 /*
883 * Compute the DLL's entry point's address.
884 */
885 EntryPoint = (PEPFUNC) (ImageBase
886 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
887 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
888 return EntryPoint;
889 }
890
891 NTSTATUS LdrUnloadDll(PDLL Dll)
892 {
893 PDLLMAIN_FUNC Entrypoint;
894 NTSTATUS Status;
895
896 if ( Dll == NULL || Dll == &LdrDllListHead )
897 return -1;
898
899
900 if ( Dll->ReferenceCount > 1 )
901 {
902 Dll->ReferenceCount--;
903 return STATUS_SUCCESS;
904 }
905
906 if (( Dll->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL ) == IMAGE_FILE_DLL ) {
907
908 Entrypoint = (PDLLMAIN_FUNC) LdrPEStartup(Dll->BaseAddress,
909 Dll->SectionHandle);
910 if (Entrypoint != NULL)
911 {
912 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
913 if (FALSE == Entrypoint(Dll,
914 DLL_PROCESS_DETACH,
915 NULL))
916 {
917 DPRINT("NTDLL.LDR: DLL failed to detach\n");
918 return -1;
919 }
920 else
921 {
922 DPRINT("NTDLL.LDR: DLL detached successfully\n");
923 }
924 }
925 else
926 {
927 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
928 }
929
930 }
931 Status = ZwUnmapViewOfSection(NtCurrentProcess(),
932 Dll->BaseAddress);
933
934 ZwClose(Dll->SectionHandle);
935
936 return Status;
937 }
938
939 static IMAGE_RESOURCE_DIRECTORY_ENTRY * LdrGetNextEntry(IMAGE_RESOURCE_DIRECTORY *ResourceDir, LPCWSTR ResourceName, ULONG Offset)
940 {
941
942
943 WORD NumberOfNamedEntries;
944 WORD NumberOfIdEntries;
945 WORD Entries;
946 ULONG Length;
947
948 if ( (((ULONG)ResourceDir) & 0xF0000000) != 0 ) {
949 return (IMAGE_RESOURCE_DIRECTORY_ENTRY *)NULL;
950 }
951
952
953 NumberOfIdEntries = ResourceDir->NumberOfIdEntries;
954 NumberOfNamedEntries = ResourceDir->NumberOfNamedEntries;
955 if ( ( NumberOfIdEntries + NumberOfNamedEntries) == 0) {
956 return &ResourceDir->DirectoryEntries[0];
957 }
958
959 if ( HIWORD(ResourceName) != 0 ) {
960 Length = wcslen(ResourceName);
961 Entries = ResourceDir->NumberOfNamedEntries;
962 do {
963 IMAGE_RESOURCE_DIR_STRING_U *DirString;
964
965 Entries--;
966 DirString = (IMAGE_RESOURCE_DIR_STRING_U *)(((ULONG)ResourceDir->DirectoryEntries[Entries].Name & (~0xF0000000)) + Offset);
967
968 if ( DirString->Length == Length && wcscmp(DirString->NameString, ResourceName ) == 0 ) {
969 return &ResourceDir->DirectoryEntries[Entries];
970 }
971 } while (Entries > 0);
972 }
973 else {
974 Entries = ResourceDir->NumberOfIdEntries + ResourceDir->NumberOfNamedEntries;
975 do {
976 Entries--;
977
978 if ( (LPWSTR)ResourceDir->DirectoryEntries[Entries].Name == ResourceName ) {
979 return &ResourceDir->DirectoryEntries[Entries];
980 }
981 } while (Entries > ResourceDir->NumberOfNamedEntries);
982
983 }
984
985
986
987 return NULL;
988
989 }
990
991
992
993 NTSTATUS LdrFindResource_U(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY **ResourceDataEntry,LPCWSTR ResourceName, ULONG ResourceType,ULONG Language)
994 {
995 IMAGE_RESOURCE_DIRECTORY *ResourceTypeDir;
996 IMAGE_RESOURCE_DIRECTORY *ResourceNameDir;
997 IMAGE_RESOURCE_DIRECTORY *ResourceLangDir;
998
999 IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceTypeDirEntry;
1000 IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceNameDirEntry;
1001 IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceLangDirEntry;
1002
1003 PIMAGE_OPTIONAL_HEADER OptionalHeader;
1004
1005
1006
1007 ULONG Offset;
1008
1009 OptionalHeader = & Dll->Headers->OptionalHeader;
1010 ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY)
1011 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
1012 ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY)
1013 ((ULONG)ResourceTypeDir + (ULONG)Dll->BaseAddress);
1014
1015
1016 Offset = (ULONG)ResourceTypeDir;
1017
1018 ResourceTypeDirEntry = LdrGetNextEntry(ResourceTypeDir, (LPWSTR)ResourceType, Offset);
1019
1020 if ( ResourceTypeDirEntry != NULL ) {
1021 ResourceNameDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceTypeDirEntry->OffsetToData & (~0xF0000000)) + Offset);
1022
1023 ResourceNameDirEntry = LdrGetNextEntry(ResourceNameDir, ResourceName, Offset);
1024
1025 if ( ResourceNameDirEntry != NULL ) {
1026
1027 ResourceLangDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceNameDirEntry->OffsetToData & (~0xF0000000)) + Offset);
1028
1029 ResourceLangDirEntry = LdrGetNextEntry(ResourceLangDir, (LPWSTR)Language, Offset);
1030 if ( ResourceLangDirEntry != NULL ) {
1031
1032 *ResourceDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)(ResourceLangDirEntry->OffsetToData +
1033 (ULONG)ResourceTypeDir);
1034 return STATUS_SUCCESS;
1035 }
1036 else {
1037 return -1;
1038 }
1039 }
1040 else {
1041 return -1;
1042 }
1043
1044 }
1045
1046 return -1;
1047
1048 }
1049
1050 NTSTATUS LdrAccessResource(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry, void **Data)
1051 {
1052 PIMAGE_SECTION_HEADER Sections;
1053 int i;
1054
1055 if ( Data == NULL )
1056 return -1;
1057
1058 if ( ResourceDataEntry == NULL )
1059 return -1;
1060
1061 if ( Dll == NULL )
1062 return -1;
1063
1064 Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(Dll->BaseAddress);
1065
1066 for ( i = 0;
1067 (i < Dll->Headers->FileHeader.NumberOfSections);
1068 i++
1069 )
1070 {
1071 if (Sections[i].VirtualAddress <= ResourceDataEntry->OffsetToData
1072 && Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize > ResourceDataEntry->OffsetToData )
1073 break;
1074 }
1075
1076 if ( i == Dll->Headers->FileHeader.NumberOfSections ) {
1077 *Data = NULL;
1078 return -1;
1079 }
1080
1081 *Data = (void *)(((ULONG)Dll->BaseAddress + ResourceDataEntry->OffsetToData - (ULONG)Sections[i].VirtualAddress) +
1082 (ULONG)Sections[i].PointerToRawData);
1083
1084
1085 return STATUS_SUCCESS;
1086 }
1087
1088 /* EOF */