Compilation bug fixed (due to having used an "unknown" field in the
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
index 24aa603..085f831 100644 (file)
-/*
+/* $Id: loader.c,v 1.74 2001/04/23 22:00:28 ea Exp $
+ * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ldr/loader.c
  * PURPOSE:         Loaders for PE executables
  * PROGRAMMERS:     Jean Michault
  *                  Rex Jolliff (rex@lvcablemodem.com)
+ *                  Jason Filby (jasonfilby@yahoo.com)
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
  * UPDATE HISTORY:
- *   DW   22/05/98  Created
- *   RJJ  10/12/98  Completed image loader function and added hooks for MZ/PE
- *   RJJ  10/12/98  Built driver loader function and added hooks for PE/COFF
- *   RJJ  10/12/98  Rolled in David's code to load COFF drivers
- *   JM   14/12/98  Built initail PE user module loader
+ *   DW   22/05/98   Created
+ *   RJJ  10/12/98   Completed image loader function and added hooks for MZ/PE
+ *   RJJ  10/12/98   Built driver loader function and added hooks for PE/COFF
+ *   RJJ  10/12/98   Rolled in David's code to load COFF drivers
+ *   JM   14/12/98   Built initial PE user module loader
+ *   RJJ  06/03/99   Moved user PE loader into NTDLL
+ *   JF   26/01/2000 Recoded some parts to retrieve export details correctly
+ *   DW   27/06/2000 Removed redundant header files
+ *   CSH  11/04/2001 Added automatic loading of module symbols if they exist
  */
 
+
 /* INCLUDES *****************************************************************/
 
-#include <internal/i386/segment.h>
-#include <internal/kernel.h>
-#include <internal/linkage.h>
+#include <limits.h>
+#include <ddk/ntddk.h>
+#include <internal/config.h>
 #include <internal/module.h>
+#include <internal/ntoskrnl.h>
+#include <internal/mm.h>
 #include <internal/ob.h>
-#include <internal/string.h>
-#include <internal/symbol.h>
-
-#include <ddk/ntddk.h>
+#include <internal/ps.h>
+#include <internal/ldr.h>
+#include <internal/pool.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
+
+/* FIXME: this should appear in a kernel header file  */
+NTSTATUS IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry);
+
 /* MACROS ********************************************************************/
 
+#define  MODULE_ROOT_NAME  L"\\Modules\\"
+
 /* GLOBALS *******************************************************************/
 
-POBJECT_TYPE ObModuleType = NULL;
+LIST_ENTRY ModuleListHead;
+POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
+LIST_ENTRY ModuleTextListHead;
+STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
+/* STATIC MODULE_TEXT_SECTION HalTextSection; */
+
+#define TAG_DRIVER_MEM  TAG('D', 'R', 'V', 'M')
+#define TAG_SYM_BUF     TAG('S', 'Y', 'M', 'B')
 
 /* FORWARD DECLARATIONS ******************************************************/
 
-NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename);
-NTSTATUS LdrProcessDriver(PVOID ModuleLoadBase);
+PMODULE_OBJECT  LdrLoadModule(PUNICODE_STRING Filename);
+PMODULE_OBJECT  LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName);
+PVOID  LdrGetExportAddress(PMODULE_OBJECT ModuleObject, char *Name, unsigned short Hint);
+static PMODULE_OBJECT LdrOpenModule(PUNICODE_STRING  Filename);
+static NTSTATUS LdrCreateModule(PVOID ObjectBody,
+                                PVOID Parent,
+                                PWSTR RemainingPath,
+                                POBJECT_ATTRIBUTES ObjectAttributes);
+static VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
+                                   PUNICODE_STRING FullName);
 
 /*  PE Driver load support  */
-static NTSTATUS LdrPEProcessDriver(PVOID ModuleLoadBase);
-static unsigned int LdrGetKernelSymbolAddr(char *Name);
-
-/*  COFF Driver load support  */
-static NTSTATUS LdrCOFFProcessDriver(PVOID ModuleLoadBase);
-static BOOLEAN LdrCOFFDoRelocations(module *Module, unsigned int SectionIndex);
-static BOOLEAN LdrCOFFDoAddr32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation);
-static BOOLEAN LdrCOFFDoReloc32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation);
-static void LdrCOFFGetSymbolName(module *Module, unsigned int Idx, char *Name);
-static unsigned int LdrCOFFGetSymbolValue(module *Module, unsigned int Idx);
-static unsigned int LdrCOFFGetSymbolValueByName(module *Module, char *SymbolName, unsigned int Idx);
-
-/*  Image loader forward delcarations  */
-static NTSTATUS LdrProcessMZImage(HANDLE ProcessHandle, HANDLE ModuleHandle, HANDLE FileHandle);
-static NTSTATUS LdrProcessPEImage(HANDLE ProcessHandle, HANDLE ModuleHandle, HANDLE FileHandle);
-static NTSTATUS LdrProcessBinImage(HANDLE ProcessHandle, HANDLE ModuleHandle, HANDLE FileHandle);
+static PMODULE_OBJECT  LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName);
+static PVOID  LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
+                                    char *Name,
+                                    unsigned short Hint);
+static PMODULE_OBJECT LdrPEGetModuleObject(PUNICODE_STRING ModuleName);
+static PVOID LdrPEFixupForward(PCHAR ForwardName);
+
 
 /* FUNCTIONS *****************************************************************/
 
+VOID
+LdrInitDebug(PLOADER_MODULE Module, PWCH Name)
+{
+  PLIST_ENTRY current_entry;
+  MODULE_TEXT_SECTION* current;
+
+  current_entry = ModuleTextListHead.Flink;
+  while (current_entry != &ModuleTextListHead)
+    {
+      current = 
+       CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
+      if (wcscmp(current->Name, Name) == 0)
+       {
+         break;
+       }
+      current_entry = current_entry->Flink;
+    }
+
+  if (current_entry == &ModuleTextListHead)
+    {
+      return;
+    }
+  
+  current->SymbolsBase = (PVOID)Module->ModStart;
+  current->SymbolsLength = Module->ModEnd - Module->ModStart;
+}
+
+VOID
+LdrInit1(VOID)
+{
+  PIMAGE_DOS_HEADER DosHeader;
+  PIMAGE_FILE_HEADER FileHeader;
+  PIMAGE_OPTIONAL_HEADER OptionalHeader;
+  PIMAGE_SECTION_HEADER SectionList;
+
+  InitializeListHead(&ModuleTextListHead);
+
+  DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
+  FileHeader =
+    (PIMAGE_FILE_HEADER) ((DWORD)KERNEL_BASE + 
+                         DosHeader->e_lfanew + sizeof(ULONG));
+  OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
+    ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
+  SectionList = (PIMAGE_SECTION_HEADER)
+    ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
+  NtoskrnlTextSection.Base = KERNEL_BASE;
+  NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
+    SectionList[0].VirtualAddress;
+  NtoskrnlTextSection.Name = L"ntoskrnl.exe";
+  NtoskrnlTextSection.SymbolsBase = NULL;
+  NtoskrnlTextSection.SymbolsLength = 0;
+  InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
+}
+
 VOID LdrInitModuleManagement(VOID)
 {
-  ANSI_STRING AnsiString;
+  HANDLE DirHandle, ModuleHandle;
+  NTSTATUS Status;
+  WCHAR NameBuffer[60];
+  UNICODE_STRING ModuleName;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  PIMAGE_DOS_HEADER DosHeader;
+  PMODULE_OBJECT ModuleObject;
+
+  /*  Register the process object type  */
+  IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
+  IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'T');
+  IoDriverObjectType->TotalObjects = 0;
+  IoDriverObjectType->TotalHandles = 0;
+  IoDriverObjectType->MaxObjects = ULONG_MAX;
+  IoDriverObjectType->MaxHandles = ULONG_MAX;
+  IoDriverObjectType->PagedPoolCharge = 0;
+  IoDriverObjectType->NonpagedPoolCharge = sizeof(MODULE);
+  IoDriverObjectType->Dump = NULL;
+  IoDriverObjectType->Open = NULL;
+  IoDriverObjectType->Close = NULL;
+  IoDriverObjectType->Delete = NULL;
+  IoDriverObjectType->Parse = NULL;
+  IoDriverObjectType->Security = NULL;
+  IoDriverObjectType->QueryName = NULL;
+  IoDriverObjectType->OkayToClose = NULL;
+  IoDriverObjectType->Create = LdrCreateModule;
+  RtlInitUnicodeString(&IoDriverObjectType->TypeName, L"Driver");
+
+  /*  Create Modules object directory  */
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  *(wcsrchr(NameBuffer, L'\\')) = 0;
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+  DPRINT("Create dir: %wZ\n", &ModuleName);
+  Status = NtCreateDirectoryObject(&DirHandle, 0, &ObjectAttributes);
+  assert(NT_SUCCESS(Status));
+
+  /*  Add module entry for NTOSKRNL  */
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  wcscat(NameBuffer, L"ntoskrnl.exe");
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  DPRINT("Kernel's Module name is: %wZ\n", &ModuleName);
+
+  /*  Initialize ObjectAttributes for ModuleObject  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+
+  /*  Create module object  */
+  ModuleHandle = 0;
+  ModuleObject = ObCreateObject(&ModuleHandle,
+                                STANDARD_RIGHTS_REQUIRED,
+                                &ObjectAttributes,
+                                IoDriverObjectType);
+  assert(ModuleObject != NULL);
+
+   InitializeListHead(&ModuleListHead);
+
+   /*  Initialize ModuleObject data  */
+   ModuleObject->Base = (PVOID) KERNEL_BASE;
+   ModuleObject->Flags = MODULE_FLAG_PE;
+   InsertTailList(&ModuleListHead,
+                 &ModuleObject->ListEntry);
+   RtlCreateUnicodeString(&ModuleObject->FullName,
+                         L"ntoskrnl.exe");
+   LdrpBuildModuleBaseName(&ModuleObject->BaseName,
+                          &ModuleObject->FullName);
+
+  DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
+  ModuleObject->Image.PE.FileHeader =
+    (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
+    DosHeader->e_lfanew + sizeof(ULONG));
+  ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
+    ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
+  ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
+    ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
+  ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
+    ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
+  DPRINT("ModuleObject:%08x  entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
+   ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
+
+  /* FIXME: Add fake module entry for HAL */
 
-  /*  Register the process object type  */   
-  ObModuleType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-  ObModuleType->TotalObjects = 0;
-  ObModuleType->TotalHandles = 0;
-  ObModuleType->MaxObjects = ULONG_MAX;
-  ObModuleType->MaxHandles = ULONG_MAX;
-  ObModuleType->PagedPoolCharge = 0;
-  ObModuleType->NonpagedPoolCharge = sizeof(MODULE);
-  ObModuleType->Dump = NULL;
-  ObModuleType->Open = NULL;
-  ObModuleType->Close = NULL;
-  ObModuleType->Delete = NULL;
-  ObModuleType->Parse = NULL;
-  ObModuleType->Security = NULL;
-  ObModuleType->QueryName = NULL;
-  ObModuleType->OkayToClose = NULL;
-  RtlInitAnsiString(&AnsiString, "Module");
-  RtlAnsiStringToUnicodeString(&ObModuleType->TypeName, &AnsiString, TRUE);
 }
 
 /*
  * load the auto config drivers.
  */
