Implement DLL loading on the client side (partial implementation).
authorMarcus Brinkmann <marcus.brinkmann@ruhr-uni-bochum.de>
Tue, 5 Oct 2010 04:04:16 +0000 (06:04 +0200)
committerMarcus Brinkmann <marcus.brinkmann@ruhr-uni-bochum.de>
Tue, 5 Oct 2010 04:04:16 +0000 (06:04 +0200)
loader/ntdll_loader.c
loader/ntdll_virtual.c

index 14e430c..f5ee763 100644 (file)
 \r
 #include "wine.h"\r
 \r
+/* convert PE image VirtualAddress to Real Address */\r
+static void *get_rva( HMODULE module, DWORD va )\r
+{\r
+  return (void *)((char *)module + va);\r
+}\r
+\r
+\r
+#define USE_HIMEMCE_MAP\r
+#ifdef USE_HIMEMCE_MAP\r
+/* Support for DLL loading.  */\r
+\r
+#include "himemce-map.h"\r
+\r
+static int himemce_map_initialized;\r
+static struct himemce_map *himemce_map;\r
+int himemce_mod_loaded[HIMEMCE_MAP_MAX_MODULES];\r
+\r
+static void\r
+himemce_map_init ()\r
+{\r
+  void *ptr;\r
+  /* Only try once.  */\r
+  if (himemce_map_initialized)\r
+         return;\r
+  himemce_map_initialized = 1;\r
+  himemce_map = himemce_map_open ();
+  if (! himemce_map)
+    {
+               TRACE ("can not open himemce map\n");
+        return;\r
+    }\r
+  TRACE ("himemce map found at %p (reserving 0x%x bytes at %p)\n", himemce_map,\r
+         himemce_map->low_start, himemce_map->low_size);\r
+  ptr = VirtualAlloc(himemce_map->low_start, himemce_map->low_size,\r
+           MEM_RESERVE, PAGE_EXECUTE_READWRITE);\r
+  if (! ptr)\r
+  {\r
+         TRACE ("failed to reserve memory: %i\n", GetLastError ());\r
+         himemce_map_close (himemce_map);\r
+         himemce_map = NULL;\r
+      return;\r
+  }\r
+}\r
+\r
+\r
+# define page_mask  0xfff\r
+# define page_shift 12\r
+# define page_size  0x1000\r
+\r
+#define ROUND_SIZE(size) \\r
+  (((SIZE_T)(size) + page_mask) & ~page_mask)\r
+\r
+static SIZE_T\r
+section_size (IMAGE_SECTION_HEADER *sec)\r
+{\r
+  static const SIZE_T sector_align = 0x1ff;\r
+  SIZE_T map_size, file_size, end;\r
+\r
+  if (!sec->Misc.VirtualSize)\r
+    map_size = ROUND_SIZE( sec->SizeOfRawData );\r
+  else\r
+    map_size = ROUND_SIZE( sec->Misc.VirtualSize );\r
+\r
+  file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align;\r
+  if (file_size > map_size) file_size = map_size;\r
+  end = ROUND_SIZE( file_size );\r
+  if (end > map_size) end = map_size;\r
+  return end;\r
+}\r
+\r
+\r
+/* Returns the base of the module after loading it, if necessary.\r
+   NULL if not found, -1 if a fatal error occurs.  */\r
+void *\r
+himemce_map_load_dll (const char *name)\r
+{\r
+  struct himemce_module *mod;\r
+  int modidx;\r
+  char *ptr;\r
+  IMAGE_DOS_HEADER *dos;\r
+  IMAGE_NT_HEADERS *nt;\r
+  IMAGE_SECTION_HEADER *sec;\r
+  int sec_cnt;\r
+  int idx;\r
+  const IMAGE_IMPORT_DESCRIPTOR *imports;\r
+  DWORD imports_size;\r
+\r
+  himemce_map_init ();\r
+  if (! himemce_map)\r
+         return NULL;\r
+\r
+  mod = himemce_map_find_module (himemce_map, name);\r
+  if (!mod)\r
+         return NULL;\r
+  modidx = mod - himemce_map->module;\r
+  if (himemce_mod_loaded[modidx])\r
+         return mod->base;\r
+\r
+  /* First map the sections low.  */\r
+  ptr = mod->base;\r
+  dos = (IMAGE_DOS_HEADER *) ptr;\r
+  nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);\r
+  sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader\r
+                                  + nt->FileHeader.SizeOfOptionalHeader);\r
+  sec_cnt = nt->FileHeader.NumberOfSections;\r
+  for (idx = 0; idx < sec_cnt; idx++)\r
+  {\r
+       size_t secsize;\r
+       char *secptr;\r
+\r
+       if (! sec[idx].PointerToLinenumbers)\r
+         continue;\r
+       secsize = section_size (&sec[idx]);\r
+    secptr = VirtualAlloc ((void *) sec[idx].PointerToLinenumbers,\r
+               secsize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
+       if (! secptr)\r
+       {\r
+               TRACE ("could not allocate 0x%x bytes of low memory at %p: %i\n",\r
+                       secsize, sec[idx].PointerToLinenumbers, GetLastError ());\r
+               return (void *) -1;\r
+       }\r
+    memcpy (secptr, ptr + sec[idx].VirtualAddress, secsize);\r
+  }\r
+\r
+  /* To break circles, we claim that we loaded before recursing.  */\r
+  himemce_mod_loaded[modidx]++;\r
+  imports = MyRtlImageDirectoryEntryToData ((HMODULE) ptr, TRUE,\r
+                                            IMAGE_DIRECTORY_ENTRY_IMPORT,\r
+                                            &imports_size);\r
+  if (imports)\r
+  {\r
+       idx = 0;\r
+       while (imports[idx].Name && imports[idx].FirstThunk)\r
+       {\r
+               char *iname = ptr + imports[idx].Name;\r
+               void *ibase;\r
+\r
+               /* Recursion!  */\r
+               ibase = himemce_map_load_dll (iname);\r
+               if (ibase == (void *) -1)\r
+                       return (void *) -1;\r
+               /* Nothing to do if ibase !=0: Successful loading of high DLL.  */\r
+               if (ibase == 0)\r
+               {\r
+                       ibase = LoadLibrary (iname);\r
+                       if (!ibase)\r
+                       {\r
+                               TRACE ("Could not find %s, dependency of %s\n", iname, name);\r
+                               return (void *) -1;\r
+                       }\r
+               }\r
+               idx++;\r
+       }\r
+  }\r
+  return ptr;\r
+}\r
+\r
+\r
+static void *\r
+get_rva_low (char *module, size_t rva)\r
+{\r
+  IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;\r
+  IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(module + dos->e_lfanew);\r
+  IMAGE_SECTION_HEADER *sec;\r
+  int sec_cnt;\r
+  int idx;\r
+\r
+  sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeO\\r
+fOptionalHeader);\r
+  sec_cnt = nt->FileHeader.NumberOfSections;\r
+\r
+  for (idx = 0; idx < sec_cnt; idx++)\r
+    {\r
+      if (! sec[idx].PointerToLinenumbers)\r
+        continue;\r
+      if (rva >= sec[idx].VirtualAddress\r
+          && rva < sec[idx].VirtualAddress + section_size (&sec[idx]))\r
+                break;\r
+    }\r
+  if (idx == sec_cnt)\r
+    return (void *)((char *)module + rva);\r
+\r
+  return (void *)((char *)sec[idx].PointerToLinenumbers\r
+                  + (rva - sec[idx].VirtualAddress));\r
+}\r
+\r
+\r
+static FARPROC\r
+find_ordinal_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,\r
+                     DWORD exp_size, DWORD ordinal, LPCWSTR load_path)\r
+{\r
+  FARPROC proc;\r
+  const DWORD *functions = get_rva (module, exports->AddressOfFunctions);\r
+\r
+  if (ordinal >= exports->NumberOfFunctions)\r
+    {\r
+      TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );\r
+      return NULL;\r
+    }\r
+  if (!functions[ordinal]) return NULL;\r
+\r
+#if 0\r
+  /* if the address falls into the export dir, it's a forward */\r
+  if (((const char *)proc >= (const char *)exports) &&\r
+      ((const char *)proc < (const char *)exports + exp_size))\r
+    return find_forwarded_export( module, (const char *)proc, load_path );\r
+#endif\r
+\r
+  proc = get_rva_low (module, functions[ordinal]);\r
+  return proc;\r
+}\r
+\r
+static FARPROC\r
+find_named_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,\r
+                   DWORD exp_size, const char *name, int hint, LPCWSTR load_path)\r
+{\r
+  const WORD *ordinals = get_rva (module, exports->AddressOfNameOrdinals);\r
+  const DWORD *names = get_rva (module, exports->AddressOfNames);\r
+  int min = 0, max = exports->NumberOfNames - 1;\r
+\r
+  /* first check the hint */\r
+  if (hint >= 0 && hint <= max)\r
+    {\r
+      char *ename = get_rva( module, names[hint] );\r
+      if (!strcmp( ename, name ))\r
+        return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path);\r
+    }\r
+\r
+  /* then do a binary search */\r
+  while (min <= max)\r
+    {\r
+      int res, pos = (min + max) / 2;\r
+      char *ename = get_rva( module, names[pos] );\r
+      if (!(res = strcmp( ename, name )))\r
+        return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path);\r
+      if (res > 0) max = pos - 1;\r
+      else min = pos + 1;\r
+    }\r
+  return NULL;\r
+}\r
+\r
+#endif\r
+\r
+\r
 PIMAGE_NT_HEADERS MyRtlImageNtHeader(HMODULE hModule)\r
 {\r
     IMAGE_NT_HEADERS *ret;\r
@@ -115,13 +359,6 @@ PVOID MyRtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULON
 }\r
 \r
 \r
