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 * PROGRAMMER: Rex Jolliff (rex@lvcablemodem.com)
9 * RJJ 10/12/98 Completed loader function and added hooks for MZ/PE
12 /* INCLUDES *****************************************************************/
14 #include <internal/i386/segment.h>
15 #include <internal/kernel.h>
16 #include <internal/linkage.h>
17 #include <internal/module.h>
18 #include <internal/string.h>
19 #include <internal/symbol.h>
21 #include <ddk/ntddk.h>
25 #include <internal/debug.h>
29 /* FUNCTIONS *****************************************************************/
31 /* COFF Driver load support **************************************************/
32 static BOOLEAN
LdrCOFFDoRelocations(module
*Module
, unsigned int SectionIndex
);
33 static BOOLEAN
LdrCOFFDoAddr32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
);
34 static BOOLEAN
LdrCOFFDoReloc32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
);
35 static void LdrCOFFGetSymbolName(module
*Module
, unsigned int Idx
, char *Name
);
36 static unsigned int LdrCOFFGetSymbolValue(module
*Module
, unsigned int Idx
);
37 static unsigned int LdrCOFFGetKernelSymbolAddr(char *Name
);
38 static unsigned int LdrCOFFGetSymbolValueByName(module
*Module
, char *SymbolName
, unsigned int Idx
);
41 LdrCOFFProcessDriver(HANDLE FileHandle
)
52 FILE_STANDARD_INFORMATION FileStdInfo
;
53 PDRIVER_INITIALIZE EntryRoutine
;
55 /* Get the size of the file for the section */
56 Status
= ZwQueryInformationFile(FileHandle
,
60 FileStandardInformation
);
61 if (!NT_SUCCESS(Status
))
67 /* Allocate nonpageable memory for driver */
68 ModuleLoadBase
= ExAllocatePool(NonPagedPool
,
69 GET_LARGE_INTEGER_LOW_PART(FileStdInfo
.AllocationSize
));
70 if (ModuleLoadBase
== NULL
)
72 return STATUS_INSUFFICIENT_RESOURCES
;
76 /* Load driver into memory chunk */
77 Status
= ZwReadFile(FileHandle
,
80 GET_LARGE_INTEGER_LOW_PART(FileStdInfo
.AllocationSize
),
82 if (!NT_SUCCESS(Status
))
84 ExFreePool(ModuleLoadBase
);
89 /* Get header pointers */
90 FileHeader
= ModuleLoadBase
;
91 AOUTHeader
= ModuleLoadBase
+ FILHSZ
;
94 /* Check COFF magic value */
95 if (I386BADMAG(*FileHeader
))
97 DbgPrint("Module has bad magic value (%x)\n",
99 ExFreePool(ModuleLoadBase
);
100 return STATUS_UNSUCCESSFUL
;
104 /* Allocate and initialize a module definition structure */
105 Module
= (module
*) ExAllocatePool(NonPagedPool
, sizeof(module
));
108 ExFreePool(ModuleLoadBase
);
109 return STATUS_INSUFFICIENT_RESOURCES
;
111 Module
->sym_list
= (SYMENT
*)(ModuleLoadBase
+ FileHeader
->f_symptr
);
112 Module
->str_tab
= (char *)(ModuleLoadBase
+ FileHeader
->f_symptr
+
113 FileHeader
->f_nsyms
* SYMESZ
);
114 Module
->scn_list
= (SCNHDR
*)(ModuleLoadBase
+ FILHSZ
+
115 FileHeader
->f_opthdr
);
117 Module
->raw_data_off
= (ULONG
) ModuleLoadBase
;
118 Module
->nsyms
= FileHeader
->f_nsyms
;
121 /* Determine the length of the module */
122 for (i
= 0; i
< FileHeader
->f_nscns
; i
++)
124 DPRINT("Section name: %.8s\n", Module
->scn_list
[i
].s_name
);
125 DPRINT("size %x vaddr %x size %x\n",
127 Module
->scn_list
[i
].s_vaddr
,
128 Module
->scn_list
[i
].s_size
);
129 if (Module
->scn_list
[i
].s_flags
& STYP_TEXT
)
131 Module
->text_base
= Module
->scn_list
[i
].s_vaddr
;
133 if (Module
->scn_list
[i
].s_flags
& STYP_DATA
)
135 Module
->data_base
= Module
->scn_list
[i
].s_vaddr
;
137 if (Module
->scn_list
[i
].s_flags
& STYP_BSS
)
139 Module
->bss_base
= Module
->scn_list
[i
].s_vaddr
;
142 (Module
->scn_list
[i
].s_vaddr
+ Module
->scn_list
[i
].s_size
))
144 Module
->size
= Module
->size
+ Module
->scn_list
[i
].s_vaddr
+
145 Module
->scn_list
[i
].s_size
;
150 /* Allocate a section for the module */
151 Module
->base
= (unsigned int) MmAllocateSection(Module
->size
);
152 if (Module
->base
== 0)
154 DbgPrint("Failed to alloc section for module\n");
156 ExFreePool(ModuleLoadBase
);
157 return STATUS_INSUFFICIENT_RESOURCES
;
161 /* Adjust section vaddrs for allocated area */
162 Module
->data_base
= Module
->data_base
+ Module
->base
;
163 Module
->text_base
= Module
->text_base
+ Module
->base
;
164 Module
->bss_base
= Module
->bss_base
+ Module
->base
;
166 /* Relocate module and fixup imports */
167 for (i
= 0; i
< FileHeader
->f_nscns
; i
++)
169 if (Module
->scn_list
[i
].s_flags
& STYP_TEXT
||
170 Module
->scn_list
[i
].s_flags
& STYP_DATA
)
172 memcpy((PVOID
)(Module
->base
+ Module
->scn_list
[i
].s_vaddr
),
173 (PVOID
)(ModuleLoadBase
+ Module
->scn_list
[i
].s_scnptr
),
174 Module
->scn_list
[i
].s_size
);
175 if (!LdrCOFFDoRelocations(Module
, i
))
177 DPRINT("Relocation failed for section %s\n",
178 Module
->scn_list
[i
].s_name
);
180 ExFreePool(ModuleLoadBase
);
181 return STATUS_UNSUCCESSFUL
;
184 if (Module
->scn_list
[i
].s_flags
& STYP_BSS
)
186 memset((PVOID
)(Module
->base
+ Module
->scn_list
[i
].s_vaddr
),
188 Module
->scn_list
[i
].s_size
);
192 DbgPrint("Module base: %x\n", Module
->base
);
194 /* Find the entry point */
197 for (i
= 0; i
< FileHeader
->f_nsyms
; i
++)
199 LdrCOFFGetSymbolName(Module
, i
, SymbolName
);
200 if (!strcmp(SymbolName
, "_DriverEntry"))
202 EntryOffset
= Module
->sym_list
[i
].e_value
;
204 DPRINT("Found entry at %x\n", EntryOffset
);
209 DbgPrint("No module entry point defined\n");
211 ExFreePool(ModuleLoadBase
);
212 return STATUS_UNSUCCESSFUL
;
215 /* Call the module initalization routine */
216 EntryRoutine
= (PDRIVER_INITIALIZE
)(Module
->base
+ EntryOffset
);
218 return InitalizeLoadedDriver(EntryRoutine
);
221 /* LdrCOFFDoRelocations
222 * FUNCTION: Do the relocations for a module section
224 * Module = Pointer to the module
225 * SectionIndex = Index of the section to be relocated
226 * RETURNS: Success or failure
230 LdrCOFFDoRelocations(module
*Module
, unsigned int SectionIndex
)
232 SCNHDR
*Section
= &Module
->scn_list
[SectionIndex
];
233 RELOC
*Relocation
= (RELOC
*)(Module
->raw_data_off
+ Section
->s_relptr
);
236 DPRINT("SectionIndex %d Name %.8s Relocs %d\n",
238 Module
->scn_list
[SectionIndex
].s_name
,
241 for (j
= 0; j
< Section
->s_nreloc
; j
++)
243 DbgPrint("vaddr %x ", Relocation
->r_vaddr
);
244 DbgPrint("symndex %x ", Relocation
->r_symndx
);
246 switch (Relocation
->r_type
)
249 if (!LdrCOFFDoAddr32Reloc(Module
, Section
, Relocation
))
256 if (!LdrCOFFDoReloc32Reloc(Module
, Section
, Relocation
))
263 DbgPrint("%.8s: Unknown relocation type %x at %d in module\n",
264 Module
->scn_list
[SectionIndex
].s_name
,
271 DPRINT("%.8s: relocations done\n", Module
->scn_list
[SectionIndex
].s_name
);
277 * FUNCTION: Performs a addr32 relocation on a loaded module
279 * mod = module to perform the relocation on
280 * scn = Section to perform the relocation in
281 * reloc = Pointer to a data structure describing the relocation
282 * RETURNS: Success or failure
283 * NOTE: This fixes up a relocation needed when changing the base address of a
288 LdrCOFFDoAddr32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
)
291 unsigned int *Location
;
293 Value
= LdrCOFFGetSymbolValue(Module
, Relocation
->r_symndx
);
294 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
295 DbgPrint("ADDR32 loc %x value %x *loc %x ", Location
, Value
, *Location
);
296 *Location
= (*Location
) + Module
->base
;
302 * FUNCTION: Performs a reloc32 relocation on a loaded module
304 * mod = module to perform the relocation on
305 * scn = Section to perform the relocation in
306 * reloc = Pointer to a data structure describing the relocation
307 * RETURNS: Success or failure
308 * NOTE: This fixes up an undefined reference to a kernel function in a module
312 LdrCOFFDoReloc32Reloc(module
*Module
, SCNHDR
*Section
, RELOC
*Relocation
)
316 unsigned int *Location
;
318 memset(Name
, 0, 255);
319 LdrCOFFGetSymbolName(Module
, Relocation
->r_symndx
, Name
);
320 Value
= (unsigned int) LdrCOFFGetKernelSymbolAddr(Name
);
323 Value
= LdrCOFFGetSymbolValueByName(Module
, Name
, Relocation
->r_symndx
);
326 DbgPrint("Undefined symbol %s in module\n", Name
);
329 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
330 // (*Location) = (*Location) + Value + Module->base - Section->s_vaddr;
331 (*Location
) = (*Location
);
332 DPRINT("Module->base %x Section->s_vaddr %x\n",
338 DPRINT("REL32 value %x name %s\n", Value
, Name
);
339 Location
= (unsigned int *)(Module
->base
+ Relocation
->r_vaddr
);
340 DPRINT("old %x ", *Location
);
341 DPRINT("Module->base %x Section->s_vaddr %x\n",
344 (*Location
) = (*Location
) + Value
- Module
->base
+ Section
->s_vaddr
;
345 DPRINT("new %x\n", *Location
);
352 * FUNCTION: Get the name of a symbol from a loaded module by ordinal
355 * i = index of symbol
356 * name (OUT) = pointer to a string where the symbol name will be
361 LdrCOFFGetSymbolName(module
*Module
, unsigned int Idx
, char *Name
)
363 if (Module
->sym_list
[Idx
].e
.e_name
[0] != 0)
365 strncpy(Name
, Module
->sym_list
[Idx
].e
.e_name
, 8);
370 strcpy(Name
, &Module
->str_tab
[Module
->sym_list
[Idx
].e
.e
.e_offset
]);
375 * FUNCTION: Get the value of a module defined symbol
378 * i = index of symbol
379 * RETURNS: The value of the symbol
380 * NOTE: This fixes up references to known sections
384 LdrCOFFGetSymbolValue(module
*Module
, unsigned int Idx
)
388 LdrCOFFGetSymbolName(Module
, Idx
, Name
);
389 DbgPrint("name %s ", Name
);
391 /* Check if the symbol is a section we have relocated */
392 if (strcmp(Name
, ".text") == 0)
394 return Module
->text_base
;
396 if (strcmp(Name
, ".data") == 0)
398 return Module
->data_base
;
400 if (strcmp(Name
, ".bss") == 0)
402 return Module
->bss_base
;
405 return Module
->sym_list
[Idx
].e_value
;
409 * FUNCTION: Get the address of a kernel symbol
412 * RETURNS: The address of the symbol on success
417 LdrCOFFGetKernelSymbolAddr(char *Name
)
421 while (symbol_table
[i
].name
!= NULL
)
423 if (strcmp(symbol_table
[i
].name
, Name
) == 0)
425 return symbol_table
[i
].value
;
434 LdrCOFFGetSymbolValueByName(module
*Module
,
441 DPRINT("LdrCOFFGetSymbolValueByName(sname %s, idx %x)\n", SymbolName
, Idx
);
443 for (i
= 0; i
< Module
->nsyms
; i
++)
445 LdrCOFFGetSymbolName(Module
, i
, Name
);
446 DPRINT("Scanning %s Value %x\n", Name
, Module
->sym_list
[i
].e_value
);
447 if (strcmp(Name
, SymbolName
) == 0)
449 DPRINT("Returning %x\n", Module
->sym_list
[i
].e_value
);
450 return Module
->sym_list
[i
].e_value
;
461 LdrProcessPEDriver(HANDLE FileHandle
, PIMAGE_DOS_HEADER DosHeader
)
463 return STATUS_NOT_IMPLEMENTED
;
467 LdrLoadDriver(PUNICODE_STRING Filename
)
469 * FUNCTION: Loads a kernel driver
471 * FileName = Driver to load
475 char BlockBuffer
[512];
478 OBJECT_ATTRIBUTES FileObjectAttributes
;
479 PIMAGE_DOS_HEADER PEDosHeader
;
481 /* Open the Driver */
482 InitializeObjectAttributes(&FileObjectAttributes
,
487 Status
= ZwOpenFile(&FileHandle
, 0, &FileObjectAttributes
, NULL
, 0, 0);
488 if (!NT_SUCCESS(Status
))
493 /* Read first block of image to determine type */
494 Status
= ZwReadFile(FileHandle
, 0, 0, 0, 0, BlockBuffer
, 512, 0, 0);
495 if (!NT_SUCCESS(Status
))
501 /* If MZ header exists */
502 PEDosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
503 if (PEDosHeader
->e_magic
== 0x54AD && PEDosHeader
->e_lfanew
!= 0L)
505 Status
= LdrProcessPEDriver(FileHandle
, PEDosHeader
);
506 if (!NT_SUCCESS(Status
))
512 if (PEDosHeader
->e_magic
== 0x54AD)
515 return STATUS_NOT_IMPLEMENTED
;
517 else /* Assume coff format and load */
519 Status
= LdrCOFFProcessDriver(FileHandle
);
520 if (!NT_SUCCESS(Status
))
527 return STATUS_NOT_IMPLEMENTED
;
531 LdrProcessMZImage(HANDLE ProcessHandle
,
533 PIMAGE_DOS_HEADER DosHeader
)
536 /* FIXME: map VDM into low memory */
537 /* FIXME: Build/Load image sections */
539 return STATUS_NOT_IMPLEMENTED
;
543 LdrProcessPEImage(HANDLE ProcessHandle
,
545 PIMAGE_DOS_HEADER DosHeader
)
547 // PIMAGE_NT_HEADERS PEHeader;
548 // PIMAGE_SECTION_HEADER Sections;
550 // FIXME: Check architechture
551 // FIXME: Build/Load image sections
552 // FIXME: do relocations code sections
553 // FIXME: resolve imports
556 return STATUS_NOT_IMPLEMENTED
;
560 * FUNCTION: Loads a PE executable into the specified process
562 * Filename = File to load
563 * ProcessHandle = handle
568 LdrLoadImage(PUNICODE_STRING Filename
, HANDLE ProcessHandle
)
570 char BlockBuffer
[512];
575 OBJECT_ATTRIBUTES FileObjectAttributes
;
576 PIMAGE_DOS_HEADER PEDosHeader
;
578 HANDLE SectionHandle
;
581 /* FIXME: should DLLs be named sections? */
583 /* Open the image file */
584 InitializeObjectAttributes(&FileObjectAttributes
,
589 Status
= ZwOpenFile(&FileHandle
, 0, &FileObjectAttributes
, NULL
, 0, 0);
590 if (!NT_SUCCESS(Status
))
595 /* Read first block of image to determine type */
596 Status
= ZwReadFile(FileHandle
, 0, 0, 0, 0, BlockBuffer
, 512, 0, 0);
597 if (!NT_SUCCESS(Status
))
603 /* If MZ header exists */
604 PEDosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
605 if (PEDosHeader
->e_magic
== 0x54AD && PEDosHeader
->e_lfanew
!= 0L)
607 Status
= LdrProcessPEImage(ProcessHandle
,
610 if (!NT_SUCCESS(Status
))
615 else if (PEDosHeader
->e_magic
== 0x54AD)
617 Status
= LdrProcessMZImage(ProcessHandle
,
620 if (!NT_SUCCESS(Status
))
625 else /* Assume bin format and load */
627 FILE_STANDARD_INFORMATION FileStdInfo
;
629 /* Get the size of the file for the section */
630 Status
= ZwQueryInformationFile(FileHandle
,
634 FileStandardInformation
);
635 if (!NT_SUCCESS(Status
))
641 /* Create the section for the code */
642 Status
= ZwCreateSection(&SectionHandle
,
650 if (!NT_SUCCESS(Status
))
655 /* Map a view of the section into the desired process */
656 BaseAddress
= (PVOID
)0x10000;
657 SectionSize
= GET_LARGE_INTEGER_LOW_PART(FileStdInfo
.AllocationSize
);
658 Status
= ZwMapViewOfSection(SectionHandle
,
668 if (!NT_SUCCESS(Status
))
670 /* FIXME: destroy the section here */
675 /* Setup the context for the initial thread */
676 memset(&Context
,0,sizeof(CONTEXT
));
677 Context
.SegSs
= USER_DS
;
678 Context
.Esp
= 0x2000;
679 Context
.EFlags
= 0x202;
680 Context
.SegCs
= USER_CS
;
681 Context
.Eip
= 0x10000;
682 Context
.SegDs
= USER_DS
;
683 Context
.SegEs
= USER_DS
;
684 Context
.SegFs
= USER_DS
;
685 Context
.SegGs
= USER_DS
;
687 /* Create the stack for the process */
688 BaseAddress
= (PVOID
) 0x1000;
689 SectionSize
= 0x1000;
690 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
696 if (!NT_SUCCESS(Status
))
698 /* FIXME: unmap the section here */
699 /* FIXME: destroy the section here */
704 /* Create the initial thread */
705 Status
= ZwCreateThread(&ThreadHandle
,
713 if (!NT_SUCCESS(Status
))
715 /* FIXME: destroy the stack memory block here */
716 /* FIXME: unmap the section here */
717 /* FIXME: destroy the section here */
722 /* FIXME: {else} could check for a.out, ELF, COFF, etc. images here... */