~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ntdll/loader.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Loader functions
  3  *
  4  * Copyright 1995, 2003 Alexandre Julliard
  5  * Copyright 2002 Dmitry Timoshkov for CodeWeavers
  6  *
  7  * This library is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU Lesser General Public
  9  * License as published by the Free Software Foundation; either
 10  * version 2.1 of the License, or (at your option) any later version.
 11  *
 12  * This library is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this library; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  */
 21 
 22 #include "config.h"
 23 #include "wine/port.h"
 24 
 25 #include <assert.h>
 26 #include <stdarg.h>
 27 #ifdef HAVE_SYS_MMAN_H
 28 # include <sys/mman.h>
 29 #endif
 30 
 31 #define NONAMELESSUNION
 32 #define NONAMELESSSTRUCT
 33 
 34 #include "ntstatus.h"
 35 #define WIN32_NO_STATUS
 36 #include "windef.h"
 37 #include "winnt.h"
 38 #include "winternl.h"
 39 
 40 #include "wine/exception.h"
 41 #include "wine/library.h"
 42 #include "wine/pthread.h"
 43 #include "wine/unicode.h"
 44 #include "wine/debug.h"
 45 #include "wine/server.h"
 46 #include "ntdll_misc.h"
 47 #include "ddk/wdm.h"
 48 
 49 WINE_DEFAULT_DEBUG_CHANNEL(module);
 50 WINE_DECLARE_DEBUG_CHANNEL(relay);
 51 WINE_DECLARE_DEBUG_CHANNEL(snoop);
 52 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
 53 WINE_DECLARE_DEBUG_CHANNEL(imports);
 54 
 55 /* we don't want to include winuser.h */
 56 #define RT_MANIFEST                         ((ULONG_PTR)24)
 57 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
 58 
 59 extern struct wine_pthread_functions pthread_functions;
 60 
 61 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
 62 
 63 static int process_detaching = 0;  /* set on process detach to avoid deadlocks with thread detach */
 64 static int free_lib_count;   /* recursion depth of LdrUnloadDll calls */
 65 
 66 static const char * const reason_names[] =
 67 {
 68     "PROCESS_DETACH",
 69     "PROCESS_ATTACH",
 70     "THREAD_ATTACH",
 71     "THREAD_DETACH",
 72     NULL, NULL, NULL, NULL,
 73     "WINE_PREATTACH"
 74 };
 75 
 76 static const WCHAR dllW[] = {'.','d','l','l',0};
 77 
 78 /* internal representation of 32bit modules. per process. */
 79 typedef struct _wine_modref
 80 {
 81     LDR_MODULE            ldr;
 82     int                   nDeps;
 83     struct _wine_modref **deps;
 84 } WINE_MODREF;
 85 
 86 /* info about the current builtin dll load */
 87 /* used to keep track of things across the register_dll constructor call */
 88 struct builtin_load_info
 89 {
 90     const WCHAR *load_path;
 91     const WCHAR *filename;
 92     NTSTATUS     status;
 93     WINE_MODREF *wm;
 94 };
 95 
 96 static struct builtin_load_info default_load_info;
 97 static struct builtin_load_info *builtin_load_info = &default_load_info;
 98 
 99 static HANDLE main_exe_file;
