Add tentative support for DllMain of high loaded DLLs.
[wincetools.git] / loader / ntdll_loader.c
1 /* From wine1.2-1.1.42/dlls/ntdll/loader.c  */
2
3 /*
4  * Loader functions
5  *
6  * Copyright 1995, 2003 Alexandre Julliard
7  * Copyright 2002 Dmitry Timoshkov for CodeWeavers
8  * Copyright 2010 g10 Code GmbH
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25
26
27 #include <assert.h>
28
29 #undef USE_DLMALLOC
30 #ifdef USE_DLMALLOC
31 #include "dlmalloc.h"
32 #endif
33
34 #include "wine.h"
35
36 /* convert PE image VirtualAddress to Real Address */
37 static void *get_rva( HMODULE module, DWORD va )
38 {
39   return (void *)((char *)module + va);
40 }
41
42
43 #define USE_HIMEMCE_MAP
44 #ifdef USE_HIMEMCE_MAP
45 /* Support for DLL loading.  */
46
47 #include "himemce-map.h"
48
49 static int himemce_map_initialized;
50 static struct himemce_map *himemce_map;
51 int himemce_mod_loaded[HIMEMCE_MAP_MAX_MODULES];
52
53 void
54 himemce_invoke_dll_mains (DWORD reason, LPVOID reserved)
55 {
56   int i;
57
58   if (! himemce_map)
59     return NULL;
60
61   for (i = 0; i < himemce_map->nr_modules; i++)
62     if (himemce_mod_loaded[modidx])
63       {
64         char *ptr = himemce_map->module[i].base;
65         IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)ptr;
66         IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
67         BOOL WINAPI (*dllmain) (HINSTANCE, DWORD, LPVOID);
68         BOOL res;
69
70         dllmain = nt->OptionalHeader.AddressOfEntryPoint;
71         res = (*dllmain) (ptr, reason, reserved);
72         if (reason == DLL_PROCESS_ATTACH && !res)
73           {
74             ERR ("attaching %s failed (ignored)", himemce_map->module[i].name);
75           }
76       }
77 }
78
79
80 static void
81 himemce_map_init ()
82 {
83   void *ptr;
84   /* Only try once.  */
85   if (himemce_map_initialized)
86     return;
87   himemce_map_initialized = 1;
88   himemce_map = himemce_map_open ();
89   if (! himemce_map)
90     {
91       TRACE ("can not open himemce map\n");
92       return;
93     }
94   TRACE ("himemce map found at %p (reserving 0x%x bytes at %p)\n", himemce_map,
95          himemce_map->low_start, himemce_map->low_size);
96   ptr = VirtualAlloc(himemce_map->low_start, himemce_map->low_size,
97                      MEM_RESERVE, PAGE_EXECUTE_READWRITE);
98   if (! ptr)
99     {
100       TRACE ("failed to reserve memory: %i\n", GetLastError ());
101       himemce_map_close (himemce_map);
102       himemce_map = NULL;
103       return;
104     }
105
106   himemce_set_dllmain_cb (himemce_invoke_dll_mains);
107 }
108
109
110 # define page_mask  0xfff
111 # define page_shift 12
112 # define page_size  0x1000
113
114 #define ROUND_SIZE(size)                        \
115   (((SIZE_T)(size) + page_mask) & ~page_mask)
116
117 static SIZE_T
118 section_size (IMAGE_SECTION_HEADER *sec)
119 {
120   static const SIZE_T sector_align = 0x1ff;
121   SIZE_T map_size, file_size, end;
122   
123   if (!sec->Misc.VirtualSize)
124     map_size = ROUND_SIZE( sec->SizeOfRawData );
125   else
126     map_size = ROUND_SIZE( sec->Misc.VirtualSize );
127   
128   file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align)
129                + sector_align) & ~sector_align;
130   if (file_size > map_size) file_size = map_size;
131   end = ROUND_SIZE( file_size );
132   if (end > map_size) end = map_size;
133   return end;
134 }
135
136
137 /* Returns the base of the module after loading it, if necessary.
138    NULL if not found, -1 if a fatal error occurs.  */
139 void *
140 himemce_map_load_dll (const char *name)
141 {
142   struct himemce_module *mod;
143   int modidx;
144   char *ptr;
145   IMAGE_DOS_HEADER *dos;
146   IMAGE_NT_HEADERS *nt;
147   IMAGE_SECTION_HEADER *sec;
148   int sec_cnt;
149   int idx;
150   const IMAGE_IMPORT_DESCRIPTOR *imports;
151   DWORD imports_size;
152   
153   himemce_map_init ();
154   if (! himemce_map)
155     return NULL;
156   
157   mod = himemce_map_find_module (himemce_map, name);
158   if (!mod)
159     return NULL;
160   modidx = mod - himemce_map->module;
161   if (himemce_mod_loaded[modidx])
162     return mod->base;
163   
164   /* First map the sections low.  */
165   ptr = mod->base;
166   dos = (IMAGE_DOS_HEADER *) ptr;
167   nt = (IMAGE_NT_HEADERS *) (ptr + dos->e_lfanew);
168   sec = (IMAGE_SECTION_HEADER *) ((char*) &nt->OptionalHeader
169                                   + nt->FileHeader.SizeOfOptionalHeader);
170   sec_cnt = nt->FileHeader.NumberOfSections;
171   for (idx = 0; idx < sec_cnt; idx++)
172     {
173       size_t secsize;
174       char *secptr;
175       
176       if (! sec[idx].PointerToLinenumbers)
177         continue;
178       secsize = section_size (&sec[idx]);
179       secptr = VirtualAlloc ((void *) sec[idx].PointerToLinenumbers,
180                              secsize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
181       if (! secptr)
182         {
183           TRACE ("could not allocate 0x%x bytes of low memory at %p: %i\n",
184                  secsize, sec[idx].PointerToLinenumbers, GetLastError ());
185           return (void *) -1;
186         }
187       memcpy (secptr, ptr + sec[idx].VirtualAddress, secsize);
188     }
189   
190   /* To break circles, we claim that we loaded before recursing.  */
191   himemce_mod_loaded[modidx]++;
192   imports = MyRtlImageDirectoryEntryToData ((HMODULE) ptr, TRUE,
193                                             IMAGE_DIRECTORY_ENTRY_IMPORT,
194                                             &imports_size);
195   if (imports)
196     {
197       idx = 0;
198       while (imports[idx].Name && imports[idx].FirstThunk)
199         {
200           char *iname = ptr + imports[idx].Name;
201           void *ibase;
202           
203           /* Recursion!  */
204           ibase = himemce_map_load_dll (iname);
205           if (ibase == (void *) -1)
206             return (void *) -1;
207           /* Nothing to do if ibase !=0: Successful loading of high DLL.  */
208           if (ibase == 0)
209             {
210               ibase = LoadLibrary (iname);
211               if (!ibase)
212                 {
213                   TRACE ("Could not find %s, dependency of %s\n", iname, name);
214                   return (void *) -1;
215                 }
216             }
217           idx++;
218         }
219     }
220   return ptr;
221 }
222
223
224 static void *
225 get_rva_low (char *module, size_t rva)
226 {
227   IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;
228   IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(module + dos->e_lfanew);
229   IMAGE_SECTION_HEADER *sec;
230   int sec_cnt;
231   int idx;
232   
233   sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader
234                                 + nt->FileHeader.SizeOfalHeader);
235   sec_cnt = nt->FileHeader.NumberOfSections;
236
237   for (idx = 0; idx < sec_cnt; idx++)
238     {
239       if (! sec[idx].PointerToLinenumbers)
240         continue;
241       if (rva >= sec[idx].VirtualAddress
242           && rva < sec[idx].VirtualAddress + section_size (&sec[idx]))
243         break;
244     }
245   if (idx == sec_cnt)
246     return (void *)((char *)module + rva);
247   
248   return (void *)((char *)sec[idx].PointerToLinenumbers
249                   + (rva - sec[idx].VirtualAddress));
250 }
251
252
253 static FARPROC
254 find_ordinal_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,
255                      DWORD exp_size, DWORD ordinal, LPCWSTR load_path)
256 {
257   FARPROC proc;
258   const DWORD *functions = get_rva (module, exports->AddressOfFunctions);
259   
260   if (ordinal >= exports->NumberOfFunctions)
261     {
262       TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
263       return NULL;
264     }
265   if (!functions[ordinal]) return NULL;
266   
267 #if 0
268   /* if the address falls into the export dir, it's a forward */
269   if (((const char *)proc >= (const char *)exports) &&
270       ((const char *)proc < (const char *)exports + exp_size))
271     return find_forwarded_export( module, (const char *)proc, load_path );
272 #endif
273
274   proc = get_rva_low (module, functions[ordinal]);
275   return proc;
276 }
277
278 static FARPROC
279 find_named_export (void *module, const IMAGE_EXPORT_DIRECTORY *exports,
280                    DWORD exp_size, const char *name, int hint,
281                    LPCWSTR load_path)
282 {
283   const WORD *ordinals = get_rva (module, exports->AddressOfNameOrdinals);
284   const DWORD *names = get_rva (module, exports->AddressOfNames);
285   int min = 0, max = exports->NumberOfNames - 1;
286   
287   /* first check the hint */
288   if (hint >= 0 && hint <= max)
289     {
290       char *ename = get_rva( module, names[hint] );
291       if (!strcmp( ename, name ))
292         return find_ordinal_export( module, exports, exp_size,
293                                     ordinals[hint], load_path);
294     }
295   
296   /* then do a binary search */
297   while (min <= max)
298     {
299       int res, pos = (min + max) / 2;
300       char *ename = get_rva( module, names[pos] );
301       if (!(res = strcmp( ename, name )))
302         return find_ordinal_export( module, exports, exp_size,
303                                     ordinals[pos], load_path);
304       if (res > 0) max = pos - 1;
305       else min = pos + 1;
306     }
307   return NULL;
308 }
309
310 #endif
311
312
313 PIMAGE_NT_HEADERS MyRtlImageNtHeader(HMODULE hModule)
314 {
315   IMAGE_NT_HEADERS *ret;
316   IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
317   
318   ret = NULL;
319   if (dos->e_magic == IMAGE_DOS_SIGNATURE)
320     {
321       ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
322       if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
323     }
324   return ret;
325 }
326
327 \f
328 /* internal representation of 32bit modules. per process. */
329 typedef struct _wine_modref
330 {
331     LDR_MODULE            ldr;
332     int                   nDeps;
333     struct _wine_modref **deps;
334 } WINE_MODREF;
335
336 /* FIXME: cmp with himemce-map.h */
337 #define MAX_MODREFS 64
338 WINE_MODREF *modrefs[MAX_MODREFS];
339 int nr_modrefs;
340
341
342 static WINE_MODREF *current_modref;
343
344
345 /* convert from straight ASCII to Unicode without depending on the current codepage */
346 static void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
347 {
348   while (len--) *dst++ = (unsigned char)*src++;
349 }
350
351
352 /***********************************************************************
353  *           RtlImageDirectoryEntryToData   (NTDLL.@)
354  */
355 PVOID MyRtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
356 {
357   const IMAGE_NT_HEADERS *nt;
358   DWORD addr;
359
360   if ((ULONG_PTR)module & 1)  /* mapped as data file */
361     {
362       module = (HMODULE)((ULONG_PTR)module & ~1);
363       image = FALSE;
364     }
365   if (!(nt = MyRtlImageNtHeader( module ))) return NULL;
366   if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
367     {
368       const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
369
370       if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
371       if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
372       *size = nt64->OptionalHeader.DataDirectory[dir].Size;
373       if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
374     }
375   else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
376     {
377       const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
378
379       if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
380       if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
381       *size = nt32->OptionalHeader.DataDirectory[dir].Size;
382       if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
383     }
384   else return NULL;
385
386 #if 0
387   /* not mapped as image, need to find the section containing the virtual address */
388   return RtlImageRvaToVa( nt, module, addr, NULL );
389 #else
390   return NULL;
391 #endif
392 }
393
394
395 #define allocate_stub(x,y) (0xdeadbeef)
396
397 /*************************************************************************
398  *              import_dll
399  *
400  * Import the dll specified by the given import descriptor.
401  * The loader_section must be locked while calling this function.
402  */
403 static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
404 {
405   NTSTATUS status = STATUS_SUCCESS;
406   //  WINE_MODREF *wmImp;
407   HMODULE imp_mod;
408 #ifdef USE_HIMEMCE_MAP
409   void *imp_base = 0;
410   const IMAGE_EXPORT_DIRECTORY *exports;
411   DWORD exp_size;
412 #endif
413   const IMAGE_THUNK_DATA *import_list;
414   IMAGE_THUNK_DATA *thunk_list;
415   WCHAR buffer[32];
416   const char *name = get_rva( module, descr->Name );
417   DWORD len = strlen(name);
418 #if 0
419   PVOID protect_base;
420   SIZE_T protect_size = 0;
421   DWORD protect_old;
422 #endif
423 #ifdef USE_DLMALLOC
424   int iscoredll = 0;
425 #endif
426
427   thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
428   if (descr->OriginalFirstThunk)
429     import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );
430   else
431     import_list = thunk_list;
432
433   while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */
434
435 #ifdef USE_DLMALLOC
436   if (! _stricmp (name, "coredll.dll"))
437     iscoredll = 1;
438 #endif
439
440 #ifdef USE_HIMEMCE_MAP
441   imp_base = himemce_map_load_dll (name);
442   if (imp_base == (void *) -1)
443     status = GetLastError ();
444   if (imp_base)
445     goto loaded;
446 #endif
447
448   if (len * sizeof(WCHAR) < sizeof(buffer))
449     {
450       ascii_to_unicode( buffer, name, len );
451       buffer[len] = 0;
452       //      status = load_dll( load_path, buffer, 0, &wmImp );
453       imp_mod = LoadLibrary (buffer);
454           if (imp_mod == INVALID_HANDLE_VALUE)
455             status = GetLastError ();
456   }
457   else  /* need to allocate a larger buffer */
458     {
459       WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );
460       if (!ptr) return NULL;
461       ascii_to_unicode( ptr, name, len );
462       ptr[len] = 0;
463       // status = load_dll( load_path, ptr, 0, &wmImp );
464           imp_mod = LoadLibrary (ptr);
465           if (imp_mod == INVALID_HANDLE_VALUE)
466             status = GetLastError ();
467           free (ptr);
468     }
469 #ifdef USE_HIMEMCE_MAP
470 loaded:
471 #endif
472   if (status)
473     {
474       if (status == STATUS_DLL_NOT_FOUND)
475         TRACE("Library %s (which is needed by %s) not found\n",
476             name, current_modref->ldr.FullDllName);
477       else
478         TRACE("Loading library %s (which is needed by %s) failed (error %x).\n",
479             name, current_modref->ldr.FullDllName, status);
480       return NULL;
481     }
482   
483 #if 0
484   /* unprotect the import address table since it can be located in
485    * readonly section */
486   while (import_list[protect_size].u1.Ordinal) protect_size++;
487   protect_base = thunk_list;
488   protect_size *= sizeof(*thunk_list);
489   NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
490                           &protect_size, PAGE_WRITECOPY, &protect_old );
491 #endif
492
493 #ifdef USE_HIMEMCE_MAP
494  if (imp_base)
495  {
496    exports = MyRtlImageDirectoryEntryToData( imp_base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
497
498   if (!exports)
499     {
500       /* set all imported function to deadbeef */
501       while (import_list->u1.Ordinal)
502         {
503           if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
504             {
505               int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
506               TRACE("No implementation for %s.%d", name, ordinal );
507               thunk_list->u1.Function = (PDWORD)(ULONG_PTR)allocate_stub( name, IntToPtr(ordinal) );
508             }
509           else
510             {
511               IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
512               TRACE("No implementation for %s.%s", name, pe_name->Name );
513               thunk_list->u1.Function = (PDWORD)(ULONG_PTR)allocate_stub( name, (const char*)pe_name->Name );
514             }
515           TRACE(" imported from %s, allocating stub %p\n",
516                current_modref->ldr.FullDllName,
517                (void *)thunk_list->u1.Function );
518           import_list++;
519           thunk_list++;
520         }
521       goto done;
522     }
523  }
524 #endif
525
526   while (import_list->u1.Ordinal)
527     {
528       if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
529         {
530           int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
531
532 #ifdef USE_HIMEMCE_MAP
533           if (imp_base)
534                 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)find_ordinal_export( imp_base, exports, exp_size,
535                                                                       ordinal - exports->Base, load_path );
536           else
537 #endif
538
539 #ifdef USE_DLMALLOC
540           if (iscoredll)
541             {
542 #define COREDLL_MALLOC 1041
543 #define COREDLL_CALLOC 1346
544 #define COREDLL_FREE 1018
545 #define COREDLL_REALLOC 1054
546
547               if (ordinal == COREDLL_MALLOC)
548                 thunk_list->u1.Function = (PWORD) dlmalloc;
549               else if (ordinal == COREDLL_CALLOC)
550                 thunk_list->u1.Function = (PWORD) dlcalloc;
551               else if (ordinal == COREDLL_FREE)
552                 thunk_list->u1.Function = (PWORD) dlfree;
553               else if (ordinal == COREDLL_REALLOC)
554                 thunk_list->u1.Function = (PWORD) dlrealloc;
555               else
556                 thunk_list->u1.Function = (PWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));
557             }
558           else
559 #endif
560             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));
561
562           if (!thunk_list->u1.Function)
563             {
564               thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );
565               TRACE("No implementation for %s.%d imported from %s, setting to %p\n",
566                     name, ordinal, current_modref->ldr.FullDllName,
567                     (void *)thunk_list->u1.Function );
568             }
569           TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
570         }
571       else  /* import by name */
572         {
573           IMAGE_IMPORT_BY_NAME *pe_name;
574           const char *symname;
575           pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
576           symname = (const char*)pe_name->Name;
577
578 #ifdef USE_HIMEMCE_MAP
579           if (imp_base)
580                   thunk_list->u1.Function = (PDWORD)(ULONG_PTR)find_named_export( imp_base, exports, exp_size,
581                                                                           (const char*)pe_name->Name,
582                                                                           pe_name->Hint, load_path );
583           else
584 #endif
585 #ifdef USE_DLMALLOC
586           if (iscoredll)
587             {
588               if (! strcmp (symname, "malloc"))
589                 thunk_list->u1.Function = (PWORD) dlmalloc;
590               else if (! strcmp (symname, "calloc"))
591                 thunk_list->u1.Function = (PWORD) dlcalloc;
592               else if (! strcmp (symname, "free"))
593                 thunk_list->u1.Function = (PWORD) dlfree;
594               else if (! strcmp (symname, "realloc"))
595                 thunk_list->u1.Function = (PWORD) dlrealloc;
596               else
597                 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, symname);
598             }
599           else
600 #endif
601             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, symname);
602           if (!thunk_list->u1.Function)
603             {
604               thunk_list->u1.Function = (PDWORD) allocate_stub (name, symname);
605               TRACE("No implementation for %s.%s imported from %s, setting to %p\n",
606                     name, symname, current_modref->ldr.FullDllName,
607                     (void *)thunk_list->u1.Function );
608             }
609           TRACE("--- %s %s.%d = %p\n",
610                 symname, name, pe_name->Hint, (void *)thunk_list->u1.Function);
611         }
612       import_list++;
613       thunk_list++;
614     }
615 done:
616 #if 0
617   /* restore old protection of the import address table */
618   NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
619   return wmImp;
620 #endif
621   return (void*)1;
622 }
623
624
625
626 /****************************************************************
627  *       fixup_imports
628  *
629  * Fixup all imports of a given module.
630  * The loader_section must be locked while calling this function.
631  */
632 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
633 {
634   int i, nb_imports;
635   const IMAGE_IMPORT_DESCRIPTOR *imports;
636   WINE_MODREF *prev;
637   DWORD size;
638   NTSTATUS status;
639   //  ULONG_PTR cookie;
640
641   if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
642   wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
643   
644   if (!(imports = MyRtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
645                                                   IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
646     return STATUS_SUCCESS;
647   
648   nb_imports = 0;
649   while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
650   
651   if (!nb_imports) return STATUS_SUCCESS;  /* no imports */
652   
653 #if 0
654   if (!create_module_activation_context( &wm->ldr ))
655     RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
656 #endif
657   
658 #if 0
659   /* Allocate module dependency list */
660   wm->nDeps = nb_imports;
661   wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
662 #endif
663
664   /* load the imported modules. They are automatically
665    * added to the modref list of the process.
666    */
667   prev = current_modref;
668   current_modref = wm;
669   status = STATUS_SUCCESS;
670   for (i = 0; i < nb_imports; i++)
671     {
672       //      if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
673       if (! import_dll( wm->ldr.BaseAddress, &imports[i], load_path ))
674         status = STATUS_DLL_NOT_FOUND;
675     }
676   current_modref = prev;
677   //  if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
678
679 #ifdef USE_HIMEMCE_MAP
680   himemce_invoke_dll_mains (DLL_PROCESS_ATTACH, NULL);
681 #endif
682
683   return status;
684 }
685
686
687 static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
688 {
689         return FALSE;
690 }
691
692
693 /*************************************************************************
694  *              get_modref
695  *
696  * Looks for the referenced HMODULE in the current process
697  * The loader_section must be locked while calling this function.
698  */
699 static WINE_MODREF *get_modref( HMODULE hmod )
700 {
701   int i;
702   for (i = 0; i < nr_modrefs; i++)
703     if (modrefs[i]->ldr.BaseAddress == hmod)
704       return modrefs[i];
705   return NULL;
706 }
707
708
709
710 static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
711 {
712     WINE_MODREF *wm;
713     const WCHAR *p;
714     const IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader(hModule);
715 #if 0
716     PLIST_ENTRY entry, mark;
717 #endif
718
719     if (!(wm = malloc (sizeof(*wm)))) return NULL;
720
721     wm->nDeps    = 0;
722     wm->deps     = NULL;
723
724     wm->ldr.BaseAddress   = hModule;
725     wm->ldr.EntryPoint    = NULL;
726     wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
727     wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;
728     wm->ldr.LoadCount     = 1;
729     wm->ldr.TlsIndex      = -1;
730     wm->ldr.SectionHandle = NULL;
731     wm->ldr.CheckSum      = 0;
732     wm->ldr.TimeDateStamp = 0;
733     wm->ldr.ActivationContext = 0;
734
735     wcscpy (wm->ldr.FullDllName, filename);
736     if ((p = wcsrchr( wm->ldr.FullDllName, L'\\' ))) p++;
737     else p = wm->ldr.FullDllName;
738     wcscpy (wm->ldr.BaseDllName, p );
739
740     if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))
741     {
742         wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
743         if (nt->OptionalHeader.AddressOfEntryPoint)
744             wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
745     }
746
747 #if 0
748     InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
749                    &wm->ldr.InLoadOrderModuleList);
750
751     /* insert module in MemoryList, sorted in increasing base addresses */
752     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
753     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
754     {
755         if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
756             break;
757     }
758     entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
759     wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
760     wm->ldr.InMemoryOrderModuleList.Flink = entry;
761     entry->Blink = &wm->ldr.InMemoryOrderModuleList;
762
763     /* wait until init is called for inserting into this list */
764     wm->ldr.InInitializationOrderModuleList.Flink = NULL;
765     wm->ldr.InInitializationOrderModuleList.Blink = NULL;
766 #endif
767
768     modrefs[nr_modrefs++] = wm;
769
770     return wm;
771 }
772
773
774 static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
775                                  DWORD flags, WINE_MODREF** pwm )
776 {
777   void *module;
778   HANDLE mapping;
779   LARGE_INTEGER size;
780   SIZE_T len = 0;
781   WINE_MODREF *wm;
782   NTSTATUS status;
783
784   TRACE("Trying native dll %S\n", name);
785   
786   size.QuadPart = 0;
787   status = MyNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
788                               NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
789   if (status != STATUS_SUCCESS) return status;
790   
791   module = NULL;
792   status = MyNtMapViewOfSection( mapping, NtCurrentProcess(),
793                                  &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
794   CloseHandle( mapping );
795   if (status < 0) return status;
796   
797   /* create the MODREF */
798   
799   if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;
800   
801   /* fixup imports */
802   
803   if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
804     {
805 #if 1
806       return (STATUS_NOT_IMPLEMENTED);
807 #else
808       if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)
809         {
810 #if 0
811           /* the module has only be inserted in the load & memory order lists */
812           RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
813           RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
814           
815           /* FIXME: there are several more dangling references
816            * left. Including dlls loaded by this dll before the
817            * failed one. Unrolling is rather difficult with the
818            * current structure and we can leave them lying
819            * around with no problems, so we don't care.
820            * As these might reference our wm, we don't free it.
821            */
822 #endif
823           return status;
824         }
825 #endif
826     }
827   
828   TRACE( "Loaded %S at %p: native\n", wm->ldr.FullDllName, module );
829   
830   wm->ldr.LoadCount = 1;
831   *pwm = wm;
832   return STATUS_SUCCESS;
833 }
834
835
836 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
837                                WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
838 {
839   HMODULE hnd = GetModuleHandle (NULL);
840   int len;
841   
842   assert (handle);
843   assert (*size == MAX_PATH);
844   
845   if (libname[0] == L'/' || libname[0] == L'\\')
846     {
847       wcscpy (filename, libname);
848     }
849   else
850     {
851       len = GetModuleFileName (hnd, filename, MAX_PATH);
852       filename[len++] = L'\\';
853       wcscpy (&filename[len], libname);
854     }
855   TRACE( "opening %S\n", filename);
856   
857   if (handle)
858     {
859       *handle = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL,
860                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
861       TRACE ("find_dll_file: 0x%p (0x%x)\n", *handle, GetFileSize (*handle, NULL));
862     }
863   return STATUS_SUCCESS;
864 }
865
866
867 static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
868 {
869     WCHAR filename[MAX_PATH];
870     ULONG size;
871     HANDLE handle = 0;
872     NTSTATUS nts;
873
874     TRACE( "looking for %S in %S\n", libname, load_path ? load_path : L"default path" );
875
876     *pwm = NULL;
877     size = MAX_PATH;
878     find_dll_file( load_path, libname, filename, &size, pwm, &handle );
879     
880     if (!handle)
881       nts = STATUS_DLL_NOT_FOUND;
882     else
883       nts = load_native_dll( load_path, filename, handle, flags, pwm );
884     
885     if (nts == STATUS_SUCCESS)
886       {
887         /* Initialize DLL just loaded */
888         TRACE("Loaded module %S at %p\n", filename, (*pwm)->ldr.BaseAddress);
889         if (handle)
890           CloseHandle( handle );
891         return nts;
892       }
893     
894     TRACE("Failed to load module %S; status=%x\n", libname, nts);
895     if (handle)
896       CloseHandle( handle );
897     return nts;
898 }
899
900
901 NTSTATUS MyLdrLoadDll(LPCWSTR path_name, DWORD flags,
902                       LPCWSTR libname, HMODULE* hModule)
903 {
904   WINE_MODREF *wm;
905   NTSTATUS nts;
906
907   /* Support for dll path removed.  */
908   nts = load_dll( path_name, libname, flags, &wm );
909
910   /* For now.  */
911   assert (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS);
912 #if 0
913   if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
914     {
915       nts = process_attach( wm, NULL );
916       if (nts != STATUS_SUCCESS)
917         {
918           LdrUnloadDll(wm->ldr.BaseAddress);
919           wm = NULL;
920         }
921     }
922 #endif
923   *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
924
925   return nts;
926 }
927
928
929
930 /***********************************************************************
931  *           LdrProcessRelocationBlock  (NTDLL.@)
932  *
933  * Apply relocations to a given page of a mapped PE image.
934  */
935 IMAGE_BASE_RELOCATION * MyLdrProcessRelocationBlock( void *page, UINT count,
936                                                      USHORT *relocs, INT_PTR delta )
937 {
938   while (count--)
939     {
940       USHORT offset = *relocs & 0xfff;
941       int type = *relocs >> 12;
942       switch(type)
943         {
944         case IMAGE_REL_BASED_ABSOLUTE:
945           break;
946 #if 1
947         case IMAGE_REL_BASED_HIGH:
948           *(short *)((char *)page + offset) += HIWORD(delta);
949           break;
950         case IMAGE_REL_BASED_LOW:
951           *(short *)((char *)page + offset) += LOWORD(delta);
952           break;
953         case IMAGE_REL_BASED_HIGHLOW:
954           *(int *)((char *)page + offset) += delta;
955           break;
956 #else
957         case IMAGE_REL_BASED_DIR64:
958           *(INT_PTR *)((char *)page + offset) += delta;
959           break;
960 #endif
961         default:
962           TRACE("Unknown/unsupported fixup type %x.\n", type);
963           return NULL;
964         }
965       relocs++;
966     }
967   return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
968 }
969
970
971 void MyLdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
972                            ULONG_PTR unknown3, ULONG_PTR unknown4 )
973 {
974   static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
975   NTSTATUS status;
976   WINE_MODREF *wm;
977   LPCWSTR load_path = NULL;
978   PEB *peb = current_peb();
979   IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader( peb->ImageBaseAddress );
980   void (*_kernel_start) (void *ptr) = kernel_start;
981
982 #if 0
983   if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */
984 #endif
985
986   /* allocate the modref for the main exe (if not already done) */
987   wm = get_modref( peb->ImageBaseAddress );
988   assert( wm );
989   if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
990     {
991       TRACE("%S is a dll, not an executable\n", wm->ldr.FullDllName );
992       exit(1);
993     }
994
995   //  peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
996   //  version_init( wm->ldr.FullDllName );
997
998   //  LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,
999   //                                 REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );
1000
1001   /* the main exe needs to be the first in the load order list */
1002   //  RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
1003   //  InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
1004
1005   //  if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;
1006   //  if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;
1007
1008   //  actctx_init();
1009   //  load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1010   if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
1011   //  if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
1012   //  if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
1013   //  heap_set_debug_flags( GetProcessHeap() );
1014
1015 #if 0
1016   /* FIXME: This may be interesting at some point.  */
1017   status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );
1018   if (status != STATUS_SUCCESS) goto error;
1019 #endif
1020
1021   //  virtual_release_address_space( nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE );
1022   //  virtual_clear_thread_stack();
1023   //  wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
1024   // stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
1025   _kernel_start (peb);
1026
1027  error:
1028   TRACE( "Main exe initialization for %S failed, status %x\n",
1029          wm->ldr.FullDllName, status);
1030          //      peb->ProcessParameters->ImagePathName, status );
1031   //  NtTerminateProcess( GetCurrentProcess(), status );
1032   exit (1);
1033 }