-VOID LdrLoadAutoConfigDrivers(VOID)
+static VOID LdrLoadAutoConfigDriver (LPWSTR    RelativeDriverName)
+{
+   WCHAR               TmpFileName [MAX_PATH];
+   NTSTATUS    Status;
+   UNICODE_STRING      DriverName;
+
+   DbgPrint("Loading %S\n",RelativeDriverName);
+
+   wcscpy(TmpFileName, L"\\SystemRoot\\system32\\drivers\\");
+   wcscat(TmpFileName, RelativeDriverName);
+   RtlInitUnicodeString (&DriverName, TmpFileName);
+
+   Status = LdrLoadDriver(&DriverName);
+   if (!NT_SUCCESS(Status))
+     {
+       DbgPrint("driver load failed, status (%x)\n", Status);
+//     KeBugCheck(0);
+     }
+}
+
+#ifdef KDBG
+
+BOOLEAN LdrReadLine(PCHAR Line,
+                    PVOID *Buffer,
+                    PULONG Size)
+{
+  CHAR ch;
+  PCHAR Block;
+
+  if (*Size == 0)
+    return FALSE;
+
+  Block = *Buffer;
+  while ((*Size > 0) && ((ch = *Block) != (CHAR)13))
+    {
+      *Line = ch;
+      Line++;
+      Block++;
+      *Size -= 1;
+    }
+  *Line = (CHAR)0;
+
+  Block++;
+  *Size -= 1;
+
+  if ((*Size > 0) && (*Block == (CHAR)10))
+    {
+      Block++;
+      *Size -= 1;
+    }
+
+  *Buffer = Block;
+
+  return TRUE;
+}
+
+ULONG HexL(PCHAR Buffer)
+{
+  CHAR ch;
+  UINT i, j;
+  ULONG Value;
+
+  j     = 32;
+  i     = 0;
+  Value = 0;
+  while ((j > 0) && ((ch = Buffer[i]) != ' '))
+    {
+      j -= 4;
+      if ((ch >= '0') && (ch <= '9'))
+        Value |= ((ch - '0') << j);
+        if ((ch >= 'A') && (ch <= 'F'))
+          Value |= ((10 + (ch - 'A')) << j);
+        else
+          if ((ch >= 'a') && (ch <= 'f'))
+            Value |= ((10 + (ch - 'a')) << j);
+      i++;
+    }
+  return Value;
+}
+
+PSYMBOL LdrParseLine(PCHAR Line,
+                     PULONG ImageBase,
+                     PBOOLEAN ImageBaseValid)
+/*
+    Line format: [ADDRESS] <TYPE> <NAME>
+    TYPE:
+      U = ?
+      A = Image information
+      t = Symbol in text segment
+      T = Symbol in text segment
+      d = Symbol in data segment
+      D = Symbol in data segment
+      b = Symbol in BSS segment
+      B = Symbol in BSS segment
+      ? = Unknown segment or symbol in unknown segment
+*/
+{
+  ANSI_STRING AnsiString;
+  CHAR Buffer[128];
+  PSYMBOL Symbol;
+  ULONG Address;
+  PCHAR Str;
+  CHAR Type;
+
+  *ImageBaseValid = FALSE;
+
+  if ((Line[0] == (CHAR)0) || (Line[0] == ' '))
+    return NULL;
+
+  Address = HexL(Line);
+
+  Line = strchr(Line, ' ');
+  if (Line == NULL)
+    return NULL;
+
+  Line++;
+  Type = *Line;
+
+  Line = strchr(Line, ' ');
+  if (Line == NULL)
+    return NULL;
+
+  Line++;
+  Str = strchr(Line, ' ');
+  if (Str == NULL)
+    strcpy((char*)&Buffer, Line);
+  else
+    strncpy((char*)&Buffer, Line, Str - Line);
+
+  if ((Type == 'A') && (strcmp((char*)&Buffer, "__image_base__")) == 0)
+    {
+      *ImageBase      = Address;
+      *ImageBaseValid = TRUE;
+      return NULL;
+    }
+
+  /* We only want symbols in the .text segment */
+  if ((Type != 't') && (Type != 'T'))
+    return NULL;
+
+  /* Discard other symbols we can't use */
+  if ((Buffer[0] != '_') || ((Buffer[0] == '_') && (Buffer[1] == '_')))
+    return NULL;
+
+  Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL));
+  if (!Symbol)
+    return NULL;
+
+  Symbol->Next = NULL;
+
+  Symbol->RelativeAddress = Address;
+
+  RtlInitAnsiString(&AnsiString, (PCSZ)&Buffer);
+  RtlAnsiStringToUnicodeString(&Symbol->Name, &AnsiString, TRUE);
+
+  return Symbol;
+}
+
+VOID LdrLoadModuleSymbols(PMODULE_OBJECT ModuleObject,
+                         MODULE_TEXT_SECTION* ModuleTextSection)
+/*
+   Symbols must be sorted by address, e.g.
+   "nm --numeric-sort module.sys > module.sym"
+ */
 {
+  WCHAR TmpFileName[MAX_PATH];
+  LPWSTR Start, Ext;
+  ULONG Length, Tmp;
+  UNICODE_STRING Filename;
+  OBJECT_ATTRIBUTES ObjectAttributes;
   NTSTATUS Status;
-  ANSI_STRING AnsiDriverName;
-  UNICODE_STRING DriverName;
+  HANDLE FileHandle;
+  PVOID FileBuffer, FilePtr;
+  CHAR Line[256];
+  FILE_STANDARD_INFORMATION FileStdInfo;
+  BOOLEAN ImageBaseValid;
+  ULONG ImageBase = 0;
+  PSYMBOL Symbol, CurrentSymbol = NULL;
+
+  /*  Get the path to the symbol store  */
+  wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\");
+
+  /*  Get the symbol filename from the module name  */
+  Start = wcsrchr(ModuleObject->BaseName.Buffer, L'\\');
+  if (Start == NULL)
+    Start = ModuleObject->BaseName.Buffer;
+  else
+    Start++;
+
+  Ext = wcsrchr(ModuleObject->BaseName.Buffer, L'.');
+  if (Ext != NULL)
+    Length = Ext - Start;
+  else
+    Length = wcslen(Start);
+
+  wcsncat(TmpFileName, Start, Length);
+  wcscat(TmpFileName, L".sym");
+  RtlInitUnicodeString(&Filename, TmpFileName);
+
+  /*  Open the file  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &Filename,
+                             0,
+                             NULL,
+                             NULL);
+
+  Status = ZwOpenFile(&FileHandle,
+                      FILE_ALL_ACCESS,
+                      &ObjectAttributes,
+                      NULL, 0, 0);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("Could not open symbol file: %wZ\n", &Filename);
+      return;
+    }
 
-  RtlInitAnsiString(&AnsiDriverName,"\\??\\C:\\reactos\\system\\drivers\\keyboard.o"); 
-  RtlAnsiStringToUnicodeString(&DriverName, &AnsiDriverName, TRUE);
-  Status = LdrLoadDriver(&DriverName);
-  RtlFreeUnicodeString(&DriverName);
+  DbgPrint("Loading symbols from %wZ...\n", &Filename);
+
+  /*  Get the size of the file  */
+  Status = ZwQueryInformationFile(FileHandle,
+                                  NULL,
+                                  &FileStdInfo,
+                                  sizeof(FileStdInfo),
+                                  FileStandardInformation);
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("driver load failed, status;%d(%x)\n", Status, Status);
-      DbgPrintErrorMessage(Status);
+      DPRINT("Could not get file size\n");
+      return;
+    }
+
+  /*  Allocate nonpageable memory for symbol file  */
+  FileBuffer = ExAllocatePool(NonPagedPool,
+                              FileStdInfo.EndOfFile.u.LowPart);
+
+  if (FileBuffer == NULL)
+    {
+      DPRINT("Could not allocate memory for symbol file\n");
+      return;
     }
-  RtlInitAnsiString(&AnsiDriverName,"\\??\\C:\\reactos\\system\\drivers\\blues.o"); 
-  RtlAnsiStringToUnicodeString(&DriverName, &AnsiDriverName, TRUE);
-  Status = LdrLoadDriver(&DriverName);
-  RtlFreeUnicodeString(&DriverName);
+   
+  /*  Load file into memory chunk  */
+  Status = ZwReadFile(FileHandle, 
+                      0, 0, 0, 0, 
+                      FileBuffer, 
+                      FileStdInfo.EndOfFile.u.LowPart, 
+                      0, 0);
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("driver load failed, status;%d(%x)\n", Status, Status);
-      DbgPrintErrorMessage(Status);
+      DPRINT("Could not read symbol file into memory\n");
+      ExFreePool(FileBuffer);
+      return;
+    }
+
+  ZwClose(FileHandle);
+
+  ModuleTextSection->Symbols.SymbolCount = 0;
+  ModuleTextSection->Symbols.Symbols     = NULL;
+
+  FilePtr = FileBuffer;
+  Length  = FileStdInfo.EndOfFile.u.LowPart;
+
+  while (LdrReadLine((PCHAR)&Line, &FilePtr, &Length))
+    {
+      Symbol = LdrParseLine((PCHAR)&Line, &Tmp, &ImageBaseValid);
+
+      if (ImageBaseValid)
+        ImageBase = Tmp;
+
+      if (Symbol != NULL)
+        {
+          Symbol->RelativeAddress -= ImageBase;
+
+          if (ModuleTextSection->Symbols.Symbols == NULL)
+            ModuleTextSection->Symbols.Symbols = Symbol;
+          else
+            CurrentSymbol->Next = Symbol;
+
+          CurrentSymbol = Symbol;
+
+          ModuleTextSection->Symbols.SymbolCount++;
+        }
+    }
+
+  ExFreePool(FileBuffer);
+}
+
+#endif /* KDBG */
+
+VOID LdrLoadAutoConfigDrivers (VOID)
+{
+
+#ifdef KDBG
+
+  NTSTATUS Status;
+  WCHAR NameBuffer[60];
+  UNICODE_STRING ModuleName;
+  PMODULE_OBJECT ModuleObject;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING RemainingPath;
+
+  /* Load symbols for ntoskrnl.exe and hal.dll because \SystemRoot
+     is created after their module entries */
+
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  wcscat(NameBuffer, L"ntoskrnl.exe");
+  RtlInitUnicodeString(&ModuleName, NameBuffer);
+
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+  
+  Status = ObFindObject(&ObjectAttributes,
+                        (PVOID*)&ModuleObject,
+                        &RemainingPath,
+                        NULL);
+  if (NT_SUCCESS(Status)) {
+    RtlFreeUnicodeString(&RemainingPath);
+
+    LdrLoadModuleSymbols(ModuleObject, &NtoskrnlTextSection);
+  }
+
+  /* FIXME: Load symbols for hal.dll */
+
+#endif /* KDBG */
+
+   /*
+    * Keyboard driver
+    */
+   LdrLoadAutoConfigDriver( L"keyboard.sys" );
+   
+   /*
+    * Raw console driver
+    */
+   LdrLoadAutoConfigDriver( L"blue.sys" );
+   
+   /*
+    * 
+    */
+   LdrLoadAutoConfigDriver(L"vidport.sys");
+   
+   /*
+    * 
+    */
+   LdrLoadAutoConfigDriver(L"vgamp.sys");
+   
+   /*
+    * Minix filesystem driver
+    */
+   LdrLoadAutoConfigDriver(L"minixfs.sys");
+
+   /*
+    * Networking
+    */
+#if 0
+   /*
+    * NDIS library
+    */
+   LdrLoadAutoConfigDriver(L"ndis.sys");
+
+   /*
+    * Novell Eagle 2000 driver
+    */
+   LdrLoadAutoConfigDriver(L"ne2000.sys");
+
+   /*
+    * TCP/IP protocol driver
+    */
+   LdrLoadAutoConfigDriver(L"tcpip.sys");
+
+   /*
+    * TDI test driver
+    */
+   LdrLoadAutoConfigDriver(L"tditest.sys");
+
+   /*
+    * Ancillary Function Driver
+    */
+   LdrLoadAutoConfigDriver(L"afd.sys");
+#endif
+}
+
+
+static NTSTATUS 
+LdrCreateModule(PVOID ObjectBody,
+                PVOID Parent,
+                PWSTR RemainingPath,
+                POBJECT_ATTRIBUTES ObjectAttributes)
+{
+  DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
+         ObjectBody,
+         Parent,
+         RemainingPath);
+  if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
+    {
+      return  STATUS_UNSUCCESSFUL;
+    }
+  if (Parent != NULL && RemainingPath != NULL)
+    {
+      ObAddEntryDirectory(Parent, ObjectBody, RemainingPath + 1);
     }