100 static UINT tls_module_count;      /* number of modules with TLS directory */
101 static UINT tls_total_size;        /* total size of TLS storage */
102 static const IMAGE_TLS_DIRECTORY **tls_dirs;  /* array of TLS directories */
103 
104 UNICODE_STRING windows_dir = { 0, 0, NULL };  /* windows directory */
105 UNICODE_STRING system_dir = { 0, 0, NULL };  /* system directory */
106 
107 static RTL_CRITICAL_SECTION loader_section;
108 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
109 {
110     0, 0, &loader_section,
111     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
112       0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
113 };
114 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
115 
116 static WINE_MODREF *cached_modref;
117 static WINE_MODREF *current_modref;
118 static WINE_MODREF *last_failed_modref;
119 
120 static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm );
121 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
122 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
123                                   DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
124 
125 /* convert PE image VirtualAddress to Real Address */
126 static inline void *get_rva( HMODULE module, DWORD va )
127 {
128     return (void *)((char *)module + va);
129 }
130 
131 /* check whether the file name contains a path */
132 static inline int contains_path( LPCWSTR name )
133 {
134     return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
135 }
136 
137 /* convert from straight ASCII to Unicode without depending on the current codepage */
138 static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
139 {
140     while (len--) *dst++ = (unsigned char)*src++;
141 }
142 
143 
144 /*************************************************************************
145  *              call_dll_entry_point
146  *
147  * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
148  * their entry point, so we need a small asm wrapper.
149  */
150 #ifdef __i386__
151 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
152 __ASM_GLOBAL_FUNC(call_dll_entry_point,
153                   "pushl %ebp\n\t"
154                   "movl %esp,%ebp\n\t"
155                   "pushl %ebx\n\t"
156                   "subl $8,%esp\n\t"
157                   "pushl 20(%ebp)\n\t"
158                   "pushl 16(%ebp)\n\t"
159                   "pushl 12(%ebp)\n\t"
160                   "movl 8(%ebp),%eax\n\t"
161                   "call *%eax\n\t"
162                   "leal -4(%ebp),%esp\n\t"
163                   "popl %ebx\n\t"
164                   "popl %ebp\n\t"
165                   "ret" )
166 #else /* __i386__ */
167 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
168                                          UINT reason, void *reserved )
169 {
170     return proc( module, reason, reserved );
171 }
172 #endif /* __i386__ */
173 
174 
175 #ifdef __i386__
176 /*************************************************************************
177  *              stub_entry_point
178  *
179  * Entry point for stub functions.
180  */
181 static void stub_entry_point( const char *dll, const char *name, ... )
182 {
183     EXCEPTION_RECORD rec;
184 
185     rec.ExceptionCode           = EXCEPTION_WINE_STUB;
186     rec.ExceptionFlags          = EH_NONCONTINUABLE;
187     rec.ExceptionRecord         = NULL;
188 #ifdef __GNUC__
189     rec.ExceptionAddress        = __builtin_return_address(0);
190 #else
191     rec.ExceptionAddress        = *((void **)&dll - 1);
192 #endif
193     rec.NumberParameters        = 2;
194     rec.ExceptionInformation[0] = (ULONG_PTR)dll;
195     rec.ExceptionInformation[1] = (ULONG_PTR)name;
196     for (;;) RtlRaiseException( &rec );
197 }
198 
199 
200 #include "pshpack1.h"
201 struct stub
202 {
203     BYTE        popl_eax;   /* popl %eax */
204     BYTE        pushl1;     /* pushl $name */
205     const char *name;
206     BYTE        pushl2;     /* pushl $dll */
207     const char *dll;
208     BYTE        pushl_eax;  /* pushl %eax */
209     BYTE        jmp;        /* jmp stub_entry_point */
210     DWORD       entry;
211 };
212 #include "poppack.h"
213 
214 /*************************************************************************
215  *              allocate_stub
216  *
217  * Allocate a stub entry point.
218  */
219 static ULONG_PTR allocate_stub( const char *dll, const char *name )
220 {
221 #define MAX_SIZE 65536
222     static struct stub *stubs;
223     static unsigned int nb_stubs;
224     struct stub *stub;
225 
226     if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
227 
228     if (!stubs)
229     {
230         SIZE_T size = MAX_SIZE;
231         if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
232                                      MEM_COMMIT, PAGE_EXECUTE_WRITECOPY ) != STATUS_SUCCESS)
233             return 0xdeadbeef;
234     }
235     stub = &stubs[nb_stubs++];
236     stub->popl_eax  = 0x58;  /* popl %eax */
237     stub->pushl1    = 0x68;  /* pushl $name */
238     stub->name      = name;
239     stub->pushl2    = 0x68;  /* pushl $dll */
240     stub->dll       = dll;
241     stub->pushl_eax = 0x50;  /* pushl %eax */
242     stub->jmp       = 0xe9;  /* jmp stub_entry_point */
243     stub->entry     = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
244     return (ULONG_PTR)stub;
245 }
246 
247 #else  /* __i386__ */
248 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
249 #endif  /* __i386__ */
250 
251 
252 /*************************************************************************
253  *              get_modref
254  *
255  * Looks for the referenced HMODULE in the current process
256  * The loader_section must be locked while calling this function.
257  */
258 static WINE_MODREF *get_modref( HMODULE hmod )
259 {
260     PLIST_ENTRY mark, entry;
261     PLDR_MODULE mod;
262 
263     if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
264 
265     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
266     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
267     {
268         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
269         if (mod->BaseAddress == hmod)
270             return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
271         if (mod->BaseAddress > (void*)hmod) break;
272     }
273     return NULL;
274 }
275 
276 
277 /**********************************************************************
278  *          find_basename_module
279  *
280  * Find a module from its base name.
281  * The loader_section must be locked while calling this function
282  */
283 static WINE_MODREF *find_basename_module( LPCWSTR name )
284 {
285     PLIST_ENTRY mark, entry;
286 
287     if (cached_modref && !strcmpiW( name, cached_modref->ldr.BaseDllName.Buffer ))
288         return cached_modref;
289 
290     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
291     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
292     {
293         LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
294         if (!strcmpiW( name, mod->BaseDllName.Buffer ))
295         {
296             cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
297             return cached_modref;
298         }
299     }
300     return NULL;
301 }
302 
303 
304 /**********************************************************************
305  *          find_fullname_module
306  *
307  * Find a module from its full path name.
308  * The loader_section must be locked while calling this function
309  */
310 static WINE_MODREF *find_fullname_module( LPCWSTR name )
311 {
312     PLIST_ENTRY mark, entry;
313 
314     if (cached_modref && !strcmpiW( name, cached_modref->ldr.FullDllName.Buffer ))
315         return cached_modref;
316 
317     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
318     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
319     {
320         LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
321         if (!strcmpiW( name, mod->FullDllName.Buffer ))
322         {
323             cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
324             return cached_modref;
325         }
326     }
327     return NULL;
328 }
329 
330 
331 /*************************************************************************
332  *              find_forwarded_export
333  *
334  * Find the final function pointer for a forwarded function.
335  * The loader_section must be locked while calling this function.
336  */
337 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
338 {
339     const IMAGE_EXPORT_DIRECTORY *exports;
340     DWORD exp_size;
341     WINE_MODREF *wm;
342     WCHAR mod_name[32];
343     const char *end = strrchr(forward, '.');
344     FARPROC proc = NULL;
345 
346     if (!end) return NULL;
347     if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL;
348     ascii_to_unicode( mod_name, forward, end - forward );
349     mod_name[end - forward] = 0;
350     if (!strchrW( mod_name, '.' ))
351     {
352         if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name) - sizeof(dllW)) return NULL;
353         memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
354     }
355 
356     if (!(wm = find_basename_module( mod_name )))
357     {
358         TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
359         if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS &&
360             !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
361         {
362             if (process_attach( wm, NULL ) != STATUS_SUCCESS)
363             {
364                 LdrUnloadDll( wm->ldr.BaseAddress );
365                 wm = NULL;
366             }
367         }
368 
369         if (!wm)
370         {
371             ERR( "module not found for forward '%s' used by %s\n",
372                  forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
373             return NULL;
374         }
375     }
376     if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
377                                                  IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
378         proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, end + 1, -1, load_path );
379 
380     if (!proc)
381     {
382         ERR("function not found for forward '%s' used by %s."
383             " If you are using builtin %s, try using the native one instead.\n",
384             forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
385             debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
386     }
387     return proc;
388 }
389 
390 
391 /*************************************************************************
392  *              find_ordinal_export
393  *
394  * Find an exported function by ordinal.
395  * The exports base must have been subtracted from the ordinal already.
396  * The loader_section must be locked while calling this function.
397  */
398 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
399                                     DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
400 {
401     FARPROC proc;
402     const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
403 
404     if (ordinal >= exports->NumberOfFunctions)
405     {
406         TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
407         return NULL;
408     }
409     if (!functions[ordinal]) return NULL;
410 
411     proc = get_rva( module, functions[ordinal] );
412 
413     /* if the address falls into the export dir, it's a forward */
414     if (((const char *)proc >= (const char *)exports) && 
415         ((const char *)proc < (const char *)exports + exp_size))
416         return find_forwarded_export( module, (const char *)proc, load_path );
417 
418     if (TRACE_ON(snoop))
419     {
420         const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
421         proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
422     }
423     if (TRACE_ON(relay))
424     {
425         const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
426         proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
427     }
428     return proc;
429 }
430 
431 
432 /*************************************************************************
433  *              find_named_export
434  *
435  * Find an exported function by name.
436  * The loader_section must be locked while calling this function.
437  */
438 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
439                                   DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
440 {
441     const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
442     const DWORD *names = get_rva( module, exports->AddressOfNames );
443     int min = 0, max = exports->NumberOfNames - 1;
444 
445     /* first check the hint */
446     if (hint >= 0 && hint <= max)
447     {
448         char *ename = get_rva( module, names[hint] );
449         if (!strcmp( ename, name ))
450             return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
451     }
452 
453     /* then do a binary search */
454     while (min <= max)
455     {
456         int res, pos = (min + max) / 2;
457         char *ename = get_rva( module, names[pos] );
458         if (!(res = strcmp( ename, name )))
459             return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
460         if (res > 0) max = pos - 1;
461         else min = pos + 1;
462     }
463     return NULL;
464 
465 }
466 
467 
468 /*************************************************************************
469  *              import_dll
470  *
471  * Import the dll specified by the given import descriptor.
472  * The loader_section must be locked while calling this function.
473  */
474 static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
475 {
476     NTSTATUS status;
477     WINE_MODREF *wmImp;
478     HMODULE imp_mod;
479     const IMAGE_EXPORT_DIRECTORY *exports;
480     DWORD exp_size;
481     const IMAGE_THUNK_DATA *import_list;
482     IMAGE_THUNK_DATA *thunk_list;
483     WCHAR buffer[32];
484     const char *name = get_rva( module, descr->Name );
485     DWORD len = strlen(name);
486     PVOID protect_base;
487     SIZE_T protect_size = 0;
488     DWORD protect_old;
489 
490     thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
491     if (descr->u.OriginalFirstThunk)
492         import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
493     else
494         import_list = thunk_list;
495 
496     while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */
497 
498     if (len * sizeof(WCHAR) < sizeof(buffer))
499     {
500         ascii_to_unicode( buffer, name, len );
501         buffer[len] = 0;
502         status = load_dll( load_path, buffer, 0, &wmImp );
503     }
504     else  /* need to allocate a larger buffer */
505     {
506         WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
507         if (!ptr) return NULL;
508         ascii_to_unicode( ptr, name, len );
509         ptr[len] = 0;
510         status = load_dll( load_path, ptr, 0, &wmImp );
511         RtlFreeHeap( GetProcessHeap(), 0, ptr );
512     }
513 
514     if (status)
515     {
516         if (status == STATUS_DLL_NOT_FOUND)
517             ERR("Library %s (which is needed by %s) not found\n",
518                 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
519         else
520             ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
521                 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
522         return NULL;
523     }
524 
525     /* unprotect the import address table since it can be located in
526      * readonly section */
527     while (import_list[protect_size].u1.Ordinal) protect_size++;
528     protect_base = thunk_list;
529     protect_size *= sizeof(*thunk_list);
530     NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
531                             &protect_size, PAGE_WRITECOPY, &protect_old );
532 
533     imp_mod = wmImp->ldr.BaseAddress;
534     exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
535 
536     if (!exports)
537     {
538         /* set all imported function to deadbeef */
539         while (import_list->u1.Ordinal)
540         {
541             if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
542             {
543                 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
544                 WARN("No implementation for %s.%d", name, ordinal );
545                 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
546             }
547             else
548             {
549                 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
550                 WARN("No implementation for %s.%s", name, pe_name->Name );
551                 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
552             }
553             WARN(" imported from %s, allocating stub %p\n",
554                  debugstr_w(current_modref->ldr.FullDllName.Buffer),
555                  (void *)thunk_list->u1.Function );
556             import_list++;
557             thunk_list++;
558         }
559         goto done;
560     }
561 
562     while (import_list->u1.Ordinal)
563     {
564         if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
565         {
566             int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
567 
568             thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
569                                                                       ordinal - exports->Base, load_path );
570             if (!thunk_list->u1.Function)
571             {
572                 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
573                 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
574                      name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
575                      (void *)thunk_list->u1.Function );
576             }
577             TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
578         }
579         else  /* import by name */
580         {
581             IMAGE_IMPORT_BY_NAME *pe_name;
582             pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
583             thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
584                                                                     (const char*)pe_name->Name,
585                                                                     pe_name->Hint, load_path );
586             if (!thunk_list->u1.Function)
587             {
588                 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
589                 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
590                      name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
591                      (void *)thunk_list->u1.Function );
592             }
593             TRACE_(imports)("--- %s %s.%d = %p\n",
594                             pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
595         }
596         import_list++;
597         thunk_list++;
598     }
599 
600 done:
601     /* restore old protection of the import address table */
602     NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
603     return wmImp;
604 }
605 
606 
607 /***********************************************************************
608  *           create_module_activation_context
609  */
610 static NTSTATUS create_module_activation_context( LDR_MODULE *module )
611 {
612     NTSTATUS status;
613     LDR_RESOURCE_INFO info;
614     const IMAGE_RESOURCE_DATA_ENTRY *entry;
615 
616     info.Type = RT_MANIFEST;
617     info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
618     info.Language = 0;
619     if (!(status = LdrFindResource_U( module->BaseAddress, &info, 3, &entry )))
620     {
621         ACTCTXW ctx;
622         ctx.cbSize   = sizeof(ctx);
623         ctx.lpSource = NULL;
624         ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
625         ctx.hModule  = module->BaseAddress;
626         ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
627         status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
628     }
629     return status;
630 }
631 
632 
633 /****************************************************************
634  *       fixup_imports
635  *
636  * Fixup all imports of a given module.
637  * The loader_section must be locked while calling this function.
638  */
639 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
640 {
641     int i, nb_imports;
642     const IMAGE_IMPORT_DESCRIPTOR *imports;
643     WINE_MODREF *prev;
644     DWORD size;
645     NTSTATUS status;
646     ULONG_PTR cookie;
647 
648     if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
649     wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
650 
651     if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
652                                                   IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
653         return STATUS_SUCCESS;
654 
655     nb_imports = 0;
656     while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
657 
658     if (!nb_imports) return STATUS_SUCCESS;  /* no imports */
659 
660     if (!create_module_activation_context( &wm->ldr ))
661         RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
662 
663     /* Allocate module dependency list */
664     wm->nDeps = nb_imports;
665     wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
666 
667     /* load the imported modules. They are automatically
668      * added to the modref list of the process.
669      */
670     prev = current_modref;
671     current_modref = wm;
672     status = STATUS_SUCCESS;
673     for (i = 0; i < nb_imports; i++)
674     {
675         if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
676             status = STATUS_DLL_NOT_FOUND;
677     }
678     current_modref = prev;
679     if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
680     return status;
681 }
682 
683 
684 /*************************************************************************
685  *              alloc_module
686  *
687  * Allocate a WINE_MODREF structure and add it to the process list
688  * The loader_section must be locked while calling this function.
689  */
690 static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
691 {
692     WINE_MODREF *wm;
693     const WCHAR *p;
694     const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
695     PLIST_ENTRY entry, mark;
696 
697     if (!(wm = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wm) ))) return NULL;
698 
699     wm->nDeps    = 0;
700     wm->deps     = NULL;
701 
702     wm->ldr.BaseAddress   = hModule;
703     wm->ldr.EntryPoint    = NULL;
704     wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
705     wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;
706     wm->ldr.LoadCount     = 1;
707     wm->ldr.TlsIndex      = -1;
708     wm->ldr.SectionHandle = NULL;
709     wm->ldr.CheckSum      = 0;
710     wm->ldr.TimeDateStamp = 0;
711     wm->ldr.ActivationContext = 0;
712 
713     RtlCreateUnicodeString( &wm->ldr.FullDllName, filename );
714     if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
715     else p = wm->ldr.FullDllName.Buffer;
716     RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
717 
718     if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
719     {
720         wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
721         if (nt->OptionalHeader.AddressOfEntryPoint)
722             wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
723     }
724 
725     InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
726                    &wm->ldr.InLoadOrderModuleList);
727 
728     /* insert module in MemoryList, sorted in increasing base addresses */
729     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
730     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
731     {
732         if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
733             break;
734     }
735     entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
736     wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
737     wm->ldr.InMemoryOrderModuleList.Flink = entry;
738     entry->Blink = &wm->ldr.InMemoryOrderModuleList;
739 
740     /* wait until init is called for inserting into this list */
741     wm->ldr.InInitializationOrderModuleList.Flink = NULL;
742     wm->ldr.InInitializationOrderModuleList.Blink = NULL;
743 
744     if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
745     {
746         WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
747         VIRTUAL_SetForceExec( TRUE );
748     }
749     return wm;
750 }
751 
752 
753 /*************************************************************************
754  *              alloc_process_tls
755  *
756  * Allocate the process-wide structure for module TLS storage.
757  */
758 static NTSTATUS alloc_process_tls(void)
759 {
760     PLIST_ENTRY mark, entry;
761     PLDR_MODULE mod;
762     const IMAGE_TLS_DIRECTORY *dir;
763     ULONG size, i;
764 
765     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
766     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
767     {
768         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
769         if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
770                                                   IMAGE_DIRECTORY_ENTRY_TLS, &size )))
771             continue;
772         size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
773         if (!size) continue;
774         tls_total_size += size;
775         tls_module_count++;
776     }
777     if (!tls_module_count) return STATUS_SUCCESS;
778 
779     TRACE( "count %u size %u\n", tls_module_count, tls_total_size );
780 
781     tls_dirs = RtlAllocateHeap( GetProcessHeap(), 0, tls_module_count * sizeof(*tls_dirs) );
782     if (!tls_dirs) return STATUS_NO_MEMORY;
783 
784     for (i = 0, entry = mark->Flink; entry != mark; entry = entry->Flink)
785     {
786         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
787         if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
788                                                   IMAGE_DIRECTORY_ENTRY_TLS, &size )))
789             continue;
790         tls_dirs[i] = dir;
791         *(DWORD *)dir->AddressOfIndex = i;
792         mod->TlsIndex = i;
793         mod->LoadCount = -1;  /* can't unload it */
794         i++;
795     }
796     return STATUS_SUCCESS;
797 }
798 
799 
800 /*************************************************************************
801  *              alloc_thread_tls
802  *
803  * Allocate the per-thread structure for module TLS storage.
804  */
805 static NTSTATUS alloc_thread_tls(void)
806 {
807     void **pointers;
808     char *data;
809     UINT i;
810 
811     if (!tls_module_count) return STATUS_SUCCESS;
812 
813     if (!(pointers = RtlAllocateHeap( GetProcessHeap(), 0,
814                                       tls_module_count * sizeof(*pointers) )))
815         return STATUS_NO_MEMORY;
816 
817     if (!(data = RtlAllocateHeap( GetProcessHeap(), 0, tls_total_size )))
818     {
819         RtlFreeHeap( GetProcessHeap(), 0, pointers );
820         return STATUS_NO_MEMORY;
821     }
822 
823     for (i = 0; i < tls_module_count; i++)
824     {
825         const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
826         ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
827 
828         TRACE( "thread %04x idx %d: %d/%d bytes from %p to %p\n",
829                GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
830                (void *)dir->StartAddressOfRawData, data );
831 
832         pointers[i] = data;
833         memcpy( data, (void *)dir->StartAddressOfRawData, size );
834         data += size;
835         memset( data, 0, dir->SizeOfZeroFill );
836         data += dir->SizeOfZeroFill;
837     }
838     NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
839     return STATUS_SUCCESS;
840 }
841 
842 
843 /*************************************************************************
844  *              call_tls_callbacks
845  */
846 static void call_tls_callbacks( HMODULE module, UINT reason )
847 {
848     const IMAGE_TLS_DIRECTORY *dir;
849     const PIMAGE_TLS_CALLBACK *callback;
850     ULONG dirsize;
851 
852     dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
853     if (!dir || !dir->AddressOfCallBacks) return;
854 
855     for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
856     {
857         if (TRACE_ON(relay))
858             DPRINTF("%04x:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
859                     GetCurrentThreadId(), *callback, module, reason_names[reason] );
860         __TRY
861         {
862             (*callback)( module, reason, NULL );
863         }
864         __EXCEPT_ALL
865         {
866             if (TRACE_ON(relay))
867                 DPRINTF("%04x:exception in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
868                         GetCurrentThreadId(), callback, module, reason_names[reason] );
869             return;
870         }
871         __ENDTRY
872         if (TRACE_ON(relay))
873             DPRINTF("%04x:Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
874                     GetCurrentThreadId(), *callback, module, reason_names[reason] );
875     }
876 }
877 
878 
879 /*************************************************************************
880  *              MODULE_InitDLL
881  */
882 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
883 {
884     WCHAR mod_name[32];
885     NTSTATUS status = STATUS_SUCCESS;
886     DLLENTRYPROC entry = wm->ldr.EntryPoint;
887     void *module = wm->ldr.BaseAddress;
888     BOOL retv = TRUE;
889 
890     /* Skip calls for modules loaded with special load flags */
891 
892     if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
893     if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
894     if (!entry) return STATUS_SUCCESS;
895 
896     if (TRACE_ON(relay))
897     {
898         size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
899         memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
900         mod_name[len / sizeof(WCHAR)] = 0;
901         DPRINTF("%04x:Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
902                 GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
903                 reason_names[reason], lpReserved );
904     }
905     else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
906                reason_names[reason], lpReserved );