add current directory to default search path so programs can find their own dlls
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.47 2001/09/01 19:36:30 rex Exp $
2 *
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)
9 */
10
11 /*
12 * TODO:
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
22 #include <windows.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27 #include <napi/shared_data.h>
28
29
30 #ifdef DBG_NTDLL_LDR_UTILS
31 #define NDEBUG
32 #endif
33 #include <ntdll/ntdll.h>
34
35 /* PROTOTYPES ****************************************************************/
36
37
38 /* Type for a DLL's entry point */
39 typedef
40 WINBOOL
41 STDCALL
42 (* PDLLMAIN_FUNC) (
43 HANDLE hInst,
44 ULONG ul_reason_for_call,
45 LPVOID lpReserved
46 );
47
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);
51
52
53 /* FUNCTIONS *****************************************************************/
54
55
56 #ifdef KDBG
57
58 VOID LdrLoadModuleSymbols(PLDR_MODULE ModuleObject)
59 {
60 NtSystemDebugControl(
61 0xffffffff,
62 (PVOID)ModuleObject,
63 0,
64 NULL,
65 0,
66 NULL);
67 }
68
69 #endif /* KDBG */
70
71
72 /***************************************************************************
73 * NAME LOCAL
74 * LdrAdjustDllName
75 *
76 * DESCRIPTION
77 * Adjusts the name of a dll to a fully qualified name.
78 *
79 * ARGUMENTS
80 * FullDllName: Pointer to caller supplied storage for the fully
81 * qualified dll name.
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
85 *
86 * RETURN VALUE
87 * None
88 *
89 * REVISIONS
90 *
91 * NOTE
92 * A given path is not affected by the adjustment, but the file
93 * name only:
94 * ntdll --> ntdll.dll
95 * ntdll. --> ntdll
96 * ntdll.xyz --> ntdll.xyz
97 */
98
99 static VOID
100 LdrAdjustDllName (PUNICODE_STRING FullDllName,
101 PUNICODE_STRING DllName,
102 BOOLEAN BaseName)
103 {
104 WCHAR Buffer[MAX_PATH];
105 ULONG Length;
106 PWCHAR Extension;
107 PWCHAR Pointer;
108
109 Length = DllName->Length / sizeof(WCHAR);
110
111 if (BaseName == TRUE)
112 {
113 /* get the base dll name */
114 Pointer = DllName->Buffer + Length;
115 Extension = Pointer;
116
117 do
118 {
119 --Pointer;
120 }
121 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
122
123 Pointer++;
124 Length = Extension - Pointer;
125 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
126 }
127 else
128 {
129 /* get the full dll name */
130 memmove (Buffer, DllName->Buffer, DllName->Length);
131 }
132
133 /* Build the DLL's absolute name */
134 Extension = wcsrchr (Buffer, L'.');
135 if ((Extension != NULL) && (*Extension == L'.'))
136 {
137 /* with extension - remove dot if it's the last character */
138 if (Buffer[Length - 1] == L'.')
139 Length--;
140 Buffer[Length] = 0;
141 }
142 else
143 {
144 /* name without extension - assume that it is .dll */
145 memmove (Buffer + Length, L".dll", 10);
146 }
147
148 RtlCreateUnicodeString (FullDllName,
149 Buffer);
150 }
151
152
153 /***************************************************************************
154 * NAME EXPORTED
155 * LdrLoadDll
156 *
157 * DESCRIPTION
158 *
159 * ARGUMENTS
160 *
161 * RETURN VALUE
162 *
163 * REVISIONS
164 *
165 * NOTE
166 *
167 */
168
169 NTSTATUS STDCALL
170 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
171 IN ULONG LoadFlags,
172 IN PUNICODE_STRING Name,
173 OUT PVOID *BaseAddress OPTIONAL)
174 {
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;
182 NTSTATUS Status;
183 PIMAGE_NT_HEADERS NTHeaders;
184 ULONG ImageSize;
185 ULONG InitialViewSize;
186 PVOID ImageBase;
187 HANDLE FileHandle;
188 HANDLE SectionHandle;
189 PDLLMAIN_FUNC Entrypoint = NULL;
190 PLDR_MODULE Module;
191
192 if (Name == NULL)
193 {
194 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
195 return STATUS_SUCCESS;
196 }
197
198 *BaseAddress = NULL;
199
200 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
201 Name, BaseAddress);
202
203 /* adjust the full dll name */
204 LdrAdjustDllName (&AdjustedName,
205 Name,
206 FALSE);
207 DPRINT("AdjustedName: %wZ\n", &AdjustedName);
208
209 /*
210 * Test if dll is already loaded.
211 */
212 if (LdrFindDll(&Module, &AdjustedName) == STATUS_SUCCESS)
213 {
214 DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
215 if (Module->LoadCount != -1)
216 Module->LoadCount++;
217 *BaseAddress = Module->BaseAddress;
218 return STATUS_SUCCESS;
219 }
220 DPRINT("Loading \"%wZ\"\n", Name);
221
222 if (SearchPath == NULL)
223 {
224 PKUSER_SHARED_DATA SharedUserData =
225 (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
226
227 SearchPath = SearchPathBuffer;
228 wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
229 wcscat (SearchPathBuffer, L"\\system32;");
230 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
231 wcscat (SearchPathBuffer, L";.");
232 }
233
234 DPRINT("SearchPath %S\n", SearchPath);
235
236 if (RtlDosSearchPath_U (SearchPath,
237 AdjustedName.Buffer,
238 NULL,
239 MAX_PATH,
240 FullDosName,
241 NULL) == 0)
242 return STATUS_DLL_NOT_FOUND;
243
244 DPRINT("FullDosName %S\n", FullDosName);
245
246 RtlFreeUnicodeString (&AdjustedName);
247
248 if (!RtlDosPathNameToNtPathName_U (FullDosName,
249 &FullNtFileName,
250 NULL,
251 NULL))
252 return STATUS_DLL_NOT_FOUND;
253
254 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
255
256 InitializeObjectAttributes(&FileObjectAttributes,
257 &FullNtFileName,
258 0,
259 NULL,
260 NULL);
261
262 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
263
264 Status = ZwOpenFile(&FileHandle,
265 FILE_ALL_ACCESS,
266 &FileObjectAttributes,
267 NULL,
268 0,
269 0);
270 if (!NT_SUCCESS(Status))
271 {
272 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
273 &FullNtFileName, Status);
274 RtlFreeUnicodeString (&FullNtFileName);
275 return Status;
276 }
277 RtlFreeUnicodeString (&FullNtFileName);
278
279 Status = ZwReadFile(FileHandle,
280 0,
281 0,
282 0,
283 0,
284 BlockBuffer,
285 sizeof(BlockBuffer),
286 0,
287 0);
288 if (!NT_SUCCESS(Status))
289 {
290 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
291 ZwClose(FileHandle);
292 return Status;
293 }
294 /*
295 * Overlay DOS and NT headers structures to the
296 * buffer with DLL's header raw data.
297 */
298 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
299 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
300 /*
301 * Check it is a PE image file.
302 */
303 if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
304 || (DosHeader->e_lfanew == 0L)
305 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
306 {
307 DPRINT("NTDLL format invalid\n");
308 ZwClose(FileHandle);
309
310 return STATUS_UNSUCCESSFUL;
311 }
312
313 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
314 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
315
316 DPRINT("ImageBase 0x%08x\n", ImageBase);
317
318 /*
319 * Create a section for dll.
320 */
321 Status = ZwCreateSection(&SectionHandle,
322 SECTION_ALL_ACCESS,
323 NULL,
324 NULL,
325 PAGE_READWRITE,
326 SEC_COMMIT | SEC_IMAGE,
327 FileHandle);
328 if (!NT_SUCCESS(Status))
329 {
330 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
331 ZwClose(FileHandle);
332 return Status;
333 }
334
335 /*
336 * Map the dll into the process.
337 */
338 InitialViewSize = 0;
339 ImageBase = 0;
340 Status = ZwMapViewOfSection(SectionHandle,
341 NtCurrentProcess(),
342 &ImageBase,
343 0,
344 InitialViewSize,
345 NULL,
346 &InitialViewSize,
347 0,
348 MEM_COMMIT,
349 PAGE_READWRITE);
350 if (!NT_SUCCESS(Status))
351 {
352 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
353 Status);
354 ZwClose(FileHandle);
355 return(Status);
356 }
357 ZwClose(FileHandle);
358
359 /* relocate dll and fixup import table */
360 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
361 IMAGE_FILE_DLL)
362 {
363 Entrypoint =
364 (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle);
365 }
366
367 /* build module entry */
368 Module = RtlAllocateHeap(RtlGetProcessHeap(),
369 0,
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)
377 {
378 /* loading while app is running */
379 Module->LoadCount = 1;
380 }
381 else
382 {
383 /*
384 * loading while app is initializing
385 * dll must not be unloaded
386 */
387 Module->LoadCount = -1;
388 }
389
390 Module->TlsIndex = 0;
391 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
392 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
393
394 RtlCreateUnicodeString (&Module->FullDllName,
395 FullDosName);
396 RtlCreateUnicodeString (&Module->BaseDllName,
397 wcsrchr(FullDosName, L'\\') + 1);
398 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
399
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 */
406
407 #ifdef KDBG
408 LdrLoadModuleSymbols(Module);
409 #endif /* KDBG */
410
411 /* initialize dll */
412 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
413 IMAGE_FILE_DLL)
414 {
415 if (Module->EntryPoint != 0)
416 {
417 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
418
419 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
420 if (FALSE == Entrypoint(Module->BaseAddress,
421 DLL_PROCESS_ATTACH,
422 NULL))
423 {
424 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
425 &Module->BaseDllName);
426 /* FIXME: should clean up and fail */
427 }
428 else
429 {
430 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
431 &Module->BaseDllName);
432 }
433 }
434 else
435 {
436 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
437 &Module->BaseDllName);
438 }
439 }
440
441 *BaseAddress = Module->BaseAddress;
442 return STATUS_SUCCESS;
443 }
444
445
446 /***************************************************************************
447 * NAME LOCAL
448 * LdrFindDll
449 *
450 * DESCRIPTION
451 *
452 * ARGUMENTS
453 *
454 * RETURN VALUE
455 *
456 * REVISIONS
457 *
458 * NOTE
459 *
460 */
461 static NTSTATUS LdrFindDll(PLDR_MODULE *Dll, PUNICODE_STRING Name)
462 {
463 PLIST_ENTRY ModuleListHead;
464 PLIST_ENTRY Entry;
465 PLDR_MODULE Module;
466
467 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name);
468
469 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
470 Entry = ModuleListHead->Flink;
471
472 // NULL is the current process
473 if ( Name == NULL )
474 {
475 *Dll = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
476 return STATUS_SUCCESS;
477 }
478
479 while (Entry != ModuleListHead)
480 {
481 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
482
483 DPRINT("Scanning %wZ %wZ\n", &Module->BaseDllName, Name);
484
485 if (RtlCompareUnicodeString(&Module->BaseDllName, Name, TRUE) == 0)
486 {
487 *Dll = Module;
488 return STATUS_SUCCESS;
489 }
490
491 Entry = Entry->Flink;
492 }
493
494 DPRINT("Failed to find dll %wZ\n", Name);
495
496 return STATUS_UNSUCCESSFUL;
497 }
498
499 /**********************************************************************
500 * NAME LOCAL
501 * LdrFixupForward
502 *
503 * DESCRIPTION
504 *
505 * ARGUMENTS
506 *
507 * RETURN VALUE
508 *
509 * REVISIONS
510 *
511 * NOTE
512 *
513 */
514 static PVOID
515 LdrFixupForward(PCHAR ForwardName)
516 {
517 CHAR NameBuffer[128];
518 UNICODE_STRING DllName;
519 UNICODE_STRING FunctionName;
520 NTSTATUS Status;
521 PCHAR p;
522 PVOID BaseAddress;
523
524 strcpy(NameBuffer, ForwardName);
525 p = strchr(NameBuffer, '.');
526 if (p != NULL)
527 {
528 *p = 0;
529
530 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
531 RtlCreateUnicodeStringFromAsciiz (&DllName,
532 NameBuffer);
533
534 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
535 if (!NT_SUCCESS(Status))
536 {
537 Status = LdrLoadDll(NULL,
538 0,
539 &DllName,
540 &BaseAddress);
541 if (!NT_SUCCESS(Status))
542 {
543 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
544 RtlFreeUnicodeString (&DllName);
545 return NULL;
546 }
547 }
548
549 RtlFreeUnicodeString (&DllName);
550 DPRINT("BaseAddress: %p\n", BaseAddress);
551
552 return LdrGetExportByName(BaseAddress, p+1, -1);
553 }
554
555 return NULL;
556 }
557
558
559 /**********************************************************************
560 * NAME LOCAL
561 * LdrGetExportByOrdinal
562 *
563 * DESCRIPTION
564 *
565 * ARGUMENTS
566 *
567 * RETURN VALUE
568 *
569 * REVISIONS
570 *
571 * NOTE
572 *
573 */
574 static PVOID
575 LdrGetExportByOrdinal (
576 PVOID BaseAddress,
577 ULONG Ordinal
578 )
579 {
580 PIMAGE_EXPORT_DIRECTORY ExportDir;
581 PDWORD * ExFunctions;
582 USHORT * ExOrdinals;
583
584 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
585 RtlImageDirectoryEntryToData (BaseAddress,
586 TRUE,
587 IMAGE_DIRECTORY_ENTRY_EXPORT,
588 NULL);
589
590
591 ExOrdinals = (USHORT *)
592 RVA(
593 BaseAddress,
594 ExportDir->AddressOfNameOrdinals
595 );
596 ExFunctions = (PDWORD *)
597 RVA(
598 BaseAddress,
599 ExportDir->AddressOfFunctions
600 );
601 DbgPrint(
602 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
603 Ordinal,
604 ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
605 );
606 return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
607 }
608
609
610 /**********************************************************************
611 * NAME LOCAL
612 * LdrGetExportByName
613 *
614 * DESCRIPTION
615 *
616 * ARGUMENTS
617 *
618 * RETURN VALUE
619 *
620 * REVISIONS
621 *
622 * NOTE
623 *
624 */
625 static PVOID
626 LdrGetExportByName(PVOID BaseAddress,
627 PUCHAR SymbolName,
628 WORD Hint)
629 {
630 PIMAGE_EXPORT_DIRECTORY ExportDir;
631 PDWORD * ExFunctions;
632 PDWORD * ExNames;
633 USHORT * ExOrdinals;
634 ULONG i;
635 PVOID ExName;
636 ULONG Ordinal;
637 PVOID Function;
638 ULONG minn, maxn;
639 ULONG ExportDirSize;
640
641 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
642
643 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
644 RtlImageDirectoryEntryToData(BaseAddress,
645 TRUE,
646 IMAGE_DIRECTORY_ENTRY_EXPORT,
647 &ExportDirSize);
648 if (ExportDir == NULL)
649 {
650 DbgPrint("LdrGetExportByName(): no export directory!\n");
651 return NULL;
652 }
653
654 /*
655 * Get header pointers
656 */
657 ExNames = (PDWORD *)RVA(BaseAddress,
658 ExportDir->AddressOfNames);
659 ExOrdinals = (USHORT *)RVA(BaseAddress,
660 ExportDir->AddressOfNameOrdinals);
661 ExFunctions = (PDWORD *)RVA(BaseAddress,
662 ExportDir->AddressOfFunctions);
663
664 /*
665 * Check the hint first
666 */
667 if (Hint < ExportDir->NumberOfFunctions)
668 {
669 ExName = RVA(BaseAddress, ExNames[Hint]);
670 if (strcmp(ExName, SymbolName) == 0)
671 {
672 Ordinal = ExOrdinals[Hint];
673 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
674 if (((ULONG)Function >= (ULONG)ExportDir) &&
675 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
676 {
677 DPRINT("Forward: %s\n", (PCHAR)Function);
678 Function = LdrFixupForward((PCHAR)Function);
679 }
680 if (Function != NULL)
681 return Function;
682 }
683 }
684
685 /*
686 * Try a binary search first
687 */
688 minn = 0;
689 maxn = ExportDir->NumberOfFunctions;
690 while (minn <= maxn)
691 {
692 ULONG mid;
693 LONG res;
694
695 mid = (minn + maxn) / 2;
696
697 ExName = RVA(BaseAddress, ExNames[mid]);
698 res = strcmp(ExName, SymbolName);
699 if (res == 0)
700 {
701 Ordinal = ExOrdinals[mid];
702 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
703 if (((ULONG)Function >= (ULONG)ExportDir) &&
704 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
705 {
706 DPRINT("Forward: %s\n", (PCHAR)Function);
707 Function = LdrFixupForward((PCHAR)Function);
708 }
709 if (Function != NULL)
710 return Function;
711 }
712 else if (minn == maxn)
713 {
714 DPRINT("LdrGetExportByName(): binary search failed\n");
715 break;
716 }
717 else if (res > 0)
718 {
719 maxn = mid - 1;
720 }
721 else
722 {
723 minn = mid + 1;
724 }
725 }
726
727 /*
728 * Fall back on a linear search
729 */
730 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
731 for (i = 0; i < ExportDir->NumberOfFunctions; i++)
732 {
733 ExName = RVA(BaseAddress, ExNames[i]);
734 if (strcmp(ExName,SymbolName) == 0)
735 {
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))
741 {
742 DPRINT("Forward: %s\n", (PCHAR)Function);
743 Function = LdrFixupForward((PCHAR)Function);
744 }
745 return Function;
746 }
747 }
748 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
749 return NULL;
750 }
751
752
753 /**********************************************************************
754 * NAME LOCAL
755 * LdrPerformRelocations
756 *
757 * DESCRIPTION
758 * Relocate a DLL's memory image.
759 *
760 * ARGUMENTS
761 *
762 * RETURN VALUE
763 *
764 * REVISIONS
765 *
766 * NOTE
767 *
768 */
769 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
770 PVOID ImageBase)
771 {
772 USHORT NumberOfEntries;
773 PUSHORT pValue16;
774 ULONG RelocationRVA;
775 ULONG Delta32;
776 ULONG Offset;
777 PULONG pValue32;
778 PRELOCATION_DIRECTORY RelocationDir;
779 PRELOCATION_ENTRY RelocationBlock;
780 int i;
781
782
783 RelocationRVA = NTHeaders->OptionalHeader
784 .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
785 .VirtualAddress;
786
787 if (RelocationRVA)
788 {
789 RelocationDir = (PRELOCATION_DIRECTORY)
790 ((PCHAR)ImageBase + RelocationRVA);
791
792 while (RelocationDir->SizeOfBlock)
793 {
794 Delta32 = (ULONG)(ImageBase -
795 NTHeaders->OptionalHeader.ImageBase);
796 RelocationBlock = (PRELOCATION_ENTRY) (
797 RelocationRVA
798 + ImageBase
799 + sizeof (RELOCATION_DIRECTORY)
800 );
801 NumberOfEntries = (
802 RelocationDir->SizeOfBlock
803 - sizeof (RELOCATION_DIRECTORY)
804 )
805 / sizeof (RELOCATION_ENTRY);
806
807 for ( i = 0;
808 (i < NumberOfEntries);
809 i++
810 )
811 {
812 Offset = (
813 RelocationBlock[i].TypeOffset
814 & 0xfff
815 )
816 + RelocationDir->VirtualAddress;
817 /*
818 * What kind of relocations should we perform
819 * for the current entry?
820 */
821 switch (RelocationBlock[i].TypeOffset >> 12)
822 {
823 case TYPE_RELOC_ABSOLUTE:
824 break;
825
826 case TYPE_RELOC_HIGH:
827 pValue16 = (PUSHORT) (ImageBase + Offset);
828 *pValue16 += Delta32 >> 16;
829 break;
830
831 case TYPE_RELOC_LOW:
832 pValue16 = (PUSHORT)(ImageBase + Offset);
833 *pValue16 += Delta32 & 0xffff;
834 break;
835
836 case TYPE_RELOC_HIGHLOW:
837 pValue32 = (PULONG) (ImageBase + Offset);
838 *pValue32 += Delta32;
839 break;
840
841 case TYPE_RELOC_HIGHADJ:
842 /* FIXME: do the highadjust fixup */
843 DPRINT(
844 "TYPE_RELOC_HIGHADJ fixup not implemented"
845 ", sorry\n"
846 );
847 return(STATUS_UNSUCCESSFUL);
848
849 default:
850 DPRINT("unexpected fixup type\n");
851 return STATUS_UNSUCCESSFUL;
852 }
853 }
854 RelocationRVA += RelocationDir->SizeOfBlock;
855 RelocationDir = (PRELOCATION_DIRECTORY) (
856 ImageBase
857 + RelocationRVA
858 );
859 }
860 }
861 return STATUS_SUCCESS;
862 }
863
864
865 /**********************************************************************
866 * NAME LOCAL
867 * LdrFixupImports
868 *
869 * DESCRIPTION
870 * Compute the entry point for every symbol the DLL imports
871 * from other modules.
872 *
873 * ARGUMENTS
874 *
875 * RETURN VALUE
876 *
877 * REVISIONS
878 *
879 * NOTE
880 *
881 */
882 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
883 PVOID ImageBase)
884 {
885 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
886 ULONG Ordinal;
887 PVOID BaseAddress;
888 NTSTATUS Status;
889
890 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
891 ImageBase);
892
893 /*
894 * Process each import module.
895 */
896 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
897 ImageBase + NTHeaders->OptionalHeader
898 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
899 .VirtualAddress);
900 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
901
902 while (ImportModuleDirectory->dwRVAModuleName)
903 {
904 PVOID * ImportAddressList;
905 PULONG FunctionNameList;
906 UNICODE_STRING DllName;
907 DWORD pName;
908 WORD pHint;
909
910 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
911 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
912
913 RtlCreateUnicodeStringFromAsciiz (&DllName,
914 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
915
916 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
917 if (!NT_SUCCESS(Status))
918 {
919 Status = LdrLoadDll(NULL,
920 0,
921 &DllName,
922 &BaseAddress);
923 RtlFreeUnicodeString (&DllName);
924 if (!NT_SUCCESS(Status))
925 {
926 DbgPrint("LdrFixupImports:failed to load %s\n"
927 ,(PCHAR)(ImageBase
928 + ImportModuleDirectory->dwRVAModuleName));
929
930 return Status;
931 }
932 }
933
934 /*
935 * Get the import address list.
936 */
937 ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
938 + ImportModuleDirectory->dwRVAFunctionAddressList);
939
940 /*
941 * Get the list of functions to import.
942 */
943 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
944 {
945 FunctionNameList = (PULONG) (
946 ImageBase
947 + ImportModuleDirectory->dwRVAFunctionNameList
948 );
949 }
950 else
951 {
952 FunctionNameList =
953 (PULONG)(ImageBase
954 + ImportModuleDirectory->dwRVAFunctionAddressList);
955 }
956 /*
957 * Walk through function list and fixup addresses.
958 */
959 while (*FunctionNameList != 0L)
960 {
961 if ((*FunctionNameList) & 0x80000000)
962 {
963 Ordinal = (*FunctionNameList) & 0x7fffffff;
964 *ImportAddressList =
965 LdrGetExportByOrdinal(BaseAddress,
966 Ordinal);
967 }
968 else
969 {
970 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
971 pHint = *(PWORD)(ImageBase + *FunctionNameList);
972
973 *ImportAddressList =
974 LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
975 if ((*ImportAddressList) == NULL)
976 {
977 DbgPrint("Failed to import %s\n", pName);
978 return STATUS_UNSUCCESSFUL;
979 }
980 }
981 ImportAddressList++;
982 FunctionNameList++;
983 }
984 ImportModuleDirectory++;
985 }
986 return STATUS_SUCCESS;
987 }
988
989
990 /**********************************************************************
991 * NAME
992 * LdrPEStartup
993 *
994 * DESCRIPTION
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.
999 *
1000 * ARGUMENTS
1001 * ImageBase
1002 * Address at which the DLL's image
1003 * is loaded.
1004 *
1005 * SectionHandle
1006 * Handle of the section that contains
1007 * the DLL's image.
1008 *
1009 * RETURN VALUE
1010 * NULL on error; otherwise the entry point
1011 * to call for initializing the DLL.
1012 *
1013 * REVISIONS
1014 *
1015 * NOTE
1016 *
1017 */
1018 PEPFUNC LdrPEStartup (PVOID ImageBase,
1019 HANDLE SectionHandle)
1020 {
1021 NTSTATUS Status;
1022 PEPFUNC EntryPoint = NULL;
1023 PIMAGE_DOS_HEADER DosHeader;
1024 PIMAGE_NT_HEADERS NTHeaders;
1025
1026 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1027 ImageBase, (ULONG)SectionHandle);
1028
1029 /*
1030 * Overlay DOS and WNT headers structures
1031 * to the DLL's image.
1032 */
1033 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1034 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1035
1036 /*
1037 * If the base address is different from the
1038 * one the DLL is actually loaded, perform any
1039 * relocation.
1040 */
1041 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1042 {
1043 DbgPrint("LDR: Performing relocations\n");
1044 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1045 if (!NT_SUCCESS(Status))
1046 {
1047 DbgPrint("LdrPerformRelocations() failed\n");
1048 return NULL;
1049 }
1050 }
1051
1052 /*
1053 * If the DLL's imports symbols from other
1054 * modules, fixup the imported calls entry points.
1055 */
1056 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1057 .VirtualAddress != 0)
1058 {
1059 DPRINT("About to fixup imports\n");
1060 Status = LdrFixupImports(NTHeaders, ImageBase);
1061 if (!NT_SUCCESS(Status))
1062 {
1063 DbgPrint("LdrFixupImports() failed\n");
1064 return NULL;
1065 }
1066 DPRINT("Fixup done\n");
1067 }
1068
1069 /*
1070 * Compute the DLL's entry point's address.
1071 */
1072 DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1073 DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1074 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1075 {
1076 EntryPoint = (PEPFUNC) (ImageBase
1077 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1078 }
1079 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1080 return EntryPoint;
1081 }
1082
1083
1084 NTSTATUS STDCALL
1085 LdrUnloadDll (IN PVOID BaseAddress)
1086 {
1087 PIMAGE_NT_HEADERS NtHeaders;
1088 PDLLMAIN_FUNC Entrypoint;
1089 PLIST_ENTRY ModuleListHead;
1090 PLIST_ENTRY Entry;
1091 PLDR_MODULE Module;
1092 NTSTATUS Status;
1093
1094 if (BaseAddress == NULL)
1095 return STATUS_SUCCESS;
1096
1097 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1098 Entry = ModuleListHead->Flink;
1099
1100 while (Entry != ModuleListHead)
1101 {
1102 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1103 if (Module->BaseAddress == BaseAddress)
1104 {
1105 if (Module->LoadCount == -1)
1106 {
1107 /* never unload this dll */
1108 return STATUS_SUCCESS;
1109 }
1110 else if (Module->LoadCount > 1)
1111 {
1112 Module->LoadCount--;
1113 return STATUS_SUCCESS;
1114 }
1115
1116 NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1117 if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1118 {
1119 if (Module->EntryPoint != 0)
1120 {
1121 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1122 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1123 Entrypoint(Module->BaseAddress,
1124 DLL_PROCESS_DETACH,
1125 NULL);
1126 }
1127 else
1128 {
1129 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1130 }
1131 }
1132 Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1133 Module->BaseAddress);
1134 ZwClose (Module->SectionHandle);
1135
1136 /* remove the module entry from the list */
1137 RtlFreeUnicodeString (&Module->FullDllName);
1138 RtlFreeUnicodeString (&Module->BaseDllName);
1139 RemoveEntryList (Entry);
1140 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1141
1142 return Status;
1143 }
1144
1145 Entry = Entry->Flink;
1146 }
1147
1148 DPRINT("NTDLL.LDR: Dll not found\n")
1149
1150 return STATUS_UNSUCCESSFUL;
1151 }
1152
1153
1154 NTSTATUS STDCALL
1155 LdrFindResource_U(PVOID BaseAddress,
1156 PLDR_RESOURCE_INFO ResourceInfo,
1157 ULONG Level,
1158 PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
1159 {
1160 PIMAGE_RESOURCE_DIRECTORY ResDir;
1161 PIMAGE_RESOURCE_DIRECTORY ResBase;
1162 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1163 NTSTATUS Status = STATUS_SUCCESS;
1164 ULONG EntryCount;
1165 PWCHAR ws;
1166 ULONG i;
1167 ULONG Id;
1168
1169 DPRINT ("LdrFindResource_U()\n");
1170
1171 /* Get the pointer to the resource directory */
1172 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1173 RtlImageDirectoryEntryToData (BaseAddress,
1174 TRUE,
1175 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1176 &i);
1177 if (ResDir == NULL)
1178 {
1179 return STATUS_RESOURCE_DATA_NOT_FOUND;
1180 }
1181
1182 DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
1183
1184 ResBase = ResDir;
1185
1186 /* Let's go into resource tree */
1187 for (i = 0; i < Level; i++)
1188 {
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)
1195 {
1196 /* Resource name is a unicode string */
1197 for (; EntryCount--; ResEntry++)
1198 {
1199 /* Scan entries for equal name */
1200 if (ResEntry->Name & 0x80000000)
1201 {
1202 ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1203 if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
1204 wcslen((PWCHAR)Id) == (int)*ws )
1205 {
1206 goto found;
1207 }
1208 }
1209 }
1210 }
1211 else
1212 {
1213 /* We use ID number instead of string */
1214 ResEntry += EntryCount;
1215 EntryCount = ResDir->NumberOfIdEntries;
1216 for (; EntryCount--; ResEntry++)
1217 {
1218 /* Scan entries for equal name */
1219 if (ResEntry->Name == Id)
1220 {
1221 DPRINT("ID entry found %x\n", Id);
1222 goto found;
1223 }
1224 }
1225 }
1226 DPRINT("Error %lu\n", i);
1227
1228 switch (i)
1229 {
1230 case 0:
1231 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1232
1233 case 1:
1234 return STATUS_RESOURCE_NAME_NOT_FOUND;
1235
1236 case 2:
1237 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1238 {
1239 /* Use the first available language */
1240 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1241 break;
1242 }
1243 return STATUS_RESOURCE_LANG_NOT_FOUND;
1244
1245 case 3:
1246 return STATUS_RESOURCE_DATA_NOT_FOUND;
1247
1248 default:
1249 return STATUS_INVALID_PARAMETER;
1250 }
1251 found:;
1252 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
1253 (ResEntry->OffsetToData & 0x7FFFFFFF));
1254 }
1255 DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
1256
1257 if (ResourceDataEntry)
1258 {
1259 *ResourceDataEntry = (PVOID)ResDir;
1260 }
1261
1262 return Status;
1263 }
1264
1265
1266 NTSTATUS STDCALL
1267 LdrAccessResource(IN PVOID BaseAddress,
1268 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
1269 OUT PVOID *Resource OPTIONAL,
1270 OUT PULONG Size OPTIONAL)
1271 {
1272 PIMAGE_SECTION_HEADER Section;
1273 PIMAGE_NT_HEADERS NtHeader;
1274 ULONG SectionRva;
1275 ULONG SectionVa;
1276 ULONG DataSize;
1277 ULONG Offset = 0;
1278 ULONG Data;
1279
1280 Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
1281 TRUE,
1282 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1283 &DataSize);
1284 if (Data == 0)
1285 return STATUS_RESOURCE_DATA_NOT_FOUND;
1286
1287 if ((ULONG)BaseAddress & 1)
1288 {
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)
1294 {
1295 return STATUS_RESOURCE_DATA_NOT_FOUND;
1296 }
1297
1298 if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
1299 {
1300 SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
1301 SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
1302 Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
1303 }
1304 }
1305
1306 if (Resource)
1307 {
1308 *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
1309 }
1310
1311 if (Size)
1312 {
1313 *Size = ResourceDataEntry->Size;
1314 }
1315
1316 return STATUS_SUCCESS;
1317 }
1318
1319
1320 NTSTATUS STDCALL
1321 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress)
1322 {
1323 PLIST_ENTRY ModuleListHead;
1324 PLIST_ENTRY Entry;
1325 PLDR_MODULE Module;
1326 NTSTATUS Status;
1327
1328 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1329 BaseAddress);
1330
1331 Status = STATUS_DLL_NOT_FOUND;
1332
1333 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1334 Entry = ModuleListHead->Flink;
1335
1336 while (Entry != ModuleListHead)
1337 {
1338 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1339
1340 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1341 &Module->BaseDllName,
1342 Module->BaseAddress);
1343
1344 if (Module->BaseAddress == BaseAddress)
1345 {
1346 if (Module->TlsIndex == 0)
1347 {
1348 Module->Flags |= 0x00040000;
1349 Status = STATUS_SUCCESS;
1350 }
1351 return Status;
1352 }
1353
1354 Entry = Entry->Flink;
1355 }
1356
1357 return Status;
1358 }
1359
1360
1361 NTSTATUS STDCALL
1362 LdrFindResourceDirectory_U (IN PVOID BaseAddress,
1363 WCHAR **name,
1364 DWORD level,
1365 OUT PVOID *addr)
1366 {
1367 PIMAGE_RESOURCE_DIRECTORY ResDir;
1368 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1369 ULONG EntryCount;
1370 ULONG i;
1371 NTSTATUS Status = STATUS_SUCCESS;
1372 WCHAR *ws;
1373
1374 /* Get the pointer to the resource directory */
1375 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1376 RtlImageDirectoryEntryToData (BaseAddress,
1377 TRUE,
1378 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1379 &i);
1380 if (ResDir == NULL)
1381 {
1382 return STATUS_RESOURCE_DATA_NOT_FOUND;
1383 }
1384
1385 /* Let's go into resource tree */
1386 for (i = 0; i < level; i++, name++)
1387 {
1388 EntryCount = ResDir->NumberOfNamedEntries;
1389 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1390 if ((ULONG)(*name) & 0xFFFF0000)
1391 {
1392 /* Resource name is a unicode string */
1393 for (; EntryCount--; ResEntry++)
1394 {
1395 /* Scan entries for equal name */
1396 if (ResEntry->Name & 0x80000000)
1397 {
1398 ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1399 if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
1400 {
1401 goto found;
1402 }
1403 }
1404 }
1405 }
1406 else
1407 {
1408 /* We use ID number instead of string */
1409 ResEntry += EntryCount;
1410 EntryCount = ResDir->NumberOfIdEntries;
1411 for (; EntryCount--; ResEntry++)
1412 {
1413 /* Scan entries for equal name */
1414 if (ResEntry->Name == (ULONG)(*name))
1415 goto found;
1416 }
1417 }
1418
1419 switch (i)
1420 {
1421 case 0:
1422 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1423
1424 case 1:
1425 return STATUS_RESOURCE_NAME_NOT_FOUND;
1426
1427 case 2:
1428 Status = STATUS_RESOURCE_LANG_NOT_FOUND;
1429 /* Just use first language entry */
1430 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1431 {
1432 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1433 break;
1434 }
1435 return Status;
1436
1437 case 3:
1438 return STATUS_RESOURCE_DATA_NOT_FOUND;
1439
1440 default:
1441 return STATUS_INVALID_PARAMETER;
1442 }
1443 found:;
1444 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
1445 }
1446
1447 if (addr)
1448 {
1449 *addr = (PVOID)ResDir;
1450 }
1451
1452 return Status;
1453 }
1454
1455
1456 NTSTATUS STDCALL
1457 LdrGetDllHandle (IN ULONG Unknown1,
1458 IN ULONG Unknown2,
1459 IN PUNICODE_STRING DllName,
1460 OUT PVOID *BaseAddress)
1461 {
1462 UNICODE_STRING FullDllName;
1463 PLIST_ENTRY ModuleListHead;
1464 PLIST_ENTRY Entry;
1465 PLDR_MODULE Module;
1466
1467 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1468 Unknown1, Unknown2, DllName, BaseAddress);
1469
1470 /* NULL is the current executable */
1471 if ( DllName == NULL )
1472 {
1473 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1474 DPRINT("BaseAddress %x\n", *BaseAddress);
1475 return STATUS_SUCCESS;
1476 }
1477
1478 LdrAdjustDllName (&FullDllName,
1479 DllName,
1480 TRUE);
1481
1482 DPRINT("FullDllName %wZ\n",
1483 &FullDllName);
1484
1485 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1486 Entry = ModuleListHead->Flink;
1487
1488 while (Entry != ModuleListHead)
1489 {
1490 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1491
1492 DPRINT("EntryPoint %x\n", Module->EntryPoint);
1493 DPRINT("Comparing %wZ and %wZ\n",
1494 &Module->BaseDllName,
1495 &FullDllName);
1496
1497 if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE))
1498 {
1499 RtlFreeUnicodeString (&FullDllName);
1500 *BaseAddress = Module->BaseAddress;
1501 DPRINT("BaseAddress %x\n", *BaseAddress);
1502 return STATUS_SUCCESS;
1503 }
1504
1505 Entry = Entry->Flink;
1506 }
1507
1508 DPRINT("Failed to find dll %wZ\n", &FullDllName);
1509 RtlFreeUnicodeString (&FullDllName);
1510 *BaseAddress = NULL;
1511 return STATUS_DLL_NOT_FOUND;
1512 }
1513
1514
1515 NTSTATUS STDCALL
1516 LdrGetProcedureAddress (IN PVOID BaseAddress,
1517 IN PANSI_STRING Name,
1518 IN ULONG Ordinal,
1519 OUT PVOID *ProcedureAddress)
1520 {
1521 PIMAGE_EXPORT_DIRECTORY ExportDir;
1522 PUSHORT OrdinalPtr;
1523 PULONG NamePtr;
1524 PULONG AddressPtr;
1525 ULONG i = 0;
1526
1527 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1528 BaseAddress, Name, Ordinal, ProcedureAddress);
1529
1530 /* Get the pointer to the export directory */
1531 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1532 RtlImageDirectoryEntryToData (BaseAddress,
1533 TRUE,
1534 IMAGE_DIRECTORY_ENTRY_EXPORT,
1535 &i);
1536
1537 DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1538
1539 if (!ExportDir || !i || !ProcedureAddress)
1540 {
1541 return STATUS_INVALID_PARAMETER;
1542 }
1543
1544 AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1545 if (Name && Name->Length)
1546 {
1547 /* by name */
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++)
1551 {
1552 if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1553 {
1554 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1555 return STATUS_SUCCESS;
1556 }
1557 }
1558 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1559 }
1560 else
1561 {
1562 /* by ordinal */
1563 Ordinal &= 0x0000FFFF;
1564 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1565 {
1566 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1567 return STATUS_SUCCESS;
1568 }
1569 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1570 }
1571
1572 return STATUS_PROCEDURE_NOT_FOUND;
1573 }
1574
1575
1576 NTSTATUS STDCALL
1577 LdrShutdownProcess (VOID)
1578 {
1579 PLIST_ENTRY ModuleListHead;
1580 PLIST_ENTRY Entry;
1581 PLDR_MODULE Module;
1582
1583 DPRINT("LdrShutdownProcess() called\n");
1584
1585 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1586
1587 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1588 Entry = ModuleListHead->Blink;
1589
1590 while (Entry != ModuleListHead)
1591 {
1592 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1593
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
1598 // be detached.
1599 if (Module->EntryPoint != 0 && Module->LoadCount == -1)
1600 {
1601 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1602
1603 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1604 Entrypoint (Module->BaseAddress,
1605 DLL_PROCESS_DETACH,
1606 NULL);
1607 }
1608
1609 Entry = Entry->Blink;
1610 }
1611
1612 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1613
1614 DPRINT("LdrShutdownProcess() done\n");
1615
1616 return STATUS_SUCCESS;
1617 }
1618
1619
1620 NTSTATUS STDCALL
1621 LdrShutdownThread (VOID)
1622 {
1623 PLIST_ENTRY ModuleListHead;
1624 PLIST_ENTRY Entry;
1625 PLDR_MODULE Module;
1626
1627 DPRINT("LdrShutdownThread() called\n");
1628
1629 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1630
1631 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1632 Entry = ModuleListHead->Blink;
1633
1634 while (Entry != ModuleListHead)
1635 {
1636 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1637
1638 DPRINT(" Unloading %wZ\n",
1639 &Module->BaseDllName);
1640
1641 if (Module->EntryPoint != 0)
1642 {
1643 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1644
1645 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1646 Entrypoint (Module->BaseAddress,
1647 DLL_THREAD_DETACH,
1648 NULL);
1649 }
1650
1651 Entry = Entry->Blink;
1652 }
1653
1654 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1655
1656 DPRINT("LdrShutdownThread() done\n");
1657
1658 return STATUS_SUCCESS;
1659 }
1660
1661 /* EOF */