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