First version of DLL preloader.
[wincetools.git] / loader / himemce-pre.c
1  /* himemce-pre.c - High Memory for Windows CE (preloader)\r
2    Copyright (C) 2010 g10 Code GmbH\r
3    Written by Marcus Brinkmann <marcus@g10code.com>\r
4 \r
5    This file is part of HiMemCE.\r
6  \r
7    HiMemCE is free software; you can redistribute it and/or modify it\r
8    under the terms of the GNU Lesser General Public License as\r
9    published by the Free Software Foundation; either version 2.1 of\r
10    the License, or (at your option) any later version.\r
11    \r
12    HiMemCE is distributed in the hope that it will be useful, but\r
13    WITHOUT ANY WARRANTY; without even the implied warranty of\r
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
15    Lesser General Public License for more details.\r
16    \r
17    You should have received a copy of the GNU Lesser General Public\r
18    License along with this program; if not, write to the Free Software\r
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
20    02111-1307, USA.  */\r
21 \r
22 #include <windows.h>\r
23 #include <assert.h>\r
24 \r
25 #include "debug.h"\r
26 \r
27 #include "kernel32_kernel_private.h"\r
28 #include "wine.h"\r
29 #include "himemce-map-provider.h"\r
30 \r
31 \r
32 # define page_mask  0xfff\r
33 # define page_shift 12\r
34 # define page_size  0x1000\r
35 \r
36 #define ROUND_SIZE(size) \\r
37   (((SIZE_T)(size) + page_mask) & ~page_mask)\r
38 \r
39 #define SECTION_IS_LOW(sec) \\r
40       (((sec)->Characteristics & IMAGE_SCN_MEM_WRITE) &&        \\r
41        ! ((sec)->Characteristics & IMAGE_SCN_MEM_SHARED))\r
42 \r
43 \r
44 /* Find all modules to preload and add them to the map.  */\r
45 static int\r
46 find_modules (struct himemce_map *map)\r
47 {\r
48   /* Five for "*.dll" and one for good luck.  */\r
49   wchar_t dirname[MAX_PATH + 6];\r
50   wchar_t filename[2 * MAX_PATH + 1];\r
51   int res;\r
52   wchar_t *end;\r
53   int idx;\r
54   HANDLE hSearch;\r
55   WIN32_FIND_DATA FileData;\r
56   BOOL bFinished = FALSE;\r
57 \r
58   res = GetModuleFileName (GetModuleHandle (NULL), dirname, MAX_PATH);\r
59   if (! res)\r
60     {\r
61       ERR ("can not determine module filename: %i\n",\r
62              GetLastError ());\r
63       return 0;\r
64     }\r
65 \r
66   idx = wcslen (dirname);\r
67   while (idx > 0 && dirname[idx - 1] != '\\' && dirname[idx - 1] != '/')\r
68     idx--;\r
69   dirname[idx] = '\0';\r
70 \r
71   wcscpy (filename, dirname);\r
72   wcscpy (&dirname[idx], L"*.dll");\r
73   end = &filename[idx];\r
74 \r
75   hSearch = FindFirstFile (dirname, &FileData);\r
76   if (hSearch == INVALID_HANDLE_VALUE)\r
77     {\r
78       ERR ("no .dll files found\n");\r
79       return 0;\r
80     }\r
81 \r
82   while (!bFinished)\r
83     {\r
84       struct himemce_module *mod;\r
85       struct binary_info info;\r
86       HANDLE hnd;\r
87 \r
88       TRACE ("considering %S: ", FileData.cFileName);\r
89 \r
90       wcscpy (end, FileData.cFileName);\r
91 \r
92       if (FileData.cFileName[0] != L'Q')\r
93         {\r
94           TRACE ("skip non-Qt library for testing\n");\r
95           goto skipit;\r
96         }\r
97 \r
98       hnd = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,\r
99                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
100       if (hnd == INVALID_HANDLE_VALUE)\r
101         {\r
102           TRACE ("skip (probe failure: %i)\n", GetLastError ());\r
103           goto skipit;\r
104         }\r
105 \r
106       MODULE_get_binary_info (hnd, &info);\r
107       CloseHandle (hnd);\r
108       if (info.machine != IMAGE_FILE_MACHINE_THUMB)\r
109         {\r
110           TRACE ("skip (machine type: %04x)\n", info.machine);\r
111           goto skipit;\r
112         }\r
113 \r
114       /* FIXME: Keep a blacklist.  Maybe exclude ARM (not THUMB)\r
115          binaries automatically (gpgme and friends).  */\r
116 \r
117       TRACE ("accept [%2i]\n", map->nr_modules);\r
118       mod = map_add_module (map, filename, 0);\r
119       if (! mod)\r
120         return 0;\r
121       \r
122     skipit:\r
123       if (!FindNextFile (hSearch, &FileData))\r
124         {\r
125           bFinished = TRUE;\r
126           \r
127           if (GetLastError () != ERROR_NO_MORE_FILES)\r
128             {\r
129               ERR ("unable to find next .dll file\n");\r
130               return 0;\r
131             }\r
132         }\r
133     }\r
134   if (!FindClose (hSearch))\r
135     {\r
136       ERR ("unable to close search handle: %i\n", GetLastError ());\r
137       return 0;\r
138     }\r
139   return 1;\r
140 }\r
141 \r
142 \r
143 static SIZE_T\r
144 section_size (IMAGE_SECTION_HEADER *sec)\r
145 {\r
146   static const SIZE_T sector_align = 0x1ff;\r
147   SIZE_T map_size, file_size, end;\r
148   \r
149   if (!sec->Misc.VirtualSize)\r
150     map_size = ROUND_SIZE( sec->SizeOfRawData );\r
151   else\r
152     map_size = ROUND_SIZE( sec->Misc.VirtualSize );\r
153   \r
154   file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align;\r
155   if (file_size > map_size) file_size = map_size;\r
156   end = ROUND_SIZE( file_size );\r
157   if (end > map_size) end = map_size;\r
158   return end;\r
159 }\r
160 \r
161 \r
162 static void *\r
163 get_rva_low (char *module, size_t rva)\r
164 {\r
165   IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;\r
166   IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(module + dos->e_lfanew);\r
167   IMAGE_SECTION_HEADER *sec;\r
168   int sec_cnt;\r
169   int idx;\r
170 \r
171   sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);\r
172   sec_cnt = nt->FileHeader.NumberOfSections;\r
173 \r
174   for (idx = 0; idx < sec_cnt; idx++)\r
175     {\r
176       if (! sec[idx].PointerToLinenumbers)\r
177         continue;\r
178       if (rva >= sec[idx].VirtualAddress\r
179           && rva < sec[idx].VirtualAddress + section_size (&sec[idx]))\r
180                 break;\r
181     }\r
182   if (idx == sec_cnt)\r
183     return (void *)((char *)module + rva);\r
184   \r
185   return (void *)((char *)sec[idx].PointerToLinenumbers\r
186                   + (rva - sec[idx].VirtualAddress));\r
187 }\r
188 \r
189   \r
190 static IMAGE_BASE_RELOCATION *\r
191 LowLdrProcessRelocationBlock (void *base, void *page, UINT count,\r
192                               USHORT *relocs)\r
193 {\r
194   char *ptr;\r
195   IMAGE_DOS_HEADER *dos;\r
196   IMAGE_NT_HEADERS *nt;\r
197   IMAGE_SECTION_HEADER *sec;\r
198   int sec_cnt;\r
199   int idx;\r
200 \r
201   ptr = base;\r
202   dos = (IMAGE_DOS_HEADER *) ptr;\r
203   nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);\r
204   sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader\r
205                                   + nt->FileHeader.SizeOfOptionalHeader);\r
206   sec_cnt = nt->FileHeader.NumberOfSections;\r
207   idx = sec_cnt;\r
208 \r
209   /* Small optimization: Exclude read-only sections at the start and\r
210      end of the list.  */\r
211   while (sec_cnt > 0 && SECTION_IS_LOW (sec))\r
212     {\r
213       sec++;\r
214       sec_cnt--;\r
215     }\r
216   while (sec_cnt > 0 && SECTION_IS_LOW (&sec[sec_cnt - 1]))\r
217     sec_cnt--;\r
218   \r
219   while (count--)\r
220     {\r
221       USHORT offset = *relocs & 0xfff;\r
222       int type = *relocs >> 12;\r
223       size_t addr;\r
224       size_t old_addr;\r
225       size_t off;\r
226 \r
227       switch(type)\r
228         {\r
229         case IMAGE_REL_BASED_ABSOLUTE:\r
230           goto nextreloc;\r
231         case IMAGE_REL_BASED_HIGH:\r
232           addr = HIWORD (*(short *)((char *)page + offset));\r
233           break;\r
234         case IMAGE_REL_BASED_LOW:\r
235           addr = LOWORD (*(short *)((char *)page + offset));\r
236           break;\r
237         case IMAGE_REL_BASED_HIGHLOW:\r
238           addr = *(int *)((char *)page + offset);\r
239           break;\r
240         default:\r
241           TRACE("Unknown/unsupported fixup type %x.\n", type);\r
242           goto nextreloc;\r
243         }\r
244 \r
245       if ((void *) addr < base)\r
246         {\r
247           ERR ("ignoring relocation that points below image");\r
248           goto nextreloc;\r
249         }\r
250       off = ((char *) addr) - ((char *) base);\r
251 \r
252       /* Check if ADDR points into a rw segment.  First check the\r
253          cached index.  */\r
254       if (idx < sec_cnt)\r
255         {\r
256           if (off >= sec[idx].VirtualAddress\r
257               && off < sec[idx].VirtualAddress + section_size (&sec[idx]))\r
258             ; /* Found it.  */\r
259           else\r
260             idx = sec_cnt;\r
261         }\r
262       if (idx == sec_cnt)\r
263         {\r
264           for (idx = 0; idx < sec_cnt; idx++)\r
265             {\r
266               if (! sec[idx].PointerToLinenumbers)\r
267                 continue;\r
268               if (off >= sec[idx].VirtualAddress\r
269                   && off < sec[idx].VirtualAddress + section_size (&sec[idx]))\r
270                 break;\r
271             }\r
272           if (idx == sec_cnt)\r
273             goto nextreloc;\r
274         }\r
275       old_addr = addr;\r
276       addr = sec[idx].PointerToLinenumbers + (off - sec[idx].VirtualAddress);\r
277 \r
278 #if 0\r
279       TRACE ("rewriting relocation at %p to rw section from %p to %p\n",\r
280              ((char *)page + offset), old_addr, addr);\r
281 #endif\r
282 \r
283       switch(type)\r
284         {\r
285         case IMAGE_REL_BASED_HIGH:\r
286           *(short *)((char *)page + offset) = HIWORD(addr);\r
287           break;\r
288         case IMAGE_REL_BASED_LOW:\r
289           *(short *)((char *)page + offset) = LOWORD(addr);\r
290           break;\r
291         case IMAGE_REL_BASED_HIGHLOW:\r
292           *(int *)((char *)page + offset) = addr;\r
293           break;\r
294         }\r
295     nextreloc:\r
296       relocs++;\r
297     }\r
298   return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */\r
299 }\r
300 \r
301 \r
302 static void\r
303 relocate_rw_sections (struct himemce_map *map, void *base)\r
304 {\r
305   char *ptr;\r
306   IMAGE_DOS_HEADER *dos;\r
307   IMAGE_NT_HEADERS *nt;\r
308   IMAGE_SECTION_HEADER *sec;\r
309   int i;\r
310   IMAGE_BASE_RELOCATION *rel, *end;\r
311   const IMAGE_DATA_DIRECTORY *relocs;\r
312 \r
313   TRACE ("adjusting rw sections at %p\n", base);\r
314 \r
315   ptr = base;\r
316   dos = (IMAGE_DOS_HEADER *) ptr;\r
317   nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);\r
318   sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader\r
319                                   + nt->FileHeader.SizeOfOptionalHeader);\r
320 \r
321   /* Go through all the sections, reserve low memory for the writable\r
322      sections.  */\r
323   for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)\r
324     {\r
325       if (SECTION_IS_LOW (sec))\r
326         {\r
327           SIZE_T map_size;\r
328 \r
329           if (! sec->Misc.VirtualSize)\r
330             map_size = ROUND_SIZE (sec->SizeOfRawData);\r
331           else\r
332             map_size = ROUND_SIZE (sec->Misc.VirtualSize);\r
333 \r
334           sec->PointerToLinenumbers = (DWORD) map_reserve_low (map, map_size);\r
335 \r
336           TRACE ("mapping r/w section %.8s at %p off %x (%lx) flags "\r
337                  "%x to low mem %p\n",\r
338                  sec->Name, ptr + sec->VirtualAddress,\r
339                  sec->PointerToRawData, map_size,\r
340                  sec->Characteristics, sec->PointerToLinenumbers);\r
341         }\r
342       else\r
343         sec->PointerToLinenumbers = 0;\r
344     }\r
345 \r
346   /* Perform base relocations pointing into low sections.  Before\r
347      that, these relocations point into the high mem address.  */\r
348 \r
349   relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
350   rel = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress);\r
351   end = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress + relocs->Size);\r
352   \r
353   while (rel < end - 1 && rel->SizeOfBlock)\r
354     {\r
355       rel = LowLdrProcessRelocationBlock\r
356         (base, ptr + rel->VirtualAddress,\r
357          (rel->SizeOfBlock - sizeof (*rel)) / sizeof (USHORT),\r
358          (USHORT *)(rel + 1));\r
359     }\r
360 }\r
361 \r
362 \r
363 /* convert PE image VirtualAddress to Real Address */\r
364 static void *\r
365 get_rva (HMODULE module, DWORD va)\r
366 {\r
367   return (void *) ((char *) module + va);\r
368 }\r
369 \r
370 \r
371 /* convert from straight ASCII to Unicode without depending on the\r
372    current codepage */\r
373 static void\r
374 ascii_to_unicode (WCHAR *dst, const char *src, size_t len)\r
375 {\r
376   while (len--)\r
377     *dst++ = (unsigned char) *src++;\r
378 }\r
379 \r
380 \r
381 #define allocate_stub(x,y) ((void *)0xdeadbeef)\r
382 \r
383 \r
384 static FARPROC\r
385 find_ordinal_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,\r
386                      DWORD exp_size, DWORD ordinal)\r
387 {\r
388   FARPROC proc;\r
389   const DWORD *functions = get_rva (module, exports->AddressOfFunctions);\r
390   \r
391   if (ordinal >= exports->NumberOfFunctions)\r
392     {\r
393       TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );\r
394       return NULL;\r
395     }\r
396   if (!functions[ordinal]) return NULL;\r
397   \r
398 #if 0\r
399   /* if the address falls into the export dir, it's a forward */\r
400   if (((const char *)proc >= (const char *)exports) && \r
401       ((const char *)proc < (const char *)exports + exp_size))\r
402     return find_forwarded_export( module, (const char *)proc, load_path );\r
403 #endif\r
404 \r
405   proc = get_rva_low (module, functions[ordinal]);\r
406   return proc;\r
407 }\r
408 \r
409 \r
410 static FARPROC\r
411 find_named_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,\r
412                    DWORD exp_size, const char *name, int hint)\r
413 {\r
414   const WORD *ordinals = get_rva (module, exports->AddressOfNameOrdinals);\r
415   const DWORD *names = get_rva (module, exports->AddressOfNames);\r
416   int min = 0, max = exports->NumberOfNames - 1;\r
417 \r
418   /* first check the hint */\r
419   if (hint >= 0 && hint <= max)\r
420     {\r
421       char *ename = get_rva( module, names[hint] );\r
422       if (!strcmp( ename, name ))\r
423         return find_ordinal_export( module, exports, exp_size, ordinals[hint]);\r
424     }\r
425 \r
426   /* then do a binary search */\r
427   while (min <= max)\r
428     {\r
429       int res, pos = (min + max) / 2;\r
430       char *ename = get_rva( module, names[pos] );\r
431       if (!(res = strcmp( ename, name )))\r
432         return find_ordinal_export( module, exports, exp_size, ordinals[pos]);\r
433       if (res > 0) max = pos - 1;\r
434       else min = pos + 1;\r
435     }\r
436   return NULL;\r
437 }\r
438 \r
439 \r
440 /*************************************************************************\r
441  *              import_dll\r
442  *\r
443  * Import the dll specified by the given import descriptor.\r
444  * The loader_section must be locked while calling this function.\r
445  */\r
446 static void *\r
447 import_dll (struct himemce_map *map, HMODULE module,\r
448             const IMAGE_IMPORT_DESCRIPTOR *descr)\r
449 {\r
450   int status = 0;\r
451   const char *name = get_rva (module, descr->Name);\r
452   DWORD len = strlen(name);\r
453   const IMAGE_THUNK_DATA *import_list;\r
454   IMAGE_THUNK_DATA *thunk_list;\r
455   void *imp_base = 0;\r
456   HMODULE imp_mod = 0;\r
457   const IMAGE_EXPORT_DIRECTORY *exports;\r
458   DWORD exp_size;\r
459   WCHAR buffer[32];\r
460   int i;\r
461 \r
462   thunk_list = get_rva (module, (DWORD)descr->FirstThunk);\r
463   if (descr->OriginalFirstThunk)\r
464     import_list = get_rva (module, (DWORD)descr->OriginalFirstThunk);\r
465   else\r
466     import_list = thunk_list;\r
467 \r
468   while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */\r
469 \r
470   /* First check for the modules in the map.  */\r
471   for (i = 0; i < map->nr_modules; i++)\r
472     {\r
473       if (! strncmp (name, map->module[i].name, len))\r
474         break;\r
475     }\r
476   if (i < map->nr_modules)\r
477     {\r
478       imp_base = map->module[i].base;\r
479       TRACE("Loading library %s internal\n", name);\r
480     }\r
481   else if (len * sizeof(WCHAR) < sizeof(buffer))\r
482     {\r
483       ascii_to_unicode( buffer, name, len );\r
484       buffer[len] = 0;\r
485       imp_mod = LoadLibrary (buffer);\r
486       if (imp_mod == INVALID_HANDLE_VALUE)\r
487         status = GetLastError ();\r
488     }\r
489   else\r
490     {\r
491       WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );\r
492       if (!ptr) return NULL;\r
493       ascii_to_unicode( ptr, name, len );\r
494       ptr[len] = 0;\r
495       imp_mod = LoadLibrary (ptr);\r
496       if (imp_mod == INVALID_HANDLE_VALUE)\r
497         status = GetLastError ();\r
498       free (ptr);\r
499     }\r
500   if (status)\r
501     {\r
502       if (status == ERROR_DLL_NOT_FOUND)\r
503         TRACE("Library %s not found\n", name);\r
504       else\r
505         TRACE("Loading library %s failed (error %x).\n",  name, status);\r
506       return NULL;\r
507     }\r
508 \r
509   if (imp_base)\r
510     {\r
511       exports = MyRtlImageDirectoryEntryToData (imp_base, TRUE,\r
512                                                 IMAGE_DIRECTORY_ENTRY_EXPORT,\r
513                                                 &exp_size);\r
514       if (!exports)\r
515         {\r
516           /* set all imported function to deadbeef */\r
517           while (import_list->u1.Ordinal)\r
518             {\r
519               if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
520                 {\r
521                   int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
522                   TRACE ("No implementation for %s.%d", name, ordinal);\r
523                   thunk_list->u1.Function\r
524                     = (PDWORD) allocate_stub (name, IntToPtr (ordinal));\r
525                 }\r
526               else\r
527                 {\r
528                   IMAGE_IMPORT_BY_NAME *pe_name\r
529                     = get_rva (module, (DWORD) import_list->u1.AddressOfData);\r
530                   TRACE ("No implementation for %s.%s", name, pe_name->Name);\r
531                   thunk_list->u1.Function\r
532                     = (PDWORD) allocate_stub (name, (const char*) pe_name->Name);\r
533                 }\r
534               import_list++;\r
535               thunk_list++;\r
536             }\r
537           goto done;\r
538         }\r
539     }\r
540   \r
541   while (import_list->u1.Ordinal)\r
542     {\r
543       if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
544         {\r
545           int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
546 \r
547           if (imp_base)\r
548             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
549               find_ordinal_export (imp_base, exports, exp_size,\r
550                                    ordinal - exports->Base);\r
551           else\r
552             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
553               GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));\r
554           if (!thunk_list->u1.Function)\r
555             {\r
556               thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );\r
557               TRACE("No implementation for %s.%d imported, setting to %p\n",\r
558                     name, ordinal,\r
559                     (void *)thunk_list->u1.Function );\r
560             }\r
561           TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );\r
562         }\r
563       else  /* import by name */\r
564         {\r
565           IMAGE_IMPORT_BY_NAME *pe_name;\r
566           pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
567           if (imp_base)\r
568             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
569               find_named_export (imp_base, exports, exp_size,\r
570                                  (const char*)pe_name->Name, pe_name->Hint);\r
571           else\r
572             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)\r
573               GetProcAddressA (imp_mod, (const char*)pe_name->Name);\r
574           if (!thunk_list->u1.Function)\r
575             {\r
576               thunk_list->u1.Function\r
577                 = (PDWORD) allocate_stub (name, (const char*)pe_name->Name);\r
578               TRACE ("No implementation for %s.%s imported, setting to %p\n",\r
579                      name, pe_name->Name, (void *)thunk_list->u1.Function);\r
580             }\r
581           TRACE("--- %s %s.%d = %p\n",\r
582                 pe_name->Name, name, pe_name->Hint,\r
583                 (void *)thunk_list->u1.Function);\r
584         }\r
585       import_list++;\r
586       thunk_list++;\r
587     }\r
588 \r
589  done:\r
590   return (void*)1;\r
591 }\r
592 \r
593 \r
594 static void\r
595 fixup_imports (struct himemce_map *map, void *base)\r
596 {\r
597   int i, nb_imports;\r
598   const IMAGE_IMPORT_DESCRIPTOR *imports;\r
599   DWORD size;\r
600 \r
601   imports = MyRtlImageDirectoryEntryToData (base, TRUE,\r
602                                             IMAGE_DIRECTORY_ENTRY_IMPORT,\r
603                                             &size);\r
604   if (!imports)\r
605     return;\r
606 \r
607   nb_imports = 0;\r
608   while (imports[nb_imports].Name && imports[nb_imports].FirstThunk)\r
609     nb_imports++;\r
610   if (!nb_imports)\r
611     return;\r
612 \r
613   for (i = 0; i < nb_imports; i++)\r
614     {\r
615       if (! import_dll (map, base, &imports[i]))\r
616         {\r
617           SetLastError (ERROR_DLL_NOT_FOUND);\r
618           break;\r
619         }\r
620     }\r
621 }\r
622 \r
623 \r
624 int\r
625 main (int argc, char *argv[])\r
626 {\r
627   struct himemce_map *map;\r
628   int result = 0;\r
629   int i;\r
630 \r
631   TRACE ("creating map file...\n");\r
632 \r
633   map = map_create ();\r
634   if (! map)\r
635     return 1;\r
636 \r
637   TRACE ("finding modules...\n");\r
638 \r
639   result = find_modules (map);\r
640   if (! result)\r
641     exit (1);\r
642 \r
643   TRACE ("loading modules...\n");\r
644 \r
645   /* For each module: load it high without resolving references.  */\r
646   for (i = 0; i < map->nr_modules; i++)\r
647     {\r
648       struct himemce_module *mod = &map->module[i];\r
649       void *base = MyLoadLibraryExW (mod->filename, 0,\r
650                                      DONT_RESOLVE_DLL_REFERENCES);\r
651 \r
652       if (! base)\r
653         {\r
654           ERR ("could not load %S: %i\n", mod->filename, GetLastError());\r
655           exit (1);\r
656         }\r
657       mod->base = base;\r
658     }\r
659 \r
660   TRACE ("relocationg writable sections...\n");\r
661 \r
662   for (i = 0; i < map->nr_modules; i++)\r
663     {\r
664       struct himemce_module *mod = &map->module[i];\r
665 \r
666       /* Allocate low mem for read-write sections and adjust\r
667          relocations pointing into them.  */\r
668       relocate_rw_sections (map, mod->base);\r
669     }\r
670 \r
671   /* Export entries are handled at time of import on the other side,\r
672      when we check for low memory mapped sections and adjust the\r
673      imported address accordingly.  */\r
674 \r
675   TRACE ("resolve module dependencies...\n");\r
676 \r
677   for (i = 0; i < map->nr_modules; i++)\r
678     {\r
679       struct himemce_module *mod = &map->module[i];\r
680 \r
681       /* Fixup imports (this loads all dependencies as well!).  */\r
682       fixup_imports (map, mod->base);\r
683     }\r
684 \r
685   TRACE ("sleeping...");\r
686 \r
687   while (1)\r
688     Sleep (3600 * 1000);\r
689 \r
690   return 0;\r
691 }\r