2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ldr/loader.c
5 * PURPOSE: Loaders for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
10 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
11 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
12 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
13 * JM 14/12/98 Built initail PE user module loader
16 /* INCLUDES *****************************************************************/
18 #include <internal/i386/segment.h>
19 #include <internal/kernel.h>
20 #include <internal/linkage.h>
21 #include <internal/module.h>
22 #include <internal/ob.h>
23 #include <internal/string.h>
24 #include <internal/symbol.h>
26 #include <ddk/ntddk.h>
29 #include <internal/debug.h>
31 /* MACROS ********************************************************************/
33 /* GLOBALS *******************************************************************/
35 POBJECT_TYPE ObModuleType
= NULL
;
37 /* FORWARD DECLARATIONS ******************************************************/
39 NTSTATUS
LdrProcessDriver(PVOID ModuleLoadBase
);
41 /* PE Driver load support */
42 static NTSTATUS
LdrPEProcessDriver(PVOID ModuleLoadBase
);
44 /* COFF Driver load support */
45 static NTSTATUS
LdrCOFFProcessDriver(PVOID ModuleLoadBase
);
46 static BOOLEAN
LdrCOFFDoRelocations(module
*Module
, unsigned int SectionIndex
);
47 static BOOLEAN
LdrCOFFDoAddr32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
);
48 static BOOLEAN
LdrCOFFDoReloc32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
);
49 static void LdrCOFFGetSymbolName(module
*Module
, unsigned int Idx
, char *Name
);
50 static unsigned int LdrCOFFGetSymbolValue(module
*Module
, unsigned int Idx
);
51 static unsigned int LdrCOFFGetKernelSymbolAddr(char *Name
);
52 static unsigned int LdrCOFFGetSymbolValueByName(module
*Module
, char *SymbolName
, unsigned int Idx
);
54 /* Image loader forward delcarations */
55 static NTSTATUS
LdrProcessMZImage(HANDLE ProcessHandle
, HANDLE ModuleHandle
, HANDLE FileHandle
);
56 static NTSTATUS
LdrProcessPEImage(HANDLE ProcessHandle
, HANDLE ModuleHandle
, HANDLE FileHandle
);
57 static NTSTATUS
LdrProcessBinImage(HANDLE ProcessHandle
, HANDLE ModuleHandle
, HANDLE FileHandle
);
59 /* FUNCTIONS *****************************************************************/
61 VOID
LdrInitModuleManagment(VOID
)
63 ANSI_STRING AnsiString
;
65 /* Register the process object type */
66 ObModuleType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
67 ObModuleType
->TotalObjects
= 0;
68 ObModuleType
->TotalHandles
= 0;
69 ObModuleType
->MaxObjects
= ULONG_MAX
;
70 ObModuleType
->MaxHandles
= ULONG_MAX
;
71 ObModuleType
->PagedPoolCharge
= 0;
72 ObModuleType
->NonpagedPoolCharge
= sizeof(MODULE
);
73 ObModuleType
->Dump
= NULL
;
74 ObModuleType
->Open
= NULL
;
75 ObModuleType
->Close
= NULL
;
76 ObModuleType
->Delete
= NULL
;
77 ObModuleType
->Parse
= NULL
;
78 ObModuleType
->Security
= NULL
;
79 ObModuleType
->QueryName
= NULL
;
80 ObModuleType
->OkayToClose
= NULL
;
81 RtlInitAnsiString(&AnsiString
, "Module");
82 RtlAnsiStringToUnicodeString(&ObModuleType
->TypeName
, &AnsiString
, TRUE
);
86 * FUNCTION: Loads a kernel driver
88 * FileName = Driver to load
93 LdrLoadDriver(PUNICODE_STRING Filename
)
98 OBJECT_ATTRIBUTES FileObjectAttributes
;
99 FILE_STANDARD_INFORMATION FileStdInfo
;
101 DbgPrint("Loading Driver %W...\n", Filename
);
103 /* Open the Driver */
104 InitializeObjectAttributes(&FileObjectAttributes
,
110 Status
= ZwOpenFile(&FileHandle
,
112 &FileObjectAttributes
,
115 if (!NT_SUCCESS(Status
))
121 /* Get the size of the file */
122 Status
= ZwQueryInformationFile(FileHandle
,
126 FileStandardInformation
);
127 if (!NT_SUCCESS(Status
))
133 /* Allocate nonpageable memory for driver */
134 ModuleLoadBase
= ExAllocatePool(NonPagedPool
,
135 GET_LARGE_INTEGER_LOW_PART(FileStdInfo
.EndOfFile
));
136 if (ModuleLoadBase
== NULL
)
138 return STATUS_INSUFFICIENT_RESOURCES
;
142 /* Load driver into memory chunk */
143 Status
= ZwReadFile(FileHandle
,
146 GET_LARGE_INTEGER_LOW_PART(FileStdInfo
.EndOfFile
),
148 if (!NT_SUCCESS(Status
))
150 ExFreePool(ModuleLoadBase
);
157 Status
= LdrProcessDriver(ModuleLoadBase
);
160 ExFreePool(ModuleLoadBase
);
162 return STATUS_SUCCESS
;
166 LdrProcessDriver(PVOID ModuleLoadBase
)
168 PIMAGE_DOS_HEADER PEDosHeader
;
170 /* If MZ header exists */
171 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
172 if (PEDosHeader
->e_magic
== IMAGE_DOS_MAGIC
&& PEDosHeader
->e_lfanew
!= 0L)
174 return LdrPEProcessDriver(ModuleLoadBase
);
176 if (PEDosHeader
->e_magic
== IMAGE_DOS_MAGIC
)
178 return STATUS_NOT_IMPLEMENTED
;
180 else /* Assume COFF format and load */
182 return LdrCOFFProcessDriver(ModuleLoadBase
);
187 LdrPEProcessDriver(PVOID ModuleLoadBase
)
189 unsigned int DriverSize
, Idx
;
190 long int RelocDelta
, NumRelocs
;
191 PVOID DriverBase
, RelocBase
;
193 PIMAGE_DOS_HEADER PEDosHeader
;
194 PIMAGE_FILE_HEADER PEFileHeader
;
195 PIMAGE_OPTIONAL_HEADER PEOptionalHeader
;
196 PIMAGE_SECTION_HEADER PESectionHeaders
;
197 PRELOCATION_DIRECTORY RelocDir
;
198 PRELOCATION_ENTRY RelocEntry
;
200 DPRINT("Processing PE Driver at module base:%08lx\n", ModuleLoadBase
);
202 /* Get header pointers */
203 PEDosHeader
= (PIMAGE_DOS_HEADER
) ModuleLoadBase
;
204 PEMagic
= (PULONG
) ((unsigned int) ModuleLoadBase
+
205 PEDosHeader
->e_lfanew
);
206 PEFileHeader
= (PIMAGE_FILE_HEADER
) ((unsigned int) ModuleLoadBase
+
207 PEDosHeader
->e_lfanew
+ sizeof(ULONG
));
208 PEOptionalHeader
= (PIMAGE_OPTIONAL_HEADER
) ((unsigned int) ModuleLoadBase
+
209 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
));
210 PESectionHeaders
= (PIMAGE_SECTION_HEADER
) ((unsigned int) ModuleLoadBase
+
211 PEDosHeader
->e_lfanew
+ sizeof(ULONG
) + sizeof(IMAGE_FILE_HEADER
) +
212 sizeof(IMAGE_OPTIONAL_HEADER
));
215 /* Check file magic numbers */
216 if (PEDosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
218 DPRINT("Incorrect MZ magic: %04x\n", PEDosHeader
->e_magic
);
219 return STATUS_UNSUCCESSFUL
;
221 if (PEDosHeader
->e_lfanew
== 0)
223 DPRINT("Invalid lfanew offset: %08x\n", PEDosHeader
->e_lfanew
);
224 return STATUS_UNSUCCESSFUL
;
226 if (*PEMagic
!= IMAGE_PE_MAGIC
)
228 DPRINT("Incorrect PE magic: %08x\n", *PEMagic
);
229 return STATUS_UNSUCCESSFUL
;
231 if (PEFileHeader
->Machine
!= IMAGE_FILE_MACHINE_I386
)
233 DPRINT("Incorrect Architechture: %04x\n", PEFileHeader
->Machine
);
234 return STATUS_UNSUCCESSFUL
;
238 /* FIXME: if image is fixed-address load, then fail */
240 /* FIXME: check/verify OS version number */
242 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
243 PEOptionalHeader
->Magic
,
244 PEOptionalHeader
->MajorLinkerVersion
,
245 PEOptionalHeader
->MinorLinkerVersion
);
246 DPRINT("Entry Point:%08lx\n", PEOptionalHeader
->AddressOfEntryPoint
);
249 /* Determine the size of the module */
250 DPRINT("Sections: (section align:%08lx)\n",
251 PEOptionalHeader
->SectionAlignment
);
253 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
255 DPRINT("Name: %-8.8s VA:%08lx RawSize:%6d Offset:%08lx CHAR:%08lx OfsAdr: %08lx\n",
256 PESectionHeaders
[Idx
].Name
,
257 PESectionHeaders
[Idx
].VirtualAddress
,
258 PESectionHeaders
[Idx
].SizeOfRawData
,
259 PESectionHeaders
[Idx
].PointerToRawData
,
260 PESectionHeaders
[Idx
].Characteristics
,
262 DriverSize
+= ROUND_UP(PESectionHeaders
[Idx
].SizeOfRawData
,
263 PEOptionalHeader
->SectionAlignment
);
265 DPRINT("DriverSize computed by using section headers: %d(%08lx)\n",
270 /* Allocate a virtual section for the module */
271 DriverBase
= MmAllocateSection(DriverSize
);
274 DbgPrint("Failed to allocate a virtual section for driver\n");
275 return STATUS_INSUFFICIENT_RESOURCES
;
279 CurrentBase
= ModuleLoadBase
;
280 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
282 /* Copy current section into current offset of virtual section */
283 if (PESectionHeaders
[Idx
].Characteristics
&
284 (IMAGE_SECTION_CHAR_CODE
| IMAGE_SECTION_CHAR_DATA
))
287 (PVOID
)(ModuleLoadBase
+ PESectionHeaders
[Idx
].PointerToRawData
),
288 PESectionHeaders
[Idx
].SizeOfRawData
);
292 memset(CurrentBase
, '\0', PESectionHeaders
[Idx
].SizeOfRawData
);
294 CurrentSize
+= ROUND_UP(PESectionHeaders
[Idx
].SizeOfRawData
,
295 PEOptionalHeader
->SectionAlignment
);
299 DriverBase
= ModuleLoadBase
;
302 /* FIXME: Perform relocation fixups */
303 RelocDelta
= (DWORD
) DriverBase
- PEOptionalHeader
->ImageBase
;
304 RelocDir
= (PRELOCATION_DIRECTORY
) ((DWORD
)ModuleLoadBase
+
305 PEOptionalHeader
->DataDirectory
[
306 IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
);
307 DPRINT("Relocs: ModuleLoadBase: %08lx RelocDelta %08lx\n",
310 while (RelocDir
->SizeOfBlock
!= 0)
312 NumRelocs
= (RelocDir
->SizeOfBlock
- sizeof(RELOCATION_DIRECTORY
)) /
314 DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
316 RelocDir
->VirtualAddress
,
318 RelocEntry
= (PRELOCATION_ENTRY
) ((DWORD
)RelocDir
+
319 sizeof(RELOCATION_DIRECTORY
));
320 for (Idx
= 0; Idx
< NumRelocs
; Idx
++)
322 DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
323 DriverBase
+ RelocDir
->VirtualAddress
+
324 (RelocEntry
[Idx
].TypeOffset
& 0x0fff),
325 (RelocEntry
[Idx
].TypeOffset
>> 12) & 0xf,
326 (RelocEntry
[Idx
].TypeOffset
>> 12) & 0xf ? "HIGHLOW" : "ABS",
327 *(PDWORD
)((DWORD
) DriverBase
+ RelocDir
->VirtualAddress
+
328 (RelocEntry
[Idx
].TypeOffset
& 0x0fff)),
329 (*(PDWORD
)((DWORD
) DriverBase
+ RelocDir
->VirtualAddress
+
330 (RelocEntry
[Idx
].TypeOffset
& 0x0fff))) + RelocDelta
);
332 RelocDir
= (PRELOCATION_DIRECTORY
)((DWORD
)RelocDir
+
333 RelocDir
->SizeOfBlock
);
339 /* FIXME: perform import fixups */
340 /* FIXME: compute address of entry point */
344 /* return InitializeLoadedDriver(EntryPoint); */
345 return STATUS_NOT_IMPLEMENTED
;
349 LdrCOFFProcessDriver(PVOID ModuleLoadBase
)
352 char SymbolName
[255];
358 PDRIVER_INITIALIZE EntryRoutine
;
360 /* Get header pointers */
361 FileHeader
= ModuleLoadBase
;
362 AOUTHeader
= ModuleLoadBase
+ FILHSZ
;
365 /* Check COFF magic value */
366 if (I386BADMAG(*FileHeader
))
368 DbgPrint("Module has bad magic value (%x)\n",
369 FileHeader
->f_magic
);
370 return STATUS_UNSUCCESSFUL
;
374 /* Allocate and initialize a module definition structure */
375 Module
= (module
*) ExAllocatePool(NonPagedPool
, sizeof(module
));
378 return STATUS_INSUFFICIENT_RESOURCES
;
380 Module
->sym_list
= (SYMENT
*)(ModuleLoadBase
+ FileHeader
->f_symptr
);
381 Module
->str_tab
= (char *)(ModuleLoadBase
+ FileHeader
->f_symptr
+
382 FileHeader
->f_nsyms
* SYMESZ
);
383 Module
->scn_list
= (SCNHDR
*)(ModuleLoadBase
+ FILHSZ
+
384 FileHeader
->f_opthdr
);
386 Module
->raw_data_off
= (ULONG
) ModuleLoadBase
;
387 Module
->nsyms
= FileHeader
->f_nsyms
;
390 /* Determine the length of the module */
391 for (i
= 0; i
< FileHeader
->f_nscns
; i
++)
393 DPRINT("Section name: %.8s\n", Module
->scn_list
[i
].s_name
);
394 DPRINT("size %x vaddr %x size %x\n",
396 Module
->scn_list
[i
].s_vaddr
,
397 Module
->scn_list
[i
].s_size
);
398 if (Module
->scn_list
[i
].s_flags
& STYP_TEXT
)
400 Module
->text_base
= Module
->scn_list
[i
].s_vaddr
;
402 if (Module
->scn_list
[i
].s_flags
& STYP_DATA
)
404 Module
->data_base
= Module
->scn_list
[i
].s_vaddr
;
406 if (Module
->scn_list
[i
].s_flags
& STYP_BSS
)
408 Module
->bss_base
= Module
->scn_list
[i
].s_vaddr
;
411 (Module
->scn_list
[i
].s_vaddr
+ Module
->scn_list
[i
].s_size
))
413 Module
->size
= Module
->size
+ Module
->scn_list
[i
].s_vaddr
+
414 Module
->scn_list
[i
].s_size
;
419 /* Allocate a section for the module */
420 Module
->base
= (unsigned int) MmAllocateSection(Module
->size
);
421 if (Module
->base
== 0)
423 DbgPrint("Failed to alloc section for module\n");
425 return STATUS_INSUFFICIENT_RESOURCES
;
429 /* Adjust section vaddrs for allocated area */
430 Module
->data_base
= Module
->data_base
+ Module
->base
;
431 Module
->text_base
= Module
->text_base
+ Module
->base
;
432 Module
->bss_base
= Module
->bss_base
+ Module
->base
;
434 /* Relocate module and fixup imports */
435 for (i
= 0; i
< FileHeader
->f_nscns
; i
++)
437 if (Module
->scn_list
[i
].s_flags
& STYP_TEXT
||
438 Module
->scn_list
[i
].s_flags
& STYP_DATA
)
440 memcpy((PVOID
)(Module
->base
+ Module
->scn_list
[i
].s_vaddr
),
441 (PVOID
)(ModuleLoadBase
+ Module
->scn_list
[i
].s_scnptr
),
442 Module
->scn_list
[i
].s_size
);
443 if (!LdrCOFFDoRelocations(Module
, i
))
445 DPRINT("Relocation failed for section %s\n",
446 Module
->scn_list
[i
].s_name
);
448 /* FIXME: unallocate all sections here */
452 return STATUS_UNSUCCESSFUL
;
455 if (Module
->scn_list
[i
].s_flags
& STYP_BSS
)
457 memset((PVOID
)(Module
->base
+ Module
->scn_list
[i
].s_vaddr
),
459 Module
->scn_list
[i
].s_size
);
463 DbgPrint("Module base: %x\n", Module
->base
);
465 /* Find the entry point */
468 for (i
= 0; i
< FileHeader
->f_nsyms
; i
++)
470 LdrCOFFGetSymbolName(Module
, i
, SymbolName
);
471 if (!strcmp(SymbolName
, "_DriverEntry"))
473 EntryOffset
= Module
->sym_list
[i
].e_value
;
475 DPRINT("Found entry at %x\n", EntryOffset
);
480 DbgPrint("No module entry point defined\n");
483 /* FIXME: unallocate all sections here */
485 return STATUS_UNSUCCESSFUL
;
488 /* Get the address of the module initalization routine */
489 EntryRoutine
= (PDRIVER_INITIALIZE
)(Module
->base
+ EntryOffset
);
494 return InitalizeLoadedDriver(EntryRoutine
);
497 /* LdrCOFFDoRelocations
498 * FUNCTION: Do the relocations for a module section
500 * Module = Pointer to the module
501 * SectionIndex = Index of the section to be relocated
502 * RETURNS: Success or failure
506 LdrCOFFDoRelocations(module
*Module
, unsigned int SectionIndex
)
508 SCNHDR
*Section
= &Module
->scn_list
[SectionIndex
];
509 RELOC
*Relocation
= (RELOC
*)(Module
->raw_data_off
+ Section
->s_relptr
);
512 DPRINT("SectionIndex %d Name %.8s Relocs %d\n",
514 Module
->scn_list
[SectionIndex
].s_name
,
517 for (j
= 0; j
< Section
->s_nreloc
; j
++)
519 DPRINT("vaddr %x symndex %x",
521 Relocation
->r_symndx
);
523 switch (Relocation
->r_type
)
526 if (!LdrCOFFDoAddr32Reloc(Module
, Section
, Relocation
))
533 if (!LdrCOFFDoReloc32Reloc(Module
, Section
, Relocation
))
540 DPRINT("%.8s: Unknown relocation type %x at %d in module\n",
541 Module
->scn_list
[SectionIndex
].s_name
,
548 DPRINT("%.8s: relocations done\n", Module
->scn_list
[SectionIndex
].s_name
);
554 * FUNCTION: Performs a addr32 relocation on a loaded module
556 * mod = module to perform the relocation on
557 * scn = Section to perform the relocation in
558 * reloc = Pointer to a data structure describing the relocation
559 * RETURNS: Success or failure
560 * NOTE: This fixes up a relocation needed when changing the base address of a
565 LdrCOFFDoAddr32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
)
568 unsigned int *Location
;
570 Value
= LdrCOFFGetSymbolValue(Module
, Relocation
->r_symndx
);
571 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
572 DPRINT("ADDR32 loc %x value %x *loc %x\n", Location
, Value
, *Location
);
573 *Location
= (*Location
) + Module
->base
;
579 * FUNCTION: Performs a reloc32 relocation on a loaded module
581 * mod = module to perform the relocation on
582 * scn = Section to perform the relocation in
583 * reloc = Pointer to a data structure describing the relocation
584 * RETURNS: Success or failure
585 * NOTE: This fixes up an undefined reference to a kernel function in a module
589 LdrCOFFDoReloc32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
)
593 unsigned int *Location
;
595 memset(Name
, 0, 255);
596 LdrCOFFGetSymbolName(Module
, Relocation
->r_symndx
, Name
);
597 Value
= (unsigned int) LdrCOFFGetKernelSymbolAddr(Name
);
600 Value
= LdrCOFFGetSymbolValueByName(Module
, Name
, Relocation
->r_symndx
);
603 DbgPrint("Undefined symbol %s in module\n", Name
);
606 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
607 // (*Location) = (*Location) + Value + Module->base - Section->s_vaddr;
608 (*Location
) = (*Location
);
609 DPRINT("Module->base %x Section->s_vaddr %x\n",
615 DPRINT("REL32 value %x name %s\n", Value
, Name
);
616 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
617 DPRINT("old %x ", *Location
);
618 DPRINT("Module->base %x Section->s_vaddr %x\n",
621 (*Location
) = (*Location
) + Value
- Module
->base
+ Section
->s_vaddr
;
622 DPRINT("new %x\n", *Location
);
629 * FUNCTION: Get the name of a symbol from a loaded module by ordinal
632 * i = index of symbol
633 * name (OUT) = pointer to a string where the symbol name will be
638 LdrCOFFGetSymbolName(module
*Module
, unsigned int Idx
, char *Name
)
640 if (Module
->sym_list
[Idx
].e
.e_name
[0] != 0)
642 strncpy(Name
, Module
->sym_list
[Idx
].e
.e_name
, 8);
647 strcpy(Name
, &Module
->str_tab
[Module
->sym_list
[Idx
].e
.e
.e_offset
]);
652 * FUNCTION: Get the value of a module defined symbol
655 * i = index of symbol
656 * RETURNS: The value of the symbol
657 * NOTE: This fixes up references to known sections
661 LdrCOFFGetSymbolValue(module
*Module
, unsigned int Idx
)
665 LdrCOFFGetSymbolName(Module
, Idx
, Name
);
666 DPRINT("name %s ", Name
);
668 /* Check if the symbol is a section we have relocated */
669 if (strcmp(Name
, ".text") == 0)
671 return Module
->text_base
;
673 if (strcmp(Name
, ".data") == 0)
675 return Module
->data_base
;
677 if (strcmp(Name
, ".bss") == 0)
679 return Module
->bss_base
;
682 return Module
->sym_list
[Idx
].e_value
;
686 * FUNCTION: Get the address of a kernel symbol
689 * RETURNS: The address of the symbol on success
694 LdrCOFFGetKernelSymbolAddr(char *Name
)
698 while (symbol_table
[i
].name
!= NULL
)
700 if (strcmp(symbol_table
[i
].name
, Name
) == 0)
702 return symbol_table
[i
].value
;
711 LdrCOFFGetSymbolValueByName(module
*Module
,
718 DPRINT("LdrCOFFGetSymbolValueByName(sname %s, idx %x)\n", SymbolName
, Idx
);
720 for (i
= 0; i
< Module
->nsyms
; i
++)
722 LdrCOFFGetSymbolName(Module
, i
, Name
);
723 DPRINT("Scanning %s Value %x\n", Name
, Module
->sym_list
[i
].e_value
);
724 if (strcmp(Name
, SymbolName
) == 0)
726 DPRINT("Returning %x\n", Module
->sym_list
[i
].e_value
);
727 return Module
->sym_list
[i
].e_value
;
734 NTSTATUS
LdrLoadLibrary(HANDLE ProcessHandle
,
735 PHANDLE ModuleHandle
,
740 ANSI_STRING afilename
;
741 UNICODE_STRING ufilename
,umodName
;
742 PMODULE
*Library
, *Module
;
743 OBJECT_ATTRIBUTES attr
;
747 /* FIXME: this is broke */
748 /* FIXME: check for module already loaded */
749 /* FIXME: otherwise load module */
750 /* FIXME: we need to fix how modules are loaded so that they can
753 /* If module is already loaded, get a reference and return it */
754 strcpy(name2
, "\\modules\\");
756 RtlInitAnsiString(&afilename
, name2
);
757 RtlAnsiStringToUnicodeString(&umodName
, &afilename
, TRUE
);
758 InitializeObjectAttributes(&attr
, &umodName
, 0, NULL
, NULL
);
759 Status
= ObOpenObjectByName(&attr
, (PVOID
*) &Library
, &Ignored
);
760 DPRINT("LoadLibrary : Status=%x,pLibrary=%x\n",Status
, Library
);
761 if (!NT_SUCCESS(Status
) || Library
== NULL
)
763 strcpy(name2
, "\\??\\C:\\reactos\\system\\");
765 RtlInitAnsiString(&afilename
, name2
);
766 RtlAnsiStringToUnicodeString(&ufilename
, &afilename
, TRUE
);
767 DPRINT("LoadLibrary,load %s\n", name2
);
768 Library
= LdrLoadImage(&ufilename
);
769 /* FIXME: execute start code ? */
770 Module
= ObGenericCreateObject(NULL
, PROCESS_ALL_ACCESS
, &attr
, ObModuleType
);
773 memcpy(Module
, Library
, PMODULE
);
777 DbgPrint("library object not created\n");
779 RtlFreeUnicodeString(&ufilename
);
780 Status
= ObOpenObjectByName(&attr
, (PVOID
*)&Library
, &Ignored
);
784 DPRINT("Library already loaded\n");
787 RtlFreeUnicodeString(&umodName
);
789 return STATUS_SUCCESS
;
796 * Loads a module into the specified process
798 * HANDLE ProcessHandle handle of the process to load the module into
799 * PHANDLE ModuleHandle handle of the loaded module
800 * PUNICODE_STRING Filename name of the module to load
806 LdrLoadImage(HANDLE ProcessHandle
,
807 PHANDLE ModuleHandle
,
808 PUNICODE_STRING Filename
)
810 char BlockBuffer
[1024];
812 OBJECT_ATTRIBUTES FileObjectAttributes
;
815 PIMAGE_DOS_HEADER PEDosHeader
;
817 /* FIXME: should DLLs be named sections? */
819 /* Open the image file */
820 InitializeObjectAttributes(&FileObjectAttributes
,
825 Status
= ZwOpenFile(&FileHandle
, 0, &FileObjectAttributes
, NULL
, 0, 0);
826 if (!NT_SUCCESS(Status
))
831 /* Build a module structure for the image */
832 Module
= ObGenericCreateObject(ModuleHandle
,
842 /* Read first block of image to determine type */
843 Status
= ZwReadFile(FileHandle
, 0, 0, 0, 0, BlockBuffer
, 1024, 0, 0);
844 if (!NT_SUCCESS(Status
))
846 ObDereferenceObject(*ModuleHandle
);
847 *ModuleHandle
= NULL
;
853 /* If MZ header exists */
854 PEDosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
855 if (PEDosHeader
->e_magic
== IMAGE_DOS_MAGIC
&&
856 PEDosHeader
->e_lfanew
!= 0L &&
857 *(PULONG
)((PUCHAR
)BlockBuffer
+ PEDosHeader
->e_lfanew
) == IMAGE_PE_MAGIC
)
859 Status
= LdrProcessPEImage(ProcessHandle
,
863 else if (PEDosHeader
->e_magic
== 0x54AD)
865 Status
= LdrProcessMZImage(ProcessHandle
,
869 else /* Assume bin format and load */
871 Status
= LdrProcessBinImage(ProcessHandle
,
875 /* FIXME: {else} could check for a.out, ELF, COFF, etc. images here... */
877 /* FIXME: should we unconditionally dereference the module handle here? */
878 if (!NT_SUCCESS(Status
))
880 ObDereferenceObject(*ModuleHandle
);
881 *ModuleHandle
= NULL
;
889 LdrProcessMZImage(HANDLE ProcessHandle
,
894 /* FIXME: map VDM into low memory */
895 /* FIXME: Build/Load image sections */
897 return STATUS_NOT_IMPLEMENTED
;
901 LdrProcessPEImage(HANDLE ProcessHandle
,
908 PIMAGE_DOS_HEADER DosHeader
;
909 PIMAGE_NT_HEADERS NTHeaders
;
911 LARGE_INTEGER SectionOffset
;
913 /* Allocate memory for headers */
914 Module
= HEADER_TO_BODY(ModuleHandle
);
917 return STATUS_UNSUCCESSFUL
;
919 DosHeader
= (PIMAGE_DOS_HEADER
)ExAllocatePool(NonPagedPool
,
920 sizeof(IMAGE_DOS_HEADER
) +
921 sizeof(IMAGE_NT_HEADERS
));
922 if (DosHeader
== NULL
)
924 return STATUS_UNSUCCESSFUL
;
926 NTHeaders
= (PIMAGE_NT_HEADERS
)((PUCHAR
) DosHeader
+ sizeof(IMAGE_DOS_HEADER
));
928 /* Read the headers into memory */
929 memset(Module
, '\0', sizeof(PMODULE
));
930 Status
= ZwReadFile(FileHandle
,
931 NULL
, NULL
, NULL
, NULL
,
933 sizeof(IMAGE_DOS_HEADER
),
935 if (!NT_SUCCESS(Status
))
937 ExFreePool(DosHeader
);
940 SET_LARGE_INTEGER_HIGH_PART(SectionOffset
, 0);
941 SET_LARGE_INTEGER_LOW_PART(SectionOffset
, DosHeader
->e_lfanew
);
942 Status
= ZwReadFile(FileHandle
,
943 NULL
, NULL
, NULL
, NULL
,
945 sizeof(IMAGE_NT_HEADERS
),
948 if (!NT_SUCCESS(Status
))
950 ExFreePool(DosHeader
);
954 /* Allocate memory in process for image */
955 Module
->Flags
= MODULE_FLAG_PE
;
956 Module
->Base
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
957 Module
->Size
= NTHeaders
->OptionalHeader
.SizeOfImage
;
958 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
964 if (!NT_SUCCESS(Status
))
966 ExFreePool(DosHeader
);
970 /* Load headers into virtual memory */
971 Status
= ZwReadFile(FileHandle
,
972 NULL
, NULL
, NULL
, NULL
,
974 NTHeaders
->OptionalHeader
.SizeOfHeaders
,
976 if (!NT_SUCCESS(Status
))
978 ZwFreeVirtualMemory(ProcessHandle
,
982 ExFreePool(DosHeader
);
986 /* Adjust module pointers into virtual memory */
987 DosHeader
= (PIMAGE_DOS_HEADER
) Module
->Base
;
988 NTHeaders
= (PIMAGE_NT_HEADERS
) ((PUCHAR
)Module
->Base
+
989 DosHeader
->e_lfanew
);
990 Module
->Image
.PE
.FileHeader
= (PIMAGE_FILE_HEADER
) ((PUCHAR
)NTHeaders
+
992 Module
->Image
.PE
.OptionalHeader
= (PIMAGE_OPTIONAL_HEADER
)
993 ((PUCHAR
)Module
->Image
.PE
.FileHeader
+ sizeof(IMAGE_FILE_HEADER
));
994 Module
->Image
.PE
.SectionList
= (PCOFF_SECTION_HEADER
) ((PUCHAR
)NTHeaders
+
995 sizeof(IMAGE_NT_HEADERS
));
997 /* Build Image Sections */
998 /* FIXME: should probably use image directory to load sections. */
999 for (i
= 0; i
< Module
->Image
.PE
.FileHeader
->NumberOfSections
; i
++)
1001 DPRINT("section %d\n", i
);
1002 BaseSection
= (PVOID
)((PCHAR
) Module
->Base
+
1003 Module
->Image
.PE
.SectionList
[i
].s_vaddr
);
1005 /* Load code and initialized data sections from disk */
1006 if ((Module
->Image
.PE
.SectionList
[i
].s_flags
& STYP_TEXT
) ||
1007 (Module
->Image
.PE
.SectionList
[i
].s_flags
& STYP_DATA
))
1009 SET_LARGE_INTEGER_HIGH_PART(SectionOffset
, 0);
1010 SET_LARGE_INTEGER_LOW_PART(SectionOffset
,
1011 Module
->Image
.PE
.SectionList
[i
].s_scnptr
);
1013 /* FIXME: should probably map sections into sections */
1014 Status
= ZwReadFile(FileHandle
,
1015 NULL
, NULL
, NULL
, NULL
,
1016 Module
->Base
+ Module
->Image
.PE
.SectionList
[i
].s_vaddr
,
1017 min(Module
->Image
.PE
.SectionList
[i
].s_size
,
1018 Module
->Image
.PE
.SectionList
[i
].s_paddr
),
1020 if (!NT_SUCCESS(Status
))
1022 ZwFreeVirtualMemory(ProcessHandle
,
1026 ExFreePool(DosHeader
);
1030 else if (Module
->Image
.PE
.SectionList
[i
].s_flags
& STYP_BSS
)
1032 memset((PVOID
)(Module
->Base
+
1033 Module
->Image
.PE
.SectionList
[i
].s_vaddr
),
1035 Module
->Image
.PE
.SectionList
[i
].s_size
);
1039 /* Resolve Import Library references */
1040 if (Module
->Image
.PE
.OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
)
1042 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1044 /* Process each import module */
1045 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)
1046 ((PUCHAR
)Module
->Base
+ Module
->Image
.PE
.OptionalHeader
->
1047 DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
);
1048 while (ImportModuleDirectory
->dwRVAModuleName
)
1051 PVOID
*LibraryExports
;
1052 PVOID
*ImportAddressList
; // was pImpAddr
1053 PULONG FunctionNameList
;
1057 /* Load the library module into the process */
1058 /* FIXME: this should take a UNICODE string */
1059 Status
= LdrLoadLibrary(ProcessHandle
,
1061 (PCHAR
)(Module
->Base
+
1062 ImportModuleDirectory
->dwRVAModuleName
));
1063 if (!NT_SUCCESS(Status
))
1065 /* FIXME: Dereference all loaded modules */
1066 ZwFreeVirtualMemory(ProcessHandle
,
1070 ExFreePool(DosHeader
);
1075 /* Get the address of the export list for the library */
1076 LibraryExports
= (PVOID
*)(Library
->Base
+
1077 Library
->Image
.PE
.OptionalHeader
->
1078 DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
].VirtualAddress
+
1079 sizeof(IMAGE_EXPORT_DIRECTORY
));
1081 /* Get the import address list */
1082 ImportAddressList
= (PVOID
*)
1083 ((PCHAR
)Module
->Image
.PE
.OptionalHeader
->ImageBase
+
1084 ImportModuleDirectory
->dwRVAFunctionAddressList
);
1086 /* Get the list of functions to import */
1087 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1089 FunctionNameList
= (PULONG
) ((PCHAR
)Module
->Base
+
1090 ImportModuleDirectory
->dwRVAFunctionNameList
);
1094 FunctionNameList
= (PULONG
) ((PCHAR
)Module
->Base
+
1095 ImportModuleDirectory
->dwRVAFunctionAddressList
);
1098 /* Walk through function list and fixup addresses */
1099 while(*FunctionNameList
!= 0L)
1101 if ((*FunctionNameList
) & 0x80000000) // hint
1103 *ImportAddressList
= LibraryExports
[(*FunctionNameList
) & 0x7fffffff];
1107 pName
= (DWORD
)((PCHAR
)Module
->Base
+ *FunctionNameList
+ 2);
1108 pHint
= (PWORD
)((PCHAR
)Module
->Base
+ *FunctionNameList
);
1110 /* FIXME: verify name */
1112 *ImportAddressList
= LibraryExports
[*pHint
];
1115 /* FIXME: verify value of hint */
1117 ImportAddressList
++;
1120 ImportModuleDirectory
++;
1125 if (Module
->Base
!= (PVOID
)Module
->Image
.PE
.OptionalHeader
->ImageBase
)
1127 USHORT NumberOfEntries
;
1129 ULONG RelocationRVA
;
1130 ULONG Delta32
, Offset
;
1132 PRELOCATION_DIRECTORY RelocationDir
;
1133 PRELOCATION_ENTRY RelocationBlock
;
1135 RelocationRVA
= NTHeaders
->OptionalHeader
.DataDirectory
[
1136 IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
;
1139 RelocationDir
= (PRELOCATION_DIRECTORY
)
1140 ((PCHAR
)Module
->Base
+ RelocationRVA
);
1141 while (RelocationDir
->SizeOfBlock
)
1143 Delta32
= (unsigned long)(Module
->Base
- NTHeaders
->OptionalHeader
.ImageBase
);
1144 RelocationBlock
= (PRELOCATION_ENTRY
)
1145 (RelocationRVA
+ Module
->Base
+ sizeof(RELOCATION_DIRECTORY
));
1147 (RelocationDir
->SizeOfBlock
- sizeof(RELOCATION_DIRECTORY
)) /
1148 sizeof(RELOCATION_ENTRY
);
1149 for (i
= 0; i
< NumberOfEntries
; i
++)
1151 Offset
= (RelocationBlock
[i
].TypeOffset
& 0xfff) + RelocationDir
->VirtualAddress
;
1152 switch (RelocationBlock
[i
].TypeOffset
>> 12)
1154 case TYPE_RELOC_ABSOLUTE
:
1157 case TYPE_RELOC_HIGH
:
1158 pValue16
= (PUSHORT
) (Module
->Base
+ Offset
);
1159 *pValue16
+= Delta32
>> 16;
1162 case TYPE_RELOC_LOW
:
1163 pValue16
= (PUSHORT
)(Module
->Base
+ Offset
);
1164 *pValue16
+= Delta32
& 0xffff;
1167 case TYPE_RELOC_HIGHLOW
:
1168 pValue32
= (PULONG
) (Module
->Base
+ Offset
);
1169 *pValue32
+= Delta32
;
1172 case TYPE_RELOC_HIGHADJ
:
1173 /* FIXME: do the highadjust fixup */
1174 DbgPrint("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1178 DbgPrint("unexpected fixup type\n");
1180 /* FIXME: Dereference all loaded modules */
1182 ZwFreeVirtualMemory(ProcessHandle
,
1186 ExFreePool(DosHeader
);
1187 return STATUS_UNSUCCESSFUL
;
1190 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1191 RelocationDir
= (PRELOCATION_DIRECTORY
)((PCHAR
)Module
->Base
+
1197 /* FIXME: Create the stack for the process */
1198 /* FIXME: Setup the context for the initial thread */
1199 /* FIXME: Create the initial thread */
1201 // fail: ZwFreeVirtualMemory(ProcessHandle, Module->ImageBase, 0, MEM_RELEASE);
1202 ExFreePool(DosHeader
);
1204 return STATUS_NOT_IMPLEMENTED
;
1208 LdrProcessBinImage(HANDLE ProcessHandle
,
1209 HANDLE ModuleHandle
,
1213 FILE_STANDARD_INFORMATION FileStdInfo
;
1215 HANDLE ThreadHandle
;
1217 HANDLE SectionHandle
;
1220 /* FIXME: should set module pointers */
1222 /* Get the size of the file for the section */
1223 Status
= ZwQueryInformationFile(FileHandle
,
1226 sizeof(FileStdInfo
),
1227 FileStandardInformation
);
1228 if (!NT_SUCCESS(Status
))
1233 /* Create the section for the code */
1234 Status
= ZwCreateSection(&SectionHandle
,
1241 if (!NT_SUCCESS(Status
))
1246 /* Map a view of the section into the desired process */
1247 BaseAddress
= (PVOID
)0x10000;
1248 SectionSize
= GET_LARGE_INTEGER_LOW_PART(FileStdInfo
.AllocationSize
);
1249 Status
= ZwMapViewOfSection(SectionHandle
,
1259 if (!NT_SUCCESS(Status
))
1261 /* FIXME: destroy the section here */
1265 /* Setup the context for the initial thread */
1266 memset(&Context
,0,sizeof(CONTEXT
));
1267 Context
.SegSs
= USER_DS
;
1268 Context
.Esp
= 0x2000;
1269 Context
.EFlags
= 0x202;
1270 Context
.SegCs
= USER_CS
;
1271 Context
.Eip
= 0x10000;
1272 Context
.SegDs
= USER_DS
;
1273 Context
.SegEs
= USER_DS
;
1274 Context
.SegFs
= USER_DS
;
1275 Context
.SegGs
= USER_DS
;
1277 /* Create the stack for the process */
1278 BaseAddress
= (PVOID
) 0x1000;
1279 SectionSize
= 0x1000;
1280 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
1286 if (!NT_SUCCESS(Status
))
1288 /* FIXME: unmap the section here */
1289 /* FIXME: destroy the section here */
1294 /* Create the initial thread */
1295 Status
= ZwCreateThread(&ThreadHandle
,
1303 if (!NT_SUCCESS(Status
))
1305 /* FIXME: destroy the stack memory block here */
1306 /* FIXME: unmap the section here */
1307 /* FIXME: destroy the section here */
1311 return STATUS_SUCCESS
;