-/* convert PE image VirtualAddress to Real Address */\r
-static void *get_rva( HMODULE module, DWORD va )\r
-{\r
-  return (void *)((char *)module + va);\r
-}\r
-\r
-\r
 #define allocate_stub(x,y) (0xdeadbeef)\r
 \r
 /*************************************************************************\r
@@ -135,8 +372,11 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
   NTSTATUS status = STATUS_SUCCESS;\r
   //  WINE_MODREF *wmImp;\r
   HMODULE imp_mod;\r
-  //  const IMAGE_EXPORT_DIRECTORY *exports;\r
-  //  DWORD exp_size;\r
+#ifdef USE_HIMEMCE_MAP\r
+  void *imp_base = 0;\r
+  const IMAGE_EXPORT_DIRECTORY *exports;\r
+  DWORD exp_size;\r
+#endif\r
   const IMAGE_THUNK_DATA *import_list;\r
   IMAGE_THUNK_DATA *thunk_list;\r
   WCHAR buffer[32];\r
@@ -164,16 +404,23 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
     iscoredll = 1;\r
 #endif\r
 \r
+#ifdef USE_HIMEMCE_MAP\r
+  imp_base = himemce_map_load_dll (name);\r
+  if (imp_base == (void *) -1)\r
+    status = GetLastError ();\r
+  if (imp_base)\r
+    goto loaded;\r
+#endif\r
+\r
   if (len * sizeof(WCHAR) < sizeof(buffer))\r
     {\r
-\r
       ascii_to_unicode( buffer, name, len );\r
       buffer[len] = 0;\r
       //      status = load_dll( load_path, buffer, 0, &wmImp );\r
       imp_mod = LoadLibrary (buffer);\r
-      if (imp_mod == INVALID_HANDLE_VALUE)\r
-       status = GetLastError ();\r
-    }\r
+         if (imp_mod == INVALID_HANDLE_VALUE)\r
+           status = GetLastError ();\r
+  }\r
   else  /* need to allocate a larger buffer */\r
     {\r
       WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );\r
