1 /* $Id: utils.c,v 1.42 2001/03/26 16:33:10 dwelch 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 *****************************************************************/
55 /***************************************************************************
60 * Adjusts the name of a dll to a fully qualified name.
63 * FullDllName: Pointer to caller supplied storage for the fully
65 * DllName: Pointer to the dll name.
66 * BaseName: TRUE: Only the file name is passed to FullDllName
67 * FALSE: The full path is preserved in FullDllName
75 * A given path is not affected by the adjustment, but the file
79 * ntdll.xyz --> ntdll.xyz
83 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
84 PUNICODE_STRING DllName
,
87 WCHAR Buffer
[MAX_PATH
];
92 Length
= DllName
->Length
/ sizeof(WCHAR
);
96 /* get the base dll name */
97 Pointer
= DllName
->Buffer
+ Length
;
104 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
107 Length
= Extension
- Pointer
;
108 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
112 /* get the full dll name */
113 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
116 /* Build the DLL's absolute name */
117 Extension
= wcsrchr (Buffer
, L
'.');
118 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
120 /* with extension - remove dot if it's the last character */
121 if (Buffer
[Length
- 1] == L
'.')
127 /* name without extension - assume that it is .dll */
128 memmove (Buffer
+ Length
, L
".dll", 10);
131 RtlCreateUnicodeString (FullDllName
,
136 /***************************************************************************
153 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
155 IN PUNICODE_STRING Name
,
156 OUT PVOID
*BaseAddress OPTIONAL
)
158 WCHAR SearchPathBuffer
[MAX_PATH
];
159 WCHAR FullDosName
[MAX_PATH
];
160 UNICODE_STRING AdjustedName
;
161 UNICODE_STRING FullNtFileName
;
162 OBJECT_ATTRIBUTES FileObjectAttributes
;
163 char BlockBuffer
[1024];
164 PIMAGE_DOS_HEADER DosHeader
;
166 PIMAGE_NT_HEADERS NTHeaders
;
168 ULONG InitialViewSize
;
171 HANDLE SectionHandle
;
172 PDLLMAIN_FUNC Entrypoint
= NULL
;
177 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
178 return STATUS_SUCCESS
;
183 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
186 /* adjust the full dll name */
187 LdrAdjustDllName (&AdjustedName
,
190 DPRINT("AdjustedName: %wZ\n", &AdjustedName
);
193 * Test if dll is already loaded.
195 if (LdrFindDll(&Module
, &AdjustedName
) == STATUS_SUCCESS
)
197 DPRINT("DLL %wZ already loaded.\n", &AdjustedName
);
198 if (Module
->LoadCount
!= -1)
200 *BaseAddress
= Module
->BaseAddress
;
201 return STATUS_SUCCESS
;
203 DPRINT("Loading \"%wZ\"\n", Name
);
205 if (SearchPath
== NULL
)
207 PKUSER_SHARED_DATA SharedUserData
=
208 (PKUSER_SHARED_DATA
)USER_SHARED_DATA_BASE
;
210 SearchPath
= SearchPathBuffer
;
211 wcscpy (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
212 wcscat (SearchPathBuffer
, L
"\\system32;");
213 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
216 DPRINT("SearchPath %S\n", SearchPath
);
218 if (RtlDosSearchPath_U (SearchPath
,
224 return STATUS_DLL_NOT_FOUND
;
226 DPRINT("FullDosName %S\n", FullDosName
);
228 RtlFreeUnicodeString (&AdjustedName
);
230 if (!RtlDosPathNameToNtPathName_U (FullDosName
,
234 return STATUS_DLL_NOT_FOUND
;
236 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
238 InitializeObjectAttributes(&FileObjectAttributes
,
244 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
246 Status
= ZwOpenFile(&FileHandle
,
248 &FileObjectAttributes
,
252 if (!NT_SUCCESS(Status
))
254 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
255 &FullNtFileName
, Status
);
256 RtlFreeUnicodeString (&FullNtFileName
);
259 RtlFreeUnicodeString (&FullNtFileName
);
261 Status
= ZwReadFile(FileHandle
,
270 if (!NT_SUCCESS(Status
))
272 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
277 * Overlay DOS and NT headers structures to the
278 * buffer with DLL's header raw data.
280 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
281 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
283 * Check it is a PE image file.
285 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
286 || (DosHeader
->e_lfanew
== 0L)
287 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
289 DPRINT("NTDLL format invalid\n");
292 return STATUS_UNSUCCESSFUL
;
295 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
296 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
298 DPRINT("ImageBase 0x%08x\n", ImageBase
);
301 * Create a section for dll.
303 Status
= ZwCreateSection(&SectionHandle
,
308 SEC_COMMIT
| SEC_IMAGE
,
310 if (!NT_SUCCESS(Status
))
312 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
318 * Map the dll into the process.
322 Status
= ZwMapViewOfSection(SectionHandle
,
332 if (!NT_SUCCESS(Status
))
334 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
341 /* relocate dll and fixup import table */
342 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
346 (PDLLMAIN_FUNC
) LdrPEStartup(ImageBase
, SectionHandle
);
349 /* build module entry */
350 Module
= RtlAllocateHeap(RtlGetProcessHeap(),
352 sizeof (LDR_MODULE
));
353 Module
->BaseAddress
= (PVOID
)ImageBase
;
354 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
355 if (Module
->EntryPoint
!= 0)
356 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
357 Module
->SizeOfImage
= ImageSize
;
358 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
360 /* loading while app is running */
361 Module
->LoadCount
= 1;
366 * loading while app is initializing
367 * dll must not be unloaded
369 Module
->LoadCount
= -1;
372 Module
->TlsIndex
= 0;
373 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
374 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
376 RtlCreateUnicodeString (&Module
->FullDllName
,
378 RtlCreateUnicodeString (&Module
->BaseDllName
,
379 wcsrchr(FullDosName
, L
'\\') + 1);
380 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
382 /* FIXME: aquire loader lock */
383 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
384 &Module
->InLoadOrderModuleList
);
385 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
386 &Module
->InInitializationOrderModuleList
);
387 /* FIXME: release loader lock */
390 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
393 if (Module
->EntryPoint
!= 0)
395 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
397 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
398 if (FALSE
== Entrypoint(Module
->BaseAddress
,
402 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
403 &Module
->BaseDllName
);
404 /* FIXME: should clean up and fail */
408 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
409 &Module
->BaseDllName
);
414 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
415 &Module
->BaseDllName
);
419 *BaseAddress
= Module
->BaseAddress
;
420 return STATUS_SUCCESS
;
424 /***************************************************************************
439 static NTSTATUS
LdrFindDll(PLDR_MODULE
*Dll
, PUNICODE_STRING Name
)
441 PLIST_ENTRY ModuleListHead
;
445 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name
);
447 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
448 Entry
= ModuleListHead
->Flink
;
450 // NULL is the current process
453 *Dll
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
454 return STATUS_SUCCESS
;
457 while (Entry
!= ModuleListHead
)
459 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
461 DPRINT("Scanning %wZ %wZ\n", &Module
->BaseDllName
, Name
);
463 if (RtlCompareUnicodeString(&Module
->BaseDllName
, Name
, TRUE
) == 0)
466 return STATUS_SUCCESS
;
469 Entry
= Entry
->Flink
;
472 DPRINT("Failed to find dll %wZ\n", Name
);
474 return STATUS_UNSUCCESSFUL
;
477 /**********************************************************************
493 LdrFixupForward(PCHAR ForwardName
)
495 CHAR NameBuffer
[128];
496 UNICODE_STRING DllName
;
497 UNICODE_STRING FunctionName
;
502 strcpy(NameBuffer
, ForwardName
);
503 p
= strchr(NameBuffer
, '.');
508 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
509 RtlCreateUnicodeStringFromAsciiz (&DllName
,
512 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
513 if (!NT_SUCCESS(Status
))
515 Status
= LdrLoadDll(NULL
,
519 if (!NT_SUCCESS(Status
))
521 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName
);
522 RtlFreeUnicodeString (&DllName
);
527 RtlFreeUnicodeString (&DllName
);
528 DPRINT("BaseAddress: %p\n", BaseAddress
);
530 return LdrGetExportByName(BaseAddress
, p
+1, -1);
537 /**********************************************************************
539 * LdrGetExportByOrdinal
553 LdrGetExportByOrdinal (
558 PIMAGE_EXPORT_DIRECTORY ExportDir
;
559 PDWORD
* ExFunctions
;
562 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
563 RtlImageDirectoryEntryToData (BaseAddress
,
565 IMAGE_DIRECTORY_ENTRY_EXPORT
,
569 ExOrdinals
= (USHORT
*)
572 ExportDir
->AddressOfNameOrdinals
574 ExFunctions
= (PDWORD
*)
577 ExportDir
->AddressOfFunctions
580 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
582 ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]
584 return(ExFunctions
[ExOrdinals
[Ordinal
- ExportDir
->Base
]]);
588 /**********************************************************************
604 LdrGetExportByName(PVOID BaseAddress
,
608 PIMAGE_EXPORT_DIRECTORY ExportDir
;
609 PDWORD
* ExFunctions
;
619 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
621 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
622 RtlImageDirectoryEntryToData(BaseAddress
,
624 IMAGE_DIRECTORY_ENTRY_EXPORT
,
628 * Get header pointers
630 ExNames
= (PDWORD
*)RVA(BaseAddress
,
631 ExportDir
->AddressOfNames
);
632 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
633 ExportDir
->AddressOfNameOrdinals
);
634 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
635 ExportDir
->AddressOfFunctions
);
638 * Check the hint first
640 if (Hint
< ExportDir
->NumberOfFunctions
)
642 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
643 if (strcmp(ExName
, SymbolName
) == 0)
645 Ordinal
= ExOrdinals
[Hint
];
646 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
647 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
648 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
650 DPRINT("Forward: %s\n", (PCHAR
)Function
);
651 Function
= LdrFixupForward((PCHAR
)Function
);
653 if (Function
!= NULL
)
659 * Try a binary search first
661 minn
= 0, maxn
= ExportDir
->NumberOfFunctions
;
667 mid
= (minn
+ maxn
) / 2;
669 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
670 res
= strcmp(ExName
, SymbolName
);
673 Ordinal
= ExOrdinals
[mid
];
674 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
675 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
676 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
678 DPRINT("Forward: %s\n", (PCHAR
)Function
);
679 Function
= LdrFixupForward((PCHAR
)Function
);
681 if (Function
!= NULL
)
694 * Fall back on a linear search
697 DbgPrint("LDR: Falling back on a linear search of export table\n");
698 for (i
= 0; i
< ExportDir
->NumberOfFunctions
; i
++)
700 ExName
= RVA(BaseAddress
, ExNames
[i
]);
701 if (strcmp(ExName
,SymbolName
) == 0)
703 Ordinal
= ExOrdinals
[i
];
704 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
705 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
706 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
707 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
709 DPRINT("Forward: %s\n", (PCHAR
)Function
);
710 Function
= LdrFixupForward((PCHAR
)Function
);
715 DbgPrint("LdrGetExportByName() = failed to find %s\n",SymbolName
);
720 /**********************************************************************
722 * LdrPerformRelocations
725 * Relocate a DLL's memory image.
736 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
739 USHORT NumberOfEntries
;
745 PRELOCATION_DIRECTORY RelocationDir
;
746 PRELOCATION_ENTRY RelocationBlock
;
750 RelocationRVA
= NTHeaders
->OptionalHeader
751 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
]
756 RelocationDir
= (PRELOCATION_DIRECTORY
)
757 ((PCHAR
)ImageBase
+ RelocationRVA
);
759 while (RelocationDir
->SizeOfBlock
)
761 Delta32
= (ULONG
)(ImageBase
-
762 NTHeaders
->OptionalHeader
.ImageBase
);
763 RelocationBlock
= (PRELOCATION_ENTRY
) (
766 + sizeof (RELOCATION_DIRECTORY
)
769 RelocationDir
->SizeOfBlock
770 - sizeof (RELOCATION_DIRECTORY
)
772 / sizeof (RELOCATION_ENTRY
);
775 (i
< NumberOfEntries
);
780 RelocationBlock
[i
].TypeOffset
783 + RelocationDir
->VirtualAddress
;
785 * What kind of relocations should we perform
786 * for the current entry?
788 switch (RelocationBlock
[i
].TypeOffset
>> 12)
790 case TYPE_RELOC_ABSOLUTE
:
793 case TYPE_RELOC_HIGH
:
794 pValue16
= (PUSHORT
) (ImageBase
+ Offset
);
795 *pValue16
+= Delta32
>> 16;
799 pValue16
= (PUSHORT
)(ImageBase
+ Offset
);
800 *pValue16
+= Delta32
& 0xffff;
803 case TYPE_RELOC_HIGHLOW
:
804 pValue32
= (PULONG
) (ImageBase
+ Offset
);
805 *pValue32
+= Delta32
;
808 case TYPE_RELOC_HIGHADJ
:
809 /* FIXME: do the highadjust fixup */
811 "TYPE_RELOC_HIGHADJ fixup not implemented"
814 return(STATUS_UNSUCCESSFUL
);
817 DPRINT("unexpected fixup type\n");
818 return STATUS_UNSUCCESSFUL
;
821 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
822 RelocationDir
= (PRELOCATION_DIRECTORY
) (
828 return STATUS_SUCCESS
;
832 /**********************************************************************
837 * Compute the entry point for every symbol the DLL imports
838 * from other modules.
849 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
852 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
857 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
861 * Process each import module.
863 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
864 ImageBase
+ NTHeaders
->OptionalHeader
865 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
867 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
869 while (ImportModuleDirectory
->dwRVAModuleName
)
871 PVOID
* ImportAddressList
;
872 PULONG FunctionNameList
;
873 UNICODE_STRING DllName
;
877 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
878 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
880 RtlCreateUnicodeStringFromAsciiz (&DllName
,
881 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
883 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
884 if (!NT_SUCCESS(Status
))
886 Status
= LdrLoadDll(NULL
,
890 RtlFreeUnicodeString (&DllName
);
891 if (!NT_SUCCESS(Status
))
893 DbgPrint("LdrFixupImports:failed to load %s\n"
895 + ImportModuleDirectory
->dwRVAModuleName
));
902 * Get the import address list.
904 ImportAddressList
= (PVOID
*)(NTHeaders
->OptionalHeader
.ImageBase
905 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
908 * Get the list of functions to import.
910 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
912 FunctionNameList
= (PULONG
) (
914 + ImportModuleDirectory
->dwRVAFunctionNameList
921 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
924 * Walk through function list and fixup addresses.
926 while (*FunctionNameList
!= 0L)
928 if ((*FunctionNameList
) & 0x80000000)
930 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
932 LdrGetExportByOrdinal(BaseAddress
,
937 pName
= (DWORD
) (ImageBase
+ *FunctionNameList
+ 2);
938 pHint
= *(PWORD
)(ImageBase
+ *FunctionNameList
);
941 LdrGetExportByName(BaseAddress
, (PUCHAR
)pName
, pHint
);
942 if ((*ImportAddressList
) == NULL
)
944 DbgPrint("Failed to import %s\n", pName
);
945 return STATUS_UNSUCCESSFUL
;
951 ImportModuleDirectory
++;
953 return STATUS_SUCCESS
;
957 /**********************************************************************
962 * 1. Map the DLL's sections into memory.
963 * 2. Relocate, if needed the DLL.
964 * 3. Fixup any imported symbol.
965 * 4. Compute the DLL's entry point.
969 * Address at which the DLL's image
973 * Handle of the section that contains
977 * NULL on error; otherwise the entry point
978 * to call for initializing the DLL.
985 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
986 HANDLE SectionHandle
)
989 PEPFUNC EntryPoint
= NULL
;
990 PIMAGE_DOS_HEADER DosHeader
;
991 PIMAGE_NT_HEADERS NTHeaders
;
993 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
994 ImageBase
, (ULONG
)SectionHandle
);
997 * Overlay DOS and WNT headers structures
998 * to the DLL's image.
1000 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1001 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1004 * If the base address is different from the
1005 * one the DLL is actually loaded, perform any
1008 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1010 DbgPrint("LDR: Performing relocations\n");
1011 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1012 if (!NT_SUCCESS(Status
))
1014 DbgPrint("LdrPerformRelocations() failed\n");
1020 * If the DLL's imports symbols from other
1021 * modules, fixup the imported calls entry points.
1023 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1024 .VirtualAddress
!= 0)
1026 DPRINT("About to fixup imports\n");
1027 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
1028 if (!NT_SUCCESS(Status
))
1030 DbgPrint("LdrFixupImports() failed\n");
1033 DPRINT("Fixup done\n");
1037 * Compute the DLL's entry point's address.
1039 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1040 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1041 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1043 EntryPoint
= (PEPFUNC
) (ImageBase
1044 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1046 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1052 LdrUnloadDll (IN PVOID BaseAddress
)
1054 PIMAGE_NT_HEADERS NtHeaders
;
1055 PDLLMAIN_FUNC Entrypoint
;
1056 PLIST_ENTRY ModuleListHead
;
1061 if (BaseAddress
== NULL
)
1062 return STATUS_SUCCESS
;
1064 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1065 Entry
= ModuleListHead
->Flink
;
1067 while (Entry
!= ModuleListHead
);
1069 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1070 if (Module
->BaseAddress
== BaseAddress
)
1072 if (Module
->LoadCount
== -1)
1074 /* never unload this dll */
1075 return STATUS_SUCCESS
;
1077 else if (Module
->LoadCount
> 1)
1079 Module
->LoadCount
--;
1080 return STATUS_SUCCESS
;
1083 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1084 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1086 if (Module
->EntryPoint
!= 0)
1088 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1089 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1090 Entrypoint(Module
->BaseAddress
,
1096 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1099 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1100 Module
->BaseAddress
);
1101 ZwClose (Module
->SectionHandle
);
1103 /* remove the module entry from the list */
1104 RtlFreeUnicodeString (&Module
->FullDllName
);
1105 RtlFreeUnicodeString (&Module
->BaseDllName
);
1106 RemoveEntryList (Entry
);
1107 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1112 Entry
= Entry
->Flink
;
1115 DPRINT("NTDLL.LDR: Dll not found\n")
1117 return STATUS_UNSUCCESSFUL
;
1122 LdrFindResource_U(PVOID BaseAddress
,
1123 PLDR_RESOURCE_INFO ResourceInfo
,
1125 PIMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
)
1127 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1128 PIMAGE_RESOURCE_DIRECTORY ResBase
;
1129 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1130 NTSTATUS Status
= STATUS_SUCCESS
;
1136 DPRINT ("LdrFindResource_U()\n");
1138 /* Get the pointer to the resource directory */
1139 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1140 RtlImageDirectoryEntryToData (BaseAddress
,
1142 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1146 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1149 DPRINT("ResourceDirectory: %x\n", (ULONG
)ResDir
);
1153 /* Let's go into resource tree */
1154 for (i
= 0; i
< Level
; i
++)
1156 DPRINT("ResDir: %x\n", (ULONG
)ResDir
);
1157 Id
= ((PULONG
)ResourceInfo
)[i
];
1158 EntryCount
= ResDir
->NumberOfNamedEntries
;
1159 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1160 DPRINT("ResEntry %x\n", (ULONG
)ResEntry
);
1161 if (Id
& 0xFFFF0000)
1163 /* Resource name is a unicode string */
1164 for (; EntryCount
--; ResEntry
++)
1166 /* Scan entries for equal name */
1167 if (ResEntry
->Name
& 0x80000000)
1169 ws
= (PWCHAR
)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1170 if (!wcsncmp((PWCHAR
)Id
, ws
+ 1, *ws
) &&
1171 wcslen((PWCHAR
)Id
) == (int)*ws
)
1180 /* We use ID number instead of string */
1181 ResEntry
+= EntryCount
;
1182 EntryCount
= ResDir
->NumberOfIdEntries
;
1183 for (; EntryCount
--; ResEntry
++)
1185 /* Scan entries for equal name */
1186 if (ResEntry
->Name
== Id
)
1188 DPRINT("ID entry found %x\n", Id
);
1193 DPRINT("Error %lu\n", i
);
1198 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1201 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1204 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1206 /* Use the first available language */
1207 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1210 return STATUS_RESOURCE_LANG_NOT_FOUND
;
1213 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1216 return STATUS_INVALID_PARAMETER
;
1219 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResBase
+
1220 (ResEntry
->OffsetToData
& 0x7FFFFFFF));
1222 DPRINT("ResourceDataEntry: %x\n", (ULONG
)ResDir
);
1224 if (ResourceDataEntry
)
1226 *ResourceDataEntry
= (PVOID
)ResDir
;
1234 LdrAccessResource(IN PVOID BaseAddress
,
1235 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
,
1236 OUT PVOID
*Resource OPTIONAL
,
1237 OUT PULONG Size OPTIONAL
)
1239 PIMAGE_SECTION_HEADER Section
;
1240 PIMAGE_NT_HEADERS NtHeader
;
1247 Data
= (ULONG
)RtlImageDirectoryEntryToData (BaseAddress
,
1249 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1252 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1254 if ((ULONG
)BaseAddress
& 1)
1256 /* loaded as ordinary file */
1257 NtHeader
= RtlImageNtHeader((PVOID
)((ULONG
)BaseAddress
& ~1UL));
1258 Offset
= (ULONG
)BaseAddress
- Data
+ NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
;
1259 Section
= RtlImageRvaToSection (NtHeader
, BaseAddress
, NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
);
1260 if (Section
== NULL
)
1262 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1265 if (Section
->Misc
.VirtualSize
< ResourceDataEntry
->OffsetToData
)
1267 SectionRva
= RtlImageRvaToSection (NtHeader
, BaseAddress
, ResourceDataEntry
->OffsetToData
)->VirtualAddress
;
1268 SectionVa
= RtlImageRvaToVa(NtHeader
, BaseAddress
, SectionRva
, NULL
);
1269 Offset
= SectionRva
- SectionVa
+ Data
- Section
->VirtualAddress
;
1275 *Resource
= (PVOID
)(ResourceDataEntry
->OffsetToData
- Offset
+ (ULONG
)BaseAddress
);
1280 *Size
= ResourceDataEntry
->Size
;
1283 return STATUS_SUCCESS
;
1288 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress
)
1290 PLIST_ENTRY ModuleListHead
;
1295 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1298 Status
= STATUS_DLL_NOT_FOUND
;
1300 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1301 Entry
= ModuleListHead
->Flink
;
1303 while (Entry
!= ModuleListHead
)
1305 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1307 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1308 &Module
->BaseDllName
,
1309 Module
->BaseAddress
);
1311 if (Module
->BaseAddress
== BaseAddress
)
1313 if (Module
->TlsIndex
== 0)
1315 Module
->Flags
|= 0x00040000;
1316 Status
= STATUS_SUCCESS
;
1321 Entry
= Entry
->Flink
;
1329 LdrFindResourceDirectory_U (IN PVOID BaseAddress
,
1334 PIMAGE_RESOURCE_DIRECTORY ResDir
;
1335 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry
;
1338 NTSTATUS Status
= STATUS_SUCCESS
;
1341 /* Get the pointer to the resource directory */
1342 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)
1343 RtlImageDirectoryEntryToData (BaseAddress
,
1345 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
1349 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1352 /* Let's go into resource tree */
1353 for (i
= 0; i
< level
; i
++, name
++)
1355 EntryCount
= ResDir
->NumberOfNamedEntries
;
1356 ResEntry
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(ResDir
+ 1);
1357 if ((ULONG
)(*name
) & 0xFFFF0000)
1359 /* Resource name is a unicode string */
1360 for (; EntryCount
--; ResEntry
++)
1362 /* Scan entries for equal name */
1363 if (ResEntry
->Name
& 0x80000000)
1365 ws
= (WCHAR
*)((ULONG
)ResDir
+ (ResEntry
->Name
& 0x7FFFFFFF));
1366 if (!wcsncmp( *name
, ws
+ 1, *ws
) && wcslen( *name
) == (int)*ws
)
1375 /* We use ID number instead of string */
1376 ResEntry
+= EntryCount
;
1377 EntryCount
= ResDir
->NumberOfIdEntries
;
1378 for (; EntryCount
--; ResEntry
++)
1380 /* Scan entries for equal name */
1381 if (ResEntry
->Name
== (ULONG
)(*name
))
1389 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
1392 return STATUS_RESOURCE_NAME_NOT_FOUND
;
1395 Status
= STATUS_RESOURCE_LANG_NOT_FOUND
;
1396 /* Just use first language entry */
1397 if (ResDir
->NumberOfNamedEntries
|| ResDir
->NumberOfIdEntries
)
1399 ResEntry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResDir
+ 1);
1405 return STATUS_RESOURCE_DATA_NOT_FOUND
;
1408 return STATUS_INVALID_PARAMETER
;
1411 ResDir
= (PIMAGE_RESOURCE_DIRECTORY
)((ULONG
)ResDir
+ ResEntry
->OffsetToData
);
1416 *addr
= (PVOID
)ResDir
;
1424 LdrGetDllHandle (IN ULONG Unknown1
,
1426 IN PUNICODE_STRING DllName
,
1427 OUT PVOID
*BaseAddress
)
1429 UNICODE_STRING FullDllName
;
1430 PLIST_ENTRY ModuleListHead
;
1434 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1435 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1437 /* NULL is the current executable */
1438 if ( DllName
== NULL
)
1440 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1441 DPRINT("BaseAddress %x\n", *BaseAddress
);
1442 return STATUS_SUCCESS
;
1445 LdrAdjustDllName (&FullDllName
,
1449 DPRINT("FullDllName %wZ\n",
1452 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1453 Entry
= ModuleListHead
->Flink
;
1455 while (Entry
!= ModuleListHead
)
1457 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1459 DPRINT("EntryPoint %x\n", Module
->EntryPoint
);
1460 DPRINT("Comparing %wZ and %wZ\n",
1461 &Module
->BaseDllName
,
1464 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
))
1466 RtlFreeUnicodeString (&FullDllName
);
1467 *BaseAddress
= Module
->BaseAddress
;
1468 DPRINT("BaseAddress %x\n", *BaseAddress
);
1469 return STATUS_SUCCESS
;
1472 Entry
= Entry
->Flink
;
1475 DPRINT("Failed to find dll %wZ\n", &FullDllName
);
1476 RtlFreeUnicodeString (&FullDllName
);
1477 *BaseAddress
= NULL
;
1478 return STATUS_DLL_NOT_FOUND
;
1483 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1484 IN PANSI_STRING Name
,
1486 OUT PVOID
*ProcedureAddress
)
1488 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1494 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1495 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1497 /* Get the pointer to the export directory */
1498 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1499 RtlImageDirectoryEntryToData (BaseAddress
,
1501 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1504 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1506 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1508 return STATUS_INVALID_PARAMETER
;
1511 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1512 if (Name
&& Name
->Length
)
1515 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1516 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1517 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1519 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1521 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1522 return STATUS_SUCCESS
;
1525 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1530 Ordinal
&= 0x0000FFFF;
1531 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1533 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1534 return STATUS_SUCCESS
;
1536 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1539 return STATUS_PROCEDURE_NOT_FOUND
;
1544 LdrShutdownProcess (VOID
)
1546 PLIST_ENTRY ModuleListHead
;
1550 DPRINT("LdrShutdownProcess() called\n");
1552 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1554 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1555 Entry
= ModuleListHead
->Blink
;
1557 while (Entry
!= ModuleListHead
)
1559 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1561 DPRINT(" Unloading %wZ\n",
1562 &Module
->BaseDllName
);
1564 if (Module
->EntryPoint
!= 0)
1566 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1568 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1569 Entrypoint (Module
->BaseAddress
,
1574 Entry
= Entry
->Blink
;
1577 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1579 DPRINT("LdrShutdownProcess() done\n");
1581 return STATUS_SUCCESS
;
1586 LdrShutdownThread (VOID
)
1588 PLIST_ENTRY ModuleListHead
;
1592 DPRINT("LdrShutdownThread() called\n");
1594 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1596 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1597 Entry
= ModuleListHead
->Blink
;
1599 while (Entry
!= ModuleListHead
)
1601 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1603 DPRINT(" Unloading %wZ\n",
1604 &Module
->BaseDllName
);
1606 if (Module
->EntryPoint
!= 0)
1608 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1610 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1611 Entrypoint (Module
->BaseAddress
,
1616 Entry
= Entry
->Blink
;
1619 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1621 DPRINT("LdrShutdownThread() done\n");
1623 return STATUS_SUCCESS
;