Convert to unix line endings.
[wincetools.git] / loader / himemce-pre.c
index bf93c25..fcbf09a 100644 (file)
- /* himemce-pre.c - High Memory for Windows CE (preloader)\r
-   Copyright (C) 2010 g10 Code GmbH\r
-   Written by Marcus Brinkmann <marcus@g10code.com>\r
-\r
-   This file is part of HiMemCE.\r
\r
-   HiMemCE is free software; you can redistribute it and/or modify it\r
-   under the terms of the GNU Lesser General Public License as\r
-   published by the Free Software Foundation; either version 2.1 of\r
-   the License, or (at your option) any later version.\r
-   \r
-   HiMemCE is distributed in the hope that it will be useful, but\r
-   WITHOUT ANY WARRANTY; without even the implied warranty of\r
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-   Lesser General Public License for more details.\r
-   \r
-   You should have received a copy of the GNU Lesser General Public\r
-   License along with this program; if not, write to the Free Software\r
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
-   02111-1307, USA.  */\r
-\r
-#include <windows.h>\r
-#include <assert.h>\r
-\r
-#include "debug.h"\r
-\r
-#include "kernel32_kernel_private.h"\r
-#include "wine.h"\r
-#include "himemce-map-provider.h"\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
-#define SECTION_IS_LOW(sec) \\r
-      (((sec)->Characteristics & IMAGE_SCN_MEM_WRITE) &&       \\r
-       ! ((sec)->Characteristics & IMAGE_SCN_MEM_SHARED))\r
-\r
-\r
-/* Find all modules to preload and add them to the map.  */\r
-static int\r
-find_modules (struct himemce_map *map)\r
-{\r
-  /* Five for "*.dll" and one for good luck.  */\r
-  wchar_t dirname[MAX_PATH + 6];\r
-  wchar_t filename[2 * MAX_PATH + 1];\r
-  int res;\r
-  wchar_t *end;\r
-  int idx;\r
-  HANDLE hSearch;\r
-  WIN32_FIND_DATA FileData;\r
-  BOOL bFinished = FALSE;\r
-\r
-  res = GetModuleFileName (GetModuleHandle (NULL), dirname, MAX_PATH);\r
-  if (! res)\r
-    {\r
-      ERR ("can not determine module filename: %i\n",\r
-            GetLastError ());\r
-      return 0;\r
-    }\r
-\r
-  idx = wcslen (dirname);\r
-  while (idx > 0 && dirname[idx - 1] != '\\' && dirname[idx - 1] != '/')\r
-    idx--;\r
-  dirname[idx] = '\0';\r
-\r
-  wcscpy (filename, dirname);\r
-  wcscpy (&dirname[idx], L"*.dll");\r
-  end = &filename[idx];\r
-\r
-  hSearch = FindFirstFile (dirname, &FileData);\r
-  if (hSearch == INVALID_HANDLE_VALUE)\r
-    {\r
-      ERR ("no .dll files found\n");\r
-      return 0;\r
-    }\r
-\r
-  while (!bFinished)\r
-    {\r
-      struct himemce_module *mod;\r
-      struct binary_info info;\r
-      HANDLE hnd;\r
-\r
-      TRACE ("considering %S: ", FileData.cFileName);\r
-\r
-      wcscpy (end, FileData.cFileName);\r
-\r
-      if (FileData.cFileName[0] != L'Q')\r
-       {\r
-         TRACE ("skip non-Qt library for testing\n");\r
-         goto skipit;\r
-       }\r
-\r
-      hnd = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,\r
-                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
-      if (hnd == INVALID_HANDLE_VALUE)\r
-       {\r
-         TRACE ("skip (probe failure: %i)\n", GetLastError ());\r
-         goto skipit;\r
-       }\r
-\r
-      MODULE_get_binary_info (hnd, &info);\r
-      CloseHandle (hnd);\r
-      if (info.machine != IMAGE_FILE_MACHINE_THUMB)\r
-       {\r
-         TRACE ("skip (machine type: %04x)\n", info.machine);\r
-         goto skipit;\r
-       }\r
-\r
-      /* FIXME: Keep a blacklist.  Maybe exclude ARM (not THUMB)\r
-        binaries automatically (gpgme and friends).  */\r
-\r
-      TRACE ("accept [%2i]\n", map->nr_modules);\r
-      mod = map_add_module (map, filename, 0);\r
-      if (! mod)\r
-       return 0;\r
-      \r
-    skipit:\r
-      if (!FindNextFile (hSearch, &FileData))\r
-       {\r
-         bFinished = TRUE;\r
-         \r
-         if (GetLastError () != ERROR_NO_MORE_FILES)\r
-           {\r
-             ERR ("unable to find next .dll file\n");\r
-             return 0;\r
-           }\r
-       }\r
-    }\r
-  if (!FindClose (hSearch))\r
-    {\r
-      ERR ("unable to close search handle: %i\n", GetLastError ());\r
-      return 0;\r
-    }\r
-  return 1;\r
-}\r
-\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
-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.SizeOfOptionalHeader);\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 IMAGE_BASE_RELOCATION *\r
-LowLdrProcessRelocationBlock (void *base, void *page, UINT count,\r
-                             USHORT *relocs)\r
-{\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
-\r
-  ptr = 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
-  idx = sec_cnt;\r
-\r
-  /* Small optimization: Exclude read-only sections at the start and\r
-     end of the list.  */\r
-  while (sec_cnt > 0 && SECTION_IS_LOW (sec))\r
-    {\r
-      sec++;\r
-      sec_cnt--;\r
-    }\r
-  while (sec_cnt > 0 && SECTION_IS_LOW (&sec[sec_cnt - 1]))\r
-    sec_cnt--;\r
-  \r
-  while (count--)\r
-    {\r
-      USHORT offset = *relocs & 0xfff;\r
-      int type = *relocs >> 12;\r
-      size_t addr;\r
-      size_t old_addr;\r
-      size_t off;\r
-\r
-      switch(type)\r
-        {\r
-        case IMAGE_REL_BASED_ABSOLUTE:\r
-         goto nextreloc;\r
-        case IMAGE_REL_BASED_HIGH:\r
-         addr = HIWORD (*(short *)((char *)page + offset));\r
-         break;\r
-        case IMAGE_REL_BASED_LOW:\r
-         addr = LOWORD (*(short *)((char *)page + offset));\r
-         break;\r
-        case IMAGE_REL_BASED_HIGHLOW:\r
-         addr = *(int *)((char *)page + offset);\r
-         break;\r
-        default:\r
-         TRACE("Unknown/unsupported fixup type %x.\n", type);\r
-         goto nextreloc;\r
-        }\r
-\r
-      if ((void *) addr < base)\r
-       {\r
-         ERR ("ignoring relocation that points below image");\r
-         goto nextreloc;\r
-       }\r
-      off = ((char *) addr) - ((char *) base);\r
-\r
-      /* Check if ADDR points into a rw segment.  First check the\r
-        cached index.  */\r
-      if (idx < sec_cnt)\r
-       {\r
-         if (off >= sec[idx].VirtualAddress\r
-             && off < sec[idx].VirtualAddress + section_size (&sec[idx]))\r
-           ; /* Found it.  */\r
-         else\r
-           idx = sec_cnt;\r
-       }\r
-      if (idx == sec_cnt)\r
-       {\r
-         for (idx = 0; idx < sec_cnt; idx++)\r
-           {\r
-             if (! sec[idx].PointerToLinenumbers)\r
-               continue;\r
-             if (off >= sec[idx].VirtualAddress\r
-                 && off < sec[idx].VirtualAddress + section_size (&sec[idx]))\r
-               break;\r
-           }\r
-         if (idx == sec_cnt)\r
-           goto nextreloc;\r
-       }\r
-      old_addr = addr;\r
-      addr = sec[idx].PointerToLinenumbers + (off - sec[idx].VirtualAddress);\r
-\r
-#if 0\r
-      TRACE ("rewriting relocation at %p to rw section from %p to %p\n",\r
-            ((char *)page + offset), old_addr, addr);\r
-#endif\r
-\r
-      switch(type)\r
-        {\r
-        case IMAGE_REL_BASED_HIGH:\r
-         *(short *)((char *)page + offset) = HIWORD(addr);\r
-         break;\r
-        case IMAGE_REL_BASED_LOW:\r
-         *(short *)((char *)page + offset) = LOWORD(addr);\r
-         break;\r
-        case IMAGE_REL_BASED_HIGHLOW:\r
-         *(int *)((char *)page + offset) = addr;\r
-         break;\r
-        }\r
-    nextreloc:\r
-      relocs++;\r
-    }\r
-  return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */\r
-}\r
-\r
-\r
-static void\r
-relocate_rw_sections (struct himemce_map *map, void *base)\r
-{\r
-  char *ptr;\r
-  IMAGE_DOS_HEADER *dos;\r
-  IMAGE_NT_HEADERS *nt;\r
-  IMAGE_SECTION_HEADER *sec;\r
-  int i;\r
-  IMAGE_BASE_RELOCATION *rel, *end;\r
-  const IMAGE_DATA_DIRECTORY *relocs;\r
-\r
-  TRACE ("adjusting rw sections at %p\n", base);\r
-\r
-  ptr = 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
-\r
-  /* Go through all the sections, reserve low memory for the writable\r
-     sections.  */\r
-  for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)\r
-    {\r
-      if (SECTION_IS_LOW (sec))\r
-       {\r
-         SIZE_T map_size;\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
-         sec->PointerToLinenumbers = (DWORD) map_reserve_low (map, map_size);\r
-\r
-         TRACE ("mapping r/w section %.8s at %p off %x (%lx) flags "\r
-                "%x to low mem %p\n",\r
-                sec->Name, ptr + sec->VirtualAddress,\r
-                sec->PointerToRawData, map_size,\r
-                sec->Characteristics, sec->PointerToLinenumbers);\r
-       }\r
-      else\r
-       sec->PointerToLinenumbers = 0;\r
-    }\r
-\r
-  /* Perform base relocations pointing into low sections.  Before\r
-     that, these relocations point into the high mem address.  */\r
-\r
-  relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
-  rel = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress);\r
-  end = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress + relocs->Size);\r
-  \r
-  while (rel < end - 1 && rel->SizeOfBlock)\r
-    {\r
-      rel = LowLdrProcessRelocationBlock\r
-       (base, ptr + rel->VirtualAddress,\r
-        (rel->SizeOfBlock - sizeof (*rel)) / sizeof (USHORT),\r
-        (USHORT *)(rel + 1));\r
-    }\r
-}\r
-\r
-\r
-/* convert PE image VirtualAddress to Real Address */\r
-static void *\r
-get_rva (HMODULE module, DWORD va)\r
-{\r
-  return (void *) ((char *) module + va);\r
-}\r
-\r
-\r
-/* convert from straight ASCII to Unicode without depending on the\r
-   current codepage */\r
-static void\r
-ascii_to_unicode (WCHAR *dst, const char *src, size_t len)\r
-{\r
-  while (len--)\r
-    *dst++ = (unsigned char) *src++;\r
-}\r
-\r
-\r
-#define allocate_stub(x,y) ((void *)0xdeadbeef)\r
-\r
-\r
-static FARPROC\r
-find_ordinal_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,\r
-                    DWORD exp_size, DWORD ordinal)\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
-\r
-static FARPROC\r
-find_named_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,\r
-                  DWORD exp_size, const char *name, int hint)\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]);\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]);\r
-      if (res > 0) max = pos - 1;\r
-      else min = pos + 1;\r
-    }\r
-  return NULL;\r
-}\r
-\r
-\r
-/*************************************************************************\r
- *              import_dll\r
- *\r
- * Import the dll specified by the given import descriptor.\r
- * The loader_section must be locked while calling this function.\r
- */\r
-static void *\r
-import_dll (struct himemce_map *map, HMODULE module,\r
-           const IMAGE_IMPORT_DESCRIPTOR *descr)\r
-{\r
-  int status = 0;\r
-  const char *name = get_rva (module, descr->Name);\r
-  DWORD len = strlen(name);\r
-  const IMAGE_THUNK_DATA *import_list;\r
-  IMAGE_THUNK_DATA *thunk_list;\r
-  void *imp_base = 0;\r
-  HMODULE imp_mod = 0;\r
-  const IMAGE_EXPORT_DIRECTORY *exports;\r
-  DWORD exp_size;\r
-  WCHAR buffer[32];\r
-  int i;\r
-\r
-  thunk_list = get_rva (module, (DWORD)descr->FirstThunk);\r
-  if (descr->OriginalFirstThunk)\r
-    import_list = get_rva (module, (DWORD)descr->OriginalFirstThunk);\r
-  else\r
-    import_list = thunk_list;\r
-\r
-  while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */\r
-\r
-  /* First check for the modules in the map.  */\r
-  for (i = 0; i < map->nr_modules; i++)\r
-    {\r
-      if (! strncmp (name, map->module[i].name, len))\r
-       break;\r
-    }\r
-  if (i < map->nr_modules)\r
-    {\r
-      imp_base = map->module[i].base;\r
-      TRACE("Loading library %s internal\n", name);\r
-    }\r
-  else if (len * sizeof(WCHAR) < sizeof(buffer))\r
-    {\r
-      ascii_to_unicode( buffer, name, len );\r
-      buffer[len] = 0;\r
-      imp_mod = LoadLibrary (buffer);\r
-      if (imp_mod == INVALID_HANDLE_VALUE)\r
-       status = GetLastError ();\r
-    }\r
-  else\r
-    {\r
-      WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );\r
-      if (!ptr) return NULL;\r
-      ascii_to_unicode( ptr, name, len );\r
-      ptr[len] = 0;\r
-      imp_mod = LoadLibrary (ptr);\r
-      if (imp_mod == INVALID_HANDLE_VALUE)\r
-       status = GetLastError ();\r
-      free (ptr);\r
-    }\r
-  if (status)\r
-    {\r
-      if (status == ERROR_DLL_NOT_FOUND)\r
-       TRACE("Library %s not found\n", name);\r
-      else\r
-       TRACE("Loading library %s failed (error %x).\n",  name, status);\r
-      return NULL;\r
-    }\r
-\r
-  if (imp_base)\r
-    {\r
-      exports = MyRtlImageDirectoryEntryToData (imp_base, TRUE,\r
-                                               IMAGE_DIRECTORY_ENTRY_EXPORT,\r
-                                               &exp_size);\r
-      if (!exports)\r
-       {\r
-         /* set all imported function to deadbeef */\r
-         while (import_list->u1.Ordinal)\r
-           {\r
-             if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
-               {\r
-                 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
-                 TRACE ("No implementation for %s.%d", name, ordinal);\r
-                 thunk_list->u1.Function\r
-                   = (PDWORD) allocate_stub (name, IntToPtr (ordinal));\r
-               }\r
-             else\r
-               {\r
-                 IMAGE_IMPORT_BY_NAME *pe_name\r
-                   = get_rva (module, (DWORD) import_list->u1.AddressOfData);\r
-                 TRACE ("No implementation for %s.%s", name, pe_name->Name);\r
-                 thunk_list->u1.Function\r
-                   = (PDWORD) allocate_stub (name, (const char*) pe_name->Name);\r
-               }\r
-             import_list++;\r
-             thunk_list++;\r
-           }\r
-         goto done;\r
-       }\r
-    }\r
-  \r
-  while (import_list->u1.Ordinal)\r
-    {\r
-      if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
-        {\r
-         int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
-\r
-         if (imp_base)\r
-           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
-             find_ordinal_export (imp_base, exports, exp_size,\r
-                                  ordinal - exports->Base);\r
-         else\r
-           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
-             GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));\r
-         if (!thunk_list->u1.Function)\r
-            {\r
-             thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );\r
-             TRACE("No implementation for %s.%d imported, setting to %p\n",\r
-                   name, ordinal,\r
-                   (void *)thunk_list->u1.Function );\r
-            }\r
-         TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );\r
-        }\r
-      else  /* import by name */\r
-        {\r
-         IMAGE_IMPORT_BY_NAME *pe_name;\r
-         pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
-         if (imp_base)\r
-           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
-             find_named_export (imp_base, exports, exp_size,\r
-                                (const char*)pe_name->Name, pe_name->Hint);\r
-         else\r
-           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
-             GetProcAddressA (imp_mod, (const char*)pe_name->Name);\r
-         if (!thunk_list->u1.Function)\r
-            {\r
-             thunk_list->u1.Function\r
-               = (PDWORD) allocate_stub (name, (const char*)pe_name->Name);\r
-             TRACE ("No implementation for %s.%s imported, setting to %p\n",\r
-                    name, pe_name->Name, (void *)thunk_list->u1.Function);\r
-            }\r
-         TRACE("--- %s %s.%d = %p\n",\r
-               pe_name->Name, name, pe_name->Hint,\r
-               (void *)thunk_list->u1.Function);\r
-        }\r
-      import_list++;\r
-      thunk_list++;\r
-    }\r
-\r
- done:\r
-  return (void*)1;\r
-}\r
-\r
-\r
-static void\r
-fixup_imports (struct himemce_map *map, void *base)\r
-{\r
-  int i, nb_imports;\r
-  const IMAGE_IMPORT_DESCRIPTOR *imports;\r
-  DWORD size;\r
-\r
-  imports = MyRtlImageDirectoryEntryToData (base, TRUE,\r
-                                           IMAGE_DIRECTORY_ENTRY_IMPORT,\r
-                                           &size);\r
-  if (!imports)\r
-    return;\r
-\r
-  nb_imports = 0;\r
-  while (imports[nb_imports].Name && imports[nb_imports].FirstThunk)\r
-    nb_imports++;\r
-  if (!nb_imports)\r
-    return;\r
-\r
-  for (i = 0; i < nb_imports; i++)\r
-    {\r
-      if (! import_dll (map, base, &imports[i]))\r
-       {\r
-         SetLastError (ERROR_DLL_NOT_FOUND);\r
-         break;\r
-       }\r
-    }\r
-}\r
-\r
-\r
-int\r
-main (int argc, char *argv[])\r
-{\r
-  struct himemce_map *map;\r
-  int result = 0;\r
-  int i;\r
-\r
-  TRACE ("creating map file...\n");\r
-\r
-  map = map_create ();\r
-  if (! map)\r
-    return 1;\r
-\r
-  TRACE ("finding modules...\n");\r
-\r
-  result = find_modules (map);\r
-  if (! result)\r
-    exit (1);\r
-\r
-  TRACE ("loading modules...\n");\r
-\r
-  /* For each module: load it high without resolving references.  */\r
-  for (i = 0; i < map->nr_modules; i++)\r
-    {\r
-      struct himemce_module *mod = &map->module[i];\r
-      void *base = MyLoadLibraryExW (mod->filename, 0,\r
-                                    DONT_RESOLVE_DLL_REFERENCES);\r
-\r
-      if (! base)\r
-       {\r
-         ERR ("could not load %S: %i\n", mod->filename, GetLastError());\r
-         exit (1);\r
-       }\r
-      mod->base = base;\r
-    }\r
-\r
-  TRACE ("relocationg writable sections...\n");\r
-\r
-  for (i = 0; i < map->nr_modules; i++)\r
-    {\r
-      struct himemce_module *mod = &map->module[i];\r
-\r
-      /* Allocate low mem for read-write sections and adjust\r
-        relocations pointing into them.  */\r
-      relocate_rw_sections (map, mod->base);\r
-    }\r
-\r
-  /* Export entries are handled at time of import on the other side,\r
-     when we check for low memory mapped sections and adjust the\r
-     imported address accordingly.  */\r
-\r
-  TRACE ("resolve module dependencies...\n");\r
-\r
-  for (i = 0; i < map->nr_modules; i++)\r
-    {\r
-      struct himemce_module *mod = &map->module[i];\r
-\r
-      /* Fixup imports (this loads all dependencies as well!).  */\r
-      fixup_imports (map, mod->base);\r
-    }\r
-\r
-  TRACE ("sleeping...");\r
-\r
-  while (1)\r
-    Sleep (3600 * 1000);\r
-\r
-  return 0;\r
-}\r
+ /* himemce-pre.c - High Memory for Windows CE (preloader)
+   Copyright (C) 2010 g10 Code GmbH
+   Written by Marcus Brinkmann <marcus@g10code.com>
+
+   This file is part of HiMemCE.
+   HiMemCE is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+   
+   HiMemCE is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+   
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#include <windows.h>
+#include <assert.h>
+
+#include "debug.h"
+
+#include "kernel32_kernel_private.h"
+#include "wine.h"
+#include "himemce-map-provider.h"
+
+
+# define page_mask  0xfff
+# define page_shift 12
+# define page_size  0x1000
+
+#define ROUND_SIZE(size) \
+  (((SIZE_T)(size) + page_mask) & ~page_mask)
+
+#define SECTION_IS_LOW(sec) \
+      (((sec)->Characteristics & IMAGE_SCN_MEM_WRITE) &&       \
+       ! ((sec)->Characteristics & IMAGE_SCN_MEM_SHARED))
+
+
+/* Find all modules to preload and add them to the map.  */
+static int
+find_modules (struct himemce_map *map)
+{
+  /* Five for "*.dll" and one for good luck.  */
+  wchar_t dirname[MAX_PATH + 6];
+  wchar_t filename[2 * MAX_PATH + 1];
+  int res;
+  wchar_t *end;
+  int idx;
+  HANDLE hSearch;
+  WIN32_FIND_DATA FileData;
+  BOOL bFinished = FALSE;
+
+  res = GetModuleFileName (GetModuleHandle (NULL), dirname, MAX_PATH);
+  if (! res)
+    {
+      ERR ("can not determine module filename: %i\n",
+            GetLastError ());
+      return 0;
+    }
+
+  idx = wcslen (dirname);
+  while (idx > 0 && dirname[idx - 1] != '\\' && dirname[idx - 1] != '/')
+    idx--;
+  dirname[idx] = '\0';
+
+  wcscpy (filename, dirname);
+  wcscpy (&dirname[idx], L"*.dll");
+  end = &filename[idx];
+
+  hSearch = FindFirstFile (dirname, &FileData);
+  if (hSearch == INVALID_HANDLE_VALUE)
+    {
+      ERR ("no .dll files found\n");
+      return 0;
+    }
+
+  while (!bFinished)
+    {
+      struct himemce_module *mod;
+      struct binary_info info;
+      HANDLE hnd;
+
+      TRACE ("considering %S: ", FileData.cFileName);
+
+      wcscpy (end, FileData.cFileName);
+
+      if (FileData.cFileName[0] != L'Q')
+       {
+         TRACE ("skip non-Qt library for testing\n");
+         goto skipit;
+       }
+
+      hnd = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+      if (hnd == INVALID_HANDLE_VALUE)
+       {
+         TRACE ("skip (probe failure: %i)\n", GetLastError ());
+         goto skipit;
+       }
+
+      MODULE_get_binary_info (hnd, &info);
+      CloseHandle (hnd);
+      if (info.machine != IMAGE_FILE_MACHINE_THUMB)
+       {
+         TRACE ("skip (machine type: %04x)\n", info.machine);
+         goto skipit;
+       }
+
+      /* FIXME: Keep a blacklist.  Maybe exclude ARM (not THUMB)
+        binaries automatically (gpgme and friends).  */
+
+      TRACE ("accept [%2i]\n", map->nr_modules);
+      mod = map_add_module (map, filename, 0);
+      if (! mod)
+       return 0;
+      
+    skipit:
+      if (!FindNextFile (hSearch, &FileData))
+       {
+         bFinished = TRUE;
+         
+         if (GetLastError () != ERROR_NO_MORE_FILES)
+           {
+             ERR ("unable to find next .dll file\n");
+             return 0;
+           }
+       }
+    }
+  if (!FindClose (hSearch))
+    {
+      ERR ("unable to close search handle: %i\n", GetLastError ());
+      return 0;
+    }
+  return 1;
+}
+
+
+static SIZE_T
+section_size (IMAGE_SECTION_HEADER *sec)
+{
+  static const SIZE_T sector_align = 0x1ff;
+  SIZE_T map_size, file_size, end;
+  
+  if (!sec->Misc.VirtualSize)
+    map_size = ROUND_SIZE( sec->SizeOfRawData );
+  else
+    map_size = ROUND_SIZE( sec->Misc.VirtualSize );
+  
+  file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align;
+  if (file_size > map_size) file_size = map_size;
+  end = ROUND_SIZE( file_size );
+  if (end > map_size) end = map_size;
+  return end;
+}
+
+
+static void *
+get_rva_low (char *module, size_t rva)
+{
+  IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;
+  IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(module + dos->e_lfanew);
+  IMAGE_SECTION_HEADER *sec;
+  int sec_cnt;
+  int idx;
+
+  sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
+  sec_cnt = nt->FileHeader.NumberOfSections;
+
+  for (idx = 0; idx < sec_cnt; idx++)
+    {
+      if (! sec[idx].PointerToLinenumbers)
+       continue;
+      if (rva >= sec[idx].VirtualAddress
+         && rva < sec[idx].VirtualAddress + section_size (&sec[idx]))
+               break;
+    }
+  if (idx == sec_cnt)
+    return (void *)((char *)module + rva);
+  
+  return (void *)((char *)sec[idx].PointerToLinenumbers
+                 + (rva - sec[idx].VirtualAddress));
+}
+
+  
+static IMAGE_BASE_RELOCATION *
+LowLdrProcessRelocationBlock (void *base, void *page, UINT count,
+                             USHORT *relocs)
+{
+  char *ptr;
+  IMAGE_DOS_HEADER *dos;
+  IMAGE_NT_HEADERS *nt;
+  IMAGE_SECTION_HEADER *sec;
+  int sec_cnt;
+  int idx;
+
+  ptr = base;
+  dos = (IMAGE_DOS_HEADER *) ptr;
+  nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);
+  sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader
+                                 + nt->FileHeader.SizeOfOptionalHeader);
+  sec_cnt = nt->FileHeader.NumberOfSections;
+  idx = sec_cnt;
+
+  /* Small optimization: Exclude read-only sections at the start and
+     end of the list.  */
+  while (sec_cnt > 0 && SECTION_IS_LOW (sec))
+    {
+      sec++;
+      sec_cnt--;
+    }
+  while (sec_cnt > 0 && SECTION_IS_LOW (&sec[sec_cnt - 1]))
+    sec_cnt--;
+  
+  while (count--)
+    {
+      USHORT offset = *relocs & 0xfff;
+      int type = *relocs >> 12;
+      size_t addr;
+      size_t old_addr;
+      size_t off;
+
+      switch(type)
+        {
+        case IMAGE_REL_BASED_ABSOLUTE:
+         goto nextreloc;
+        case IMAGE_REL_BASED_HIGH:
+         addr = HIWORD (*(short *)((char *)page + offset));
+         break;
+        case IMAGE_REL_BASED_LOW:
+         addr = LOWORD (*(short *)((char *)page + offset));
+         break;
+        case IMAGE_REL_BASED_HIGHLOW:
+         addr = *(int *)((char *)page + offset);
+         break;
+        default:
+         TRACE("Unknown/unsupported fixup type %x.\n", type);
+         goto nextreloc;
+        }
+
+      if ((void *) addr < base)
+       {
+         ERR ("ignoring relocation that points below image");
+         goto nextreloc;
+       }
+      off = ((char *) addr) - ((char *) base);
+
+      /* Check if ADDR points into a rw segment.  First check the
+        cached index.  */
+      if (idx < sec_cnt)
+       {
+         if (off >= sec[idx].VirtualAddress
+             && off < sec[idx].VirtualAddress + section_size (&sec[idx]))
+           ; /* Found it.  */
+         else
+           idx = sec_cnt;
+       }
+      if (idx == sec_cnt)
+       {
+         for (idx = 0; idx < sec_cnt; idx++)
+           {
+             if (! sec[idx].PointerToLinenumbers)
+               continue;
+             if (off >= sec[idx].VirtualAddress
+                 && off < sec[idx].VirtualAddress + section_size (&sec[idx]))
+               break;
+           }
+         if (idx == sec_cnt)
+           goto nextreloc;
+       }
+      old_addr = addr;
+      addr = sec[idx].PointerToLinenumbers + (off - sec[idx].VirtualAddress);
+
+#if 0
+      TRACE ("rewriting relocation at %p to rw section from %p to %p\n",
+            ((char *)page + offset), old_addr, addr);
+#endif
+
+      switch(type)
+        {
+        case IMAGE_REL_BASED_HIGH:
+         *(short *)((char *)page + offset) = HIWORD(addr);
+         break;
+        case IMAGE_REL_BASED_LOW:
+         *(short *)((char *)page + offset) = LOWORD(addr);
+         break;
+        case IMAGE_REL_BASED_HIGHLOW:
+         *(int *)((char *)page + offset) = addr;
+         break;
+        }
+    nextreloc:
+      relocs++;
+    }
+  return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
+}
+
+
+static void
+relocate_rw_sections (struct himemce_map *map, void *base)
+{
+  char *ptr;
+  IMAGE_DOS_HEADER *dos;
+  IMAGE_NT_HEADERS *nt;
+  IMAGE_SECTION_HEADER *sec;
+  int i;
+  IMAGE_BASE_RELOCATION *rel, *end;
+  const IMAGE_DATA_DIRECTORY *relocs;
+
+  TRACE ("adjusting rw sections at %p\n", base);
+
+  ptr = base;
+  dos = (IMAGE_DOS_HEADER *) ptr;
+  nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);
+  sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader
+                                 + nt->FileHeader.SizeOfOptionalHeader);
+
+  /* Go through all the sections, reserve low memory for the writable
+     sections.  */
+  for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
+    {
+      if (SECTION_IS_LOW (sec))
+       {
+         SIZE_T map_size;
+
+         if (! sec->Misc.VirtualSize)
+           map_size = ROUND_SIZE (sec->SizeOfRawData);
+         else
+           map_size = ROUND_SIZE (sec->Misc.VirtualSize);
+
+         sec->PointerToLinenumbers = (DWORD) map_reserve_low (map, map_size);
+
+         TRACE ("mapping r/w section %.8s at %p off %x (%lx) flags "
+                "%x to low mem %p\n",
+                sec->Name, ptr + sec->VirtualAddress,
+                sec->PointerToRawData, map_size,
+                sec->Characteristics, sec->PointerToLinenumbers);
+       }
+      else
+       sec->PointerToLinenumbers = 0;
+    }
+
+  /* Perform base relocations pointing into low sections.  Before
+     that, these relocations point into the high mem address.  */
+
+  relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+  rel = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress);
+  end = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress + relocs->Size);
+  
+  while (rel < end - 1 && rel->SizeOfBlock)
+    {
+      rel = LowLdrProcessRelocationBlock
+       (base, ptr + rel->VirtualAddress,
+        (rel->SizeOfBlock - sizeof (*rel)) / sizeof (USHORT),
+        (USHORT *)(rel + 1));
+    }
+}
+
+
+/* convert PE image VirtualAddress to Real Address */
+static void *
+get_rva (HMODULE module, DWORD va)
+{
+  return (void *) ((char *) module + va);
+}
+
+
+/* convert from straight ASCII to Unicode without depending on the
+   current codepage */
+static void
+ascii_to_unicode (WCHAR *dst, const char *src, size_t len)
+{
+  while (len--)
+    *dst++ = (unsigned char) *src++;
+}
+
+
+#define allocate_stub(x,y) ((void *)0xdeadbeef)
+
+
+static FARPROC
+find_ordinal_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,
+                    DWORD exp_size, DWORD ordinal)
+{
+  FARPROC proc;
+  const DWORD *functions = get_rva (module, exports->AddressOfFunctions);
+  
+  if (ordinal >= exports->NumberOfFunctions)
+    {
+      TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
+      return NULL;
+    }
+  if (!functions[ordinal]) return NULL;
+  
+#if 0
+  /* if the address falls into the export dir, it's a forward */
+  if (((const char *)proc >= (const char *)exports) && 
+      ((const char *)proc < (const char *)exports + exp_size))
+    return find_forwarded_export( module, (const char *)proc, load_path );
+#endif
+
+  proc = get_rva_low (module, functions[ordinal]);
+  return proc;
+}
+
+
+static FARPROC
+find_named_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,
+                  DWORD exp_size, const char *name, int hint)
+{
+  const WORD *ordinals = get_rva (module, exports->AddressOfNameOrdinals);
+  const DWORD *names = get_rva (module, exports->AddressOfNames);
+  int min = 0, max = exports->NumberOfNames - 1;
+
+  /* first check the hint */
+  if (hint >= 0 && hint <= max)
+    {
+      char *ename = get_rva( module, names[hint] );
+      if (!strcmp( ename, name ))
+       return find_ordinal_export( module, exports, exp_size, ordinals[hint]);
+    }
+
+  /* then do a binary search */
+  while (min <= max)
+    {
+      int res, pos = (min + max) / 2;
+      char *ename = get_rva( module, names[pos] );
+      if (!(res = strcmp( ename, name )))
+       return find_ordinal_export( module, exports, exp_size, ordinals[pos]);
+      if (res > 0) max = pos - 1;
+      else min = pos + 1;
+    }
+  return NULL;
+}
+
+
+/*************************************************************************
+ *              import_dll
+ *
+ * Import the dll specified by the given import descriptor.
+ * The loader_section must be locked while calling this function.
+ */
+static void *
+import_dll (struct himemce_map *map, HMODULE module,
+           const IMAGE_IMPORT_DESCRIPTOR *descr)
+{
+  int status = 0;
+  const char *name = get_rva (module, descr->Name);
+  DWORD len = strlen(name);
+  const IMAGE_THUNK_DATA *import_list;
+  IMAGE_THUNK_DATA *thunk_list;
+  void *imp_base = 0;
+  HMODULE imp_mod = 0;
+  const IMAGE_EXPORT_DIRECTORY *exports;
+  DWORD exp_size;
+  WCHAR buffer[32];
+  int i;
+
+  thunk_list = get_rva (module, (DWORD)descr->FirstThunk);
+  if (descr->OriginalFirstThunk)
+    import_list = get_rva (module, (DWORD)descr->OriginalFirstThunk);
+  else
+    import_list = thunk_list;
+
+  while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */
+
+  /* First check for the modules in the map.  */
+  for (i = 0; i < map->nr_modules; i++)
+    {
+      if (! strncmp (name, map->module[i].name, len))
+       break;
+    }
+  if (i < map->nr_modules)
+    {
+      imp_base = map->module[i].base;
+      TRACE("Loading library %s internal\n", name);
+    }
+  else if (len * sizeof(WCHAR) < sizeof(buffer))
+    {
+      ascii_to_unicode( buffer, name, len );
+      buffer[len] = 0;
+      imp_mod = LoadLibrary (buffer);
+      if (imp_mod == INVALID_HANDLE_VALUE)
+       status = GetLastError ();
+    }
+  else
+    {
+      WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );
+      if (!ptr) return NULL;
+      ascii_to_unicode( ptr, name, len );
+      ptr[len] = 0;
+      imp_mod = LoadLibrary (ptr);
+      if (imp_mod == INVALID_HANDLE_VALUE)
+       status = GetLastError ();
+      free (ptr);
+    }
+  if (status)
+    {
+      if (status == ERROR_DLL_NOT_FOUND)
+       TRACE("Library %s not found\n", name);
+      else
+       TRACE("Loading library %s failed (error %x).\n",  name, status);
+      return NULL;
+    }
+
+  if (imp_base)
+    {
+      exports = MyRtlImageDirectoryEntryToData (imp_base, TRUE,
+                                               IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                               &exp_size);
+      if (!exports)
+       {
+         /* set all imported function to deadbeef */
+         while (import_list->u1.Ordinal)
+           {
+             if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
+               {
+                 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
+                 TRACE ("No implementation for %s.%d", name, ordinal);
+                 thunk_list->u1.Function
+                   = (PDWORD) allocate_stub (name, IntToPtr (ordinal));
+               }
+             else
+               {
+                 IMAGE_IMPORT_BY_NAME *pe_name
+                   = get_rva (module, (DWORD) import_list->u1.AddressOfData);
+                 TRACE ("No implementation for %s.%s", name, pe_name->Name);
+                 thunk_list->u1.Function
+                   = (PDWORD) allocate_stub (name, (const char*) pe_name->Name);
+               }
+             import_list++;
+             thunk_list++;
+           }
+         goto done;
+       }
+    }
+  
+  while (import_list->u1.Ordinal)
+    {
+      if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
+        {
+         int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
+
+         if (imp_base)
+           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)
+             find_ordinal_export (imp_base, exports, exp_size,
+                                  ordinal - exports->Base);
+         else
+           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)
+             GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));
+         if (!thunk_list->u1.Function)
+            {
+             thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );
+             TRACE("No implementation for %s.%d imported, setting to %p\n",
+                   name, ordinal,
+                   (void *)thunk_list->u1.Function );
+            }
+         TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
+        }
+      else  /* import by name */
+        {
+         IMAGE_IMPORT_BY_NAME *pe_name;
+         pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
+         if (imp_base)
+           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)
+             find_named_export (imp_base, exports, exp_size,
+                                (const char*)pe_name->Name, pe_name->Hint);
+         else
+           thunk_list->u1.Function = (PDWORD)(ULONG_PTR)
+             GetProcAddressA (imp_mod, (const char*)pe_name->Name);
+         if (!thunk_list->u1.Function)
+            {
+             thunk_list->u1.Function
+               = (PDWORD) allocate_stub (name, (const char*)pe_name->Name);
+             TRACE ("No implementation for %s.%s imported, setting to %p\n",
+                    name, pe_name->Name, (void *)thunk_list->u1.Function);
+            }
+         TRACE("--- %s %s.%d = %p\n",
+               pe_name->Name, name, pe_name->Hint,
+               (void *)thunk_list->u1.Function);
+        }
+      import_list++;
+      thunk_list++;
+    }
+
+ done:
+  return (void*)1;
+}
+
+
+static void
+fixup_imports (struct himemce_map *map, void *base)
+{
+  int i, nb_imports;
+  const IMAGE_IMPORT_DESCRIPTOR *imports;
+  DWORD size;
+
+  imports = MyRtlImageDirectoryEntryToData (base, TRUE,
+                                           IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                           &size);
+  if (!imports)
+    return;
+
+  nb_imports = 0;
+  while (imports[nb_imports].Name && imports[nb_imports].FirstThunk)
+    nb_imports++;
+  if (!nb_imports)
+    return;
+
+  for (i = 0; i < nb_imports; i++)
+    {
+      if (! import_dll (map, base, &imports[i]))
+       {
+         SetLastError (ERROR_DLL_NOT_FOUND);
+         break;
+       }
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  struct himemce_map *map;
+  int result = 0;
+  int i;
+
+  TRACE ("creating map file...\n");
+
+  map = map_create ();
+  if (! map)
+    return 1;
+
+  TRACE ("finding modules...\n");
+
+  result = find_modules (map);
+  if (! result)
+    exit (1);
+
+  TRACE ("loading modules...\n");
+
+  /* For each module: load it high without resolving references.  */
+  for (i = 0; i < map->nr_modules; i++)
+    {
+      struct himemce_module *mod = &map->module[i];
+      void *base = MyLoadLibraryExW (mod->filename, 0,
+                                    DONT_RESOLVE_DLL_REFERENCES);
+
+      if (! base)
+       {
+         ERR ("could not load %S: %i\n", mod->filename, GetLastError());
+         exit (1);
+       }
+      mod->base = base;
+    }
+
+  TRACE ("relocationg writable sections...\n");
+
+  for (i = 0; i < map->nr_modules; i++)
+    {
+      struct himemce_module *mod = &map->module[i];
+
+      /* Allocate low mem for read-write sections and adjust
+        relocations pointing into them.  */
+      relocate_rw_sections (map, mod->base);
+    }
+
+  /* Export entries are handled at time of import on the other side,
+     when we check for low memory mapped sections and adjust the
+     imported address accordingly.  */
+
+  TRACE ("resolve module dependencies...\n");
+
+  for (i = 0; i < map->nr_modules; i++)
+    {
+      struct himemce_module *mod = &map->module[i];
+
+      /* Fixup imports (this loads all dependencies as well!).  */
+      fixup_imports (map, mod->base);
+    }
+
+  TRACE ("sleeping...");
+
+  while (1)
+    Sleep (3600 * 1000);
+
+  return 0;
+}