@@ -181,11 +428,14 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
       ascii_to_unicode( ptr, name, len );\r
       ptr[len] = 0;\r
       // status = load_dll( load_path, ptr, 0, &wmImp );\r
-      imp_mod = LoadLibrary (ptr);\r
-      if (imp_mod == INVALID_HANDLE_VALUE)\r
-       status = GetLastError ();\r
-      free (ptr);\r
+         imp_mod = LoadLibrary (ptr);\r
+         if (imp_mod == INVALID_HANDLE_VALUE)\r
+           status = GetLastError ();\r
+         free (ptr);\r
     }\r
+#ifdef USE_HIMEMCE_MAP\r
+loaded:\r
+#endif\r
   if (status)\r
     {\r
       if (status == STATUS_DLL_NOT_FOUND)\r
@@ -196,7 +446,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
            name, current_modref->ldr.FullDllName, status);\r
       return NULL;\r
     }\r
-\r
+  \r
 #if 0\r
   /* unprotect the import address table since it can be located in\r
    * readonly section */\r
@@ -207,9 +457,10 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
                          &protect_size, PAGE_WRITECOPY, &protect_old );\r
 #endif\r
 \r
-#if 0\r
-  imp_mod = wmImp->ldr.BaseAddress;\r
-  exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );\r
+#ifdef USE_HIMEMCE_MAP\r
+ if (imp_base)\r
+ {\r
+   exports = MyRtlImageDirectoryEntryToData( imp_base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );\r
 \r
   if (!exports)\r
     {\r
@@ -219,16 +470,16 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
          if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
             {\r
              int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
-             WARN("No implementation for %s.%d", name, ordinal );\r
-             thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );\r
+             TRACE("No implementation for %s.%d", name, ordinal );\r
+             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)allocate_stub( name, IntToPtr(ordinal) );\r
             }\r
          else\r
             {\r
              IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
-             WARN("No implementation for %s.%s", name, pe_name->Name );\r
-             thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );\r
+             TRACE("No implementation for %s.%s", name, pe_name->Name );\r
+             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)allocate_stub( name, (const char*)pe_name->Name );\r
             }\r