+
+  return  STATUS_SUCCESS;
 }
 
 /*
@@ -120,81 +643,162 @@ VOID LdrLoadAutoConfigDrivers(VOID)
  * RETURNS: Status
  */
 
-NTSTATUS 
-LdrLoadDriver(PUNICODE_STRING Filename)
+NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename)
+{
+  PMODULE_OBJECT  ModuleObject;
+
+  ModuleObject = LdrLoadModule(Filename);
+  if (ModuleObject == 0)
+    {
+      return  STATUS_UNSUCCESSFUL;
+    }
+
+  /* FIXME: should we dereference the ModuleObject here?  */
+
+  return IoInitializeDriver(ModuleObject->EntryPoint);
+}
+
+NTSTATUS LdrLoadGdiDriver (PUNICODE_STRING DriverName,
+                          PVOID *ImageAddress,
+                          PVOID *SectionPointer,
+                          PVOID *EntryPoint,
+                          PVOID *ExportSectionPointer)
+{
+  PMODULE_OBJECT  ModuleObject;
+
+  ModuleObject = LdrLoadModule(DriverName);
+  if (ModuleObject == 0)
+    {
+      return  STATUS_UNSUCCESSFUL;
+    }
+
+  if (ImageAddress)
+    *ImageAddress = ModuleObject->Base;
+
+//  if (SectionPointer)
+//    *SectionPointer = ModuleObject->
+
+  if (EntryPoint)
+    *EntryPoint = ModuleObject->EntryPoint;
+
+//  if (ExportSectionPointer)
+//    *ExportSectionPointer = ModuleObject->
+
+  return STATUS_SUCCESS;
+}
+
+
+PMODULE_OBJECT
+LdrLoadModule(PUNICODE_STRING Filename)
 {
   PVOID ModuleLoadBase;
   NTSTATUS Status;
   HANDLE FileHandle;
-  OBJECT_ATTRIBUTES FileObjectAttributes;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  PMODULE_OBJECT  ModuleObject;
   FILE_STANDARD_INFORMATION FileStdInfo;
 
-  DbgPrint("Loading Driver %W...\n", Filename);
+  /*  Check for module already loaded  */
+  if ((ModuleObject = LdrOpenModule(Filename)) != NULL)
+    {
+      return  ModuleObject;
+    }
+
+  DPRINT("Loading Module %wZ...\n", Filename);
 
-  /*  Open the Driver  */
-  InitializeObjectAttributes(&FileObjectAttributes,
-                             Filename, 
+  /*  Open the Module  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             Filename,
                              0,
                              NULL,
                              NULL);
   CHECKPOINT;
-  Status = ZwOpenFile(&FileHandle, 
-                      FILE_ALL_ACCESS, 
-                      &FileObjectAttributes, 
+  Status = NtOpenFile(&FileHandle,
+                      FILE_ALL_ACCESS,
+                      &ObjectAttributes,
                       NULL, 0, 0);
   CHECKPOINT;
   if (!NT_SUCCESS(Status))
     {
-      return Status;
+      DbgPrint("Could not open module file: %wZ\n", Filename);
+      return  0;
     }
   CHECKPOINT;
 
   /*  Get the size of the file  */
-  Status = ZwQueryInformationFile(FileHandle,
+  Status = NtQueryInformationFile(FileHandle,
                                   NULL,
                                   &FileStdInfo,
                                   sizeof(FileStdInfo),
                                   FileStandardInformation);
   if (!NT_SUCCESS(Status))
     {
-      return Status;
+      DbgPrint("Could not get file size\n");
+      return  0;
     }
   CHECKPOINT;
 
   /*  Allocate nonpageable memory for driver  */
-  ModuleLoadBase = ExAllocatePool(NonPagedPool, 
-                 GET_LARGE_INTEGER_LOW_PART(FileStdInfo.EndOfFile));
+  ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
+                                        FileStdInfo.EndOfFile.u.LowPart,
+                                        TAG_DRIVER_MEM);
+
   if (ModuleLoadBase == NULL)
     {
-      return STATUS_INSUFFICIENT_RESOURCES;
+      DbgPrint("could not allocate memory for module");
+      return  0;
     }
   CHECKPOINT;
-
+   
   /*  Load driver into memory chunk  */
-  Status = ZwReadFile(FileHandle, 
+  Status = NtReadFile(FileHandle, 
                       0, 0, 0, 0, 
                       ModuleLoadBase, 
-                      GET_LARGE_INTEGER_LOW_PART(FileStdInfo.EndOfFile)
+                      FileStdInfo.EndOfFile.u.LowPart
                       0, 0);
   if (!NT_SUCCESS(Status))
     {
+      DbgPrint("could not read module file into memory");
       ExFreePool(ModuleLoadBase);
-      return Status;
+
+      return  0;
     }
   CHECKPOINT;
 
-  ZwClose(FileHandle);
+  NtClose(FileHandle);
 
-  Status = LdrProcessDriver(ModuleLoadBase);
+  ModuleObject = LdrProcessModule(ModuleLoadBase, Filename);
 
   /*  Cleanup  */
   ExFreePool(ModuleLoadBase);
 
-  return STATUS_SUCCESS;
+  return  ModuleObject;
 }
 
 NTSTATUS
-LdrProcessDriver(PVOID ModuleLoadBase)
+LdrProcessDriver(PVOID ModuleLoadBase, PCHAR FileName)
+{
+   PMODULE_OBJECT ModuleObject;
+   UNICODE_STRING ModuleName;
+
+   RtlCreateUnicodeStringFromAsciiz(&ModuleName,
+                                   FileName);
+   ModuleObject = LdrProcessModule(ModuleLoadBase,
+                                  &ModuleName);
+   RtlFreeUnicodeString(&ModuleName);
+   if (ModuleObject == NULL)
+     {
+       DPRINT1("Driver load was unsuccessful\n");
+       return(STATUS_UNSUCCESSFUL);
+     }
+
+   /* FIXME: should we dereference the ModuleObject here?  */
+
+   return(IoInitializeDriver(ModuleObject->EntryPoint));
+}
+
+PMODULE_OBJECT
+LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName)
 {
   PIMAGE_DOS_HEADER PEDosHeader;
 
@@ -202,25 +806,198 @@ LdrProcessDriver(PVOID ModuleLoadBase)
   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
   if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
     {
-      return LdrPEProcessDriver(ModuleLoadBase);
+      return LdrPEProcessModule(ModuleLoadBase, ModuleName);
+    }
+
+  DPRINT1("Module wasn't PE\n");
+  return 0;
+}
+
+static PMODULE_OBJECT 
+LdrOpenModule(PUNICODE_STRING  Filename)
+{
+  NTSTATUS  Status;
+  WCHAR  NameBuffer[60];
+  UNICODE_STRING  ModuleName;
+  OBJECT_ATTRIBUTES  ObjectAttributes;
+  PMODULE_OBJECT  ModuleObject;
+  UNICODE_STRING RemainingPath;
+
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  if (wcsrchr(Filename->Buffer, '\\') != 0)
+    {
+      wcscat(NameBuffer, wcsrchr(Filename->Buffer, '\\') + 1);
+    }
+  else
+    {
+      wcscat(NameBuffer, Filename->Buffer);
+    }
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName, 
+                             0,
+                             NULL,
+                             NULL);
+
+  Status = ObFindObject(&ObjectAttributes,
+                        (PVOID *) &ModuleObject,
+                        &RemainingPath,
+                        NULL);
+  CHECKPOINT;
+  if (NT_SUCCESS(Status) && (RemainingPath.Buffer == NULL || *(RemainingPath.Buffer) == 0))
+    {
+      DPRINT("Module %wZ at %p\n", Filename, ModuleObject);
+      RtlFreeUnicodeString (&RemainingPath);
+
+      return  ModuleObject;
     }
-  if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC)
+
+  RtlFreeUnicodeString (&RemainingPath);
+
+  return  NULL;
+}
+
+PVOID
+LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
+                    char *Name,
+                    unsigned short Hint)
+{
+  if (ModuleObject->Flags & MODULE_FLAG_PE)
     {
-      return STATUS_NOT_IMPLEMENTED;
+      return LdrPEGetExportAddress(ModuleObject, Name, Hint);
     }
-  else  /*  Assume COFF format and load  */
+  else
     {
-      return LdrCOFFProcessDriver(ModuleLoadBase);
+      return 0;
     }
 }
 
