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 );