Replace malloc and friends.
[wincetools.git] / loader / ntdll_loader.c
1 /* From wine1.2-1.1.42/dlls/ntdll/loader.c  */\r
2 \r
3 /*\r
4  * Loader functions\r
5  *\r
6  * Copyright 1995, 2003 Alexandre Julliard\r
7  * Copyright 2002 Dmitry Timoshkov for CodeWeavers\r
8  * Copyright 2010 g10 Code GmbH\r
9  *\r
10  * This library is free software; you can redistribute it and/or\r
11  * modify it under the terms of the GNU Lesser General Public\r
12  * License as published by the Free Software Foundation; either\r
13  * version 2.1 of the License, or (at your option) any later version.\r
14  *\r
15  * This library is distributed in the hope that it will be useful,\r
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
18  * Lesser General Public License for more details.\r
19  *\r
20  * You should have received a copy of the GNU Lesser General Public\r
21  * License along with this library; if not, write to the Free Software\r
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
23  */\r
24 \r
25 \r
26 \r
27 #include <assert.h>\r
28 \r
29 #include "dlmalloc.h"\r
30 #include "wine.h"\r
31 \r
32 PIMAGE_NT_HEADERS MyRtlImageNtHeader(HMODULE hModule)\r
33 {\r
34     IMAGE_NT_HEADERS *ret;\r
35     IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;\r
36 \r
37     ret = NULL;\r
38     if (dos->e_magic == IMAGE_DOS_SIGNATURE)\r
39     {\r
40         ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);\r
41         if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;\r
42     }\r
43     return ret;\r
44 }\r
45 \r
46 \f\r
47 /* internal representation of 32bit modules. per process. */\r
48 typedef struct _wine_modref\r
49 {\r
50     LDR_MODULE            ldr;\r
51     int                   nDeps;\r
52     struct _wine_modref **deps;\r
53 } WINE_MODREF;\r
54 \r
55 /* FIXME: cmp with himemce-map.h */\r
56 #define MAX_MODREFS 64\r
57 WINE_MODREF *modrefs[MAX_MODREFS];\r
58 int nr_modrefs;\r
59 \r
60 \r
61 static WINE_MODREF *current_modref;\r
62 \r
63 \r
64 /* convert from straight ASCII to Unicode without depending on the current codepage */\r
65 static void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )\r
66 {\r
67   while (len--) *dst++ = (unsigned char)*src++;\r
68 }\r
69 \r
70 \r
71 /***********************************************************************\r
72  *           RtlImageDirectoryEntryToData   (NTDLL.@)\r
73  */\r
74 PVOID MyRtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )\r
75 {\r
76   const IMAGE_NT_HEADERS *nt;\r
77   DWORD addr;\r
78 \r
79   if ((ULONG_PTR)module & 1)  /* mapped as data file */\r
80     {\r
81       module = (HMODULE)((ULONG_PTR)module & ~1);\r
82       image = FALSE;\r
83     }\r
84   if (!(nt = MyRtlImageNtHeader( module ))) return NULL;\r
85   if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\r
86     {\r
87       const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;\r
88 \r
89       if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;\r
90       if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;\r
91       *size = nt64->OptionalHeader.DataDirectory[dir].Size;\r
92       if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;\r
93     }\r
94   else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\r
95     {\r
96       const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;\r
97 \r
98       if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;\r
99       if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;\r
100       *size = nt32->OptionalHeader.DataDirectory[dir].Size;\r
101       if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;\r
102     }\r
103   else return NULL;\r
104 \r
105 #if 0\r
106   /* not mapped as image, need to find the section containing the virtual address */\r
107   return RtlImageRvaToVa( nt, module, addr, NULL );\r
108 #else\r
109   return NULL;\r
110 #endif\r
111 }\r
112 \r
113 \r
114 /* convert PE image VirtualAddress to Real Address */\r
115 static void *get_rva( HMODULE module, DWORD va )\r
116 {\r
117   return (void *)((char *)module + va);\r
118 }\r
119 \r
120 \r
121 #define allocate_stub(x,y) (0xdeadbeef)\r
122 \r
123 /*************************************************************************\r
124  *              import_dll\r
125  *\r
126  * Import the dll specified by the given import descriptor.\r
127  * The loader_section must be locked while calling this function.\r
128  */\r
129 static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )\r
130 {\r
131   NTSTATUS status = STATUS_SUCCESS;\r
132   //  WINE_MODREF *wmImp;\r
133   HMODULE imp_mod;\r
134   //  const IMAGE_EXPORT_DIRECTORY *exports;\r
135   //  DWORD exp_size;\r
136   const IMAGE_THUNK_DATA *import_list;\r
137   IMAGE_THUNK_DATA *thunk_list;\r
138   WCHAR buffer[32];\r
139   const char *name = get_rva( module, descr->Name );\r
140   DWORD len = strlen(name);\r
141 #if 0\r
142   PVOID protect_base;\r
143   SIZE_T protect_size = 0;\r
144   DWORD protect_old;\r
145 #endif\r
146   int iscoredll = 0;\r
147 \r
148   thunk_list = get_rva( module, (DWORD)descr->FirstThunk );\r
149   if (descr->OriginalFirstThunk)\r
150     import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );\r
151   else\r
152     import_list = thunk_list;\r
153 \r
154   while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */\r
155 \r
156   if (! _stricmp (name, "coredll.dll"))\r
157     iscoredll = 1;\r
158 \r
159   if (len * sizeof(WCHAR) < sizeof(buffer))\r
160     {\r
161 \r
162       ascii_to_unicode( buffer, name, len );\r
163       buffer[len] = 0;\r
164       //      status = load_dll( load_path, buffer, 0, &wmImp );\r
165       imp_mod = LoadLibrary (buffer);\r
166       if (imp_mod == INVALID_HANDLE_VALUE)\r
167         status = GetLastError ();\r
168     }\r
169   else  /* need to allocate a larger buffer */\r
170     {\r
171       WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );\r
172       if (!ptr) return NULL;\r
173       ascii_to_unicode( ptr, name, len );\r
174       ptr[len] = 0;\r
175       // status = load_dll( load_path, ptr, 0, &wmImp );\r
176       imp_mod = LoadLibrary (ptr);\r
177       if (imp_mod == INVALID_HANDLE_VALUE)\r
178         status = GetLastError ();\r
179       free (ptr);\r
180     }\r
181   if (status)\r
182     {\r
183       if (status == STATUS_DLL_NOT_FOUND)\r
184         TRACE("Library %s (which is needed by %s) not found\n",\r
185             name, current_modref->ldr.FullDllName);\r
186       else\r
187         TRACE("Loading library %s (which is needed by %s) failed (error %x).\n",\r
188             name, current_modref->ldr.FullDllName, status);\r
189       return NULL;\r
190     }\r
191 \r
192 #if 0\r
193   /* unprotect the import address table since it can be located in\r
194    * readonly section */\r
195   while (import_list[protect_size].u1.Ordinal) protect_size++;\r
196   protect_base = thunk_list;\r
197   protect_size *= sizeof(*thunk_list);\r
198   NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,\r
199                           &protect_size, PAGE_WRITECOPY, &protect_old );\r
200 #endif\r
201 \r
202 #if 0\r
203   imp_mod = wmImp->ldr.BaseAddress;\r
204   exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );\r
205 \r
206   if (!exports)\r
207     {\r
208       /* set all imported function to deadbeef */\r
209       while (import_list->u1.Ordinal)\r
210         {\r
211           if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
212             {\r
213               int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
214               WARN("No implementation for %s.%d", name, ordinal );\r
215               thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );\r
216             }\r
217           else\r
218             {\r
219               IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
220               WARN("No implementation for %s.%s", name, pe_name->Name );\r
221               thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );\r
222             }\r
223           WARN(" imported from %s, allocating stub %p\n",\r
224                current_modref->ldr.FullDllName,\r
225                (void *)thunk_list->u1.Function );\r
226           import_list++;\r
227           thunk_list++;\r
228         }\r
229       goto done;\r
230     }\r
231 #endif\r
232 \r
233   while (import_list->u1.Ordinal)\r
234     {\r
235       if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
236         {\r
237           int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
238 \r
239           //      thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,\r
240           //                                                                ordinal - exports->Base, load_path );\r
241 \r
242           if (iscoredll)\r
243             {\r
244 #define COREDLL_MALLOC 1041\r
245 #define COREDLL_CALLOC 1346\r
246 #define COREDLL_FREE 1018\r
247 #define COREDLL_REALLOC 1054\r
248 \r
249               if (ordinal == COREDLL_MALLOC)\r
250                 thunk_list->u1.Function = (PWORD) dlmalloc;\r
251               else if (ordinal == COREDLL_CALLOC)\r
252                 thunk_list->u1.Function = (PWORD) dlcalloc;\r
253               else if (ordinal == COREDLL_FREE)\r
254                 thunk_list->u1.Function = (PWORD) dlfree;\r
255               else if (ordinal == COREDLL_REALLOC)\r
256                 thunk_list->u1.Function = (PWORD) dlrealloc;\r
257               else\r
258                 thunk_list->u1.Function = (PWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));\r
259             }\r
260           else\r
261             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));\r
262 \r
263           if (!thunk_list->u1.Function)\r
264             {\r
265               thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );\r
266               TRACE("No implementation for %s.%d imported from %s, setting to %p\n",\r
267                     name, ordinal, current_modref->ldr.FullDllName,\r
268                     (void *)thunk_list->u1.Function );\r
269             }\r
270           TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );\r
271         }\r
272       else  /* import by name */\r
273         {\r
274           IMAGE_IMPORT_BY_NAME *pe_name;\r
275           const char *symname = (const char*)pe_name->Name;\r
276           pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
277 \r
278           //      thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,\r
279           //                                                              (const char*)pe_name->Name,\r
280           //                                                              pe_name->Hint, load_path );\r
281 \r
282           if (iscoredll)\r
283             {\r
284               if (! strcmp (symname, "malloc"))\r
285                 thunk_list->u1.Function = (PWORD) dlmalloc;\r
286               else if (! strcmp (symname, "calloc"))\r
287                 thunk_list->u1.Function = (PWORD) dlcalloc;\r
288               else if (! strcmp (symname, "free"))\r
289                 thunk_list->u1.Function = (PWORD) dlfree;\r
290               else if (! strcmp (symname, "realloc"))\r
291                 thunk_list->u1.Function = (PWORD) dlrealloc;\r
292               else\r
293                 thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, symname);\r
294             }\r
295           else\r
296             thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, (const char*)pe_name->Name);\r
297           if (!thunk_list->u1.Function)\r
298             {\r
299               thunk_list->u1.Function = (PDWORD) allocate_stub( name, (const char*)pe_name->Name );\r
300               TRACE("No implementation for %s.%s imported from %s, setting to %p\n",\r
301                     name, pe_name->Name, current_modref->ldr.FullDllName,\r
302                     (void *)thunk_list->u1.Function );\r
303             }\r
304           TRACE("--- %s %s.%d = %p\n",\r
305                 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);\r
306         }\r
307       import_list++;\r
308       thunk_list++;\r
309     }\r
310   // done:\r
311 #if 0\r
312   /* restore old protection of the import address table */\r
313   NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );\r
314   return wmImp;\r
315 #endif\r
316   return (void*)1;\r
317 }\r
318 \r
319 \r
320 \r
321 /****************************************************************\r
322  *       fixup_imports\r
323  *\r
324  * Fixup all imports of a given module.\r
325  * The loader_section must be locked while calling this function.\r
326  */\r
327 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )\r
328 {\r
329   int i, nb_imports;\r
330   const IMAGE_IMPORT_DESCRIPTOR *imports;\r
331   WINE_MODREF *prev;\r
332   DWORD size;\r
333   NTSTATUS status;\r
334   //  ULONG_PTR cookie;\r
335 \r
336   if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */\r
337   wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;\r
338   \r
339   if (!(imports = MyRtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,\r
340                                                   IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))\r
341     return STATUS_SUCCESS;\r
342   \r
343   nb_imports = 0;\r
344   while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;\r
345   \r
346   if (!nb_imports) return STATUS_SUCCESS;  /* no imports */\r
347   \r
348 #if 0\r
349   if (!create_module_activation_context( &wm->ldr ))\r
350     RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );\r
351 #endif\r
352   \r
353 #if 0\r
354   /* Allocate module dependency list */\r
355   wm->nDeps = nb_imports;\r
356   wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );\r
357 #endif\r
358 \r
359   /* load the imported modules. They are automatically\r
360    * added to the modref list of the process.\r
361    */\r
362   prev = current_modref;\r
363   current_modref = wm;\r
364   status = STATUS_SUCCESS;\r
365   for (i = 0; i < nb_imports; i++)\r
366     {\r
367       //      if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))\r
368       if (! import_dll( wm->ldr.BaseAddress, &imports[i], load_path ))\r
369         status = STATUS_DLL_NOT_FOUND;\r
370     }\r
371   current_modref = prev;\r
372   //  if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );\r
373   return status;\r
374 }\r
375 \r
376 \r
377 static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )\r
378 {\r
379         return FALSE;\r
380 }\r
381 \r
382 \r
383 /*************************************************************************\r
384  *              get_modref\r
385  *\r
386  * Looks for the referenced HMODULE in the current process\r
387  * The loader_section must be locked while calling this function.\r
388  */\r
389 static WINE_MODREF *get_modref( HMODULE hmod )\r
390 {\r
391   int i;\r
392   for (i = 0; i < nr_modrefs; i++)\r
393     if (modrefs[i]->ldr.BaseAddress == hmod)\r
394       return modrefs[i];\r
395   return NULL;\r
396 }\r
397 \r
398 \r
399 \r
400 static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )\r
401 {\r
402     WINE_MODREF *wm;\r
403     const WCHAR *p;\r
404     const IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader(hModule);\r
405 #if 0\r
406     PLIST_ENTRY entry, mark;\r
407 #endif\r
408 \r
409     if (!(wm = malloc (sizeof(*wm)))) return NULL;\r
410 \r
411     wm->nDeps    = 0;\r
412     wm->deps     = NULL;\r
413 \r
414     wm->ldr.BaseAddress   = hModule;\r
415     wm->ldr.EntryPoint    = NULL;\r
416     wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;\r
417     wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;\r
418     wm->ldr.LoadCount     = 1;\r
419     wm->ldr.TlsIndex      = -1;\r
420     wm->ldr.SectionHandle = NULL;\r
421     wm->ldr.CheckSum      = 0;\r
422     wm->ldr.TimeDateStamp = 0;\r
423     wm->ldr.ActivationContext = 0;\r
424 \r
425     wcscpy (wm->ldr.FullDllName, filename);\r
426     if ((p = wcsrchr( wm->ldr.FullDllName, L'\\' ))) p++;\r
427     else p = wm->ldr.FullDllName;\r
428     wcscpy (wm->ldr.BaseDllName, p );\r
429 \r
430     if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))\r
431     {\r
432         wm->ldr.Flags |= LDR_IMAGE_IS_DLL;\r
433         if (nt->OptionalHeader.AddressOfEntryPoint)\r
434             wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;\r
435     }\r
436 \r
437 #if 0\r
438     InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,\r
439                    &wm->ldr.InLoadOrderModuleList);\r
440 \r
441     /* insert module in MemoryList, sorted in increasing base addresses */\r
442     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;\r
443     for (entry = mark->Flink; entry != mark; entry = entry->Flink)\r
444     {\r
445         if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)\r
446             break;\r
447     }\r
448     entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;\r
449     wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;\r
450     wm->ldr.InMemoryOrderModuleList.Flink = entry;\r
451     entry->Blink = &wm->ldr.InMemoryOrderModuleList;\r
452 \r
453     /* wait until init is called for inserting into this list */\r
454     wm->ldr.InInitializationOrderModuleList.Flink = NULL;\r
455     wm->ldr.InInitializationOrderModuleList.Blink = NULL;\r
456 #endif\r
457 \r
458     modrefs[nr_modrefs++] = wm;\r
459 \r
460     return wm;\r
461 }\r
462 \r
463 \r
464 static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,\r
465                                  DWORD flags, WINE_MODREF** pwm )\r
466 {\r
467   void *module;\r
468   HANDLE mapping;\r
469   LARGE_INTEGER size;\r
470   SIZE_T len = 0;\r
471   WINE_MODREF *wm;\r
472   NTSTATUS status;\r
473 \r
474   TRACE("Trying native dll %S\n", name);\r
475   \r
476   size.QuadPart = 0;\r
477   status = MyNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,\r
478                               NULL, &size, PAGE_READONLY, SEC_IMAGE, file );\r
479   if (status != STATUS_SUCCESS) return status;\r
480   \r
481   module = NULL;\r
482   status = MyNtMapViewOfSection( mapping, NtCurrentProcess(),\r
483                                  &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );\r
484   CloseHandle( mapping );\r
485   if (status < 0) return status;\r
486   \r
487   /* create the MODREF */\r
488   \r
489   if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;\r
490   \r
491   /* fixup imports */\r
492   \r
493   if (!(flags & DONT_RESOLVE_DLL_REFERENCES))\r
494     {\r
495 #if 1\r
496       return (STATUS_NOT_IMPLEMENTED);\r
497 #else\r
498       if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)\r
499         {\r
500 #if 0\r
501           /* the module has only be inserted in the load & memory order lists */\r
502           RemoveEntryList(&wm->ldr.InLoadOrderModuleList);\r
503           RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);\r
504           \r
505           /* FIXME: there are several more dangling references\r
506            * left. Including dlls loaded by this dll before the\r
507            * failed one. Unrolling is rather difficult with the\r
508            * current structure and we can leave them lying\r
509            * around with no problems, so we don't care.\r
510            * As these might reference our wm, we don't free it.\r
511            */\r
512 #endif\r
513           return status;\r
514         }\r
515 #endif\r
516     }\r
517   \r
518   TRACE( "Loaded %S at %p: native\n", wm->ldr.FullDllName, module );\r
519   \r
520   wm->ldr.LoadCount = 1;\r
521   *pwm = wm;\r
522   return STATUS_SUCCESS;\r
523 }\r
524 \r
525 \r
526 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,\r
527                                WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )\r
528 {\r
529   HMODULE hnd = GetModuleHandle (NULL);\r
530   int len;\r
531   \r
532   assert (handle);\r
533   assert (*size == MAX_PATH);\r
534   \r
535   if (libname[0] == L'/' || libname[0] == L'\\')\r
536     {\r
537       wcscpy (filename, libname);\r
538     }\r
539   else\r
540     {\r
541       len = GetModuleFileName (hnd, filename, MAX_PATH);\r
542       filename[len++] = L'\\';\r
543       wcscpy (&filename[len], libname);\r
544     }\r
545   TRACE( "opening %S\n", filename);\r
546   \r
547   if (handle)\r
548     {\r
549       *handle = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL,\r
550                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
551       TRACE ("find_dll_file: 0x%p (0x%x)\n", *handle, GetFileSize (*handle, NULL));\r
552     }\r
553   return STATUS_SUCCESS;\r
554 }\r
555 \r
556 \r
557 static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )\r
558 {\r
559     WCHAR filename[MAX_PATH];\r
560     ULONG size;\r
561     HANDLE handle = 0;\r
562     NTSTATUS nts;\r
563 \r
564     TRACE( "looking for %S in %S\n", libname, load_path ? load_path : L"default path" );\r
565 \r
566     *pwm = NULL;\r
567     size = MAX_PATH;\r
568     find_dll_file( load_path, libname, filename, &size, pwm, &handle );\r
569     \r
570     if (!handle)\r
571       nts = STATUS_DLL_NOT_FOUND;\r
572     else\r
573       nts = load_native_dll( load_path, filename, handle, flags, pwm );\r
574     \r
575     if (nts == STATUS_SUCCESS)\r
576       {\r
577         /* Initialize DLL just loaded */\r
578         TRACE("Loaded module %S at %p\n", filename, (*pwm)->ldr.BaseAddress);\r
579         if (handle)\r
580           CloseHandle( handle );\r
581         return nts;\r
582       }\r
583     \r
584     TRACE("Failed to load module %S; status=%x\n", libname, nts);\r
585     if (handle)\r
586       CloseHandle( handle );\r
587     return nts;\r
588 }\r
589 \r
590 \r
591 NTSTATUS MyLdrLoadDll(LPCWSTR path_name, DWORD flags,\r
592                       LPCWSTR libname, HMODULE* hModule)\r
593 {\r
594   WINE_MODREF *wm;\r
595   NTSTATUS nts;\r
596 \r
597   /* Support for dll path removed.  */\r
598   nts = load_dll( path_name, libname, flags, &wm );\r
599 \r
600   /* For now.  */\r
601   assert (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS);\r
602 #if 0\r
603   if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))\r
604     {\r
605       nts = process_attach( wm, NULL );\r
606       if (nts != STATUS_SUCCESS)\r
607         {\r
608           LdrUnloadDll(wm->ldr.BaseAddress);\r
609           wm = NULL;\r
610         }\r
611     }\r
612 #endif\r
613   *hModule = (wm) ? wm->ldr.BaseAddress : NULL;\r
614 \r
615   return nts;\r
616 }\r
617 \r
618 \r
619 \r
620 /***********************************************************************\r
621  *           LdrProcessRelocationBlock  (NTDLL.@)\r
622  *\r
623  * Apply relocations to a given page of a mapped PE image.\r
624  */\r
625 IMAGE_BASE_RELOCATION * MyLdrProcessRelocationBlock( void *page, UINT count,\r
626                                                      USHORT *relocs, INT_PTR delta )\r
627 {\r
628   while (count--)\r
629     {\r
630       USHORT offset = *relocs & 0xfff;\r
631       int type = *relocs >> 12;\r
632       switch(type)\r
633         {\r
634         case IMAGE_REL_BASED_ABSOLUTE:\r
635           break;\r
636 #if 1\r
637         case IMAGE_REL_BASED_HIGH:\r
638           *(short *)((char *)page + offset) += HIWORD(delta);\r
639           break;\r
640         case IMAGE_REL_BASED_LOW:\r
641           *(short *)((char *)page + offset) += LOWORD(delta);\r
642           break;\r
643         case IMAGE_REL_BASED_HIGHLOW:\r
644           *(int *)((char *)page + offset) += delta;\r
645           break;\r
646 #else\r
647         case IMAGE_REL_BASED_DIR64:\r
648           *(INT_PTR *)((char *)page + offset) += delta;\r
649           break;\r
650 #endif\r
651         default:\r
652           TRACE("Unknown/unsupported fixup type %x.\n", type);\r
653           return NULL;\r
654         }\r
655       relocs++;\r
656     }\r
657   return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */\r
658 }\r
659 \r
660 \r
661 void MyLdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,\r
662                            ULONG_PTR unknown3, ULONG_PTR unknown4 )\r
663 {\r
664   static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};\r
665   NTSTATUS status;\r
666   WINE_MODREF *wm;\r
667   LPCWSTR load_path = NULL;\r
668   PEB *peb = current_peb();\r
669   IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader( peb->ImageBaseAddress );\r
670   void (*_kernel_start) (void *ptr) = kernel_start;\r
671 \r
672 #if 0\r
673   if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */\r
674 #endif\r
675 \r
676   /* allocate the modref for the main exe (if not already done) */\r
677   wm = get_modref( peb->ImageBaseAddress );\r
678   assert( wm );\r
679   if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)\r
680     {\r
681       TRACE("%S is a dll, not an executable\n", wm->ldr.FullDllName );\r
682       exit(1);\r
683     }\r
684 \r
685   //  peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;\r
686   //  version_init( wm->ldr.FullDllName );\r
687 \r
688   //  LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,\r
689   //                                 REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );\r
690 \r
691   /* the main exe needs to be the first in the load order list */\r
692   //  RemoveEntryList( &wm->ldr.InLoadOrderModuleList );\r
693   //  InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );\r
694 \r
695   //  if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;\r
696   //  if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;\r
697 \r
698   //  actctx_init();\r
699   //  load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;\r
700   if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;\r
701   //  if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;\r
702   //  if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;\r
703   //  heap_set_debug_flags( GetProcessHeap() );\r
704 \r
705 #if 0\r
706   /* FIXME: This may be interesting at some point.  */\r
707   status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );\r
708   if (status != STATUS_SUCCESS) goto error;\r
709 #endif\r
710 \r
711   //  virtual_release_address_space( nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE );\r
712   //  virtual_clear_thread_stack();\r
713   //  wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );\r
714   // stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );\r
715   _kernel_start (peb);\r
716 \r
717  error:\r
718   TRACE( "Main exe initialization for %S failed, status %x\n",\r
719          wm->ldr.FullDllName, status);\r
720          //      peb->ProcessParameters->ImagePathName, status );\r
721   //  NtTerminateProcess( GetCurrentProcess(), status );\r
722   exit (1);\r
723 }\r