1 /* $Id: utils.c,v 1.47 2001/09/01 19:36:30 rex 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)
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
18 /* INCLUDES *****************************************************************/
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27 #include <napi/shared_data.h>
30 #ifdef DBG_NTDLL_LDR_UTILS
33 #include <ntdll/ntdll.h>
35 /* PROTOTYPES ****************************************************************/
38 /* Type for a DLL's entry point */
44 ULONG ul_reason_for_call
,
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
);
53 /* FUNCTIONS *****************************************************************/
58 VOID
LdrLoadModuleSymbols(PLDR_MODULE ModuleObject
)
72 /***************************************************************************
77 * Adjusts the name of a dll to a fully qualified name.
80 * FullDllName: Pointer to caller supplied storage for the fully
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
92 * A given path is not affected by the adjustment, but the file
96 * ntdll.xyz --> ntdll.xyz
100 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
101 PUNICODE_STRING DllName
,
104 WCHAR Buffer
[MAX_PATH
];
109 Length
= DllName
->Length
/ sizeof(WCHAR
);
111 if (BaseName
== TRUE
)
113 /* get the base dll name */
114 Pointer
= DllName
->Buffer
+ Length
;
121 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
124 Length
= Extension
- Pointer
;
125 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
129 /* get the full dll name */
130 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
133 /* Build the DLL's absolute name */
134 Extension
= wcsrchr (Buffer
, L
'.');
135 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
137 /* with extension - remove dot if it's the last character */
138 if (Buffer
[Length
- 1] == L
'.')
144 /* name without extension - assume that it is .dll */
145 memmove (Buffer
+ Length
, L
".dll", 10);
148 RtlCreateUnicodeString (FullDllName
,
153 /***************************************************************************
170 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
172 IN PUNICODE_STRING Name
,
173 OUT PVOID
*BaseAddress OPTIONAL
)
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
;
183 PIMAGE_NT_HEADERS NTHeaders
;
185 ULONG InitialViewSize
;
188 HANDLE SectionHandle
;
189 PDLLMAIN_FUNC Entrypoint
= NULL
;
194 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
195 return STATUS_SUCCESS
;
200 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
203 /* adjust the full dll name */
204 LdrAdjustDllName (&AdjustedName
,
207 DPRINT("AdjustedName: %wZ\n", &AdjustedName
);
210 * Test if dll is already loaded.
212 if (LdrFindDll(&Module
, &AdjustedName
) == STATUS_SUCCESS
)
214 DPRINT("DLL %wZ already loaded.\n", &AdjustedName
);
215 if (Module
->LoadCount
!= -1)
217 *BaseAddress
= Module
->BaseAddress
;
218 return STATUS_SUCCESS
;
220 DPRINT("Loading \"%wZ\"\n", Name
);
222 if (SearchPath
== NULL
)
224 PKUSER_SHARED_DATA SharedUserData
=
225 (PKUSER_SHARED_DATA
)USER_SHARED_DATA_BASE
;
227 SearchPath
= SearchPathBuffer
;
228 wcscpy (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
229 wcscat (SearchPathBuffer
, L
"\\system32;");
230 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
231 wcscat (SearchPathBuffer
, L
";.");
234 DPRINT("SearchPath %S\n", SearchPath
);
236 if (RtlDosSearchPath_U (SearchPath
,
242 return STATUS_DLL_NOT_FOUND
;
244 DPRINT("FullDosName %S\n", FullDosName
);
246 RtlFreeUnicodeString (&AdjustedName
);
248 if (!RtlDosPathNameToNtPathName_U (FullDosName
,
252 return STATUS_DLL_NOT_FOUND
;
254 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
256 InitializeObjectAttributes(&FileObjectAttributes
,
262 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
264 Status
= ZwOpenFile(&FileHandle
,
266 &FileObjectAttributes
,
270 if (!NT_SUCCESS(Status
))
272 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
273 &FullNtFileName
, Status
);
274 RtlFreeUnicodeString (&FullNtFileName
);
277 RtlFreeUnicodeString (&FullNtFileName
);
279 Status
= ZwReadFile(FileHandle
,
288 if (!NT_SUCCESS(Status
))
290 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
295 * Overlay DOS and NT headers structures to the
296 * buffer with DLL's header raw data.
298 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
299 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
301 * Check it is a PE image file.
303 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
304 || (DosHeader
->e_lfanew
== 0L)
305 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
307 DPRINT("NTDLL format invalid\n");
310 return STATUS_UNSUCCESSFUL
;
313 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
314 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
316 DPRINT("ImageBase 0x%08x\n", ImageBase
);
319 * Create a section for dll.
321 Status
= ZwCreateSection(&SectionHandle
,
326 SEC_COMMIT
| SEC_IMAGE
,
328 if (!NT_SUCCESS(Status
))
330 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
336 * Map the dll into the process.
340 Status
= ZwMapViewOfSection(SectionHandle
,
350 if (!NT_SUCCESS(Status
))
352 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
359 /* relocate dll and fixup import table */
360 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
364 (PDLLMAIN_FUNC
) LdrPEStartup(ImageBase
, SectionHandle
);
367 /* build module entry */
368 Module
= RtlAllocateHeap(RtlGetProcessHeap(),
370 sizeof (LDR_MODULE
));
371 Module
->BaseAddress
= (PVOID
)ImageBase
;
372 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
373 if (Module
->EntryPoint
!= 0)
374 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
375 Module
->SizeOfImage
= ImageSize
;
376 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
378 /* loading while app is running */
379 Module
->LoadCount
= 1;
384 * loading while app is initializing
385 * dll must not be unloaded
387 Module
->LoadCount
= -1;
390 Module
->TlsIndex
= 0;
391 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
392 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
394 RtlCreateUnicodeString (&Module
->FullDllName
,
396 RtlCreateUnicodeString (&Module
->BaseDllName
,
397 wcsrchr(FullDosName
, L
'\\') + 1);
398 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
400 /* FIXME: aquire loader lock */
401 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
402 &Module
->InLoadOrderModuleList
);
403 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
404 &Module
->InInitializationOrderModuleList
);
405 /* FIXME: release loader lock */
408 LdrLoadModuleSymbols(Module
);
412 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
415 if (Module
->EntryPoint
!= 0)
417 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
419 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
420 if (FALSE
== Entrypoint(Module
->BaseAddress
,
424 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
425 &Module
->BaseDllName
);
426 /* FIXME: should clean up and fail */
430 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
431 &Module
->BaseDllName
);
436 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
437 &Module
->BaseDllName
);
441 *BaseAddress
= Module
->BaseAddress
;
442 return STATUS_SUCCESS
;
446 /***************************************************************************
461 static NTSTATUS
LdrFindDll(PLDR_MODULE
*Dll
, PUNICODE_STRING Name
)
463 PLIST_ENTRY ModuleListHead
;
467 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name
);
469 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
470 Entry
= ModuleListHead
->Flink
;
472 // NULL is the current process
475 *Dll
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
476 return STATUS_SUCCESS
;
479 while (Entry
!= ModuleListHead
)
481 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
483 DPRINT("Scanning %wZ %wZ\n", &Module
->BaseDllName
, Name
);
485 if (RtlCompareUnicodeString(&Module
->BaseDllName
, Name
, TRUE
) == 0)
488 return STATUS_SUCCESS
;
491 Entry
= Entry
->Flink
;
494 DPRINT("Failed to find dll %wZ\n", Name
);
496 return STATUS_UNSUCCESSFUL
;
499 /**********************************************************************
515 LdrFixupForward(PCHAR ForwardName
)
517 CHAR NameBuffer
[128];
518 UNICODE_STRING DllName
;
519 UNICODE_STRING FunctionName
;
524 strcpy(NameBuffer
, ForwardName
);
525 p
= strchr(NameBuffer
, '.');
530 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
531 RtlCreateUnicodeStringFromAsciiz (&DllName
,
534 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
535 if (!NT_SUCCESS(Status
))
537 Status
= LdrLoadDll(NULL
,
541 if (!NT_SUCCESS(Status
))
543 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName
);
544 RtlFreeUnicodeString (&DllName
);
549 RtlFreeUnicodeString (&DllName
);
550 DPRINT("BaseAddress: %p\n", BaseAddress
);
552 return LdrGetExportByName(BaseAddress
, p
+1, -1);
559 /**********************************************************************
561 * LdrGetExportByOrdinal
575 LdrGetExportByOrdinal (
580 PIMAGE_EXPORT_DIRECTORY ExportDir
;
581 PDWORD
* ExFunctions
;
584 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
585 RtlImageDirectoryEntryToData (BaseAddress
,
587 IMAGE_DIRECTORY_ENTRY_EXPORT
,
591 ExOrdinals
= (USHORT
*)
594 ExportDir
->AddressOfNameOrdinals
596 ExFunctions
= (PDWORD
*)
599 ExportDir
->AddressOfFunctions
602 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
604 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
606 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
610 /**********************************************************************
626 LdrGetExportByName(PVOID BaseAddress
,
630 PIMAGE_EXPORT_DIRECTORY ExportDir
;
631 PDWORD
* ExFunctions
;
641 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
643 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
644 RtlImageDirectoryEntryToData(BaseAddress
,
646 IMAGE_DIRECTORY_ENTRY_EXPORT
,
648 if (ExportDir
== NULL
)
650 DbgPrint("LdrGetExportByName(): no export directory!\n");
655 * Get header pointers
657 ExNames
= (PDWORD
*)RVA(BaseAddress
,
658 ExportDir
->AddressOfNames
);
659 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
660 ExportDir
->AddressOfNameOrdinals
);
661 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
662 ExportDir
->AddressOfFunctions
);
665 * Check the hint first
667 if (Hint
< ExportDir
->NumberOfFunctions
)
669 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
670 if (strcmp(ExName
, SymbolName
) == 0)
672 Ordinal
= ExOrdinals
[Hint
];
673 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
674 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
675 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
677 DPRINT("Forward: %s\n", (PCHAR
)Function
);
678 Function
= LdrFixupForward((PCHAR
)Function
);
680 if (Function
!= NULL
)
686 * Try a binary search first
689 maxn
= ExportDir
->NumberOfFunctions
;
695 mid
= (minn
+ maxn
) / 2;
697 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
698 res
= strcmp(ExName
, SymbolName
);
701 Ordinal
= ExOrdinals
[mid
];
702 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
703 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
704 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
706 DPRINT("Forward: %s\n", (PCHAR
)Function
);
707 Function
= LdrFixupForward((PCHAR
)Function
);
709 if (Function
!= NULL
)
712 else if (minn
== maxn
)
714 DPRINT("LdrGetExportByName(): binary search failed\n");
728 * Fall back on a linear search
730 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
731 for (i
= 0; i
< ExportDir
->NumberOfFunctions
; i
++)
733 ExName
= RVA(BaseAddress
, ExNames
[i
]);
734 if (strcmp(ExName
,SymbolName
) == 0)
736 Ordinal
= ExOrdinals
[i
];
737 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
738 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
739 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
740 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
742 DPRINT("Forward: %s\n", (PCHAR
)Function
);
743 Function
= LdrFixupForward((PCHAR
)Function
);
748 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName
);
753 /**********************************************************************
755 * LdrPerformRelocations
758 * Relocate a DLL's memory image.
769 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
772 USHORT NumberOfEntries
;
778 PRELOCATION_DIRECTORY RelocationDir
;
779 PRELOCATION_ENTRY RelocationBlock
;
783 RelocationRVA
= NTHeaders
->OptionalHeader
784 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
789 RelocationDir
= (PRELOCATION_DIRECTORY
)
790 ((PCHAR
)ImageBase
+ RelocationRVA
);
792 while (RelocationDir
->SizeOfBlock
)
794 Delta32
= (ULONG
)(ImageBase
-
795 NTHeaders
->OptionalHeader
.ImageBase
);
796 RelocationBlock
= (PRELOCATION_ENTRY
) (
799 + sizeof (RELOCATION_DIRECTORY
)
802 RelocationDir
->SizeOfBlock
803 - sizeof (RELOCATION_DIRECTORY
)
805 / sizeof (RELOCATION_ENTRY
);
808 (i
< NumberOfEntries
);
813 RelocationBlock
[i
].TypeOffset
816 + RelocationDir
->VirtualAddress
;
818 * What kind of relocations should we perform
819 * for the current entry?
821 switch (RelocationBlock
[i
].TypeOffset
>> 12)
823 case TYPE_RELOC_ABSOLUTE
:
826 case TYPE_RELOC_HIGH
:
827 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
828 *pValue16
+= Delta32
>> 16;
832 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
833 *pValue16
+= Delta32
& 0xffff;
836 case TYPE_RELOC_HIGHLOW
:
837 pValue32
= (PULONG
) (ImageBase
+ Offset
);
838 *pValue32
+= Delta32
;
841 case TYPE_RELOC_HIGHADJ
:
842 /* FIXME: do the highadjust fixup */
844 "TYPE_RELOC_HIGHADJ fixup not implemented"
847 return(STATUS_UNSUCCESSFUL
);
850 DPRINT("unexpected fixup type\n");
851 return STATUS_UNSUCCESSFUL
;
854 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
855 RelocationDir
= (PRELOCATION_DIRECTORY
) (
861 return STATUS_SUCCESS
;
865 /**********************************************************************
870 * Compute the entry point for every symbol the DLL imports
871 * from other modules.
882 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
885 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
890 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
894 * Process each import module.
896 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
897 ImageBase
+ NTHeaders
->OptionalHeader
898 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
900 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
902 while (ImportModuleDirectory
->dwRVAModuleName
)
904 PVOID
* ImportAddressList
;
905 PULONG FunctionNameList
;
906 UNICODE_STRING DllName
;
910 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
911 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
913 RtlCreateUnicodeStringFromAsciiz (&DllName
,
914 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
916 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
917 if (!NT_SUCCESS(Status
))
919 Status
= LdrLoadDll(NULL
,
923 RtlFreeUnicodeString (&DllName
);
924 if (!NT_SUCCESS(Status
))
926 DbgPrint("LdrFixupImports:failed to load %s\n"
928 + ImportModuleDirectory
->dwRVAModuleName
));
935 * Get the import address list.
937 ImportAddressList
= (PVOID
*)(NTHeaders
->OptionalHeader
.ImageBase
938 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
941 * Get the list of functions to import.
943 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
945 FunctionNameList
= (PULONG
) (
947 + ImportModuleDirectory
->dwRVAFunctionNameList
954 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
957 * Walk through function list and fixup addresses.
959 while (*FunctionNameList
!= 0L)
961 if ((*FunctionNameList
) & 0x80000000)
963 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
965 LdrGetExportByOrdinal(BaseAddress
,
970 pName
= (DWORD
) (ImageBase
+ *FunctionNameList
+ 2);
971 pHint
= *(PWORD
)(ImageBase
+ *FunctionNameList
);
974 LdrGetExportByName(BaseAddress
, (PUCHAR
)pName
, pHint
);
975 if ((*ImportAddressList
) == NULL
)
977 DbgPrint("Failed to import %s\n", pName
);
978 return STATUS_UNSUCCESSFUL
;
984 ImportModuleDirectory
++;
986 return STATUS_SUCCESS
;
990 /**********************************************************************
995 * 1. Map the DLL's sections into memory.
996 * 2. Relocate, if needed the DLL.
997 * 3. Fixup any imported symbol.
998 * 4. Compute the DLL's entry point.
1002 * Address at which the DLL's image
1006 * Handle of the section that contains
1010 * NULL on error; otherwise the entry point
1011 * to call for initializing the DLL.
1018 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1019 HANDLE SectionHandle
)
1022 PEPFUNC EntryPoint
= NULL
;
1023 PIMAGE_DOS_HEADER DosHeader
;
1024 PIMAGE_NT_HEADERS NTHeaders
;
1026 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1027 ImageBase
, (ULONG
)SectionHandle
);
1030 * Overlay DOS and WNT headers structures
1031 * to the DLL's image.
1033 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1034 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1037 * If the base address is different from the
1038 * one the DLL is actually loaded, perform any
1041 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1043 DbgPrint("LDR: Performing relocations\n");
1044 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1045 if (!NT_SUCCESS(Status
))
1047 DbgPrint("LdrPerformRelocations() failed\n");
1053 * If the DLL's imports symbols from other
1054 * modules, fixup the imported calls entry points.
1056 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1057 .VirtualAddress
!= 0)
1059 DPRINT("About to fixup imports\n");
1060 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
1061 if (!NT_SUCCESS(Status
))
1063 DbgPrint("LdrFixupImports() failed\n");
1066 DPRINT("Fixup done\n");
1070 * Compute the DLL's entry point's address.
1072 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1073 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1074 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1076 EntryPoint
= (PEPFUNC
) (ImageBase
1077 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1079 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1085 LdrUnloadDll (IN PVOID BaseAddress
)
1087 PIMAGE_NT_HEADERS NtHeaders
;
1088 PDLLMAIN_FUNC Entrypoint
;
1089 PLIST_ENTRY ModuleListHead
;
1094 if (BaseAddress
== NULL
)
1095 return STATUS_SUCCESS
;
1097 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1098 Entry
= ModuleListHead
->Flink
;
1100 while (Entry
!= ModuleListHead
)
1102 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1103 if (Module
->BaseAddress
== BaseAddress
)
1105 if (Module
->LoadCount
== -1)
1107 /* never unload this dll */
1108 return STATUS_SUCCESS
;
1110 else if (Module
->LoadCount
> 1)
1112 Module
->LoadCount
--;
1113 return STATUS_SUCCESS
;
1116 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1117 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1119 if (Module
->EntryPoint
!= 0)
1121 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1122 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1123 Entrypoint(Module
->BaseAddress
,
1129 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1132 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1133 Module
->BaseAddress
);
1134 ZwClose (Module
->SectionHandle
);
1136 /* remove the module entry from the list */
1137 RtlFreeUnicodeString (&Module
->FullDllName
);
1138 RtlFreeUnicodeString (&Module
->BaseDllName
);
1139 RemoveEntryList (Entry
);
1140 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1145 Entry
= Entry
->Flink
;
1148 DPRINT("NTDLL.LDR: Dll not found\n")
1150 return STATUS_UNSUCCESSFUL
;
1155 LdrFindResource_U(PVOID BaseAddress
,
1156 PLDR_RESOURCE_INFO ResourceInfo
,
1158 PIMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
)
1160 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1161 PIMAGE_RESOURCE_DIRECTORY ResBase
;
1162 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1163 NTSTATUS Status
= STATUS_SUCCESS
;
1169 DPRINT ("LdrFindResource_U()\n");
1171 /* Get the pointer to the resource directory */
1172 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1173 RtlImageDirectoryEntryToData (BaseAddress
,
1175 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1179 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1182 DPRINT("ResourceDirectory: %x\n", (ULONG
)ResDir
);
1186 /* Let's go into resource tree */
1187 for (i
= 0; i
< Level
; i
++)
1189 DPRINT("ResDir: %x\n", (ULONG
)ResDir
);
1190 Id
= ((PULONG
)ResourceInfo
)[i
];
1191 EntryCount
= ResDir
->NumberOfNamedEntries
;
1192 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1193 DPRINT("ResEntry %x\n", (ULONG
)ResEntry
);
1194 if (Id
& 0xFFFF0000)
1196 /* Resource name is a unicode string */
1197 for (; EntryCount
--; ResEntry
++)
1199 /* Scan entries for equal name */
1200 if (ResEntry
->Name
& 0x80000000)
1202 ws
= (PWCHAR
)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1203 if (!wcsncmp((PWCHAR
)Id
, ws
+ 1, *ws
) &&
1204 wcslen((PWCHAR
)Id
) == (int)*ws
)
1213 /* We use ID number instead of string */
1214 ResEntry
+= EntryCount
;
1215 EntryCount
= ResDir
->NumberOfIdEntries
;
1216 for (; EntryCount
--; ResEntry
++)
1218 /* Scan entries for equal name */
1219 if (ResEntry
->Name
== Id
)
1221 DPRINT("ID entry found %x\n", Id
);
1226 DPRINT("Error %lu\n", i
);
1231 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1234 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1237 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1239 /* Use the first available language */
1240 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1243 return STATUS_RESOURCE_LANG_NOT_FOUND
;
1246 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1249 return STATUS_INVALID_PARAMETER
;
1252 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
1253 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
1255 DPRINT("ResourceDataEntry: %x\n", (ULONG
)ResDir
);
1257 if (ResourceDataEntry
)
1259 *ResourceDataEntry
= (PVOID
)ResDir
;
1267 LdrAccessResource(IN PVOID BaseAddress
,
1268 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
1269 OUT PVOID
*Resource OPTIONAL
,
1270 OUT PULONG Size OPTIONAL
)
1272 PIMAGE_SECTION_HEADER Section
;
1273 PIMAGE_NT_HEADERS NtHeader
;
1280 Data
= (ULONG
)RtlImageDirectoryEntryToData (BaseAddress
,
1282 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1285 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1287 if ((ULONG
)BaseAddress
& 1)
1289 /* loaded as ordinary file */
1290 NtHeader
= RtlImageNtHeader((PVOID
)((ULONG
)BaseAddress
& ~1UL));
1291 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1292 Section
= RtlImageRvaToSection (NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
1293 if (Section
== NULL
)
1295 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1298 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
)
1300 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
1301 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
1302 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
1308 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
1313 *Size
= ResourceDataEntry
->Size
;
1316 return STATUS_SUCCESS
;
1321 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress
)
1323 PLIST_ENTRY ModuleListHead
;
1328 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1331 Status
= STATUS_DLL_NOT_FOUND
;
1333 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1334 Entry
= ModuleListHead
->Flink
;
1336 while (Entry
!= ModuleListHead
)
1338 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1340 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1341 &Module
->BaseDllName
,
1342 Module
->BaseAddress
);
1344 if (Module
->BaseAddress
== BaseAddress
)
1346 if (Module
->TlsIndex
== 0)
1348 Module
->Flags
|= 0x00040000;
1349 Status
= STATUS_SUCCESS
;
1354 Entry
= Entry
->Flink
;
1362 LdrFindResourceDirectory_U (IN PVOID BaseAddress
,
1367 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1368 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1371 NTSTATUS Status
= STATUS_SUCCESS
;
1374 /* Get the pointer to the resource directory */
1375 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1376 RtlImageDirectoryEntryToData (BaseAddress
,
1378 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1382 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1385 /* Let's go into resource tree */
1386 for (i
= 0; i
< level
; i
++, name
++)
1388 EntryCount
= ResDir
->NumberOfNamedEntries
;
1389 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1390 if ((ULONG
)(*name
) & 0xFFFF0000)
1392 /* Resource name is a unicode string */
1393 for (; EntryCount
--; ResEntry
++)
1395 /* Scan entries for equal name */
1396 if (ResEntry
->Name
& 0x80000000)
1398 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1399 if (!wcsncmp( *name
, ws
+ 1, *ws
) && wcslen( *name
) == (int)*ws
)
1408 /* We use ID number instead of string */
1409 ResEntry
+= EntryCount
;
1410 EntryCount
= ResDir
->NumberOfIdEntries
;
1411 for (; EntryCount
--; ResEntry
++)
1413 /* Scan entries for equal name */
1414 if (ResEntry
->Name
== (ULONG
)(*name
))
1422 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1425 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1428 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
1429 /* Just use first language entry */
1430 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1432 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1438 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1441 return STATUS_INVALID_PARAMETER
;
1444 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
1449 *addr
= (PVOID
)ResDir
;
1457 LdrGetDllHandle (IN ULONG Unknown1
,
1459 IN PUNICODE_STRING DllName
,
1460 OUT PVOID
*BaseAddress
)
1462 UNICODE_STRING FullDllName
;
1463 PLIST_ENTRY ModuleListHead
;
1467 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1468 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1470 /* NULL is the current executable */
1471 if ( DllName
== NULL
)
1473 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1474 DPRINT("BaseAddress %x\n", *BaseAddress
);
1475 return STATUS_SUCCESS
;
1478 LdrAdjustDllName (&FullDllName
,
1482 DPRINT("FullDllName %wZ\n",
1485 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1486 Entry
= ModuleListHead
->Flink
;
1488 while (Entry
!= ModuleListHead
)
1490 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1492 DPRINT("EntryPoint %x\n", Module
->EntryPoint
);
1493 DPRINT("Comparing %wZ and %wZ\n",
1494 &Module
->BaseDllName
,
1497 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
))
1499 RtlFreeUnicodeString (&FullDllName
);
1500 *BaseAddress
= Module
->BaseAddress
;
1501 DPRINT("BaseAddress %x\n", *BaseAddress
);
1502 return STATUS_SUCCESS
;
1505 Entry
= Entry
->Flink
;
1508 DPRINT("Failed to find dll %wZ\n", &FullDllName
);
1509 RtlFreeUnicodeString (&FullDllName
);
1510 *BaseAddress
= NULL
;
1511 return STATUS_DLL_NOT_FOUND
;
1516 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1517 IN PANSI_STRING Name
,
1519 OUT PVOID
*ProcedureAddress
)
1521 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1527 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1528 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1530 /* Get the pointer to the export directory */
1531 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1532 RtlImageDirectoryEntryToData (BaseAddress
,
1534 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1537 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1539 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1541 return STATUS_INVALID_PARAMETER
;
1544 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1545 if (Name
&& Name
->Length
)
1548 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1549 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1550 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1552 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1554 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1555 return STATUS_SUCCESS
;
1558 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1563 Ordinal
&= 0x0000FFFF;
1564 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1566 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1567 return STATUS_SUCCESS
;
1569 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1572 return STATUS_PROCEDURE_NOT_FOUND
;
1577 LdrShutdownProcess (VOID
)
1579 PLIST_ENTRY ModuleListHead
;
1583 DPRINT("LdrShutdownProcess() called\n");
1585 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1587 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1588 Entry
= ModuleListHead
->Blink
;
1590 while (Entry
!= ModuleListHead
)
1592 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1594 DPRINT(" Unloading %S\n",
1595 &Module
->BaseDllName
);
1596 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1597 // they loaded dynamically, and when the last reference is gone, that lib will
1599 if (Module
->EntryPoint
!= 0 && Module
->LoadCount
== -1)
1601 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1603 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1604 Entrypoint (Module
->BaseAddress
,
1609 Entry
= Entry
->Blink
;
1612 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1614 DPRINT("LdrShutdownProcess() done\n");
1616 return STATUS_SUCCESS
;
1621 LdrShutdownThread (VOID
)
1623 PLIST_ENTRY ModuleListHead
;
1627 DPRINT("LdrShutdownThread() called\n");
1629 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1631 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1632 Entry
= ModuleListHead
->Blink
;
1634 while (Entry
!= ModuleListHead
)
1636 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1638 DPRINT(" Unloading %wZ\n",
1639 &Module
->BaseDllName
);
1641 if (Module
->EntryPoint
!= 0)
1643 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1645 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1646 Entrypoint (Module
->BaseAddress
,
1651 Entry
= Entry
->Blink
;
1654 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1656 DPRINT("LdrShutdownThread() done\n");
1658 return STATUS_SUCCESS
;