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