-NTSTATUS 
-LdrPEProcessDriver(PVOID ModuleLoadBase)
+NTSTATUS
+LdrpQueryModuleInformation(PVOID Buffer,
+                          ULONG Size,
+                          PULONG ReqSize)
+{
+   PLIST_ENTRY current_entry;
+   PMODULE_OBJECT current;
+   ULONG ModuleCount = 0;
+   PSYSTEM_MODULE_INFORMATION Smi;
+   ANSI_STRING AnsiName;
+   PCHAR p;
+
+//   KeAcquireSpinLock(&ModuleListLock,&oldlvl);
+
+   /* calculate required size */
+   current_entry = ModuleListHead.Flink;
+   while (current_entry != (&ModuleListHead))
+     {
+       ModuleCount++;
+       current_entry = current_entry->Flink;
+     }
+
+   *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
+       (ModuleCount - 1) * sizeof(SYSTEM_MODULE_ENTRY);
+
+   if (Size < *ReqSize)
+     {
+//     KeReleaseSpinLock(&ModuleListLock,oldlvl);
+       return STATUS_INFO_LENGTH_MISMATCH;
+     }
+
+   /* fill the buffer */
+   memset(Buffer, '=', Size);
+
+   Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
+   Smi->Count = ModuleCount;
+
+   ModuleCount = 0;
+   current_entry = ModuleListHead.Flink;
+   while (current_entry != (&ModuleListHead))
+     {
+       current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
+
+       Smi->Module[ModuleCount].Unknown2 = 0;          /* Always 0 */
+       Smi->Module[ModuleCount].BaseAddress = current->Base;
+       Smi->Module[ModuleCount].Size = current->Length;
+       Smi->Module[ModuleCount].Flags = 0;             /* Flags ??? (GN) */
+       Smi->Module[ModuleCount].EntryIndex = ModuleCount;
+
+       AnsiName.Length = 0;
+       AnsiName.MaximumLength = 256;
+       AnsiName.Buffer = Smi->Module[ModuleCount].Name;
+       RtlUnicodeStringToAnsiString(&AnsiName,
+                                    &current->FullName,
+                                    FALSE);
+
+       p = strrchr (AnsiName.Buffer, '\\');
+       if (p == NULL)
+         {
+            Smi->Module[ModuleCount].PathLength = 0;
+            Smi->Module[ModuleCount].NameLength = strlen(AnsiName.Buffer);
+         }
+       else
+         {
+            p++;
+            Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
+            Smi->Module[ModuleCount].NameLength = strlen(p);
+         }
+
+       ModuleCount++;
+       current_entry = current_entry->Flink;
+     }
+
+//   KeReleaseSpinLock(&ModuleListLock,oldlvl);
+
+   return STATUS_SUCCESS;
+}
+
+
+static VOID
+LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
+                       PUNICODE_STRING FullName)
+{
+   UNICODE_STRING Name;
+   PWCHAR p;
+   PWCHAR q;
+
+   DPRINT("LdrpBuildModuleBaseName()\n");
+   DPRINT("FullName %wZ\n", FullName);
+
+   p = wcsrchr(FullName->Buffer, '\\');
+   if (p == NULL)
+     {
+       p = FullName->Buffer;
+     }
+   else
+     {
+       p++;
+     }
+
+   DPRINT("p %S\n", p);
+
+   RtlCreateUnicodeString(&Name, p);
+
+   q = wcschr(p, '.');
+   if (q != NULL)
+     {
+       *q = (WCHAR)0;
+     }
+
+   DPRINT("p %S\n", p);
+
+   RtlCreateUnicodeString(BaseName, p);
+   RtlFreeUnicodeString(&Name);
+}
+
+
+/*  ----------------------------------------------  PE Module support */
+
+PMODULE_OBJECT
+LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName)
 {
-  unsigned int DriverSize, Idx;
-  long int RelocDelta, NumRelocs;
-  DWORD CurrentSize;
-  PVOID DriverBase, CurrentBase, EntryPoint;
+  unsigned int DriverSize, Idx, Idx2;
+  ULONG RelocDelta, NumRelocs;
+  DWORD CurrentSize, TotalRelocs;
+  PVOID DriverBase;
   PULONG PEMagic;
   PIMAGE_DOS_HEADER PEDosHeader;
   PIMAGE_FILE_HEADER PEFileHeader;
@@ -228,16 +1005,19 @@ LdrPEProcessDriver(PVOID ModuleLoadBase)
   PIMAGE_SECTION_HEADER PESectionHeaders;
   PRELOCATION_DIRECTORY RelocDir;
   PRELOCATION_ENTRY RelocEntry;
-  PMODULE Library;
+  PMODULE_OBJECT  LibraryModuleObject;
+  HANDLE  ModuleHandle;
+  PMODULE_OBJECT  ModuleObject;
   PVOID *ImportAddressList;
   PULONG FunctionNameList;
   PCHAR pName, SymbolNameBuf;
-  PWORD pHint;
-  
-  /* FIXME: this could be used to load kernel DLLs also, however */
-  /*        the image headers should be preserved in such a case */
+  WORD Hint;
+  OBJECT_ATTRIBUTES  ObjectAttributes;
+  UNICODE_STRING  ModuleName;
+  WCHAR  NameBuffer[60];
+  MODULE_TEXT_SECTION* ModuleTextSection;
 
-  DPRINT("Processing PE Driver at module base:%08lx\n", ModuleLoadBase);
+  DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
 
   /*  Get header pointers  */
   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
@@ -255,23 +1035,23 @@ LdrPEProcessDriver(PVOID ModuleLoadBase)
   /*  Check file magic numbers  */
   if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
     {
-      DPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
-      return STATUS_UNSUCCESSFUL;
+      DbgPrint("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
+      return 0;
     }
   if (PEDosHeader->e_lfanew == 0)
     {
-      DPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
-      return STATUS_UNSUCCESSFUL;
+      DbgPrint("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
+      return 0;
     }
   if (*PEMagic != IMAGE_PE_MAGIC)
     {
-      DPRINT("Incorrect PE magic: %08x\n", *PEMagic);
-      return STATUS_UNSUCCESSFUL;
+      DbgPrint("Incorrect PE magic: %08x\n", *PEMagic);
+      return 0;
     }
   if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
     {
-      DPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
-      return STATUS_UNSUCCESSFUL;
+      DbgPrint("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
+      return 0;
     }
   CHECKPOINT;
 
@@ -287,176 +1067,203 @@ LdrPEProcessDriver(PVOID ModuleLoadBase)
   CHECKPOINT;
 
   /*  Determine the size of the module  */
-  DPRINT("Sections: (section align:%08lx)\n", 
-         PEOptionalHeader->SectionAlignment);
-  DriverSize = PESectionHeaders[0].PointerToRawData;
-  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
-    {
-      DPRINT("Name:%-8.8s VA:%08lx RawSz:%6d Offs:%08lx CHAR:%08lx OfsA: %08lx\n",
-             PESectionHeaders[Idx].Name,
-             PESectionHeaders[Idx].VirtualAddress,
-             PESectionHeaders[Idx].SizeOfRawData,
-             PESectionHeaders[Idx].PointerToRawData,
-             PESectionHeaders[Idx].Characteristics,
-             DriverSize);
-      DriverSize += ROUND_UP(PESectionHeaders[Idx].SizeOfRawData,
-                             PEOptionalHeader->SectionAlignment);
-    }
-  DPRINT("DriverSize computed by using section headers: %d(%08lx)\n",
-         DriverSize,
-         DriverSize);
-       
-  /*  Allocate a virtual section for the module  */  
+  DriverSize = PEOptionalHeader->SizeOfImage;
+  DPRINT("DriverSize %x\n",DriverSize);
+
+  /*  Allocate a virtual section for the module  */
   DriverBase = MmAllocateSection(DriverSize);
   if (DriverBase == 0)
     {
       DbgPrint("Failed to allocate a virtual section for driver\n");
-      return STATUS_INSUFFICIENT_RESOURCES;
+      return 0;
     }
+   DbgPrint("DriverBase: %x\n", DriverBase);
   CHECKPOINT;
-
+  /*  Copy headers over */
+  memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
+   CurrentSize = 0;
   /*  Copy image sections into virtual section  */
-  memcpy(DriverBase, ModuleLoadBase, PESectionHeaders[0].PointerToRawData);
-  CurrentBase = (PVOID) ((DWORD)DriverBase + PESectionHeaders[0].PointerToRawData);
   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
     {
-      /*  Copy current section into current offset of virtual section  */
+      //  Copy current section into current offset of virtual section
       if (PESectionHeaders[Idx].Characteristics & 
           (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
         {
-          memcpy(CurrentBase,
-                 (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
-                 PESectionHeaders[Idx].SizeOfRawData);
+          DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
+                 PESectionHeaders[Idx].VirtualAddress + DriverBase);
+           memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
+                  (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
+                  PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
         }
       else
         {
-          memset(CurrentBase, '\0', PESectionHeaders[Idx].SizeOfRawData);
+          DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
+                 PESectionHeaders[Idx].VirtualAddress + DriverBase);
+          memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
+                 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
+
         }
-      CurrentSize += ROUND_UP(PESectionHeaders[Idx].SizeOfRawData,
+      CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
                               PEOptionalHeader->SectionAlignment);
-      CurrentBase = (PVOID)((DWORD)CurrentBase + 
-        ROUND_UP(PESectionHeaders[Idx].SizeOfRawData,
-                 PEOptionalHeader->SectionAlignment));
+
+
+//      CurrentBase = (PVOID)((DWORD)CurrentBase + 
+  //      ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
+    //             PEOptionalHeader->SectionAlignment));
     }
 
   /*  Perform relocation fixups  */
   RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
-  RelocDir = (PRELOCATION_DIRECTORY) ((DWORD)ModuleLoadBase +
-    PEOptionalHeader->DataDirectory[
+  RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
     IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
   DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
          DriverBase,
          PEOptionalHeader->ImageBase,
-         RelocDelta);
-  while (RelocDir->SizeOfBlock != 0)
+         RelocDelta);   
+  DPRINT("RelocDir %x\n",RelocDir);
+#if 1
+  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
+    {
+       if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
+        {
+           DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
+                  PESectionHeaders[Idx].Name,
+                  PESectionHeaders[Idx].PointerToRawData);
+           RelocDir = PESectionHeaders[Idx].PointerToRawData +
+             ModuleLoadBase;
+            CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
+           break;
+        }
+    }
+#else
+   RelocDir = RelocDir + (ULONG)DriverBase;
+   CurrentSize = PEOptionalHeader->DataDirectory
+                 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+#endif   
+  DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
+  TotalRelocs = 0;
+  while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
     {
       NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
         sizeof(WORD);
-      DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
+/*      DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
              RelocDir, 
              RelocDir->VirtualAddress,
-             NumRelocs);
+             NumRelocs);*/
       RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir + 
         sizeof(RELOCATION_DIRECTORY));
       for (Idx = 0; Idx < NumRelocs; Idx++)
         {
-          DPRINT("  reloc at %08lx %x %s old:%08lx new:%08lx\n", 
-                 DriverBase + RelocDir->VirtualAddress +  
-                   (RelocEntry[Idx].TypeOffset & 0x0fff),
-                 (RelocEntry[Idx].TypeOffset >> 12) & 0xf,
-                 (RelocEntry[Idx].TypeOffset >> 12) & 0xf ? "HIGHLOW" : "ABS",
-                 *(PDWORD)((DWORD) DriverBase + RelocDir->VirtualAddress +  
-                   (RelocEntry[Idx].TypeOffset & 0x0fff)),
-                 (*(PDWORD)((DWORD) DriverBase + RelocDir->VirtualAddress +  
-                   (RelocEntry[Idx].TypeOffset & 0x0fff))) + RelocDelta);
-          if (((RelocEntry[Idx].TypeOffset >> 12) & 0xf) == 3)
+          ULONG Offset;
+          ULONG Type;
+          PDWORD RelocItem;
+          
+          Offset = RelocEntry[Idx].TypeOffset & 0xfff;
+          Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
+          RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress + 
+                               Offset);
+/*        DPRINT("  reloc at %08lx %x %s old:%08lx new:%08lx\n", 
+                 RelocItem,
+                 Type,
+                 Type ? "HIGHLOW" : "ABS",
+                 *RelocItem,
+                 (*RelocItem) + RelocDelta); */
+          if (Type == 3)
             {
-              (*(PDWORD)((DWORD) DriverBase + RelocDir->VirtualAddress +  
-                   (RelocEntry[Idx].TypeOffset & 0x0fff))) += RelocDelta;
+              (*RelocItem) += RelocDelta;
             }
-          else if (((RelocEntry[Idx].TypeOffset >> 12) & 0xf) != 0)
+          else if (Type != 0)
             {
-              DPRINT("Unknown relocation type %x\n", 
-                     (RelocEntry[Idx].TypeOffset >> 12) & 0xf);
-              return STATUS_UNSUCCESSFUL;
+              DbgPrint("Unknown relocation type %x at %x\n",Type, &Type);
+              return 0;
             }
         }
+      TotalRelocs += RelocDir->SizeOfBlock;
       RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir + 
         RelocDir->SizeOfBlock);
+//      DPRINT("TotalRelocs: %08lx  CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
     }
-
+   
+  DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
+         PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
+         .VirtualAddress);
   /*  Perform import fixups  */
-  if (PEOptionalHeader->DataDirectory[
-      IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
+  if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
     {
       PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
 
-      SymbolNameBuf = ExAllocatePool(NonPagedPool, 512);
+      SymbolNameBuf = ExAllocatePoolWithTag(NonPagedPool, 512, TAG_SYM_BUF);
 
       /*  Process each import module  */
       ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
-        ((DWORD)ModuleLoadBase + PEOptionalHeader->
+        ((DWORD)DriverBase + PEOptionalHeader->
           DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+      DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
       while (ImportModuleDirectory->dwRVAModuleName)
         {
-          /* FIXME: handle kernel mode DLLs  */
-
           /*  Check to make sure that import lib is kernel  */
-          Library = NULL;
-          pName = (PCHAR) ModuleLoadBase + 
+          pName = (PCHAR) DriverBase + 
             ImportModuleDirectory->dwRVAModuleName;
-          DPRINT("Import module: %s\n", pName);
-          if (strcmp(pName, "ntoskrnl.exe") && 
-              strcmp(pName, "HAL.dll"))
+          wcscpy(NameBuffer, MODULE_ROOT_NAME);
+          for (Idx = 0; NameBuffer[Idx] != 0; Idx++)
+            ;
+          for (Idx2 = 0; pName[Idx2] != '\0'; Idx2++)
             {
-              DPRINT("Kernel mode DLLs are currently unsupported\n");
+              NameBuffer[Idx + Idx2] = (WCHAR) pName[Idx2];
             }
+          NameBuffer[Idx + Idx2] = 0;
+          RtlInitUnicodeString (&ModuleName, NameBuffer);
+          DPRINT("Import module: %wZ\n", &ModuleName);
 
-          /*  Get the import address list  */
-          ImportAddressList = (PVOID *) ((DWORD)ModuleLoadBase + 
+          LibraryModuleObject = LdrLoadModule(&ModuleName);
+          if (LibraryModuleObject == 0)
+            {
+              DbgPrint("Unknown import module: %wZ\n", &ModuleName);
+            }
+          /*  Get the import address list  */
+          ImportAddressList = (PVOID *) ((DWORD)DriverBase + 
             ImportModuleDirectory->dwRVAFunctionAddressList);
 
           /*  Get the list of functions to import  */
           if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
             {
-              FunctionNameList = (PULONG) ((DWORD)ModuleLoadBase + 
+              FunctionNameList = (PULONG) ((DWORD)DriverBase + 
                 ImportModuleDirectory->dwRVAFunctionNameList);
             }
           else
             {
-              FunctionNameList = (PULONG) ((DWORD)ModuleLoadBase + 
+              FunctionNameList = (PULONG) ((DWORD)DriverBase + 
                 ImportModuleDirectory->dwRVAFunctionAddressList);
             }
-
           /*  Walk through function list and fixup addresses  */
-          while(*FunctionNameList != 0L)
+          while (*FunctionNameList != 0L)
             {
               if ((*FunctionNameList) & 0x80000000) // hint
                 {
-                  DPRINT("  Hint: %08lx\n", *FunctionNameList);
-                  if (Library == NULL)
-                    {
-                      DPRINT("Hints for kernel symbols are not handled.\n");
-                      *ImportAddressList = 0;
-                    }
+                  pName = NULL;
+
+
+                  Hint = (*FunctionNameList) & 0xffff;
                 }
               else // hint-name
                 {
-                  pName = (PCHAR)((DWORD)ModuleLoadBase + 
+                  pName = (PCHAR)((DWORD)DriverBase + 
                                   *FunctionNameList + 2);
-                  pHint = (PWORD)((DWORD)ModuleLoadBase + *FunctionNameList);
-                  DPRINT("  Hint:%04x  Name:%s\n", pHint, pName);
-                  
-                  /*  Get address for symbol  */
-                  if (Library == NULL)
-                    {
-                      *SymbolNameBuf = '_';
-                      strcpy(SymbolNameBuf + 1, pName);
-                      *ImportAddressList = (PVOID) LdrGetKernelSymbolAddr(SymbolNameBuf);                      if (*ImportAddressList == 0L)
-                        {
-                          DPRINT("Unresolved kernel symbol: %s\n", pName);
-                        }
-                    }
+                  Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
+                }
+              DPRINT("  Hint:%04x  Name:%s\n", Hint, pName);
+
+              /*  Fixup the current import symbol  */
+              if (LibraryModuleObject != NULL)
+                {
+                  *ImportAddressList = LdrGetExportAddress(LibraryModuleObject, 
+                                                           pName, 
+                                                           Hint);
+                }
+              else
+                {
+                   DbgPrint("Unresolved kernel symbol: %s\n", pName);
+                  return(NULL);
                 }
               ImportAddressList++;
               FunctionNameList++;
@@ -467,976 +1274,228 @@ LdrPEProcessDriver(PVOID ModuleLoadBase)
       ExFreePool(SymbolNameBuf);
     }
 
-  /*  Compute address of entry point  */
-  EntryPoint = (PVOID) ((DWORD)DriverBase + PEOptionalHeader->AddressOfEntryPoint);
-
-  return InitializeLoadedDriver(EntryPoint); 
-}
-
-NTSTATUS 
-LdrCOFFProcessDriver(PVOID ModuleLoadBase)
-{
-  BOOLEAN FoundEntry;
-  char SymbolName[255];
-  int i;
-  ULONG EntryOffset;
-  FILHDR *FileHeader;
-  AOUTHDR *AOUTHeader;
-  module *Module;
-  PDRIVER_INITIALIZE EntryRoutine;
-
-  /*  Get header pointers  */
-  FileHeader = ModuleLoadBase;
-  AOUTHeader = ModuleLoadBase + FILHSZ;
-  CHECKPOINT;
-
-  /*  Check COFF magic value  */
-  if (I386BADMAG(*FileHeader))
-    {
-      DbgPrint("Module has bad magic value (%x)\n", 
-               FileHeader->f_magic);
-      return STATUS_UNSUCCESSFUL;
-    }
-  CHECKPOINT;
-   
-  /*  Allocate and initialize a module definition structure  */
-  Module = (module *) ExAllocatePool(NonPagedPool, sizeof(module));
-  if (Module == NULL)
-    {
-      return STATUS_INSUFFICIENT_RESOURCES;
-    }
-  Module->sym_list = (SYMENT *)(ModuleLoadBase + FileHeader->f_symptr);
-  Module->str_tab = (char *)(ModuleLoadBase + FileHeader->f_symptr +
-    FileHeader->f_nsyms * SYMESZ);
-  Module->scn_list = (SCNHDR *)(ModuleLoadBase + FILHSZ + 
-    FileHeader->f_opthdr);
-  Module->size = 0;
-  Module->raw_data_off = (ULONG) ModuleLoadBase;
-  Module->nsyms = FileHeader->f_nsyms;
-  CHECKPOINT;
-
-  /*  Determine the length of the module  */
-  for (i = 0; i < FileHeader->f_nscns; i++)
-    {
-      DPRINT("Section name: %.8s\n", Module->scn_list[i].s_name);
-      DPRINT("size %x vaddr %x size %x\n",
-             Module->size,
-             Module->scn_list[i].s_vaddr,
-             Module->scn_list[i].s_size);
-      if (Module->scn_list[i].s_flags & STYP_TEXT)
-        {
-          Module->text_base = Module->scn_list[i].s_vaddr;
-        }
-      if (Module->scn_list[i].s_flags & STYP_DATA)
-        {
-          Module->data_base = Module->scn_list[i].s_vaddr;
-        }
-      if (Module->scn_list[i].s_flags & STYP_BSS)
-        {
-          Module->bss_base = Module->scn_list[i].s_vaddr;
-        }
-      if (Module->size <
-          (Module->scn_list[i].s_vaddr + Module->scn_list[i].s_size))
-        {
-          Module->size = Module->size + Module->scn_list[i].s_vaddr +
-            Module->scn_list[i].s_size;
-        }
-    }
-  CHECKPOINT;
-
-  /*  Allocate a section for the module  */
-  Module->base = (unsigned int) MmAllocateSection(Module->size);
-  if (Module->base == 0)
-    {
-      DbgPrint("Failed to alloc section for module\n");
-      ExFreePool(Module);
-      return STATUS_INSUFFICIENT_RESOURCES;
-    }
-  CHECKPOINT;
-
-  /*  Adjust section vaddrs for allocated area  */
-  Module->data_base = Module->data_base + Module->base;
-  Module->text_base = Module->text_base + Module->base;
-  Module->bss_base = Module->bss_base + Module->base;
-   
-  /*  Relocate module and fixup imports  */
-  for (i = 0; i < FileHeader->f_nscns; i++)
-    {
-      if (Module->scn_list[i].s_flags & STYP_TEXT ||
-          Module->scn_list[i].s_flags & STYP_DATA)
-        {
-          memcpy((PVOID)(Module->base + Module->scn_list[i].s_vaddr),
-                 (PVOID)(ModuleLoadBase + Module->scn_list[i].s_scnptr),
-                 Module->scn_list[i].s_size);
-          if (!LdrCOFFDoRelocations(Module, i))
-            {
-              DPRINT("Relocation failed for section %s\n",
-                     Module->scn_list[i].s_name);
-
-              /* FIXME: unallocate all sections here  */
-
-              ExFreePool(Module);
-
-              return STATUS_UNSUCCESSFUL;
-            }
-        }
-      if (Module->scn_list[i].s_flags & STYP_BSS)
-        {
-          memset((PVOID)(Module->base + Module->scn_list[i].s_vaddr),
-                 0,
-                 Module->scn_list[i].s_size);
-        }
-    }
-   
-  DbgPrint("Module base: %x\n", Module->base);
-   
-  /*  Find the entry point  */
-  EntryOffset = 0L;
-  FoundEntry = FALSE;
-  for (i = 0; i < FileHeader->f_nsyms; i++)
-    {
-      LdrCOFFGetSymbolName(Module, i, SymbolName);
-      if (!strcmp(SymbolName, "_DriverEntry"))
-        {
-          EntryOffset = Module->sym_list[i].e_value;
-          FoundEntry = TRUE;
-          DPRINT("Found entry at %x\n", EntryOffset);
-        }
-    }
-  if (!FoundEntry)
-    {
-      DbgPrint("No module entry point defined\n");
-      ExFreePool(Module);
-
-      /* FIXME: unallocate all sections here  */
-
-      return STATUS_UNSUCCESSFUL;
-    }
-   
-  /*  Get the address of the module initalization routine  */
-  EntryRoutine = (PDRIVER_INITIALIZE)(Module->base + EntryOffset);
-
-  /*  Cleanup  */
-  ExFreePool(Module);
-
-  return InitializeLoadedDriver(EntryRoutine);
-}
-
-/*   LdrCOFFDoRelocations
- * FUNCTION: Do the relocations for a module section
- * ARGUMENTS:
- *          Module = Pointer to the module 
- *          SectionIndex = Index of the section to be relocated
- * RETURNS: Success or failure
- */
-
-static BOOLEAN 
-LdrCOFFDoRelocations(module *Module, unsigned int SectionIndex)
-{
-  SCNHDR *Section = &Module->scn_list[SectionIndex];
-  RELOC *Relocation = (RELOC *)(Module->raw_data_off + Section->s_relptr);
-  int j;
-   
-  DPRINT("SectionIndex %d Name %.8s Relocs %d\n",
-         SectionIndex,
-         Module->scn_list[SectionIndex].s_name,
-         Section->s_nreloc);
-
-  for (j = 0; j < Section->s_nreloc; j++)
+  /*  Create ModuleName string  */
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  if (wcsrchr(FileName->Buffer, '\\') != 0)
     {
-      DPRINT("vaddr %x symndex %x", 
-             Relocation->r_vaddr, 
-             Relocation->r_symndx);
-
-      switch (Relocation->r_type)
-        {
-          case RELOC_ADDR32:
-            if (!LdrCOFFDoAddr32Reloc(Module, Section, Relocation))
-              {
-                return FALSE;
-              }
-            break;
-            
-          case RELOC_REL32:
-            if (!LdrCOFFDoReloc32Reloc(Module, Section, Relocation))
-              {
-                return FALSE;
-              }
-            break;
-
-          default:
-            DPRINT("%.8s: Unknown relocation type %x at %d in module\n",
-                   Module->scn_list[SectionIndex].s_name,
-                   Relocation->r_type,
-                   j);
-            return FALSE;
-        }
-      Relocation++;
-    }
-   DPRINT("%.8s: relocations done\n", Module->scn_list[SectionIndex].s_name);
-   
-   return TRUE;
-}                   
-
-/*
- * FUNCTION: Performs a addr32 relocation on a loaded module
- * ARGUMENTS:
- *         mod = module to perform the relocation on
- *         scn = Section to perform the relocation in
- *         reloc = Pointer to a data structure describing the relocation
- * RETURNS: Success or failure
- * NOTE: This fixes up a relocation needed when changing the base address of a
- * module
- */
-
-static BOOLEAN
-LdrCOFFDoAddr32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation)
-{
-  unsigned int Value;
-  unsigned int *Location;
-   
-  Value = LdrCOFFGetSymbolValue(Module, Relocation->r_symndx);
-  Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
-  DPRINT("ADDR32 loc %x value %x *loc %x\n", Location, Value, *Location);
-  *Location = (*Location) + Module->base;
-   
-  return TRUE;
-}
-
-/*
- * FUNCTION: Performs a reloc32 relocation on a loaded module
- * ARGUMENTS:
- *         mod = module to perform the relocation on
- *         scn = Section to perform the relocation in
- *         reloc = Pointer to a data structure describing the relocation
- * RETURNS: Success or failure
- * NOTE: This fixes up an undefined reference to a kernel function in a module
- */
-
-static BOOLEAN
-LdrCOFFDoReloc32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation)
-{
-  char Name[255];
-  unsigned int Value;
-  unsigned int *Location;
-   
-  memset(Name, 0, 255);
-  LdrCOFFGetSymbolName(Module, Relocation->r_symndx, Name);
-  Value = (unsigned int) LdrGetKernelSymbolAddr(Name);
-  if (Value == 0L)
-    {
-      Value = LdrCOFFGetSymbolValueByName(Module, Name, Relocation->r_symndx);
-      if (Value == 0L)
-        {
-          DbgPrint("Undefined symbol %s in module\n", Name);
-          return FALSE;
-        }
-      Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
-//        (*Location) = (*Location) + Value + Module->base - Section->s_vaddr;
-      (*Location) = (*Location);
-      DPRINT("Module->base %x Section->s_vaddr %x\n", 
-             Module->base, 
-             Section->s_vaddr);
-    }
-  else
-    {
-      DPRINT("REL32 value %x name %s\n", Value, Name);
-      Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
-      DPRINT("old %x ", *Location);
-      DPRINT("Module->base %x Section->s_vaddr %x\n",
-             Module->base,
-             Section->s_vaddr);
-      (*Location) = (*Location) + Value - Module->base + Section->s_vaddr;
-      DPRINT("new %x\n", *Location);
-    }
-
-  return TRUE;
-}
-
-/*
- * FUNCTION: Get the name of a symbol from a loaded module by ordinal
- * ARGUMENTS:
- *      mod = module
- *      i = index of symbol
- *      name (OUT) = pointer to a string where the symbol name will be
- *                   stored
- */
-
-static void 
-LdrCOFFGetSymbolName(module *Module, unsigned int Idx, char *Name)
-{
-  if (Module->sym_list[Idx].e.e_name[0] != 0)
-    {
-      strncpy(Name, Module->sym_list[Idx].e.e_name, 8);
-      Name[8] = '\0';
+      wcscat(NameBuffer, wcsrchr(FileName->Buffer, '\\') + 1);
     }
   else
     {
-      strcpy(Name, &Module->str_tab[Module->sym_list[Idx].e.e.e_offset]);
+      wcscat(NameBuffer, FileName->Buffer);
     }
-}
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  DbgPrint("Module name is: %wZ\n", &ModuleName);
 
-/*
- * FUNCTION: Get the value of a module defined symbol
- * ARGUMENTS:
- *      mod = module
- *      i = index of symbol
- * RETURNS: The value of the symbol
- * NOTE: This fixes up references to known sections
- */
-
-static unsigned int 
-LdrCOFFGetSymbolValue(module *Module, unsigned int Idx)
-{
-  char Name[255];
-
-  LdrCOFFGetSymbolName(Module, Idx, Name);
-  DPRINT("name %s ", Name);
-   
-  /*  Check if the symbol is a section we have relocated  */
-  if (strcmp(Name, ".text") == 0)
-    {
-      return Module->text_base;
-    }
-  if (strcmp(Name, ".data") == 0)
-    {
-      return Module->data_base;
-    }
-  if (strcmp(Name, ".bss") == 0)
-    {
-      return Module->bss_base;
-    }
-
-  return Module->sym_list[Idx].e_value;
-}
-
-/*
- * FUNCTION: Get the address of a kernel symbol
- * ARGUMENTS:
- *      name = symbol name
- * RETURNS: The address of the symbol on success
- *          NULL on failure
- */
-
-static unsigned int  
-LdrGetKernelSymbolAddr(char *Name)
-{
-  int i = 0;
-
-  while (symbol_table[i].name != NULL)
-    {
-      if (strcmp(symbol_table[i].name, Name) == 0)
-        {
-          return symbol_table[i].value;
-        }
-      i++;
-    }
+  /*  Initialize ObjectAttributes for ModuleObject  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
 
-  return 0L;
+  /*  Create module object  */
+  ModuleHandle = 0;
+  ModuleObject = ObCreateObject(&ModuleHandle,
+                                STANDARD_RIGHTS_REQUIRED,
+                                &ObjectAttributes,
+                                IoDriverObjectType);
+
+   /*  Initialize ModuleObject data  */
+   ModuleObject->Base = DriverBase;
+   ModuleObject->Flags = MODULE_FLAG_PE;
+   InsertTailList(&ModuleListHead,
+                 &ModuleObject->ListEntry);
+   RtlCreateUnicodeString(&ModuleObject->FullName,
+                         FileName->Buffer);
+   LdrpBuildModuleBaseName(&ModuleObject->BaseName,
+                          &ModuleObject->FullName);
+
+  ModuleObject->EntryPoint = (PVOID) ((DWORD)DriverBase + 
+    PEOptionalHeader->AddressOfEntryPoint);
+  ModuleObject->Length = DriverSize;
+  DPRINT("entrypoint at %x\n", ModuleObject->EntryPoint);
+
+  ModuleObject->Image.PE.FileHeader =
+    (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
+
+  DPRINT("FileHeader at %x\n", ModuleObject->Image.PE.FileHeader);
+  ModuleObject->Image.PE.OptionalHeader = 
+    (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
+    sizeof(IMAGE_FILE_HEADER));
+  DPRINT("OptionalHeader at %x\n", ModuleObject->Image.PE.OptionalHeader);
+  ModuleObject->Image.PE.SectionList = 
+    (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
+    sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
+  DPRINT("SectionList at %x\n", ModuleObject->Image.PE.SectionList);
+
+  ModuleTextSection = ExAllocatePool(NonPagedPool, 
+                                    sizeof(MODULE_TEXT_SECTION));
+  ModuleTextSection->Base = (ULONG)DriverBase;
+  ModuleTextSection->Length = DriverSize;
+  ModuleTextSection->SymbolsBase = NULL;
+  ModuleTextSection->SymbolsLength = 0;
+  ModuleTextSection->Name = 
+    ExAllocatePool(NonPagedPool, 
+                  (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
+  wcscpy(ModuleTextSection->Name, NameBuffer);
+  InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
+
+#ifdef KDBG
+
+       /* Load symbols for module if available */
+  LdrLoadModuleSymbols(ModuleObject, ModuleTextSection);
+
+#endif /* KDBG */
+
+  return  ModuleObject;
 }
 
-static unsigned int 
-LdrCOFFGetSymbolValueByName(module *Module, 
-                            char *SymbolName,
-                            unsigned int Idx)
+static PVOID
+LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
+                      char *Name,
+                      unsigned short Hint)
 {
-  unsigned int i;
-  char Name[255];
-   
-  DPRINT("LdrCOFFGetSymbolValueByName(sname %s, idx %x)\n", SymbolName, Idx);
-   
-  for (i = 0; i < Module->nsyms; i++)
+  WORD  Idx;
+  PVOID  ExportAddress;
+  PWORD  OrdinalList;
+  PDWORD  FunctionList, NameList;
+   PIMAGE_EXPORT_DIRECTORY  ExportDir;
+   ULONG ExportDirSize;
+
+   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+     RtlImageDirectoryEntryToData(ModuleObject->Base,
+                                 TRUE,
+                                 IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                 &ExportDirSize);
+   DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
+   if (ExportDir == NULL)
+     {
+       return NULL;
+     }
+
+
+   FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
+   NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
+   OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
+
+  ExportAddress = 0;
+
+  if (Name != NULL)
     {
-      LdrCOFFGetSymbolName(Module, i, Name);
-      DPRINT("Scanning %s Value %x\n", Name, Module->sym_list[i].e_value);
-      if (strcmp(Name, SymbolName) == 0)
+      for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
         {
-          DPRINT("Returning %x\n", Module->sym_list[i].e_value);
-          return Module->sym_list[i].e_value;
-        }
-    }
-
-  return 0L;
-}
-
-NTSTATUS LdrLoadLibrary(HANDLE ProcessHandle,
-                        PHANDLE ModuleHandle,
-                        PCHAR Name)
-{
 #if 0
-  NTSTATUS Status;
-  ANSI_STRING afilename;
-  UNICODE_STRING ufilename,umodName;
-  PMODULE *Library, *Module;
-  OBJECT_ATTRIBUTES attr;
-  PWSTR Ignored;
-  char name2[512];
-
-  /* FIXME: this is broke  */
-  /* FIXME: check for module already loaded  */
-  /* FIXME: otherwise load module */
-  /* FIXME: we need to fix how modules are loaded so that they can
-            be shared... :(  */
-
-  /*  If module is already loaded, get a reference and return it  */
-  strcpy(name2, "\\modules\\");
-  strcat(name2, Name);
-  RtlInitAnsiString(&afilename, name2);
-  RtlAnsiStringToUnicodeString(&umodName, &afilename, TRUE);
-  InitializeObjectAttributes(&attr, &umodName, 0, NULL, NULL);
-  Status = ObOpenObjectByName(&attr, (PVOID *) &Library, &Ignored);
-  DPRINT("LoadLibrary : Status=%x,pLibrary=%x\n",Status, Library);
-  if (!NT_SUCCESS(Status) || Library == NULL)
-    {
-      strcpy(name2, "\\??\\C:\\reactos\\system\\");
-      strcat(name2, name);
-      RtlInitAnsiString(&afilename, name2);
-      RtlAnsiStringToUnicodeString(&ufilename, &afilename, TRUE);
-      DPRINT("LoadLibrary,load %s\n", name2);
-      Library = LdrLoadImage(&ufilename);
-      /* FIXME: execute start code ? */
-      Module = ObGenericCreateObject(NULL, PROCESS_ALL_ACCESS, &attr, ObModuleType);
-      if (Module)
-        {
-          memcpy(Module, Library, PMODULE);
-        }
-      else
-        {
-          DbgPrint("library object not created\n");
-        }
-      RtlFreeUnicodeString(&ufilename);
-      Status = ObOpenObjectByName(&attr, (PVOID *)&Library, &Ignored);
-    }
-  else
-    {
-      DPRINT("Library already loaded\n");
-      *Module = Library
-    }
-  RtlFreeUnicodeString(&umodName);
+          DPRINT("  Name:%s  NameList[%d]:%s\n", 
+                 Name, 
+                 Idx, 
+                 (DWORD) ModuleObject->Base + NameList[Idx]);
 
-  return STATUS_SUCCESS;
 #endif
-  UNIMPLEMENTED;
-}
-
-/*   LdrLoadImage
- * FUNCTION:
- *   Loads a module into the specified process
- * ARGUMENTS:
- *   HANDLE   ProcessHandle  handle of the process to load the module into
- *   PHANDLE  ModuleHandle   handle of the loaded module
- *   PUNICODE_STRING  Filename  name of the module to load
- * RETURNS: 
- *   NTSTATUS
- */
-
-NTSTATUS 
-LdrLoadImage(HANDLE ProcessHandle, 
-             PHANDLE ModuleHandle, 
-             PUNICODE_STRING Filename)
-{
-  char BlockBuffer[1024];
-  NTSTATUS Status;
-  OBJECT_ATTRIBUTES FileObjectAttributes;
-  HANDLE FileHandle;
-  PMODULE Module;
-  PIMAGE_DOS_HEADER PEDosHeader;
-
-  /*  FIXME: should DLLs be named sections?  */
-
-  /*  Open the image file  */
-  InitializeObjectAttributes(&FileObjectAttributes,
-                             Filename, 
-                             0,
-                             NULL,
-                             NULL);
-  Status = ZwOpenFile(&FileHandle, 0, &FileObjectAttributes, NULL, 0, 0);
-  if (!NT_SUCCESS(Status))
-    {
-      return Status;
+          if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
+            {
+              ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
+                FunctionList[OrdinalList[Idx]]);
+                 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
+                     ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
+                   {
+                      DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
+                      ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
+                      DPRINT("ExportAddress: %p\n", ExportAddress);
+                   }
+
+              break;
+            }
+        }
     }
-
-  /*  Build a module structure for the image  */
-  Module = ObGenericCreateObject(ModuleHandle, 
-                                 PROCESS_ALL_ACCESS, 
-                                 NULL,
-                                 ObModuleType);
-  if (Module == NULL)
+  else  /*  use hint  */
     {
-      ZwClose(FileHandle);
-      return Status;
+      ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
+        FunctionList[Hint - ExportDir->Base]);
     }
 
-  /*  Read first block of image to determine type  */
-  Status = ZwReadFile(FileHandle, 0, 0, 0, 0, BlockBuffer, 1024, 0, 0);
-  if (!NT_SUCCESS(Status))
-    {
-      ObDereferenceObject(*ModuleHandle);
-      *ModuleHandle = NULL;
-      ZwClose(FileHandle);
-
-      return Status;
-    }    
-
-  /*  If MZ header exists  */
-  PEDosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
-  if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && 
-      PEDosHeader->e_lfanew != 0L &&
-      *(PULONG)((PUCHAR)BlockBuffer + PEDosHeader->e_lfanew) == IMAGE_PE_MAGIC)
-    {
-      Status = LdrProcessPEImage(ProcessHandle, 
-                                 ModuleHandle,
-                                 FileHandle);
-    }
-  else if (PEDosHeader->e_magic == 0x54AD)
-    {
-      Status = LdrProcessMZImage(ProcessHandle, 
-                                 ModuleHandle,
-                                 FileHandle);
-    }
-  else /*  Assume bin format and load  */
-    {
-      Status = LdrProcessBinImage(ProcessHandle, 
-                                  ModuleHandle,
-                                  FileHandle);
-    }
-  /* FIXME: {else} could check for a.out, ELF, COFF, etc. images here... */
+   if (ExportAddress == 0)
+     {
+       DbgPrint("Export not found for %d:%s\n",
+                Hint,
+                Name != NULL ? Name : "(Ordinal)");
+       KeBugCheck(0);
+     }
 
-  /* FIXME: should we unconditionally dereference the module handle here?  */
-  if (!NT_SUCCESS(Status))
-    {
-      ObDereferenceObject(*ModuleHandle);
-      *ModuleHandle = NULL;
-    }
-  ZwClose(FileHandle);
-
-  return Status;
+   return ExportAddress;
 }
 
-static NTSTATUS 
-LdrProcessMZImage(HANDLE ProcessHandle, 
-                  HANDLE ModuleHandle,
-                  HANDLE FileHandle)
-{
-
-  /* FIXME: map VDM into low memory  */
-  /* FIXME: Build/Load image sections  */
-   
-  return STATUS_NOT_IMPLEMENTED;
-}
 
-static NTSTATUS 
-LdrProcessPEImage(HANDLE ProcessHandle, 
-                  HANDLE ModuleHandle,
-                  HANDLE FileHandle)
+static PMODULE_OBJECT
+LdrPEGetModuleObject(PUNICODE_STRING ModuleName)
 {
-  int i;
-  NTSTATUS Status;
-  PVOID BaseSection;
-  PIMAGE_DOS_HEADER DosHeader;
-  PIMAGE_NT_HEADERS NTHeaders;
-  PMODULE Module;
-  LARGE_INTEGER SectionOffset;
-
-  /*  Allocate memory for headers  */
-  Module = HEADER_TO_BODY(ModuleHandle);
-  if (Module == NULL)
-    {
-      return STATUS_UNSUCCESSFUL;
-    }
-  DosHeader = (PIMAGE_DOS_HEADER)ExAllocatePool(NonPagedPool, 
-                                                sizeof(IMAGE_DOS_HEADER) +
-                                                sizeof(IMAGE_NT_HEADERS));
-  if (DosHeader == NULL)
-    {
-      return STATUS_UNSUCCESSFUL;
-    }
-  NTHeaders = (PIMAGE_NT_HEADERS)((PUCHAR) DosHeader + sizeof(IMAGE_DOS_HEADER));
-  
-  /*  Read the headers into memory  */
-  memset(Module, '\0', sizeof(PMODULE));
-  Status = ZwReadFile(FileHandle,
-                      NULL, NULL, NULL, NULL,
-                      DosHeader, 
-                      sizeof(IMAGE_DOS_HEADER),
-                      0, 0);
-  if (!NT_SUCCESS(Status))
-    {
-      ExFreePool(DosHeader);
-      return Status;
-    }
-  SET_LARGE_INTEGER_HIGH_PART(SectionOffset, 0);
-  SET_LARGE_INTEGER_LOW_PART(SectionOffset, DosHeader->e_lfanew);
-  Status = ZwReadFile(FileHandle, 
-                      NULL, NULL, NULL, NULL,
-                      NTHeaders,
-                      sizeof(IMAGE_NT_HEADERS), 
-                      &SectionOffset, 
-                      0);
-  if (!NT_SUCCESS(Status))
-    {
-      ExFreePool(DosHeader);
-      return Status;
-    }
-      
-  /*  Allocate memory in process for image  */
-  Module->Flags = MODULE_FLAG_PE;
-  Module->Base = (PVOID) NTHeaders->OptionalHeader.ImageBase;
-  Module->Size = NTHeaders->OptionalHeader.SizeOfImage;
-  Status = ZwAllocateVirtualMemory(ProcessHandle,
-                                   &Module->Base,
-                                   0,
-                                   NULL,
-                                   MEM_COMMIT,
-                                   PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      ExFreePool(DosHeader);
-      return Status;
-    }
-
-  /*  Load headers into virtual memory  */
-  Status = ZwReadFile(FileHandle, 
-                      NULL, NULL, NULL, NULL,
-                      Module->Base,
-                      NTHeaders->OptionalHeader.SizeOfHeaders,
-                      0, 0);
-  if (!NT_SUCCESS(Status))
-    {
-      ZwFreeVirtualMemory(ProcessHandle, 
-                          Module->Base, 
-                          0, 
-                          MEM_RELEASE);
-      ExFreePool(DosHeader);
-      return Status;
-    }
-
-  /*  Adjust module pointers into virtual memory  */
-  DosHeader = (PIMAGE_DOS_HEADER) Module->Base;
-  NTHeaders = (PIMAGE_NT_HEADERS) ((PUCHAR)Module->Base + 
-    DosHeader->e_lfanew);
-  Module->Image.PE.FileHeader = (PIMAGE_FILE_HEADER) ((PUCHAR)NTHeaders + 
-    sizeof(DWORD));
-  Module->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
-    ((PUCHAR)Module->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
-  Module->Image.PE.SectionList = (PCOFF_SECTION_HEADER) ((PUCHAR)NTHeaders + 
-    sizeof(IMAGE_NT_HEADERS));
-
-  /*  Build Image Sections  */
-  /* FIXME: should probably use image directory to load sections. */
-  for (i = 0; i < Module->Image.PE.FileHeader->NumberOfSections; i++)
-    {
-      DPRINT("section %d\n", i);
-      BaseSection = (PVOID)((PCHAR) Module->Base + 
-        Module->Image.PE.SectionList[i].s_vaddr);
-
-      /* Load code and initialized data sections from disk  */
-      if ((Module->Image.PE.SectionList[i].s_flags & STYP_TEXT) ||
-          (Module->Image.PE.SectionList[i].s_flags & STYP_DATA))
-        {
-          SET_LARGE_INTEGER_HIGH_PART(SectionOffset, 0);
-          SET_LARGE_INTEGER_LOW_PART(SectionOffset, 
-                                     Module->Image.PE.SectionList[i].s_scnptr);
-
-          /* FIXME: should probably map sections into sections */
-          Status = ZwReadFile(FileHandle,
-                              NULL, NULL, NULL, NULL,
-                              Module->Base + Module->Image.PE.SectionList[i].s_vaddr,
-                              min(Module->Image.PE.SectionList[i].s_size,
-                                  Module->Image.PE.SectionList[i].s_paddr),
-                              &SectionOffset, 0);
-          if (!NT_SUCCESS(Status))
-            {
-              ZwFreeVirtualMemory(ProcessHandle, 
-                                  Module->Base, 
-                                  0, 
-                                  MEM_RELEASE);
-              ExFreePool(DosHeader);
-              return Status;
-            }
-        }
-      else if (Module->Image.PE.SectionList[i].s_flags & STYP_BSS)
-        {
-          memset((PVOID)(Module->Base + 
-                   Module->Image.PE.SectionList[i].s_vaddr), 
-                 0,
-                 Module->Image.PE.SectionList[i].s_size);
-        }
-    }
+   PLIST_ENTRY Entry;
+   PMODULE_OBJECT Module;
 
-  /*  Resolve Import Library references  */
-  if (Module->Image.PE.OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
-    {
-      PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
-
-      /*  Process each import module  */
-      ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
-        ((PUCHAR)Module->Base + Module->Image.PE.OptionalHeader->
-          DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
-      while (ImportModuleDirectory->dwRVAModuleName)
-        {
-          PMODULE Library;
-          PVOID *LibraryExports;
-          PVOID *ImportAddressList; // was pImpAddr
-          PULONG FunctionNameList;
-          DWORD pName;
-          PWORD pHint;
-
-          /*  Load the library module into the process  */
-          /* FIXME: this should take a UNICODE string  */
-          Status = LdrLoadLibrary(ProcessHandle,
-                                  &Library,
-                                  (PCHAR)(Module->Base + 
-                                    ImportModuleDirectory->dwRVAModuleName));
-          if (!NT_SUCCESS(Status))
-            {
-              /* FIXME: Dereference all loaded modules  */
-              ZwFreeVirtualMemory(ProcessHandle, 
-                                  Module->Base, 
-                                  0, 
-                                  MEM_RELEASE);
-              ExFreePool(DosHeader);
-
-              return Status;              
-            }          
-
-          /*  Get the address of the export list for the library  */
-          LibraryExports = (PVOID *)(Library->Base + 
-            Library->Image.PE.OptionalHeader->
-            DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress +
-            sizeof(IMAGE_EXPORT_DIRECTORY));
+   DPRINT("LdrPEGetModuleObject (ModuleName %wZ)\n",
+          ModuleName);
 
-          /*  Get the import address list  */
-          ImportAddressList = (PVOID *)
-            ((PCHAR)Module->Image.PE.OptionalHeader->ImageBase + 
-            ImportModuleDirectory->dwRVAFunctionAddressList);
+   Entry = ModuleListHead.Flink;
 
-          /*  Get the list of functions to import  */
-          if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
-            {
-              FunctionNameList = (PULONG) ((PCHAR)Module->Base + 
-                ImportModuleDirectory->dwRVAFunctionNameList);
-            }
-          else
-            {
-              FunctionNameList = (PULONG) ((PCHAR)Module->Base + 
-                ImportModuleDirectory->dwRVAFunctionAddressList);
-            }
+   while (Entry != &ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
 
-          /*  Walk through function list and fixup addresses  */
-          while(*FunctionNameList != 0L)
-            {
-              if ((*FunctionNameList) & 0x80000000) // hint
-                {
-                  *ImportAddressList = LibraryExports[(*FunctionNameList) & 0x7fffffff];
-                }
-              else // hint-name
-                {
-                  pName = (DWORD)((PCHAR)Module->Base + *FunctionNameList + 2);
-                  pHint = (PWORD)((PCHAR)Module->Base + *FunctionNameList);
+       DPRINT("Comparing %wZ and %wZ\n",
+              &Module->BaseName,
+              ModuleName);
 
-                  /* FIXME: verify name  */
+       if (!RtlCompareUnicodeString(&Module->BaseName, ModuleName, TRUE))
+         {
+            DPRINT("Module %x\n", Module);
+            return Module;
+         }
 
-                  *ImportAddressList = LibraryExports[*pHint];
-                }
+       Entry = Entry->Flink;
+     }
 
-              /* FIXME: verify value of hint  */
+   DbgPrint("LdrPEGetModuleObject: Failed to find dll %wZ\n", ModuleName);
 
-              ImportAddressList++;
-              FunctionNameList++;
-            }
-          ImportModuleDirectory++;
-        }
-    }
+   return NULL;
+}
 
-  /*  Do fixups  */
-  if (Module->Base != (PVOID)Module->Image.PE.OptionalHeader->ImageBase)
-    {
-      USHORT NumberOfEntries;
-      PUSHORT pValue16;
-      ULONG RelocationRVA;
-      ULONG Delta32, Offset;
-      PULONG pValue32;
-      PRELOCATION_DIRECTORY RelocationDir;
-      PRELOCATION_ENTRY RelocationBlock;
-
-      RelocationRVA = NTHeaders->OptionalHeader.DataDirectory[
-        IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
-      if (RelocationRVA)
-        {
-          RelocationDir = (PRELOCATION_DIRECTORY)
-            ((PCHAR)Module->Base + RelocationRVA);
-          while (RelocationDir->SizeOfBlock)
-            {
-              Delta32 = (unsigned long)(Module->Base - NTHeaders->OptionalHeader.ImageBase);
-              RelocationBlock = (PRELOCATION_ENTRY) 
-                (RelocationRVA + Module->Base + sizeof(RELOCATION_DIRECTORY));
-              NumberOfEntries = 
-                (RelocationDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
-                sizeof(RELOCATION_ENTRY);
-              for (i = 0; i < NumberOfEntries; i++)
-                {
-                  Offset = (RelocationBlock[i].TypeOffset & 0xfff) + RelocationDir->VirtualAddress;
-                  switch (RelocationBlock[i].TypeOffset >> 12)
-                    {
-                      case TYPE_RELOC_ABSOLUTE:
-                        break;
-
-                      case TYPE_RELOC_HIGH:
-                        pValue16 = (PUSHORT) (Module->Base + Offset);
-                        *pValue16 += Delta32 >> 16;
-                        break;
-
-                      case TYPE_RELOC_LOW:
-                        pValue16 = (PUSHORT)(Module->Base + Offset);
-                        *pValue16 += Delta32 & 0xffff;
-                        break;
-
-                      case TYPE_RELOC_HIGHLOW:
-                        pValue32 = (PULONG) (Module->Base + Offset);
-                        *pValue32 += Delta32;
-                        break;
-
-                      case TYPE_RELOC_HIGHADJ:
-                        /* FIXME: do the highadjust fixup  */
-                        DbgPrint("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
-//                        break;
-
-                      default:
-                        DbgPrint("unexpected fixup type\n");
-
-                        /* FIXME: Dereference all loaded modules  */
-
-                        ZwFreeVirtualMemory(ProcessHandle, 
-                                            Module->Base, 
-                                            0, 
-                                            MEM_RELEASE);
-                        ExFreePool(DosHeader);
-                        return STATUS_UNSUCCESSFUL;
-                    }
-                }
-              RelocationRVA += RelocationDir->SizeOfBlock;
-              RelocationDir = (PRELOCATION_DIRECTORY)((PCHAR)Module->Base + 
-                RelocationRVA);
-            }
-        }
-    }
 
-  /* FIXME: Create the stack for the process  */
-  /* FIXME: Setup the context for the initial thread  */
-  /* FIXME: Create the initial thread  */
+static PVOID
+LdrPEFixupForward(PCHAR ForwardName)
+{
+   CHAR NameBuffer[128];
+   UNICODE_STRING ModuleName;
+   PCHAR p;
+   PMODULE_OBJECT ModuleObject;
 
-// fail: ZwFreeVirtualMemory(ProcessHandle, Module->ImageBase, 0, MEM_RELEASE);
-  ExFreePool(DosHeader);
+   DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
 
-  return STATUS_NOT_IMPLEMENTED;
-}
+   strcpy(NameBuffer, ForwardName);
+   p = strchr(NameBuffer, '.');
+   if (p == NULL)
+     {
+       return NULL;
+     }
 
-NTSTATUS
-LdrProcessBinImage(HANDLE ProcessHandle, 
-                   HANDLE ModuleHandle,
-                   HANDLE FileHandle)
-{
-  NTSTATUS Status;
-  FILE_STANDARD_INFORMATION FileStdInfo;
-  ULONG SectionSize;
-  HANDLE ThreadHandle;   
-  CONTEXT Context;
-  HANDLE SectionHandle;
-  PVOID BaseAddress;
+   *p = 0;
 
-  /* FIXME: should set module pointers  */
+   DPRINT("Driver: %s  Function: %s\n", NameBuffer, p+1);
 
-  /*  Get the size of the file for the section  */
-  Status = ZwQueryInformationFile(FileHandle,
-                                  NULL,
-                                  &FileStdInfo,
-                                  sizeof(FileStdInfo),
-                                  FileStandardInformation);
-  if (!NT_SUCCESS(Status))
-    {
-      return Status;
-    }
+   RtlCreateUnicodeStringFromAsciiz(&ModuleName,
+                                   NameBuffer);
+   ModuleObject = LdrPEGetModuleObject(&ModuleName);
+   RtlFreeUnicodeString(&ModuleName);
 
-  /*  Create the section for the code  */
-  Status = ZwCreateSection(&SectionHandle,
-                           SECTION_ALL_ACCESS,
-                           NULL,
-                           NULL,
-                           PAGE_READWRITE,
-                           MEM_COMMIT,
-                           FileHandle);
-  if (!NT_SUCCESS(Status))
-    {
-      return Status;
-    }
+   DPRINT("ModuleObject: %p\n", ModuleObject);
 
-  /*  Map a view of the section into the desired process  */
-  BaseAddress = (PVOID)0x10000;
-  SectionSize = GET_LARGE_INTEGER_LOW_PART(FileStdInfo.AllocationSize);
-  Status = ZwMapViewOfSection(SectionHandle,
-                              ProcessHandle,
-                              &BaseAddress,
-                              0,
-                              SectionSize,
-                              NULL,
-                              &SectionSize,
-                              0,
-                              MEM_COMMIT,
-                              PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      /* FIXME: destroy the section here  */
-       return Status;
-    }
-  /*  Setup the context for the initial thread  */
-  memset(&Context,0,sizeof(CONTEXT));
-  Context.SegSs = USER_DS;
-  Context.Esp = 0x2000;
-  Context.EFlags = 0x202;
-  Context.SegCs = USER_CS;
-  Context.Eip = 0x10000;
-  Context.SegDs = USER_DS;
-  Context.SegEs = USER_DS;
-  Context.SegFs = USER_DS;
-  Context.SegGs = USER_DS;
-   
-  /*  Create the stack for the process  */
-  BaseAddress = (PVOID) 0x1000;
-  SectionSize = 0x1000;
-  Status = ZwAllocateVirtualMemory(ProcessHandle,
-                                   &BaseAddress,
-                                   0,
-                                   &SectionSize,
-                                   MEM_COMMIT,
-                                   PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      /* FIXME: unmap the section here  */
-      /* FIXME: destroy the section here  */
+   if (ModuleObject == NULL)
+     {
+       DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
+       return NULL;
+     }
 
-      return Status;
-    }
-   
-  /*  Create the initial thread  */
-  Status = ZwCreateThread(&ThreadHandle,
-                          THREAD_ALL_ACCESS,
-                          NULL,
-                          ProcessHandle,
-                          NULL,
-                          &Context,
-                          NULL,
-                          FALSE);
-  if (!NT_SUCCESS(Status))
-    {
-      /* FIXME: destroy the stack memory block here  */
-      /* FIXME: unmap the section here  */
-      /* FIXME: destroy the section here  */
-       return Status;
-    }
-
-  return STATUS_SUCCESS;
+   return LdrPEGetExportAddress(ModuleObject, p+1, 0);
 }
 
 
+/* EOF */