1 /* $Id: utils.c,v 1.12 1999/10/17 18:16:31 ariadne Exp $
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)
11 /* INCLUDES *****************************************************************/
13 #include <reactos/config.h>
14 #define WIN32_NO_STATUS
15 #define WIN32_NO_PEHDR
17 #include <ddk/ntddk.h>
20 #include <internal/string.h>
22 #include <ntdll/ldr.h>
24 #ifdef DBG_NTDLL_LDR_UTILS
27 #include <ntdll/ntdll.h>
29 /* FUNCTIONS *****************************************************************/
32 /* Type for a DLL's entry point */
38 ULONG ul_reason_for_call
,
44 LdrFindDll (PDLL
* Dll
,PCHAR Name
);
46 /**********************************************************************
68 char fqname
[255] = "\\??\\C:\\reactos\\system32\\";
69 ANSI_STRING AnsiString
;
70 UNICODE_STRING UnicodeString
;
71 OBJECT_ATTRIBUTES FileObjectAttributes
;
72 char BlockBuffer
[1024];
73 PIMAGE_DOS_HEADER DosHeader
;
75 PIMAGE_NT_HEADERS NTHeaders
;
76 PEPFUNC DllStartupAddr
;
78 ULONG InitialViewSize
;
82 PDLLMAIN_FUNC Entrypoint
;
85 DPRINT("LdrLoadDll(Base %x, Name \"%s\")\n", Dll
, Name
);
87 if ( LdrFindDll(Dll
,Name
) == STATUS_SUCCESS
)
88 return STATUS_SUCCESS
;
91 * Build the DLL's absolute name
95 DPRINT("fqname \"%s\"\n", fqname
);
97 * Open the DLL's image file.
103 RtlAnsiStringToUnicodeString(
109 InitializeObjectAttributes(
110 & FileObjectAttributes
,
117 DPRINT("Opening dll \"%s\"\n", fqname
);
122 & FileObjectAttributes
,
127 if (!NT_SUCCESS(Status
))
129 DPRINT("Dll open failed: Status = 0x%08x\n", Status
);
143 if (!NT_SUCCESS(Status
))
145 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
150 * Overlay DOS and NT headers structures to the
151 * buffer with DLL's header raw data.
153 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
154 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
156 * Check it is a PE image file.
158 if ( (DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
159 || (DosHeader
->e_lfanew
== 0L)
160 // || (*(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
161 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
)
164 DPRINT("NTDLL format invalid\n");
167 return STATUS_UNSUCCESSFUL
;
170 // NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
171 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
172 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
174 DPRINT("ImageBase 0x%08x\n", ImageBase
);
179 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
182 * Create a section for NTDLL.
184 Status
= ZwCreateSection(
193 if (!NT_SUCCESS(Status
))
195 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
200 * Map the NTDLL into the process.
204 + sizeof (IMAGE_NT_HEADERS
)
205 + sizeof (IMAGE_SECTION_HEADER
) * NTHeaders
->FileHeader
.NumberOfSections
;
206 Status
= ZwMapViewOfSection(
209 (PVOID
*) & ImageBase
,
218 if (!NT_SUCCESS(Status
))
220 DPRINT("NTDLL.LDR: map view of section failed ");
227 (*Dll
) = RtlAllocateHeap(
232 (*Dll
)->Headers
= NTHeaders
;
233 (*Dll
)->BaseAddress
= (PVOID
)ImageBase
;
234 (*Dll
)->Next
= LdrDllListHead
.Next
;
235 (*Dll
)->Prev
= & LdrDllListHead
;
236 (*Dll
)->ReferenceCount
= 1;
237 LdrDllListHead
.Next
->Prev
= (*Dll
);
238 LdrDllListHead
.Next
= (*Dll
);
241 (PDLLMAIN_FUNC
) LdrPEStartup(
245 if (Entrypoint
!= NULL
)
247 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
248 if (FALSE
== Entrypoint(
254 DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname
);
255 /* FIXME: should clean up and fail */
259 DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname
);
264 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname
);
267 return STATUS_SUCCESS
;
271 /**********************************************************************
293 PIMAGE_EXPORT_DIRECTORY ExportDir
;
295 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
298 DPRINT("NTDLL.LdrFindDll(Name %s)\n", Name
);
300 current
= & LdrDllListHead
;
303 OptionalHeader
= & current
->Headers
->OptionalHeader
;
304 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
305 OptionalHeader
->DataDirectory
[
306 IMAGE_DIRECTORY_ENTRY_EXPORT
].VirtualAddress
;
307 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
308 ((ULONG
)ExportDir
+ (ULONG
)current
->BaseAddress
);
310 DPRINT("Scanning %x %x %x\n",
312 current
->BaseAddress
,
313 (ExportDir
->Name
+ current
->BaseAddress
)
315 DPRINT("Scanning %s\n",
316 ExportDir
->Name
+ current
->BaseAddress
318 if (strcmp(ExportDir
->Name
+ current
->BaseAddress
, Name
) == 0)
321 current
->ReferenceCount
++;
322 return STATUS_SUCCESS
;
325 current
= current
->Next
;
327 } while (current
!= & LdrDllListHead
);
329 dprintf("Failed to find dll %s\n",Name
);
335 /**********************************************************************
352 HANDLE ProcessHandle
,
354 HANDLE SectionHandle
,
355 PIMAGE_NT_HEADERS NTHeaders
363 (i
< NTHeaders
->FileHeader
.NumberOfSections
);
367 PIMAGE_SECTION_HEADER Sections
;
368 LARGE_INTEGER Offset
;
371 Sections
= (PIMAGE_SECTION_HEADER
) SECHDROFFSET(ImageBase
);
372 Base
= (ULONG
) (Sections
[i
].VirtualAddress
+ ImageBase
);
373 Offset
.u
.LowPart
= Sections
[i
].PointerToRawData
;
374 Offset
.u
.HighPart
= 0;
375 Status
= ZwMapViewOfSection(
380 Sections
[i
].Misc
.VirtualSize
,
382 (PULONG
) & Sections
[i
].Misc
.VirtualSize
,
387 if (!NT_SUCCESS(Status
))
392 return STATUS_SUCCESS
;
396 /**********************************************************************
398 * LdrGetExportByOrdinal
413 LdrGetExportByOrdinal (
418 PIMAGE_EXPORT_DIRECTORY ExportDir
;
419 PDWORD
* ExFunctions
;
424 + (Module
->Headers
->OptionalHeader
425 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
430 ExOrdinals
= (USHORT
*)
433 ExportDir
->AddressOfNameOrdinals
435 ExFunctions
= (PDWORD
*)
438 ExportDir
->AddressOfFunctions
441 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
443 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
445 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
449 /**********************************************************************
471 PIMAGE_EXPORT_DIRECTORY ExportDir
;
472 PDWORD
* ExFunctions
;
480 "LdrFindExport(Module %x, SymbolName %s)\n",
487 + (Module
->Headers
->OptionalHeader
488 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
493 * Get header pointers
498 ExportDir
->AddressOfNames
500 ExOrdinals
= (USHORT
*)
503 ExportDir
->AddressOfNameOrdinals
505 ExFunctions
= (PDWORD
*)
508 ExportDir
->AddressOfFunctions
511 ( i
< ExportDir
->NumberOfFunctions
);
520 "Comparing '%s' '%s'\n",
524 if (strcmp(ExName
,SymbolName
) == 0)
526 Ordinal
= ExOrdinals
[i
];
527 return(RVA(Module
->BaseAddress
, ExFunctions
[Ordinal
]));
531 dprintf("LdrGetExportByName() = failed to find %s\n",SymbolName
);
537 /**********************************************************************
539 * LdrPerformRelocations
542 * Relocate a DLL's memory image.
555 LdrPerformRelocations (
556 PIMAGE_NT_HEADERS NTHeaders
,
560 USHORT NumberOfEntries
;
566 PRELOCATION_DIRECTORY RelocationDir
;
567 PRELOCATION_ENTRY RelocationBlock
;
572 NTHeaders
->OptionalHeader
573 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
577 RelocationDir
= (PRELOCATION_DIRECTORY
)
578 ((PCHAR
)ImageBase
+ RelocationRVA
);
580 while (RelocationDir
->SizeOfBlock
)
582 Delta32
= (unsigned long) (
584 - NTHeaders
->OptionalHeader
.ImageBase
586 RelocationBlock
= (PRELOCATION_ENTRY
) (
589 + sizeof (RELOCATION_DIRECTORY
)
592 RelocationDir
->SizeOfBlock
593 - sizeof (RELOCATION_DIRECTORY
)
595 / sizeof (RELOCATION_ENTRY
);
598 (i
< NumberOfEntries
);
603 RelocationBlock
[i
].TypeOffset
606 + RelocationDir
->VirtualAddress
;
608 * What kind of relocations should we perform
609 * for the current entry?
611 switch (RelocationBlock
[i
].TypeOffset
>> 12)
613 case TYPE_RELOC_ABSOLUTE
:
616 case TYPE_RELOC_HIGH
:
617 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
618 *pValue16
+= Delta32
>> 16;
622 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
623 *pValue16
+= Delta32
& 0xffff;
626 case TYPE_RELOC_HIGHLOW
:
627 pValue32
= (PULONG
) (ImageBase
+ Offset
);
628 *pValue32
+= Delta32
;
631 case TYPE_RELOC_HIGHADJ
:
632 /* FIXME: do the highadjust fixup */
634 "TYPE_RELOC_HIGHADJ fixup not implemented"
637 return(STATUS_UNSUCCESSFUL
);
640 DPRINT("unexpected fixup type\n");
641 return STATUS_UNSUCCESSFUL
;
644 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
645 RelocationDir
= (PRELOCATION_DIRECTORY
) (
651 return STATUS_SUCCESS
;
655 /**********************************************************************
660 * Compute the entry point for every symbol the DLL imports
661 * from other modules.
675 PIMAGE_NT_HEADERS NTHeaders
,
679 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
686 * Process each import module.
688 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
) (
690 + NTHeaders
->OptionalHeader
691 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
694 while (ImportModuleDirectory
->dwRVAModuleName
)
696 PVOID
* ImportAddressList
;
697 PULONG FunctionNameList
;
705 + ImportModuleDirectory
->dwRVAModuleName
708 if (!NT_SUCCESS(Status
))
713 * Get the import address list.
715 ImportAddressList
= (PVOID
*) (
716 NTHeaders
->OptionalHeader
.ImageBase
717 + ImportModuleDirectory
->dwRVAFunctionAddressList
720 * Get the list of functions to import.
722 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
724 FunctionNameList
= (PULONG
) (
726 + ImportModuleDirectory
->dwRVAFunctionNameList
731 FunctionNameList
= (PULONG
) (
733 + ImportModuleDirectory
->dwRVAFunctionAddressList
737 * Walk through function list and fixup addresses.
739 while (*FunctionNameList
!= 0L)
741 if ((*FunctionNameList
) & 0x80000000)
743 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
745 LdrGetExportByOrdinal(
767 if ((*ImportAddressList
) == NULL
)
769 return STATUS_UNSUCCESSFUL
;
775 ImportModuleDirectory
++;
777 return STATUS_SUCCESS
;
781 /**********************************************************************
786 * 1. Map the DLL's sections into memory.
787 * 2. Relocate, if needed the DLL.
788 * 3. Fixup any imported symbol.
789 * 4. Compute the DLL's entry point.
793 * Address at which the DLL's image
797 * Handle of the section that contains
801 * NULL on error; otherwise the entry point
802 * to call for initializing the DLL.
817 PIMAGE_DOS_HEADER DosHeader
;
818 PIMAGE_NT_HEADERS NTHeaders
;
822 * Overlay DOS and WNT headers structures
823 * to the DLL's image.
825 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
826 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
828 * Initialize image sections.
837 * If the base address is different from the
838 * one the DLL is actually loaded, perform any
841 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
843 Status
= LdrPerformRelocations(
847 if (!NT_SUCCESS(Status
))
849 dprintf("LdrPerformRelocations() failed\n");
854 * If the DLL's imports symbols from other
855 * modules, fixup the imported calls entry points.
857 if (NTHeaders
->OptionalHeader
858 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
859 .VirtualAddress
!= 0)
861 Status
= LdrFixupImports(
865 if (!NT_SUCCESS(Status
))
867 dprintf("LdrFixupImports() failed\n");
872 * Compute the DLL's entry point's address.
874 EntryPoint
= (PEPFUNC
) (
876 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
878 dprintf("LdrPEStartup() = %x\n",EntryPoint
);
882 NTSTATUS
LdrUnloadDll(PDLL Dll
)
885 PDLLMAIN_FUNC Entrypoint
;
889 if ( Dll
->ReferenceCount
> 1 ) {
890 Dll
->ReferenceCount
--;
891 return STATUS_SUCCESS
;
895 (PDLLMAIN_FUNC
) LdrPEStartup(
899 if (Entrypoint
!= NULL
)
901 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
902 if (FALSE
== Entrypoint(
908 DPRINT("NTDLL.LDR: DLL failed to detach\n");
913 DPRINT("NTDLL.LDR: DLL detached successfully\n");
918 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
922 Status
= ZwUnmapViewOfSection(
927 ZwClose(Dll
->SectionHandle
);