-         WARN(" imported from %s, allocating stub %p\n",\r
+         TRACE(" imported from %s, allocating stub %p\n",\r
               current_modref->ldr.FullDllName,\r
               (void *)thunk_list->u1.Function );\r
          import_list++;\r
@@ -236,6 +487,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
         }\r
       goto done;\r
     }\r
+ }\r
 #endif\r
 \r
   while (import_list->u1.Ordinal)\r
@@ -244,8 +496,12 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
         {\r
          int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
 \r
-         //      thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,\r
-         //                                                                ordinal - exports->Base, load_path );\r
+#ifdef USE_HIMEMCE_MAP\r
+         if (imp_base)\r
+               thunk_list->u1.Function = (PDWORD)(ULONG_PTR)find_ordinal_export( imp_base, exports, exp_size,\r
+                                                                     ordinal - exports->Base, load_path );\r
+         else\r
+#endif\r
 \r
 #ifdef USE_DLMALLOC\r
          if (iscoredll)\r
@@ -282,13 +538,17 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
       else  /* import by name */\r
         {\r
          IMAGE_IMPORT_BY_NAME *pe_name;\r
-         const char *symname = (const char*)pe_name->Name;\r
+         const char *symname;\r
          pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
+         symname = (const char*)pe_name->Name;\r
 \r
-         //      thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,\r
-         //                                                              (const char*)pe_name->Name,\r
-         //                                                              pe_name->Hint, load_path );\r
-\r
+#ifdef USE_HIMEMCE_MAP\r
+         if (imp_base)\r
+                 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)find_named_export( imp_base, exports, exp_size,\r
+                                                                         (const char*)pe_name->Name,\r
+                                                                         pe_name->Hint, load_path );\r
+         else\r
+#endif\r
 #ifdef USE_DLMALLOC\r
          if (iscoredll)\r
            {\r
@@ -305,21 +565,21 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
            }\r
          else\r
 #endif\r
-           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, (const char*)pe_name->Name);\r
+           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, symname);\r
          if (!thunk_list->u1.Function)\r
             {\r
-             thunk_list->u1.Function = (PDWORD) allocate_stub( name, (const char*)pe_name->Name );\r
+             thunk_list->u1.Function = (PDWORD) allocate_stub (name, symname);\r
              TRACE("No implementation for %s.%s imported from %s, setting to %p\n",\r
-                   name, pe_name->Name, current_modref->ldr.FullDllName,\r
+                   name, symname, current_modref->ldr.FullDllName,\r
                    (void *)thunk_list->u1.Function );\r
             }\r
          TRACE("--- %s %s.%d = %p\n",\r
-               pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);\r
+               symname, name, pe_name->Hint, (void *)thunk_list->u1.Function);\r
         }\r
       import_list++;\r
       thunk_list++;\r
     }\r
-  // done:\r
+done:\r
 #if 0\r
   /* restore old protection of the import address table */\r
   NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );\r
index 5cb643f..6c19b0f 100644 (file)
@@ -113,7 +113,7 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size,
   \r
   // FIXME: Only with NOACCESS does Windows CE prefer the high mem area\r
   // even for smaller areas.\r
-  ptr = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS /*prot*/);\r
+  ptr = VirtualAlloc(base, size < (2* 1024*1024) ? 2*1024*1024 : size, MEM_RESERVE, PAGE_NOACCESS /*prot*/);\r
   if (!ptr)\r
     {\r
       free (view);\r