1 /* $Id: utils.c,v 1.10 1999/08/29 06:59:04 ea 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_PEHDR
16 #include <ddk/ntddk.h>
19 #include <internal/string.h>
21 #include <ntdll/ldr.h>
23 #ifdef DBG_NTDLL_LDR_UTILS
26 #include <ntdll/ntdll.h>
28 /* FUNCTIONS *****************************************************************/
31 /* Type for a DLL's entry point */
37 ULONG ul_reason_for_call
,
42 /**********************************************************************
64 char fqname
[255] = "\\??\\C:\\reactos\\system32\\";
65 ANSI_STRING AnsiString
;
66 UNICODE_STRING UnicodeString
;
67 OBJECT_ATTRIBUTES FileObjectAttributes
;
68 char BlockBuffer
[1024];
69 PIMAGE_DOS_HEADER DosHeader
;
71 PIMAGE_NT_HEADERS NTHeaders
;
72 PEPFUNC DllStartupAddr
;
74 ULONG InitialViewSize
;
78 PDLLMAIN_FUNC Entrypoint
;
81 DPRINT("LdrLoadDll(Base %x, Name \"%s\")\n", Dll
, Name
);
84 * Build the DLL's absolute name
88 DPRINT("fqname \"%s\"\n", fqname
);
90 * Open the DLL's image file.
96 RtlAnsiStringToUnicodeString(
102 InitializeObjectAttributes(
103 & FileObjectAttributes
,
110 DPRINT("Opening dll \"%s\"\n", fqname
);
115 & FileObjectAttributes
,
120 if (!NT_SUCCESS(Status
))
122 DPRINT("Dll open failed: Status = 0x%08x\n", Status
);
136 if (!NT_SUCCESS(Status
))
138 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
143 * Overlay DOS and NT headers structures to the
144 * buffer with DLL's header raw data.
146 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
147 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
149 * Check it is a PE image file.
151 if ( (DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
152 || (DosHeader
->e_lfanew
== 0L)
153 // || (*(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
154 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
)
157 DPRINT("NTDLL format invalid\n");
160 return STATUS_UNSUCCESSFUL
;
163 // NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
164 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
165 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
167 DPRINT("ImageBase 0x%08x\n", ImageBase
);
172 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
175 * Create a section for NTDLL.
177 Status
= ZwCreateSection(
186 if (!NT_SUCCESS(Status
))
188 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
193 * Map the NTDLL into the process.
197 + sizeof (IMAGE_NT_HEADERS
)
198 + sizeof (IMAGE_SECTION_HEADER
) * NTHeaders
->FileHeader
.NumberOfSections
;
199 Status
= ZwMapViewOfSection(
202 (PVOID
*) & ImageBase
,
211 if (!NT_SUCCESS(Status
))
213 DPRINT("NTDLL.LDR: map view of section failed ");
220 (*Dll
) = RtlAllocateHeap(
225 (*Dll
)->Headers
= NTHeaders
;
226 (*Dll
)->BaseAddress
= (PVOID
)ImageBase
;
227 (*Dll
)->Next
= LdrDllListHead
.Next
;
228 (*Dll
)->Prev
= & LdrDllListHead
;
229 LdrDllListHead
.Next
->Prev
= (*Dll
);
230 LdrDllListHead
.Next
= (*Dll
);
233 (PDLLMAIN_FUNC
) LdrPEStartup(
237 if (Entrypoint
!= NULL
)
239 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
240 if (FALSE
== Entrypoint(
246 DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname
);
247 /* FIXME: should clean up and fail */
251 DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname
);
256 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname
);
259 return STATUS_SUCCESS
;
263 /**********************************************************************
285 PIMAGE_EXPORT_DIRECTORY ExportDir
;
287 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
290 DPRINT("NTDLL.LdrFindDll(Name %s)\n", Name
);
292 current
= & LdrDllListHead
;
295 OptionalHeader
= & current
->Headers
->OptionalHeader
;
296 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
297 OptionalHeader
->DataDirectory
[
298 IMAGE_DIRECTORY_ENTRY_EXPORT
].VirtualAddress
;
299 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
300 ((ULONG
)ExportDir
+ (ULONG
)current
->BaseAddress
);
302 DPRINT("Scanning %x %x %x\n",
304 current
->BaseAddress
,
305 (ExportDir
->Name
+ current
->BaseAddress
)
307 DPRINT("Scanning %s\n",
308 ExportDir
->Name
+ current
->BaseAddress
310 if (strcmp(ExportDir
->Name
+ current
->BaseAddress
, Name
) == 0)
313 return STATUS_SUCCESS
;
316 current
= current
->Next
;
318 } while (current
!= & LdrDllListHead
);
320 dprintf("Failed to find dll %s\n",Name
);
322 return (LdrLoadDll(Dll
, Name
));
326 /**********************************************************************
343 HANDLE ProcessHandle
,
345 HANDLE SectionHandle
,
346 PIMAGE_NT_HEADERS NTHeaders
354 (i
< NTHeaders
->FileHeader
.NumberOfSections
);
358 PIMAGE_SECTION_HEADER Sections
;
359 LARGE_INTEGER Offset
;
362 Sections
= (PIMAGE_SECTION_HEADER
) SECHDROFFSET(ImageBase
);
363 Base
= (ULONG
) (Sections
[i
].VirtualAddress
+ ImageBase
);
364 Offset
.u
.LowPart
= Sections
[i
].PointerToRawData
;
365 Offset
.u
.HighPart
= 0;
366 Status
= ZwMapViewOfSection(
371 Sections
[i
].Misc
.VirtualSize
,
373 (PULONG
) & Sections
[i
].Misc
.VirtualSize
,
378 if (!NT_SUCCESS(Status
))
383 return STATUS_SUCCESS
;
387 /**********************************************************************
389 * LdrGetExportByOrdinal
404 LdrGetExportByOrdinal (
409 PIMAGE_EXPORT_DIRECTORY ExportDir
;
410 PDWORD
* ExFunctions
;
415 + (Module
->Headers
->OptionalHeader
416 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
421 ExOrdinals
= (USHORT
*)
424 ExportDir
->AddressOfNameOrdinals
426 ExFunctions
= (PDWORD
*)
429 ExportDir
->AddressOfFunctions
432 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
434 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
436 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
440 /**********************************************************************
462 PIMAGE_EXPORT_DIRECTORY ExportDir
;
463 PDWORD
* ExFunctions
;
471 "LdrFindExport(Module %x, SymbolName %s)\n",
478 + (Module
->Headers
->OptionalHeader
479 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]
484 * Get header pointers
489 ExportDir
->AddressOfNames
491 ExOrdinals
= (USHORT
*)
494 ExportDir
->AddressOfNameOrdinals
496 ExFunctions
= (PDWORD
*)
499 ExportDir
->AddressOfFunctions
502 ( i
< ExportDir
->NumberOfFunctions
);
511 "Comparing '%s' '%s'\n",
515 if (strcmp(ExName
,SymbolName
) == 0)
517 Ordinal
= ExOrdinals
[i
];
518 return(RVA(Module
->BaseAddress
, ExFunctions
[Ordinal
]));
522 dprintf("LdrGetExportByName() = failed to find %s\n",SymbolName
);
528 /**********************************************************************
530 * LdrPerformRelocations
533 * Relocate a DLL's memory image.
546 LdrPerformRelocations (
547 PIMAGE_NT_HEADERS NTHeaders
,
551 USHORT NumberOfEntries
;
557 PRELOCATION_DIRECTORY RelocationDir
;
558 PRELOCATION_ENTRY RelocationBlock
;
563 NTHeaders
->OptionalHeader
564 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
568 RelocationDir
= (PRELOCATION_DIRECTORY
)
569 ((PCHAR
)ImageBase
+ RelocationRVA
);
571 while (RelocationDir
->SizeOfBlock
)
573 Delta32
= (unsigned long) (
575 - NTHeaders
->OptionalHeader
.ImageBase
577 RelocationBlock
= (PRELOCATION_ENTRY
) (
580 + sizeof (RELOCATION_DIRECTORY
)
583 RelocationDir
->SizeOfBlock
584 - sizeof (RELOCATION_DIRECTORY
)
586 / sizeof (RELOCATION_ENTRY
);
589 (i
< NumberOfEntries
);
594 RelocationBlock
[i
].TypeOffset
597 + RelocationDir
->VirtualAddress
;
599 * What kind of relocations should we perform
600 * for the current entry?
602 switch (RelocationBlock
[i
].TypeOffset
>> 12)
604 case TYPE_RELOC_ABSOLUTE
:
607 case TYPE_RELOC_HIGH
:
608 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
609 *pValue16
+= Delta32
>> 16;
613 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
614 *pValue16
+= Delta32
& 0xffff;
617 case TYPE_RELOC_HIGHLOW
:
618 pValue32
= (PULONG
) (ImageBase
+ Offset
);
619 *pValue32
+= Delta32
;
622 case TYPE_RELOC_HIGHADJ
:
623 /* FIXME: do the highadjust fixup */
625 "TYPE_RELOC_HIGHADJ fixup not implemented"
628 return(STATUS_UNSUCCESSFUL
);
631 DPRINT("unexpected fixup type\n");
632 return STATUS_UNSUCCESSFUL
;
635 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
636 RelocationDir
= (PRELOCATION_DIRECTORY
) (
642 return STATUS_SUCCESS
;
646 /**********************************************************************
651 * Compute the entry point for every symbol the DLL imports
652 * from other modules.
666 PIMAGE_NT_HEADERS NTHeaders
,
670 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
677 * Process each import module.
679 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
) (
681 + NTHeaders
->OptionalHeader
682 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
685 while (ImportModuleDirectory
->dwRVAModuleName
)
687 PVOID
* ImportAddressList
;
688 PULONG FunctionNameList
;
696 + ImportModuleDirectory
->dwRVAModuleName
699 if (!NT_SUCCESS(Status
))
704 * Get the import address list.
706 ImportAddressList
= (PVOID
*) (
707 NTHeaders
->OptionalHeader
.ImageBase
708 + ImportModuleDirectory
->dwRVAFunctionAddressList
711 * Get the list of functions to import.
713 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
715 FunctionNameList
= (PULONG
) (
717 + ImportModuleDirectory
->dwRVAFunctionNameList
722 FunctionNameList
= (PULONG
) (
724 + ImportModuleDirectory
->dwRVAFunctionAddressList
728 * Walk through function list and fixup addresses.
730 while (*FunctionNameList
!= 0L)
732 if ((*FunctionNameList
) & 0x80000000)
734 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
736 LdrGetExportByOrdinal(
758 if ((*ImportAddressList
) == NULL
)
760 return STATUS_UNSUCCESSFUL
;
766 ImportModuleDirectory
++;
768 return STATUS_SUCCESS
;
772 /**********************************************************************
777 * 1. Map the DLL's sections into memory.
778 * 2. Relocate, if needed the DLL.
779 * 3. Fixup any imported symbol.
780 * 4. Compute the DLL's entry point.
784 * Address at which the DLL's image
788 * Handle of the section that contains
792 * NULL on error; otherwise the entry point
793 * to call for initializing the DLL.
808 PIMAGE_DOS_HEADER DosHeader
;
809 PIMAGE_NT_HEADERS NTHeaders
;
813 * Overlay DOS and WNT headers structures
814 * to the DLL's image.
816 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
817 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
819 * Initialize image sections.
828 * If the base address is different from the
829 * one the DLL is actually loaded, perform any
832 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
834 Status
= LdrPerformRelocations(
838 if (!NT_SUCCESS(Status
))
840 dprintf("LdrPerformRelocations() failed\n");
845 * If the DLL's imports symbols from other
846 * modules, fixup the imported calls entry points.
848 if (NTHeaders
->OptionalHeader
849 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
850 .VirtualAddress
!= 0)
852 Status
= LdrFixupImports(
856 if (!NT_SUCCESS(Status
))
858 dprintf("LdrFixupImports() failed\n");
863 * Compute the DLL's entry point's address.
865 EntryPoint
= (PEPFUNC
) (
867 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
869 dprintf("LdrPEStartup() = %x\n",EntryPoint
);