Fixed LARGE_INTEGER handling
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
1 /*
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)
8 * UPDATE HISTORY:
9 * DW 22/05/98 Created
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 initial PE user module loader
14 * RJJ 06/03/99 Moved user PE loader into NTDLL
15 */
16
17 /* INCLUDES *****************************************************************/
18
19 #include <windows.h>
20
21 #include <internal/i386/segment.h>
22 #include <internal/linkage.h>
23 #include <internal/module.h>
24 #include <internal/ntoskrnl.h>
25 #include <internal/ob.h>
26 #include <internal/ps.h>
27 #include <string.h>
28 #include <internal/string.h>
29 #include <internal/symbol.h>
30
31 #include <ddk/ntddk.h>
32
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 /* FIXME: this should appear in a kernel header file */
37 NTSTATUS IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry);
38
39 /* MACROS ********************************************************************/
40
41 /* GLOBALS *******************************************************************/
42
43 POBJECT_TYPE ObModuleType = NULL;
44
45 /* FORWARD DECLARATIONS ******************************************************/
46
47 NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename);
48 NTSTATUS LdrProcessDriver(PVOID ModuleLoadBase);
49
50 /* PE Driver load support */
51 static NTSTATUS LdrPEProcessDriver(PVOID ModuleLoadBase);
52 static unsigned int LdrGetKernelSymbolAddr(char *Name);
53
54 /* COFF Driver load support */
55 static NTSTATUS LdrCOFFProcessDriver(PVOID ModuleLoadBase);
56 static BOOLEAN LdrCOFFDoRelocations(module *Module, unsigned int SectionIndex);
57 static BOOLEAN LdrCOFFDoAddr32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation);
58 static BOOLEAN LdrCOFFDoReloc32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation);
59 static void LdrCOFFGetSymbolName(module *Module, unsigned int Idx, char *Name);
60 static unsigned int LdrCOFFGetSymbolValue(module *Module, unsigned int Idx);
61 static unsigned int LdrCOFFGetSymbolValueByName(module *Module, char *SymbolName, unsigned int Idx);
62
63 /* FUNCTIONS *****************************************************************/
64
65 VOID LdrInitModuleManagement(VOID)
66 {
67 ANSI_STRING AnsiString;
68
69 /* Register the process object type */
70 ObModuleType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
71 ObModuleType->TotalObjects = 0;
72 ObModuleType->TotalHandles = 0;
73 ObModuleType->MaxObjects = ULONG_MAX;
74 ObModuleType->MaxHandles = ULONG_MAX;
75 ObModuleType->PagedPoolCharge = 0;
76 ObModuleType->NonpagedPoolCharge = sizeof(MODULE);
77 ObModuleType->Dump = NULL;
78 ObModuleType->Open = NULL;
79 ObModuleType->Close = NULL;
80 ObModuleType->Delete = NULL;
81 ObModuleType->Parse = NULL;
82 ObModuleType->Security = NULL;
83 ObModuleType->QueryName = NULL;
84 ObModuleType->OkayToClose = NULL;
85 RtlInitAnsiString(&AnsiString, "Module");
86 RtlAnsiStringToUnicodeString(&ObModuleType->TypeName, &AnsiString, TRUE);
87 }
88
89 /*
90 * load the auto config drivers.
91 */
92 VOID LdrLoadAutoConfigDrivers(VOID)
93 {
94 NTSTATUS Status;
95 ANSI_STRING AnsiDriverName;
96 UNICODE_STRING DriverName;
97
98 RtlInitAnsiString(&AnsiDriverName,"\\??\\C:\\reactos\\system\\drivers\\keyboard.sys");
99 RtlAnsiStringToUnicodeString(&DriverName, &AnsiDriverName, TRUE);
100 Status = LdrLoadDriver(&DriverName);
101 RtlFreeUnicodeString(&DriverName);
102 if (!NT_SUCCESS(Status))
103 {
104 DbgPrint("driver load failed, status;%d(%x)\n", Status, Status);
105 DbgPrintErrorMessage(Status);
106 }
107 RtlInitAnsiString(&AnsiDriverName,"\\??\\C:\\reactos\\system\\drivers\\blue.sys");
108 RtlAnsiStringToUnicodeString(&DriverName, &AnsiDriverName, TRUE);
109 Status = LdrLoadDriver(&DriverName);
110 RtlFreeUnicodeString(&DriverName);
111 if (!NT_SUCCESS(Status))
112 {
113 DbgPrint("driver load failed, status;%d(%x)\n", Status, Status);
114 DbgPrintErrorMessage(Status);
115 }
116
117 }
118
119 /*
120 * FUNCTION: Loads a kernel driver
121 * ARGUMENTS:
122 * FileName = Driver to load
123 * RETURNS: Status
124 */
125
126 NTSTATUS
127 LdrLoadDriver(PUNICODE_STRING Filename)
128 {
129 PVOID ModuleLoadBase;
130 NTSTATUS Status;
131 HANDLE FileHandle;
132 OBJECT_ATTRIBUTES FileObjectAttributes;
133 FILE_STANDARD_INFORMATION FileStdInfo;
134
135 DbgPrint("Loading Driver %W...\n", Filename);
136
137 /* Open the Driver */
138 InitializeObjectAttributes(&FileObjectAttributes,
139 Filename,
140 0,
141 NULL,
142 NULL);
143 CHECKPOINT;
144 Status = ZwOpenFile(&FileHandle,
145 FILE_ALL_ACCESS,
146 &FileObjectAttributes,
147 NULL, 0, 0);
148 CHECKPOINT;
149 if (!NT_SUCCESS(Status))
150 {
151 return Status;
152 }
153 CHECKPOINT;
154
155 /* Get the size of the file */
156 Status = ZwQueryInformationFile(FileHandle,
157 NULL,
158 &FileStdInfo,
159 sizeof(FileStdInfo),
160 FileStandardInformation);
161 if (!NT_SUCCESS(Status))
162 {
163 return Status;
164 }
165 CHECKPOINT;
166
167 /* Allocate nonpageable memory for driver */
168 ModuleLoadBase = ExAllocatePool(NonPagedPool,
169 FileStdInfo.EndOfFile.LowPart);
170 if (ModuleLoadBase == NULL)
171 {
172 return STATUS_INSUFFICIENT_RESOURCES;
173 }
174 CHECKPOINT;
175
176 /* Load driver into memory chunk */
177 Status = ZwReadFile(FileHandle,
178 0, 0, 0, 0,
179 ModuleLoadBase,
180 FileStdInfo.EndOfFile.LowPart,
181 0, 0);
182 if (!NT_SUCCESS(Status))
183 {
184 ExFreePool(ModuleLoadBase);
185 return Status;
186 }
187 CHECKPOINT;
188
189 ZwClose(FileHandle);
190
191 Status = LdrProcessDriver(ModuleLoadBase);
192
193 /* Cleanup */
194 ExFreePool(ModuleLoadBase);
195
196 return STATUS_SUCCESS;
197 }
198
199 NTSTATUS
200 LdrProcessDriver(PVOID ModuleLoadBase)
201 {
202 PIMAGE_DOS_HEADER PEDosHeader;
203
204 /* If MZ header exists */
205 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
206 if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
207 {
208 return LdrPEProcessDriver(ModuleLoadBase);
209 }
210 if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC)
211 {
212 return STATUS_NOT_IMPLEMENTED;
213 }
214 else /* Assume COFF format and load */
215 {
216 return LdrCOFFProcessDriver(ModuleLoadBase);
217 }
218 }
219
220 NTSTATUS
221 LdrPEProcessDriver(PVOID ModuleLoadBase)
222 {
223 unsigned int DriverSize, Idx;
224 ULONG RelocDelta, NumRelocs;
225 DWORD CurrentSize, TotalRelocs;
226 PVOID DriverBase, CurrentBase, EntryPoint;
227 PULONG PEMagic;
228 PIMAGE_DOS_HEADER PEDosHeader;
229 PIMAGE_FILE_HEADER PEFileHeader;
230 PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
231 PIMAGE_SECTION_HEADER PESectionHeaders;
232 PRELOCATION_DIRECTORY RelocDir;
233 PRELOCATION_ENTRY RelocEntry;
234 PMODULE Library;
235 PVOID *ImportAddressList;
236 PULONG FunctionNameList;
237 PCHAR pName, SymbolNameBuf;
238 PWORD pHint;
239
240 /* FIXME: this could be used to load kernel DLLs also, however */
241 /* the image headers should be preserved in such a case */
242
243 DPRINT("Processing PE Driver at module base:%08lx\n", ModuleLoadBase);
244
245 /* Get header pointers */
246 PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
247 PEMagic = (PULONG) ((unsigned int) ModuleLoadBase +
248 PEDosHeader->e_lfanew);
249 PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase +
250 PEDosHeader->e_lfanew + sizeof(ULONG));
251 PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase +
252 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
253 PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase +
254 PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
255 sizeof(IMAGE_OPTIONAL_HEADER));
256 CHECKPOINT;
257
258 /* Check file magic numbers */
259 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
260 {
261 DPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
262 return STATUS_UNSUCCESSFUL;
263 }
264 if (PEDosHeader->e_lfanew == 0)
265 {
266 DPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
267 return STATUS_UNSUCCESSFUL;
268 }
269 if (*PEMagic != IMAGE_PE_MAGIC)
270 {
271 DPRINT("Incorrect PE magic: %08x\n", *PEMagic);
272 return STATUS_UNSUCCESSFUL;
273 }
274 if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
275 {
276 DPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
277 return STATUS_UNSUCCESSFUL;
278 }
279 CHECKPOINT;
280
281 /* FIXME: if image is fixed-address load, then fail */
282
283 /* FIXME: check/verify OS version number */
284
285 DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n",
286 PEOptionalHeader->Magic,
287 PEOptionalHeader->MajorLinkerVersion,
288 PEOptionalHeader->MinorLinkerVersion);
289 DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
290 CHECKPOINT;
291
292 /* Determine the size of the module */
293
294 DriverSize = PEOptionalHeader->SizeOfImage;
295 DPRINT("DriverSize %x\n",DriverSize);
296
297 /* Allocate a virtual section for the module */
298 DriverBase = MmAllocateSection(DriverSize);
299 if (DriverBase == 0)
300 {
301 DbgPrint("Failed to allocate a virtual section for driver\n");
302 return STATUS_INSUFFICIENT_RESOURCES;
303 }
304 CHECKPOINT;
305 DbgPrint("Module is at base %x\n",DriverBase);
306
307 /* Copy image sections into virtual section */
308 memcpy(DriverBase, ModuleLoadBase, PESectionHeaders[0].PointerToRawData);
309 CurrentBase = (PVOID) ((DWORD)DriverBase + PESectionHeaders[0].PointerToRawData);
310 CurrentSize = 0;
311 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
312 {
313 /* Copy current section into current offset of virtual section */
314 if (PESectionHeaders[Idx].Characteristics &
315 (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
316 {
317 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
318 PESectionHeaders[Idx].VirtualAddress + DriverBase);
319 memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
320 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
321 PESectionHeaders[Idx].SizeOfRawData);
322 }
323 else
324 {
325 DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
326 PESectionHeaders[Idx].VirtualAddress + DriverBase);
327 memset(PESectionHeaders[Idx].VirtualAddress + DriverBase,
328 '\0', PESectionHeaders[Idx].SizeOfRawData);
329 }
330 CurrentSize += ROUND_UP(PESectionHeaders[Idx].SizeOfRawData,
331 PEOptionalHeader->SectionAlignment);
332 CurrentBase = (PVOID)((DWORD)CurrentBase +
333 ROUND_UP(PESectionHeaders[Idx].SizeOfRawData,
334 PEOptionalHeader->SectionAlignment));
335 }
336
337 /* Perform relocation fixups */
338 RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
339 RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
340 IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
341 DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n",
342 DriverBase,
343 PEOptionalHeader->ImageBase,
344 RelocDelta);
345 DPRINT("RelocDir %x\n",RelocDir);
346 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
347 {
348 if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
349 {
350 DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
351 PESectionHeaders[Idx].Name,
352 PESectionHeaders[Idx].PointerToRawData);
353 RelocDir = PESectionHeaders[Idx].PointerToRawData +
354 ModuleLoadBase;
355 CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
356 break;
357 }
358 }
359 DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
360 TotalRelocs = 0;
361 while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
362 {
363 NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
364 sizeof(WORD);
365 /* DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
366 RelocDir,
367 RelocDir->VirtualAddress,
368 NumRelocs);*/
369 RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir +
370 sizeof(RELOCATION_DIRECTORY));
371 for (Idx = 0; Idx < NumRelocs; Idx++)
372 {
373 ULONG Offset;
374 ULONG Type;
375 PDWORD RelocItem;
376
377 Offset = RelocEntry[Idx].TypeOffset & 0xfff;
378 Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
379 RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress +
380 Offset);
381 /* DPRINT(" reloc at %08lx %x %s old:%08lx new:%08lx\n",
382 RelocItem,
383 Type,
384 Type ? "HIGHLOW" : "ABS",
385 *RelocItem,
386 (*RelocItem) + RelocDelta); */
387 if (Type == 3)
388 {
389 (*RelocItem) += RelocDelta;
390 }
391 else if (Type != 0)
392 {
393 DPRINT("Unknown relocation type %x\n",Type);
394 return STATUS_UNSUCCESSFUL;
395 }
396 }
397 TotalRelocs += RelocDir->SizeOfBlock;
398 RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir +
399 RelocDir->SizeOfBlock);
400 // DPRINT("TotalRelocs: %08lx CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
401 }
402
403 DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
404 PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
405 .VirtualAddress);
406 /* Perform import fixups */
407 if (PEOptionalHeader->DataDirectory[
408 IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
409 {
410 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
411
412 SymbolNameBuf = ExAllocatePool(NonPagedPool, 512);
413
414 /* Process each import module */
415 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
416 ((DWORD)DriverBase + PEOptionalHeader->
417 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
418 while (ImportModuleDirectory->dwRVAModuleName)
419 {
420 /* FIXME: handle kernel mode DLLs */
421
422 /* Check to make sure that import lib is kernel */
423 Library = NULL;
424 pName = (PCHAR) DriverBase +
425 ImportModuleDirectory->dwRVAModuleName;
426 // DPRINT("Import module: %s\n", pName);
427 if (strcmp(pName, "ntoskrnl.exe")!=0 &&
428 strcmp(pName, "HAL.dll")!=0)
429 {
430 DPRINT("Kernel mode DLLs are currently unsupported\n");
431 }
432
433 /* Get the import address list */
434 ImportAddressList = (PVOID *) ((DWORD)DriverBase +
435 ImportModuleDirectory->dwRVAFunctionAddressList);
436
437 /* Get the list of functions to import */
438 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
439 {
440 FunctionNameList = (PULONG) ((DWORD)DriverBase +
441 ImportModuleDirectory->dwRVAFunctionNameList);
442 }
443 else
444 {
445 FunctionNameList = (PULONG) ((DWORD)DriverBase +
446 ImportModuleDirectory->dwRVAFunctionAddressList);
447 }
448
449 /* Walk through function list and fixup addresses */
450 while(*FunctionNameList != 0L)
451 {
452 if ((*FunctionNameList) & 0x80000000) // hint
453 {
454 // DPRINT(" Hint: %08lx\n", *FunctionNameList);
455 if (Library == NULL)
456 {
457 DPRINT("Hints for kernel symbols are not handled.\n");
458 *ImportAddressList = 0;
459 }
460 }
461 else // hint-name
462 {
463 pName = (PCHAR)((DWORD)DriverBase+
464 *FunctionNameList + 2);
465 pHint = (PWORD)((DWORD)DriverBase + *FunctionNameList);
466 // DPRINT(" Hint:%04x Name:%s\n", pHint, pName);
467
468 /* Get address for symbol */
469 if (Library == NULL)
470 {
471 *SymbolNameBuf = '_';
472 strcpy(SymbolNameBuf + 1, pName);
473 *ImportAddressList = (PVOID) LdrGetKernelSymbolAddr(SymbolNameBuf); if (*ImportAddressList == 0L)
474 {
475 DPRINT("Unresolved kernel symbol: %s\n", pName);
476 }
477 }
478 }
479 ImportAddressList++;
480 FunctionNameList++;
481 }
482 ImportModuleDirectory++;
483 }
484
485 ExFreePool(SymbolNameBuf);
486 }
487
488 /* Compute address of entry point */
489 EntryPoint = (PVOID) ((DWORD)DriverBase + PEOptionalHeader->AddressOfEntryPoint);
490 DbgPrint("Calling entrypoint at %x\n",EntryPoint);
491
492 return IoInitializeDriver(EntryPoint);
493 }
494
495 NTSTATUS
496 LdrCOFFProcessDriver(PVOID ModuleLoadBase)
497 {
498 BOOLEAN FoundEntry;
499 char SymbolName[255];
500 int i;
501 ULONG EntryOffset;
502 FILHDR *FileHeader;
503 AOUTHDR *AOUTHeader;
504 module *Module;
505 PDRIVER_INITIALIZE EntryRoutine;
506
507 /* Get header pointers */
508 FileHeader = ModuleLoadBase;
509 AOUTHeader = ModuleLoadBase + FILHSZ;
510 CHECKPOINT;
511
512 /* Check COFF magic value */
513 if (I386BADMAG(*FileHeader))
514 {
515 DbgPrint("Module has bad magic value (%x)\n",
516 FileHeader->f_magic);
517 return STATUS_UNSUCCESSFUL;
518 }
519 CHECKPOINT;
520
521 /* Allocate and initialize a module definition structure */
522 Module = (module *) ExAllocatePool(NonPagedPool, sizeof(module));
523 if (Module == NULL)
524 {
525 return STATUS_INSUFFICIENT_RESOURCES;
526 }
527 Module->sym_list = (SYMENT *)(ModuleLoadBase + FileHeader->f_symptr);
528 Module->str_tab = (char *)(ModuleLoadBase + FileHeader->f_symptr +
529 FileHeader->f_nsyms * SYMESZ);
530 Module->scn_list = (SCNHDR *)(ModuleLoadBase + FILHSZ +
531 FileHeader->f_opthdr);
532 Module->size = 0;
533 Module->raw_data_off = (ULONG) ModuleLoadBase;
534 Module->nsyms = FileHeader->f_nsyms;
535 CHECKPOINT;
536
537 /* Determine the length of the module */
538 for (i = 0; i < FileHeader->f_nscns; i++)
539 {
540 DPRINT("Section name: %.8s\n", Module->scn_list[i].s_name);
541 DPRINT("size %x vaddr %x size %x\n",
542 Module->size,
543 Module->scn_list[i].s_vaddr,
544 Module->scn_list[i].s_size);
545 if (Module->scn_list[i].s_flags & STYP_TEXT)
546 {
547 Module->text_base = Module->scn_list[i].s_vaddr;
548 }
549 if (Module->scn_list[i].s_flags & STYP_DATA)
550 {
551 Module->data_base = Module->scn_list[i].s_vaddr;
552 }
553 if (Module->scn_list[i].s_flags & STYP_BSS)
554 {
555 Module->bss_base = Module->scn_list[i].s_vaddr;
556 }
557 if (Module->size <
558 (Module->scn_list[i].s_vaddr + Module->scn_list[i].s_size))
559 {
560 Module->size = Module->size + Module->scn_list[i].s_vaddr +
561 Module->scn_list[i].s_size;
562 }
563 }
564 CHECKPOINT;
565
566 /* Allocate a section for the module */
567 Module->base = (unsigned int) MmAllocateSection(Module->size);
568 if (Module->base == 0)
569 {
570 DbgPrint("Failed to alloc section for module\n");
571 ExFreePool(Module);
572 return STATUS_INSUFFICIENT_RESOURCES;
573 }
574 CHECKPOINT;
575
576 /* Adjust section vaddrs for allocated area */
577 Module->data_base = Module->data_base + Module->base;
578 Module->text_base = Module->text_base + Module->base;
579 Module->bss_base = Module->bss_base + Module->base;
580
581 /* Relocate module and fixup imports */
582 for (i = 0; i < FileHeader->f_nscns; i++)
583 {
584 if (Module->scn_list[i].s_flags & STYP_TEXT ||
585 Module->scn_list[i].s_flags & STYP_DATA)
586 {
587 memcpy((PVOID)(Module->base + Module->scn_list[i].s_vaddr),
588 (PVOID)(ModuleLoadBase + Module->scn_list[i].s_scnptr),
589 Module->scn_list[i].s_size);
590 if (!LdrCOFFDoRelocations(Module, i))
591 {
592 DPRINT("Relocation failed for section %s\n",
593 Module->scn_list[i].s_name);
594
595 /* FIXME: unallocate all sections here */
596
597 ExFreePool(Module);
598
599 return STATUS_UNSUCCESSFUL;
600 }
601 }
602 if (Module->scn_list[i].s_flags & STYP_BSS)
603 {
604 memset((PVOID)(Module->base + Module->scn_list[i].s_vaddr),
605 0,
606 Module->scn_list[i].s_size);
607 }
608 }
609
610 DbgPrint("Module base: %x\n", Module->base);
611
612 /* Find the entry point */
613 EntryOffset = 0L;
614 FoundEntry = FALSE;
615 for (i = 0; i < FileHeader->f_nsyms; i++)
616 {
617 LdrCOFFGetSymbolName(Module, i, SymbolName);
618 if (!strcmp(SymbolName, "_DriverEntry"))
619 {
620 EntryOffset = Module->sym_list[i].e_value;
621 FoundEntry = TRUE;
622 DPRINT("Found entry at %x\n", EntryOffset);
623 }
624 }
625 if (!FoundEntry)
626 {
627 DbgPrint("No module entry point defined\n");
628 ExFreePool(Module);
629
630 /* FIXME: unallocate all sections here */
631
632 return STATUS_UNSUCCESSFUL;
633 }
634
635 /* Get the address of the module initalization routine */
636 EntryRoutine = (PDRIVER_INITIALIZE)(Module->base + EntryOffset);
637
638 /* Cleanup */
639 ExFreePool(Module);
640
641 return IoInitializeDriver(EntryRoutine);
642 }
643
644 /* LdrCOFFDoRelocations
645 * FUNCTION: Do the relocations for a module section
646 * ARGUMENTS:
647 * Module = Pointer to the module
648 * SectionIndex = Index of the section to be relocated
649 * RETURNS: Success or failure
650 */
651
652 static BOOLEAN
653 LdrCOFFDoRelocations(module *Module, unsigned int SectionIndex)
654 {
655 SCNHDR *Section = &Module->scn_list[SectionIndex];
656 RELOC *Relocation = (RELOC *)(Module->raw_data_off + Section->s_relptr);
657 int j;
658
659 DPRINT("SectionIndex %d Name %.8s Relocs %d\n",
660 SectionIndex,
661 Module->scn_list[SectionIndex].s_name,
662 Section->s_nreloc);
663
664 for (j = 0; j < Section->s_nreloc; j++)
665 {
666 DPRINT("vaddr %x symndex %x",
667 Relocation->r_vaddr,
668 Relocation->r_symndx);
669
670 switch (Relocation->r_type)
671 {
672 case RELOC_ADDR32:
673 if (!LdrCOFFDoAddr32Reloc(Module, Section, Relocation))
674 {
675 return FALSE;
676 }
677 break;
678
679 case RELOC_REL32:
680 if (!LdrCOFFDoReloc32Reloc(Module, Section, Relocation))
681 {
682 return FALSE;
683 }
684 break;
685
686 default:
687 DPRINT("%.8s: Unknown relocation type %x at %d in module\n",
688 Module->scn_list[SectionIndex].s_name,
689 Relocation->r_type,
690 j);
691 return FALSE;
692 }
693 Relocation++;
694 }
695 DPRINT("%.8s: relocations done\n", Module->scn_list[SectionIndex].s_name);
696
697 return TRUE;
698 }
699
700 /*
701 * FUNCTION: Performs a addr32 relocation on a loaded module
702 * ARGUMENTS:
703 * mod = module to perform the relocation on
704 * scn = Section to perform the relocation in
705 * reloc = Pointer to a data structure describing the relocation
706 * RETURNS: Success or failure
707 * NOTE: This fixes up a relocation needed when changing the base address of a
708 * module
709 */
710
711 static BOOLEAN
712 LdrCOFFDoAddr32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation)
713 {
714 unsigned int Value;
715 unsigned int *Location;
716
717 Value = LdrCOFFGetSymbolValue(Module, Relocation->r_symndx);
718 Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
719 DPRINT("ADDR32 loc %x value %x *loc %x\n", Location, Value, *Location);
720 *Location = (*Location) + Module->base;
721
722 return TRUE;
723 }
724
725 /*
726 * FUNCTION: Performs a reloc32 relocation on a loaded module
727 * ARGUMENTS:
728 * mod = module to perform the relocation on
729 * scn = Section to perform the relocation in
730 * reloc = Pointer to a data structure describing the relocation
731 * RETURNS: Success or failure
732 * NOTE: This fixes up an undefined reference to a kernel function in a module
733 */
734
735 static BOOLEAN
736 LdrCOFFDoReloc32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation)
737 {
738 char Name[255];
739 unsigned int Value;
740 unsigned int *Location;
741
742 memset(Name, 0, 255);
743 LdrCOFFGetSymbolName(Module, Relocation->r_symndx, Name);
744 Value = (unsigned int) LdrGetKernelSymbolAddr(Name);
745 if (Value == 0L)
746 {
747 Value = LdrCOFFGetSymbolValueByName(Module, Name, Relocation->r_symndx);
748 if (Value == 0L)
749 {
750 DbgPrint("Undefined symbol %s in module\n", Name);
751 return FALSE;
752 }
753 Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
754 // (*Location) = (*Location) + Value + Module->base - Section->s_vaddr;
755 (*Location) = (*Location);
756 DPRINT("Module->base %x Section->s_vaddr %x\n",
757 Module->base,
758 Section->s_vaddr);
759 }
760 else
761 {
762 DPRINT("REL32 value %x name %s\n", Value, Name);
763 Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
764 DPRINT("old %x ", *Location);
765 DPRINT("Module->base %x Section->s_vaddr %x\n",
766 Module->base,
767 Section->s_vaddr);
768 (*Location) = (*Location) + Value - Module->base + Section->s_vaddr;
769 DPRINT("new %x\n", *Location);
770 }
771
772 return TRUE;
773 }
774
775 /*
776 * FUNCTION: Get the name of a symbol from a loaded module by ordinal
777 * ARGUMENTS:
778 * mod = module
779 * i = index of symbol
780 * name (OUT) = pointer to a string where the symbol name will be
781 * stored
782 */
783
784 static void
785 LdrCOFFGetSymbolName(module *Module, unsigned int Idx, char *Name)
786 {
787 if (Module->sym_list[Idx].e.e_name[0] != 0)
788 {
789 strncpy(Name, Module->sym_list[Idx].e.e_name, 8);
790 Name[8] = '\0';
791 }
792 else
793 {
794 strcpy(Name, &Module->str_tab[Module->sym_list[Idx].e.e.e_offset]);
795 }
796 }
797
798 /*
799 * FUNCTION: Get the value of a module defined symbol
800 * ARGUMENTS:
801 * mod = module
802 * i = index of symbol
803 * RETURNS: The value of the symbol
804 * NOTE: This fixes up references to known sections
805 */
806
807 static unsigned int
808 LdrCOFFGetSymbolValue(module *Module, unsigned int Idx)
809 {
810 char Name[255];
811
812 LdrCOFFGetSymbolName(Module, Idx, Name);
813 DPRINT("name %s ", Name);
814
815 /* Check if the symbol is a section we have relocated */
816 if (strcmp(Name, ".text") == 0)
817 {
818 return Module->text_base;
819 }
820 if (strcmp(Name, ".data") == 0)
821 {
822 return Module->data_base;
823 }
824 if (strcmp(Name, ".bss") == 0)
825 {
826 return Module->bss_base;
827 }
828
829 return Module->sym_list[Idx].e_value;
830 }
831
832 /*
833 * FUNCTION: Get the address of a kernel symbol
834 * ARGUMENTS:
835 * name = symbol name
836 * RETURNS: The address of the symbol on success
837 * NULL on failure
838 */
839
840 static unsigned int
841 LdrGetKernelSymbolAddr(char *Name)
842 {
843 int i = 0;
844 char* s;
845
846 if ((s=strchr(Name,'@'))!=NULL)
847 {
848 *s=0;
849 DbgPrint("Name %s ",Name);
850 }
851 while (symbol_table[i].name != NULL)
852 {
853 if (strcmp(symbol_table[i].name, Name) == 0)
854 {
855 if (s!=NULL)
856 {
857 *s=0;
858 DbgPrint("Matched with %s\n",symbol_table[i].name);
859 }
860 return symbol_table[i].value;
861 }
862 i++;
863 }
864 if (s!=NULL)
865 {
866 *s=0;
867 }
868 return 0L;
869 }
870
871 static unsigned int
872 LdrCOFFGetSymbolValueByName(module *Module,
873 char *SymbolName,
874 unsigned int Idx)
875 {
876 unsigned int i;
877 char Name[255];
878
879 DPRINT("LdrCOFFGetSymbolValueByName(sname %s, idx %x)\n", SymbolName, Idx);
880
881 for (i = 0; i < Module->nsyms; i++)
882 {
883 LdrCOFFGetSymbolName(Module, i, Name);
884 DPRINT("Scanning %s Value %x\n", Name, Module->sym_list[i].e_value);
885 if (strcmp(Name, SymbolName) == 0)
886 {
887 DPRINT("Returning %x\n", Module->sym_list[i].e_value);
888 return Module->sym_list[i].e_value;
889 }
890 }
891
892 return 0L;
893 }
894