1 /* $Id: utils.c,v 1.46 2001/07/04 20:40:19 chorns 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
);
233 DPRINT("SearchPath %S\n", SearchPath
);
235 if (RtlDosSearchPath_U (SearchPath
,
241 return STATUS_DLL_NOT_FOUND
;
243 DPRINT("FullDosName %S\n", FullDosName
);
245 RtlFreeUnicodeString (&AdjustedName
);
247 if (!RtlDosPathNameToNtPathName_U (FullDosName
,
251 return STATUS_DLL_NOT_FOUND
;
253 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
255 InitializeObjectAttributes(&FileObjectAttributes
,
261 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
263 Status
= ZwOpenFile(&FileHandle
,
265 &FileObjectAttributes
,
269 if (!NT_SUCCESS(Status
))
271 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
272 &FullNtFileName
, Status
);
273 RtlFreeUnicodeString (&FullNtFileName
);
276 RtlFreeUnicodeString (&FullNtFileName
);
278 Status
= ZwReadFile(FileHandle
,
287 if (!NT_SUCCESS(Status
))
289 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
294 * Overlay DOS and NT headers structures to the
295 * buffer with DLL's header raw data.
297 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
298 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
300 * Check it is a PE image file.
302 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
303 || (DosHeader
->e_lfanew
== 0L)
304 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
306 DPRINT("NTDLL format invalid\n");
309 return STATUS_UNSUCCESSFUL
;
312 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
313 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
315 DPRINT("ImageBase 0x%08x\n", ImageBase
);
318 * Create a section for dll.
320 Status
= ZwCreateSection(&SectionHandle
,
325 SEC_COMMIT
| SEC_IMAGE
,
327 if (!NT_SUCCESS(Status
))
329 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
335 * Map the dll into the process.
339 Status
= ZwMapViewOfSection(SectionHandle
,
349 if (!NT_SUCCESS(Status
))
351 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
358 /* relocate dll and fixup import table */
359 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
363 (PDLLMAIN_FUNC
) LdrPEStartup(ImageBase
, SectionHandle
);
366 /* build module entry */
367 Module
= RtlAllocateHeap(RtlGetProcessHeap(),
369 sizeof (LDR_MODULE
));
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
)
377 /* loading while app is running */
378 Module
->LoadCount
= 1;
383 * loading while app is initializing
384 * dll must not be unloaded
386 Module
->LoadCount
= -1;
389 Module
->TlsIndex
= 0;
390 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
391 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
393 RtlCreateUnicodeString (&Module
->FullDllName
,
395 RtlCreateUnicodeString (&Module
->BaseDllName
,
396 wcsrchr(FullDosName
, L
'\\') + 1);
397 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
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 */
407 LdrLoadModuleSymbols(Module
);
411 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
414 if (Module
->EntryPoint
!= 0)
416 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
418 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
419 if (FALSE
== Entrypoint(Module
->BaseAddress
,
423 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
424 &Module
->BaseDllName
);
425 /* FIXME: should clean up and fail */
429 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
430 &Module
->BaseDllName
);
435 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
436 &Module
->BaseDllName
);
440 *BaseAddress
= Module
->BaseAddress
;
441 return STATUS_SUCCESS
;
445 /***************************************************************************
460 static NTSTATUS
LdrFindDll(PLDR_MODULE
*Dll
, PUNICODE_STRING Name
)
462 PLIST_ENTRY ModuleListHead
;
466 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name
);
468 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
469 Entry
= ModuleListHead
->Flink
;
471 // NULL is the current process
474 *Dll
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
475 return STATUS_SUCCESS
;
478 while (Entry
!= ModuleListHead
)
480 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
482 DPRINT("Scanning %wZ %wZ\n", &Module
->BaseDllName
, Name
);
484 if (RtlCompareUnicodeString(&Module
->BaseDllName
, Name
, TRUE
) == 0)
487 return STATUS_SUCCESS
;
490 Entry
= Entry
->Flink
;
493 DPRINT("Failed to find dll %wZ\n", Name
);
495 return STATUS_UNSUCCESSFUL
;
498 /**********************************************************************
514 LdrFixupForward(PCHAR ForwardName
)
516 CHAR NameBuffer
[128];
517 UNICODE_STRING DllName
;
518 UNICODE_STRING FunctionName
;
523 strcpy(NameBuffer
, ForwardName
);
524 p
= strchr(NameBuffer
, '.');
529 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
530 RtlCreateUnicodeStringFromAsciiz (&DllName
,
533 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
534 if (!NT_SUCCESS(Status
))
536 Status
= LdrLoadDll(NULL
,
540 if (!NT_SUCCESS(Status
))
542 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName
);
543 RtlFreeUnicodeString (&DllName
);
548 RtlFreeUnicodeString (&DllName
);
549 DPRINT("BaseAddress: %p\n", BaseAddress
);
551 return LdrGetExportByName(BaseAddress
, p
+1, -1);
558 /**********************************************************************
560 * LdrGetExportByOrdinal
574 LdrGetExportByOrdinal (
579 PIMAGE_EXPORT_DIRECTORY ExportDir
;
580 PDWORD
* ExFunctions
;
583 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
584 RtlImageDirectoryEntryToData (BaseAddress
,
586 IMAGE_DIRECTORY_ENTRY_EXPORT
,
590 ExOrdinals
= (USHORT
*)
593 ExportDir
->AddressOfNameOrdinals
595 ExFunctions
= (PDWORD
*)
598 ExportDir
->AddressOfFunctions
601 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
603 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
605 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
609 /**********************************************************************
625 LdrGetExportByName(PVOID BaseAddress
,
629 PIMAGE_EXPORT_DIRECTORY ExportDir
;
630 PDWORD
* ExFunctions
;
640 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
642 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
643 RtlImageDirectoryEntryToData(BaseAddress
,
645 IMAGE_DIRECTORY_ENTRY_EXPORT
,
647 if (ExportDir
== NULL
)
649 DbgPrint("LdrGetExportByName(): no export directory!\n");
654 * Get header pointers
656 ExNames
= (PDWORD
*)RVA(BaseAddress
,
657 ExportDir
->AddressOfNames
);
658 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
659 ExportDir
->AddressOfNameOrdinals
);
660 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
661 ExportDir
->AddressOfFunctions
);
664 * Check the hint first
666 if (Hint
< ExportDir
->NumberOfFunctions
)
668 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
669 if (strcmp(ExName
, SymbolName
) == 0)
671 Ordinal
= ExOrdinals
[Hint
];
672 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
673 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
674 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
676 DPRINT("Forward: %s\n", (PCHAR
)Function
);
677 Function
= LdrFixupForward((PCHAR
)Function
);
679 if (Function
!= NULL
)
685 * Try a binary search first
688 maxn
= ExportDir
->NumberOfFunctions
;
694 mid
= (minn
+ maxn
) / 2;
696 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
697 res
= strcmp(ExName
, SymbolName
);
700 Ordinal
= ExOrdinals
[mid
];
701 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
702 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
703 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
705 DPRINT("Forward: %s\n", (PCHAR
)Function
);
706 Function
= LdrFixupForward((PCHAR
)Function
);
708 if (Function
!= NULL
)
711 else if (minn
== maxn
)
713 DPRINT("LdrGetExportByName(): binary search failed\n");
727 * Fall back on a linear search
729 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
730 for (i
= 0; i
< ExportDir
->NumberOfFunctions
; i
++)
732 ExName
= RVA(BaseAddress
, ExNames
[i
]);
733 if (strcmp(ExName
,SymbolName
) == 0)
735 Ordinal
= ExOrdinals
[i
];
736 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
737 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
738 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
739 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
741 DPRINT("Forward: %s\n", (PCHAR
)Function
);
742 Function
= LdrFixupForward((PCHAR
)Function
);
747 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName
);
752 /**********************************************************************
754 * LdrPerformRelocations
757 * Relocate a DLL's memory image.
768 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
771 USHORT NumberOfEntries
;
777 PRELOCATION_DIRECTORY RelocationDir
;
778 PRELOCATION_ENTRY RelocationBlock
;
782 RelocationRVA
= NTHeaders
->OptionalHeader
783 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
788 RelocationDir
= (PRELOCATION_DIRECTORY
)
789 ((PCHAR
)ImageBase
+ RelocationRVA
);
791 while (RelocationDir
->SizeOfBlock
)
793 Delta32
= (ULONG
)(ImageBase
-
794 NTHeaders
->OptionalHeader
.ImageBase
);
795 RelocationBlock
= (PRELOCATION_ENTRY
) (
798 + sizeof (RELOCATION_DIRECTORY
)
801 RelocationDir
->SizeOfBlock
802 - sizeof (RELOCATION_DIRECTORY
)
804 / sizeof (RELOCATION_ENTRY
);
807 (i
< NumberOfEntries
);
812 RelocationBlock
[i
].TypeOffset
815 + RelocationDir
->VirtualAddress
;
817 * What kind of relocations should we perform
818 * for the current entry?
820 switch (RelocationBlock
[i
].TypeOffset
>> 12)
822 case TYPE_RELOC_ABSOLUTE
:
825 case TYPE_RELOC_HIGH
:
826 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
827 *pValue16
+= Delta32
>> 16;
831 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
832 *pValue16
+= Delta32
& 0xffff;
835 case TYPE_RELOC_HIGHLOW
:
836 pValue32
= (PULONG
) (ImageBase
+ Offset
);
837 *pValue32
+= Delta32
;
840 case TYPE_RELOC_HIGHADJ
:
841 /* FIXME: do the highadjust fixup */
843 "TYPE_RELOC_HIGHADJ fixup not implemented"
846 return(STATUS_UNSUCCESSFUL
);
849 DPRINT("unexpected fixup type\n");
850 return STATUS_UNSUCCESSFUL
;
853 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
854 RelocationDir
= (PRELOCATION_DIRECTORY
) (
860 return STATUS_SUCCESS
;
864 /**********************************************************************
869 * Compute the entry point for every symbol the DLL imports
870 * from other modules.
881 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
884 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
889 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
893 * Process each import module.
895 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
896 ImageBase
+ NTHeaders
->OptionalHeader
897 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
899 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
901 while (ImportModuleDirectory
->dwRVAModuleName
)
903 PVOID
* ImportAddressList
;
904 PULONG FunctionNameList
;
905 UNICODE_STRING DllName
;
909 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
910 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
912 RtlCreateUnicodeStringFromAsciiz (&DllName
,
913 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
915 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
916 if (!NT_SUCCESS(Status
))
918 Status
= LdrLoadDll(NULL
,
922 RtlFreeUnicodeString (&DllName
);
923 if (!NT_SUCCESS(Status
))
925 DbgPrint("LdrFixupImports:failed to load %s\n"
927 + ImportModuleDirectory
->dwRVAModuleName
));
934 * Get the import address list.
936 ImportAddressList
= (PVOID
*)(NTHeaders
->OptionalHeader
.ImageBase
937 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
940 * Get the list of functions to import.
942 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
944 FunctionNameList
= (PULONG
) (
946 + ImportModuleDirectory
->dwRVAFunctionNameList
953 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
956 * Walk through function list and fixup addresses.
958 while (*FunctionNameList
!= 0L)
960 if ((*FunctionNameList
) & 0x80000000)
962 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
964 LdrGetExportByOrdinal(BaseAddress
,
969 pName
= (DWORD
) (ImageBase
+ *FunctionNameList
+ 2);
970 pHint
= *(PWORD
)(ImageBase
+ *FunctionNameList
);
973 LdrGetExportByName(BaseAddress
, (PUCHAR
)pName
, pHint
);
974 if ((*ImportAddressList
) == NULL
)
976 DbgPrint("Failed to import %s\n", pName
);
977 return STATUS_UNSUCCESSFUL
;
983 ImportModuleDirectory
++;
985 return STATUS_SUCCESS
;
989 /**********************************************************************
994 * 1. Map the DLL's sections into memory.
995 * 2. Relocate, if needed the DLL.
996 * 3. Fixup any imported symbol.
997 * 4. Compute the DLL's entry point.
1001 * Address at which the DLL's image
1005 * Handle of the section that contains
1009 * NULL on error; otherwise the entry point
1010 * to call for initializing the DLL.
1017 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1018 HANDLE SectionHandle
)
1021 PEPFUNC EntryPoint
= NULL
;
1022 PIMAGE_DOS_HEADER DosHeader
;
1023 PIMAGE_NT_HEADERS NTHeaders
;
1025 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1026 ImageBase
, (ULONG
)SectionHandle
);
1029 * Overlay DOS and WNT headers structures
1030 * to the DLL's image.
1032 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1033 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1036 * If the base address is different from the
1037 * one the DLL is actually loaded, perform any
1040 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1042 DbgPrint("LDR: Performing relocations\n");
1043 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1044 if (!NT_SUCCESS(Status
))
1046 DbgPrint("LdrPerformRelocations() failed\n");
1052 * If the DLL's imports symbols from other
1053 * modules, fixup the imported calls entry points.
1055 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1056 .VirtualAddress
!= 0)
1058 DPRINT("About to fixup imports\n");
1059 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
1060 if (!NT_SUCCESS(Status
))
1062 DbgPrint("LdrFixupImports() failed\n");
1065 DPRINT("Fixup done\n");
1069 * Compute the DLL's entry point's address.
1071 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1072 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1073 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1075 EntryPoint
= (PEPFUNC
) (ImageBase
1076 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1078 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1084 LdrUnloadDll (IN PVOID BaseAddress
)
1086 PIMAGE_NT_HEADERS NtHeaders
;
1087 PDLLMAIN_FUNC Entrypoint
;
1088 PLIST_ENTRY ModuleListHead
;
1093 if (BaseAddress
== NULL
)
1094 return STATUS_SUCCESS
;
1096 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1097 Entry
= ModuleListHead
->Flink
;
1099 while (Entry
!= ModuleListHead
)
1101 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1102 if (Module
->BaseAddress
== BaseAddress
)
1104 if (Module
->LoadCount
== -1)
1106 /* never unload this dll */
1107 return STATUS_SUCCESS
;
1109 else if (Module
->LoadCount
> 1)
1111 Module
->LoadCount
--;
1112 return STATUS_SUCCESS
;
1115 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1116 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1118 if (Module
->EntryPoint
!= 0)
1120 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1121 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1122 Entrypoint(Module
->BaseAddress
,
1128 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1131 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1132 Module
->BaseAddress
);
1133 ZwClose (Module
->SectionHandle
);
1135 /* remove the module entry from the list */
1136 RtlFreeUnicodeString (&Module
->FullDllName
);
1137 RtlFreeUnicodeString (&Module
->BaseDllName
);
1138 RemoveEntryList (Entry
);
1139 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1144 Entry
= Entry
->Flink
;
1147 DPRINT("NTDLL.LDR: Dll not found\n")
1149 return STATUS_UNSUCCESSFUL
;
1154 LdrFindResource_U(PVOID BaseAddress
,
1155 PLDR_RESOURCE_INFO ResourceInfo
,
1157 PIMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
)
1159 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1160 PIMAGE_RESOURCE_DIRECTORY ResBase
;
1161 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1162 NTSTATUS Status
= STATUS_SUCCESS
;
1168 DPRINT ("LdrFindResource_U()\n");
1170 /* Get the pointer to the resource directory */
1171 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1172 RtlImageDirectoryEntryToData (BaseAddress
,
1174 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1178 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1181 DPRINT("ResourceDirectory: %x\n", (ULONG
)ResDir
);
1185 /* Let's go into resource tree */
1186 for (i
= 0; i
< Level
; i
++)
1188 DPRINT("ResDir: %x\n", (ULONG
)ResDir
);
1189 Id
= ((PULONG
)ResourceInfo
)[i
];
1190 EntryCount
= ResDir
->NumberOfNamedEntries
;
1191 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1192 DPRINT("ResEntry %x\n", (ULONG
)ResEntry
);
1193 if (Id
& 0xFFFF0000)
1195 /* Resource name is a unicode string */
1196 for (; EntryCount
--; ResEntry
++)
1198 /* Scan entries for equal name */
1199 if (ResEntry
->Name
& 0x80000000)
1201 ws
= (PWCHAR
)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1202 if (!wcsncmp((PWCHAR
)Id
, ws
+ 1, *ws
) &&
1203 wcslen((PWCHAR
)Id
) == (int)*ws
)
1212 /* We use ID number instead of string */
1213 ResEntry
+= EntryCount
;
1214 EntryCount
= ResDir
->NumberOfIdEntries
;
1215 for (; EntryCount
--; ResEntry
++)
1217 /* Scan entries for equal name */
1218 if (ResEntry
->Name
== Id
)
1220 DPRINT("ID entry found %x\n", Id
);
1225 DPRINT("Error %lu\n", i
);
1230 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1233 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1236 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1238 /* Use the first available language */
1239 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1242 return STATUS_RESOURCE_LANG_NOT_FOUND
;
1245 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1248 return STATUS_INVALID_PARAMETER
;
1251 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
1252 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
1254 DPRINT("ResourceDataEntry: %x\n", (ULONG
)ResDir
);
1256 if (ResourceDataEntry
)
1258 *ResourceDataEntry
= (PVOID
)ResDir
;
1266 LdrAccessResource(IN PVOID BaseAddress
,
1267 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
1268 OUT PVOID
*Resource OPTIONAL
,
1269 OUT PULONG Size OPTIONAL
)
1271 PIMAGE_SECTION_HEADER Section
;
1272 PIMAGE_NT_HEADERS NtHeader
;
1279 Data
= (ULONG
)RtlImageDirectoryEntryToData (BaseAddress
,
1281 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1284 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1286 if ((ULONG
)BaseAddress
& 1)
1288 /* loaded as ordinary file */
1289 NtHeader
= RtlImageNtHeader((PVOID
)((ULONG
)BaseAddress
& ~1UL));
1290 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1291 Section
= RtlImageRvaToSection (NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
1292 if (Section
== NULL
)
1294 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1297 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
)
1299 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
1300 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
1301 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
1307 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
1312 *Size
= ResourceDataEntry
->Size
;
1315 return STATUS_SUCCESS
;
1320 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress
)
1322 PLIST_ENTRY ModuleListHead
;
1327 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1330 Status
= STATUS_DLL_NOT_FOUND
;
1332 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1333 Entry
= ModuleListHead
->Flink
;
1335 while (Entry
!= ModuleListHead
)
1337 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1339 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1340 &Module
->BaseDllName
,
1341 Module
->BaseAddress
);
1343 if (Module
->BaseAddress
== BaseAddress
)
1345 if (Module
->TlsIndex
== 0)
1347 Module
->Flags
|= 0x00040000;
1348 Status
= STATUS_SUCCESS
;
1353 Entry
= Entry
->Flink
;
1361 LdrFindResourceDirectory_U (IN PVOID BaseAddress
,
1366 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1367 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1370 NTSTATUS Status
= STATUS_SUCCESS
;
1373 /* Get the pointer to the resource directory */
1374 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1375 RtlImageDirectoryEntryToData (BaseAddress
,
1377 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1381 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1384 /* Let's go into resource tree */
1385 for (i
= 0; i
< level
; i
++, name
++)
1387 EntryCount
= ResDir
->NumberOfNamedEntries
;
1388 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1389 if ((ULONG
)(*name
) & 0xFFFF0000)
1391 /* Resource name is a unicode string */
1392 for (; EntryCount
--; ResEntry
++)
1394 /* Scan entries for equal name */
1395 if (ResEntry
->Name
& 0x80000000)
1397 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1398 if (!wcsncmp( *name
, ws
+ 1, *ws
) && wcslen( *name
) == (int)*ws
)
1407 /* We use ID number instead of string */
1408 ResEntry
+= EntryCount
;
1409 EntryCount
= ResDir
->NumberOfIdEntries
;
1410 for (; EntryCount
--; ResEntry
++)
1412 /* Scan entries for equal name */
1413 if (ResEntry
->Name
== (ULONG
)(*name
))
1421 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1424 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1427 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
1428 /* Just use first language entry */
1429 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1431 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1437 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1440 return STATUS_INVALID_PARAMETER
;
1443 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
1448 *addr
= (PVOID
)ResDir
;
1456 LdrGetDllHandle (IN ULONG Unknown1
,
1458 IN PUNICODE_STRING DllName
,
1459 OUT PVOID
*BaseAddress
)
1461 UNICODE_STRING FullDllName
;
1462 PLIST_ENTRY ModuleListHead
;
1466 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1467 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1469 /* NULL is the current executable */
1470 if ( DllName
== NULL
)
1472 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1473 DPRINT("BaseAddress %x\n", *BaseAddress
);
1474 return STATUS_SUCCESS
;
1477 LdrAdjustDllName (&FullDllName
,
1481 DPRINT("FullDllName %wZ\n",
1484 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1485 Entry
= ModuleListHead
->Flink
;
1487 while (Entry
!= ModuleListHead
)
1489 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1491 DPRINT("EntryPoint %x\n", Module
->EntryPoint
);
1492 DPRINT("Comparing %wZ and %wZ\n",
1493 &Module
->BaseDllName
,
1496 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
))
1498 RtlFreeUnicodeString (&FullDllName
);
1499 *BaseAddress
= Module
->BaseAddress
;
1500 DPRINT("BaseAddress %x\n", *BaseAddress
);
1501 return STATUS_SUCCESS
;
1504 Entry
= Entry
->Flink
;
1507 DPRINT("Failed to find dll %wZ\n", &FullDllName
);
1508 RtlFreeUnicodeString (&FullDllName
);
1509 *BaseAddress
= NULL
;
1510 return STATUS_DLL_NOT_FOUND
;
1515 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1516 IN PANSI_STRING Name
,
1518 OUT PVOID
*ProcedureAddress
)
1520 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1526 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1527 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1529 /* Get the pointer to the export directory */
1530 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1531 RtlImageDirectoryEntryToData (BaseAddress
,
1533 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1536 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1538 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1540 return STATUS_INVALID_PARAMETER
;
1543 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1544 if (Name
&& Name
->Length
)
1547 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1548 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1549 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1551 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1553 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1554 return STATUS_SUCCESS
;
1557 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1562 Ordinal
&= 0x0000FFFF;
1563 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1565 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1566 return STATUS_SUCCESS
;
1568 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1571 return STATUS_PROCEDURE_NOT_FOUND
;
1576 LdrShutdownProcess (VOID
)
1578 PLIST_ENTRY ModuleListHead
;
1582 DPRINT("LdrShutdownProcess() called\n");
1584 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1586 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1587 Entry
= ModuleListHead
->Blink
;
1589 while (Entry
!= ModuleListHead
)
1591 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1593 DPRINT(" Unloading %S\n",
1594 &Module
->BaseDllName
);
1595 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1596 // they loaded dynamically, and when the last reference is gone, that lib will
1598 if (Module
->EntryPoint
!= 0 && Module
->LoadCount
== -1)
1600 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1602 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1603 Entrypoint (Module
->BaseAddress
,
1608 Entry
= Entry
->Blink
;
1611 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1613 DPRINT("LdrShutdownProcess() done\n");
1615 return STATUS_SUCCESS
;
1620 LdrShutdownThread (VOID
)
1622 PLIST_ENTRY ModuleListHead
;
1626 DPRINT("LdrShutdownThread() called\n");
1628 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1630 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1631 Entry
= ModuleListHead
->Blink
;
1633 while (Entry
!= ModuleListHead
)
1635 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1637 DPRINT(" Unloading %wZ\n",
1638 &Module
->BaseDllName
);
1640 if (Module
->EntryPoint
!= 0)
1642 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1644 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1645 Entrypoint (Module
->BaseAddress
,
1650 Entry
= Entry
->Blink
;
1653 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1655 DPRINT("LdrShutdownThread() done\n");
1657 return STATUS_SUCCESS
;