wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / ntdll / loader.c
blobe1810bc5ab9d042f9de2510de417c6f560acc8cc
1 /*
2 * Loader functions
4 * Copyright 1995, 2003 Alexandre Julliard
5 * Copyright 2002 Dmitry Timoshkov for CodeWeavers
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.
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.
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
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "windef.h"
31 #include "winnt.h"
32 #include "winioctl.h"
33 #include "winternl.h"
34 #include "delayloadhandler.h"
36 #include "wine/exception.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "ntdll_misc.h"
40 #include "ddk/wdm.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(module);
43 WINE_DECLARE_DEBUG_CHANNEL(relay);
44 WINE_DECLARE_DEBUG_CHANNEL(snoop);
45 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
46 WINE_DECLARE_DEBUG_CHANNEL(imports);
48 #ifdef _WIN64
49 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
50 #endif
51 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
52 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
54 /* we don't want to include winuser.h */
55 #define RT_MANIFEST ((ULONG_PTR)24)
56 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
58 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
59 typedef void (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *);
61 void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
63 const struct unix_funcs *unix_funcs = NULL;
65 /* windows directory */
66 const WCHAR windows_dir[] = L"C:\\windows";
67 /* system directory with trailing backslash */
68 const WCHAR system_dir[] = L"C:\\windows\\system32\\";
69 const WCHAR syswow64_dir[] = L"C:\\windows\\syswow64\\";
71 HMODULE kernel32_handle = 0;
73 /* system search path */
74 static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows";
76 static BOOL is_prefix_bootstrap; /* are we bootstrapping the prefix? */
77 static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
78 static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
79 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
80 static ULONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
81 static ULONG dll_safe_mode = 1; /* dll search mode */
82 static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
83 static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
84 static WCHAR *default_load_path; /* default dll search path */
86 struct dll_dir_entry
88 struct list entry;
89 WCHAR dir[1];
92 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
94 struct ldr_notification
96 struct list entry;
97 PLDR_DLL_NOTIFICATION_FUNCTION callback;
98 void *context;
101 static struct list ldr_notifications = LIST_INIT( ldr_notifications );
103 static const char * const reason_names[] =
105 "PROCESS_DETACH",
106 "PROCESS_ATTACH",
107 "THREAD_ATTACH",
108 "THREAD_DETACH",
111 struct file_id
113 BYTE ObjectId[16];
116 /* internal representation of loaded modules */
117 typedef struct _wine_modref
119 LDR_DATA_TABLE_ENTRY ldr;
120 struct file_id id;
121 int alloc_deps;
122 int nDeps;
123 struct _wine_modref **deps;
124 } WINE_MODREF;
126 static UINT tls_module_count; /* number of modules with TLS directory */
127 static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
128 LIST_ENTRY tls_links = { &tls_links, &tls_links };
130 static RTL_CRITICAL_SECTION loader_section;
131 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
133 0, 0, &loader_section,
134 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
135 0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
137 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
139 static CRITICAL_SECTION dlldir_section;
140 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
142 0, 0, &dlldir_section,
143 { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
144 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
146 static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };
148 static RTL_CRITICAL_SECTION peb_lock;
149 static RTL_CRITICAL_SECTION_DEBUG peb_critsect_debug =
151 0, 0, &peb_lock,
152 { &peb_critsect_debug.ProcessLocksList, &peb_critsect_debug.ProcessLocksList },
153 0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
155 static RTL_CRITICAL_SECTION peb_lock = { &peb_critsect_debug, -1, 0, 0, 0, 0 };
157 static PEB_LDR_DATA ldr =
159 sizeof(ldr), TRUE, NULL,
160 { &ldr.InLoadOrderModuleList, &ldr.InLoadOrderModuleList },
161 { &ldr.InMemoryOrderModuleList, &ldr.InMemoryOrderModuleList },
162 { &ldr.InInitializationOrderModuleList, &ldr.InInitializationOrderModuleList }
165 static RTL_BITMAP tls_bitmap;
166 static RTL_BITMAP tls_expansion_bitmap;
168 static WINE_MODREF *cached_modref;
169 static WINE_MODREF *current_modref;
170 static WINE_MODREF *last_failed_modref;
172 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
173 DWORD flags, WINE_MODREF** pwm );
174 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
175 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
176 DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
177 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
178 DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
180 /* convert PE image VirtualAddress to Real Address */
181 static inline void *get_rva( HMODULE module, DWORD va )
183 return (void *)((char *)module + va);
186 /* check whether the file name contains a path */
187 static inline BOOL contains_path( LPCWSTR name )
189 return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
192 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
194 typedef struct _RTL_UNLOAD_EVENT_TRACE
196 void *BaseAddress;
197 SIZE_T SizeOfImage;
198 ULONG Sequence;
199 ULONG TimeDateStamp;
200 ULONG CheckSum;
201 WCHAR ImageName[32];
202 } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
204 static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
205 static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
206 static unsigned int unload_trace_seq;
208 static void module_push_unload_trace( const LDR_DATA_TABLE_ENTRY *ldr )
210 RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
211 unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
213 ptr->BaseAddress = ldr->DllBase;
214 ptr->SizeOfImage = ldr->SizeOfImage;
215 ptr->Sequence = unload_trace_seq;
216 ptr->TimeDateStamp = ldr->TimeDateStamp;
217 ptr->CheckSum = ldr->CheckSum;
218 memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
219 ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;
221 unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
222 unload_trace_ptr = unload_traces;
225 /*********************************************************************
226 * RtlGetUnloadEventTrace [NTDLL.@]
228 RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
230 return unload_traces;
233 /*********************************************************************
234 * RtlGetUnloadEventTraceEx [NTDLL.@]
236 void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
238 static unsigned int element_size = sizeof(*unload_traces);
239 static unsigned int element_count = ARRAY_SIZE(unload_traces);
241 *size = &element_size;
242 *count = &element_count;
243 *trace = &unload_trace_ptr;
246 /*************************************************************************
247 * call_dll_entry_point
249 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
250 * their entry point, so we need a small asm wrapper. Testing indicates
251 * that only modifying esi leads to a crash, so use this one to backup
252 * ebp while running the dll entry proc.
254 #ifdef __i386__
255 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
256 __ASM_GLOBAL_FUNC(call_dll_entry_point,
257 "pushl %ebp\n\t"
258 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
259 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
260 "movl %esp,%ebp\n\t"
261 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
262 "pushl %ebx\n\t"
263 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
264 "pushl %esi\n\t"
265 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
266 "pushl %edi\n\t"
267 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
268 "movl %ebp,%esi\n\t"
269 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
270 "pushl 20(%ebp)\n\t"
271 "pushl 16(%ebp)\n\t"
272 "pushl 12(%ebp)\n\t"
273 "movl 8(%ebp),%eax\n\t"
274 "call *%eax\n\t"
275 "movl %esi,%ebp\n\t"
276 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
277 "leal -12(%ebp),%esp\n\t"
278 "popl %edi\n\t"
279 __ASM_CFI(".cfi_same_value %edi\n\t")
280 "popl %esi\n\t"
281 __ASM_CFI(".cfi_same_value %esi\n\t")
282 "popl %ebx\n\t"
283 __ASM_CFI(".cfi_same_value %ebx\n\t")
284 "popl %ebp\n\t"
285 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
286 __ASM_CFI(".cfi_same_value %ebp\n\t")
287 "ret" )
288 #else /* __i386__ */
289 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
290 UINT reason, void *reserved )
292 return proc( module, reason, reserved );
294 #endif /* __i386__ */
297 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
298 /*************************************************************************
299 * stub_entry_point
301 * Entry point for stub functions.
303 static void WINAPI stub_entry_point( const char *dll, const char *name, void *ret_addr )
305 EXCEPTION_RECORD rec;
307 rec.ExceptionCode = EXCEPTION_WINE_STUB;
308 rec.ExceptionFlags = EH_NONCONTINUABLE;
309 rec.ExceptionRecord = NULL;
310 rec.ExceptionAddress = ret_addr;
311 rec.NumberParameters = 2;
312 rec.ExceptionInformation[0] = (ULONG_PTR)dll;
313 rec.ExceptionInformation[1] = (ULONG_PTR)name;
314 for (;;) RtlRaiseException( &rec );
318 #include "pshpack1.h"
319 #ifdef __i386__
320 struct stub
322 BYTE pushl1; /* pushl $name */
323 const char *name;
324 BYTE pushl2; /* pushl $dll */
325 const char *dll;
326 BYTE call; /* call stub_entry_point */
327 DWORD entry;
329 #elif defined(__arm__)
330 struct stub
332 DWORD ldr_r0; /* ldr r0, $dll */
333 DWORD ldr_r1; /* ldr r1, $name */
334 DWORD mov_r2_lr; /* mov r2, lr */
335 DWORD ldr_pc_pc; /* ldr pc, [pc, #4] */
336 const char *dll;
337 const char *name;
338 const void* entry;
340 #elif defined(__aarch64__)
341 struct stub
343 DWORD ldr_x0; /* ldr x0, $dll */
344 DWORD ldr_x1; /* ldr x1, $name */
345 DWORD mov_x2_lr; /* mov x2, lr */
346 DWORD ldr_x16; /* ldr x16, $entry */
347 DWORD br_x16; /* br x16 */
348 const char *dll;
349 const char *name;
350 const void *entry;
352 #else
353 struct stub
355 BYTE movq_rdi[2]; /* movq $dll,%rdi */
356 const char *dll;
357 BYTE movq_rsi[2]; /* movq $name,%rsi */
358 const char *name;
359 BYTE movq_rsp_rdx[4]; /* movq (%rsp),%rdx */
360 BYTE movq_rax[2]; /* movq $entry, %rax */
361 const void* entry;
362 BYTE jmpq_rax[2]; /* jmp %rax */
364 #endif
365 #include "poppack.h"
367 /*************************************************************************
368 * allocate_stub
370 * Allocate a stub entry point.
372 static ULONG_PTR allocate_stub( const char *dll, const char *name )
374 #define MAX_SIZE 65536
375 static struct stub *stubs;
376 static unsigned int nb_stubs;
377 struct stub *stub;
379 if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
381 if (!stubs)
383 SIZE_T size = MAX_SIZE;
384 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
385 MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
386 return 0xdeadbeef;
388 stub = &stubs[nb_stubs++];
389 #ifdef __i386__
390 stub->pushl1 = 0x68; /* pushl $name */
391 stub->name = name;
392 stub->pushl2 = 0x68; /* pushl $dll */
393 stub->dll = dll;
394 stub->call = 0xe8; /* call stub_entry_point */
395 stub->entry = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
396 #elif defined(__arm__)
397 stub->ldr_r0 = 0xe59f0008; /* ldr r0, [pc, #8] ($dll) */
398 stub->ldr_r1 = 0xe59f1008; /* ldr r1, [pc, #8] ($name) */
399 stub->mov_r2_lr = 0xe1a0200e; /* mov r2, lr */
400 stub->ldr_pc_pc = 0xe59ff004; /* ldr pc, [pc, #4] */
401 stub->dll = dll;
402 stub->name = name;
403 stub->entry = stub_entry_point;
404 #elif defined(__aarch64__)
405 stub->ldr_x0 = 0x580000a0; /* ldr x0, #20 ($dll) */
406 stub->ldr_x1 = 0x580000c1; /* ldr x1, #24 ($name) */
407 stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
408 stub->ldr_x16 = 0x580000d0; /* ldr x16, #24 ($entry) */
409 stub->br_x16 = 0xd61f0200; /* br x16 */
410 stub->dll = dll;
411 stub->name = name;
412 stub->entry = stub_entry_point;
413 #else
414 stub->movq_rdi[0] = 0x48; /* movq $dll,%rcx */
415 stub->movq_rdi[1] = 0xb9;
416 stub->dll = dll;
417 stub->movq_rsi[0] = 0x48; /* movq $name,%rdx */
418 stub->movq_rsi[1] = 0xba;
419 stub->name = name;
420 stub->movq_rsp_rdx[0] = 0x4c; /* movq (%rsp),%r8 */
421 stub->movq_rsp_rdx[1] = 0x8b;
422 stub->movq_rsp_rdx[2] = 0x04;
423 stub->movq_rsp_rdx[3] = 0x24;
424 stub->movq_rax[0] = 0x48; /* movq $entry, %rax */
425 stub->movq_rax[1] = 0xb8;
426 stub->entry = stub_entry_point;
427 stub->jmpq_rax[0] = 0xff; /* jmp %rax */
428 stub->jmpq_rax[1] = 0xe0;
429 #endif
430 return (ULONG_PTR)stub;
433 #else /* __i386__ */
434 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
435 #endif /* __i386__ */
437 /* call ldr notifications */
438 static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
440 struct ldr_notification *notify, *notify_next;
441 LDR_DLL_NOTIFICATION_DATA data;
443 data.Loaded.Flags = 0;
444 data.Loaded.FullDllName = &module->FullDllName;
445 data.Loaded.BaseDllName = &module->BaseDllName;
446 data.Loaded.DllBase = module->DllBase;
447 data.Loaded.SizeOfImage = module->SizeOfImage;
449 LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
451 TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
452 notify->callback, reason, &data, notify->context );
454 notify->callback(reason, &data, notify->context);
456 TRACE_(relay)("\1Ret LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
457 notify->callback, reason, &data, notify->context );
461 /*************************************************************************
462 * get_modref
464 * Looks for the referenced HMODULE in the current process
465 * The loader_section must be locked while calling this function.
467 static WINE_MODREF *get_modref( HMODULE hmod )
469 PLIST_ENTRY mark, entry;
470 PLDR_DATA_TABLE_ENTRY mod;
472 if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref;
474 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
475 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
477 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
478 if (mod->DllBase == hmod)
479 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
481 return NULL;
485 /**********************************************************************
486 * find_basename_module
488 * Find a module from its base name.
489 * The loader_section must be locked while calling this function
491 static WINE_MODREF *find_basename_module( LPCWSTR name )
493 PLIST_ENTRY mark, entry;
494 UNICODE_STRING name_str;
496 RtlInitUnicodeString( &name_str, name );
498 if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
499 return cached_modref;
501 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
502 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
504 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
505 if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE ))
507 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
508 return cached_modref;
511 return NULL;
515 /**********************************************************************
516 * find_fullname_module
518 * Find a module from its full path name.
519 * The loader_section must be locked while calling this function
521 static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
523 PLIST_ENTRY mark, entry;
524 UNICODE_STRING name = *nt_name;
526 if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
527 name.Length -= 4 * sizeof(WCHAR); /* for \??\ prefix */
528 name.Buffer += 4;
530 if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
531 return cached_modref;
533 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
534 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
536 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
537 if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
539 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
540 return cached_modref;
543 return NULL;
547 /**********************************************************************
548 * find_fileid_module
550 * Find a module from its file id.
551 * The loader_section must be locked while calling this function
553 static WINE_MODREF *find_fileid_module( const struct file_id *id )
555 LIST_ENTRY *mark, *entry;
557 if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref;
559 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
560 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
562 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
563 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
565 if (!memcmp( &wm->id, id, sizeof(*id) ))
567 cached_modref = wm;
568 return wm;
571 return NULL;
575 /*************************************************************************
576 * grow_module_deps
578 static WINE_MODREF **grow_module_deps( WINE_MODREF *wm, int count )
580 WINE_MODREF **deps;
582 if (wm->alloc_deps)
583 deps = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, wm->deps,
584 (wm->alloc_deps + count) * sizeof(*deps) );
585 else
586 deps = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(*deps) );
588 if (deps)
590 wm->deps = deps;
591 wm->alloc_deps += count;
593 return deps;
596 /*************************************************************************
597 * find_forwarded_export
599 * Find the final function pointer for a forwarded function.
600 * The loader_section must be locked while calling this function.
602 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
604 const IMAGE_EXPORT_DIRECTORY *exports;
605 DWORD exp_size;
606 WINE_MODREF *wm;
607 WCHAR buffer[32], *mod_name = buffer;
608 const char *end = strrchr(forward, '.');
609 FARPROC proc = NULL;
611 if (!end) return NULL;
612 if ((end - forward) * sizeof(WCHAR) > sizeof(buffer) - sizeof(L".dll"))
614 if (!(mod_name = RtlAllocateHeap( GetProcessHeap(), 0,
615 (end - forward + sizeof(L".dll")) * sizeof(WCHAR) )))
616 return NULL;
618 ascii_to_unicode( mod_name, forward, end - forward );
619 mod_name[end - forward] = 0;
620 if (!wcschr( mod_name, '.' ))
621 memcpy( mod_name + (end - forward), L".dll", sizeof(L".dll") );
623 if (!(wm = find_basename_module( mod_name )))
625 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
626 if (load_dll( load_path, mod_name, L".dll", 0, &wm ) == STATUS_SUCCESS &&
627 !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
629 if (!imports_fixup_done && current_modref)
631 WINE_MODREF **deps = grow_module_deps( current_modref, 1 );
632 if (deps) deps[current_modref->nDeps++] = wm;
634 else if (process_attach( wm, NULL ) != STATUS_SUCCESS)
636 LdrUnloadDll( wm->ldr.DllBase );
637 wm = NULL;
641 if (!wm)
643 if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name );
644 ERR( "module not found for forward '%s' used by %s\n",
645 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
646 return NULL;
649 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
650 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
652 const char *name = end + 1;
654 if (*name == '#') { /* ordinal */
655 proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
656 atoi(name+1) - exports->Base, load_path );
657 } else
658 proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
661 if (!proc)
663 ERR("function not found for forward '%s' used by %s."
664 " If you are using builtin %s, try using the native one instead.\n",
665 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
666 debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
668 if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name );
669 return proc;
673 /*************************************************************************
674 * find_ordinal_export
676 * Find an exported function by ordinal.
677 * The exports base must have been subtracted from the ordinal already.
678 * The loader_section must be locked while calling this function.
680 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
681 DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
683 FARPROC proc;
684 const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
686 if (ordinal >= exports->NumberOfFunctions)
688 TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
689 return NULL;
691 if (!functions[ordinal]) return NULL;
693 proc = get_rva( module, functions[ordinal] );
695 /* if the address falls into the export dir, it's a forward */
696 if (((const char *)proc >= (const char *)exports) &&
697 ((const char *)proc < (const char *)exports + exp_size))
698 return find_forwarded_export( module, (const char *)proc, load_path );
700 if (TRACE_ON(snoop))
702 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
703 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
705 if (TRACE_ON(relay))
707 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
708 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
710 return proc;
714 /*************************************************************************
715 * find_named_export
717 * Find an exported function by name.
718 * The loader_section must be locked while calling this function.
720 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
721 DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
723 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
724 const DWORD *names = get_rva( module, exports->AddressOfNames );
725 int min = 0, max = exports->NumberOfNames - 1;
727 /* first check the hint */
728 if (hint >= 0 && hint <= max)
730 char *ename = get_rva( module, names[hint] );
731 if (!strcmp( ename, name ))
732 return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
735 /* then do a binary search */
736 while (min <= max)
738 int res, pos = (min + max) / 2;
739 char *ename = get_rva( module, names[pos] );
740 if (!(res = strcmp( ename, name )))
741 return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
742 if (res > 0) max = pos - 1;
743 else min = pos + 1;
745 return NULL;
750 /*************************************************************************
751 * import_dll
753 * Import the dll specified by the given import descriptor.
754 * The loader_section must be locked while calling this function.
756 static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
758 NTSTATUS status;
759 WINE_MODREF *wmImp;
760 HMODULE imp_mod;
761 const IMAGE_EXPORT_DIRECTORY *exports;
762 DWORD exp_size;
763 const IMAGE_THUNK_DATA *import_list;
764 IMAGE_THUNK_DATA *thunk_list;
765 WCHAR buffer[32];
766 const char *name = get_rva( module, descr->Name );
767 DWORD len = strlen(name);
768 PVOID protect_base;
769 SIZE_T protect_size = 0;
770 DWORD protect_old;
772 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
773 if (descr->u.OriginalFirstThunk)
774 import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
775 else
776 import_list = thunk_list;
778 if (!import_list->u1.Ordinal)
780 WARN( "Skipping unused import %s\n", name );
781 *pwm = NULL;
782 return TRUE;
785 while (len && name[len-1] == ' ') len--; /* remove trailing spaces */
787 if (len * sizeof(WCHAR) < sizeof(buffer))
789 ascii_to_unicode( buffer, name, len );
790 buffer[len] = 0;
791 status = load_dll( load_path, buffer, L".dll", 0, &wmImp );
793 else /* need to allocate a larger buffer */
795 WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
796 if (!ptr) return FALSE;
797 ascii_to_unicode( ptr, name, len );
798 ptr[len] = 0;
799 status = load_dll( load_path, ptr, L".dll", 0, &wmImp );
800 RtlFreeHeap( GetProcessHeap(), 0, ptr );
803 if (status)
805 if (status == STATUS_DLL_NOT_FOUND)
806 ERR("Library %s (which is needed by %s) not found\n",
807 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
808 else
809 ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
810 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
811 return FALSE;
814 /* unprotect the import address table since it can be located in
815 * readonly section */
816 while (import_list[protect_size].u1.Ordinal) protect_size++;
817 protect_base = thunk_list;
818 protect_size *= sizeof(*thunk_list);
819 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
820 &protect_size, PAGE_READWRITE, &protect_old );
822 imp_mod = wmImp->ldr.DllBase;
823 exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
825 if (!exports)
827 /* set all imported function to deadbeef */
828 while (import_list->u1.Ordinal)
830 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
832 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
833 WARN("No implementation for %s.%d", name, ordinal );
834 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
836 else
838 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
839 WARN("No implementation for %s.%s", name, pe_name->Name );
840 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
842 WARN(" imported from %s, allocating stub %p\n",
843 debugstr_w(current_modref->ldr.FullDllName.Buffer),
844 (void *)thunk_list->u1.Function );
845 import_list++;
846 thunk_list++;
848 goto done;
851 while (import_list->u1.Ordinal)
853 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
855 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
857 thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
858 ordinal - exports->Base, load_path );
859 if (!thunk_list->u1.Function)
861 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
862 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
863 name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
864 (void *)thunk_list->u1.Function );
866 TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
868 else /* import by name */
870 IMAGE_IMPORT_BY_NAME *pe_name;
871 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
872 thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
873 (const char*)pe_name->Name,
874 pe_name->Hint, load_path );
875 if (!thunk_list->u1.Function)
877 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
878 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
879 name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
880 (void *)thunk_list->u1.Function );
882 TRACE_(imports)("--- %s %s.%d = %p\n",
883 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
885 import_list++;
886 thunk_list++;
889 done:
890 /* restore old protection of the import address table */
891 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
892 *pwm = wmImp;
893 return TRUE;
897 /***********************************************************************
898 * create_module_activation_context
900 static NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
902 NTSTATUS status;
903 LDR_RESOURCE_INFO info;
904 const IMAGE_RESOURCE_DATA_ENTRY *entry;
906 info.Type = RT_MANIFEST;
907 info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
908 info.Language = 0;
909 if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
911 ACTCTXW ctx;
912 ctx.cbSize = sizeof(ctx);
913 ctx.lpSource = NULL;
914 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
915 ctx.hModule = module->DllBase;
916 ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
917 status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
919 return status;
923 /*************************************************************************
924 * is_dll_native_subsystem
926 * Check if dll is a proper native driver.
927 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
928 * while being perfectly normal DLLs. This heuristic should catch such breakages.
930 static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
932 const IMAGE_IMPORT_DESCRIPTOR *imports;
933 DWORD i, size;
934 WCHAR buffer[16];
936 if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
937 if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
938 if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
940 if ((imports = RtlImageDirectoryEntryToData( mod->DllBase, TRUE,
941 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
943 for (i = 0; imports[i].Name; i++)
945 const char *name = get_rva( mod->DllBase, imports[i].Name );
946 DWORD len = strlen(name);
947 if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
948 ascii_to_unicode( buffer, name, len + 1 );
949 if (!wcsicmp( buffer, L"ntdll.dll" ) || !wcsicmp( buffer, L"kernel32.dll" ))
951 TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
952 return FALSE;
956 return TRUE;
959 /*************************************************************************
960 * alloc_tls_slot
962 * Allocate a TLS slot for a newly-loaded module.
963 * The loader_section must be locked while calling this function.
965 static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
967 const IMAGE_TLS_DIRECTORY *dir;
968 ULONG i, size;
969 void *new_ptr;
970 LIST_ENTRY *entry;
972 if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
973 return -1;
975 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
976 if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1;
978 for (i = 0; i < tls_module_count; i++)
980 if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
981 !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
982 break;
985 TRACE( "module %p data %p-%p zerofill %u index %p callback %p flags %x -> slot %u\n", mod->DllBase,
986 (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
987 (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );
989 if (i == tls_module_count)
991 UINT new_count = max( 32, tls_module_count * 2 );
993 if (!tls_dirs)
994 new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
995 else
996 new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
997 new_count * sizeof(*tls_dirs) );
998 if (!new_ptr) return -1;
1000 /* resize the pointer block in all running threads */
1001 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1003 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1004 void **old = teb->ThreadLocalStoragePointer;
1005 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
1007 if (!new) return -1;
1008 if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
1009 teb->ThreadLocalStoragePointer = new;
1010 #ifdef __x86_64__ /* macOS-specific hack */
1011 if (teb->Reserved5[0]) ((TEB *)teb->Reserved5[0])->ThreadLocalStoragePointer = new;
1012 #endif
1013 TRACE( "thread %04lx tls block %p -> %p\n", (ULONG_PTR)teb->ClientId.UniqueThread, old, new );
1014 /* FIXME: can't free old block here, should be freed at thread exit */
1017 tls_dirs = new_ptr;
1018 tls_module_count = new_count;
1021 /* allocate the data block in all running threads */
1022 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1024 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1026 if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
1027 memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
1028 memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
1030 TRACE( "thread %04lx slot %u: %u/%u bytes at %p\n",
1031 (ULONG_PTR)teb->ClientId.UniqueThread, i, size, dir->SizeOfZeroFill, new_ptr );
1033 RtlFreeHeap( GetProcessHeap(), 0,
1034 InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1037 *(DWORD *)dir->AddressOfIndex = i;
1038 tls_dirs[i] = *dir;
1039 return i;
1043 /*************************************************************************
1044 * free_tls_slot
1046 * Free the module TLS slot on unload.
1047 * The loader_section must be locked while calling this function.
1049 static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1051 ULONG i = (USHORT)mod->TlsIndex;
1053 if (mod->TlsIndex == -1) return;
1054 assert( i < tls_module_count );
1055 memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1059 /****************************************************************
1060 * fixup_imports_ilonly
1062 * Fixup imports for an IL-only module. All we do is import mscoree.
1063 * The loader_section must be locked while calling this function.
1065 static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
1067 IMAGE_EXPORT_DIRECTORY *exports;
1068 DWORD exp_size;
1069 NTSTATUS status;
1070 void *proc = NULL;
1071 WINE_MODREF *prev, *imp;
1073 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1074 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1076 if (!grow_module_deps( wm, 1 )) return STATUS_NO_MEMORY;
1077 wm->nDeps = 1;
1079 prev = current_modref;
1080 current_modref = wm;
1081 if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp ))) wm->deps[0] = imp;
1082 current_modref = prev;
1083 if (status)
1085 ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
1086 debugstr_w(wm->ldr.BaseDllName.Buffer) );
1087 return status;
1090 TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
1092 if ((exports = RtlImageDirectoryEntryToData( imp->ldr.DllBase, TRUE,
1093 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1095 const char *name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
1096 proc = find_named_export( imp->ldr.DllBase, exports, exp_size, name, -1, load_path );
1098 if (!proc) return STATUS_PROCEDURE_NOT_FOUND;
1099 *entry = proc;
1100 return STATUS_SUCCESS;
1104 /****************************************************************
1105 * fixup_imports
1107 * Fixup all imports of a given module.
1108 * The loader_section must be locked while calling this function.
1110 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
1112 int i, dep, nb_imports;
1113 const IMAGE_IMPORT_DESCRIPTOR *imports;
1114 WINE_MODREF *prev, *imp;
1115 DWORD size;
1116 NTSTATUS status;
1117 ULONG_PTR cookie;
1119 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1120 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1122 wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr );
1124 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
1125 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1126 return STATUS_SUCCESS;
1128 nb_imports = 0;
1129 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
1131 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
1132 if (!grow_module_deps( wm, nb_imports )) return STATUS_NO_MEMORY;
1134 if (!create_module_activation_context( &wm->ldr ))
1135 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1137 /* load the imported modules. They are automatically
1138 * added to the modref list of the process.
1140 prev = current_modref;
1141 current_modref = wm;
1142 status = STATUS_SUCCESS;
1143 for (i = 0; i < nb_imports; i++)
1145 dep = wm->nDeps++;
1147 if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
1149 imp = NULL;
1150 status = STATUS_DLL_NOT_FOUND;
1152 wm->deps[dep] = imp;
1154 current_modref = prev;
1155 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1156 return status;
1160 /*************************************************************************
1161 * alloc_module
1163 * Allocate a WINE_MODREF structure and add it to the process list
1164 * The loader_section must be locked while calling this function.
1166 static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1168 WCHAR *buffer;
1169 WINE_MODREF *wm;
1170 const WCHAR *p;
1171 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1173 if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1175 wm->ldr.DllBase = hModule;
1176 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
1177 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1178 wm->ldr.TlsIndex = -1;
1179 wm->ldr.LoadCount = 1;
1180 wm->ldr.CheckSum = nt->OptionalHeader.CheckSum;
1181 wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
1183 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
1185 RtlFreeHeap( GetProcessHeap(), 0, wm );
1186 return NULL;
1188 memcpy( buffer, nt_name->Buffer + 4 /* \??\ prefix */, nt_name->Length - 4 * sizeof(WCHAR) );
1189 buffer[nt_name->Length/sizeof(WCHAR) - 4] = 0;
1190 if ((p = wcsrchr( buffer, '\\' ))) p++;
1191 else p = buffer;
1192 RtlInitUnicodeString( &wm->ldr.FullDllName, buffer );
1193 RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
1195 if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1197 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
1198 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1199 if (nt->OptionalHeader.AddressOfEntryPoint)
1200 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1203 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1204 &wm->ldr.InLoadOrderLinks);
1205 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1206 &wm->ldr.InMemoryOrderLinks);
1207 /* wait until init is called for inserting into InInitializationOrderModuleList */
1209 if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
1211 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1212 WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1213 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1215 return wm;
1219 /*************************************************************************
1220 * alloc_thread_tls
1222 * Allocate the per-thread structure for module TLS storage.
1224 static NTSTATUS alloc_thread_tls(void)
1226 void **pointers;
1227 UINT i, size;
1229 if (!tls_module_count) return STATUS_SUCCESS;
1231 if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
1232 tls_module_count * sizeof(*pointers) )))
1233 return STATUS_NO_MEMORY;
1235 for (i = 0; i < tls_module_count; i++)
1237 const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1239 if (!dir) continue;
1240 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1241 if (!size && !dir->SizeOfZeroFill) continue;
1243 if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
1245 while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
1246 RtlFreeHeap( GetProcessHeap(), 0, pointers );
1247 return STATUS_NO_MEMORY;
1249 memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
1250 memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1252 TRACE( "thread %04x slot %u: %u/%u bytes at %p\n",
1253 GetCurrentThreadId(), i, size, dir->SizeOfZeroFill, pointers[i] );
1255 NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1256 #ifdef __x86_64__ /* macOS-specific hack */
1257 if (NtCurrentTeb()->Reserved5[0])
1258 ((TEB *)NtCurrentTeb()->Reserved5[0])->ThreadLocalStoragePointer = pointers;
1259 #endif
1260 return STATUS_SUCCESS;
1264 /*************************************************************************
1265 * call_tls_callbacks
1267 static void call_tls_callbacks( HMODULE module, UINT reason )
1269 const IMAGE_TLS_DIRECTORY *dir;
1270 const PIMAGE_TLS_CALLBACK *callback;
1271 ULONG dirsize;
1273 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
1274 if (!dir || !dir->AddressOfCallBacks) return;
1276 for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1278 TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1279 *callback, module, reason_names[reason] );
1280 __TRY
1282 call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1284 __EXCEPT_ALL
1286 TRACE_(relay)("\1exception %08x in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1287 GetExceptionCode(), callback, module, reason_names[reason] );
1288 return;
1290 __ENDTRY
1291 TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1292 *callback, module, reason_names[reason] );
1296 /*************************************************************************
1297 * MODULE_InitDLL
1299 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1301 WCHAR mod_name[32];
1302 NTSTATUS status = STATUS_SUCCESS;
1303 DLLENTRYPROC entry = wm->ldr.EntryPoint;
1304 void *module = wm->ldr.DllBase;
1305 BOOL retv = FALSE;
1307 /* Skip calls for modules loaded with special load flags */
1309 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1310 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, reason );
1311 if (wm->ldr.Flags & LDR_WINE_INTERNAL && reason == DLL_PROCESS_ATTACH)
1312 unix_funcs->init_builtin_dll( wm->ldr.DllBase );
1313 if (!entry) return STATUS_SUCCESS;
1315 if (TRACE_ON(relay))
1317 size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1318 memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
1319 mod_name[len / sizeof(WCHAR)] = 0;
1320 TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1321 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1323 else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
1324 reason_names[reason], lpReserved );
1326 __TRY
1328 retv = call_dll_entry_point( entry, module, reason, lpReserved );
1329 if (!retv)
1330 status = STATUS_DLL_INIT_FAILED;
1332 __EXCEPT_ALL
1334 status = GetExceptionCode();
1335 TRACE_(relay)("\1exception %08x in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1336 status, entry, module, reason_names[reason], lpReserved );
1338 __ENDTRY
1340 /* The state of the module list may have changed due to the call
1341 to the dll. We cannot assume that this module has not been
1342 deleted. */
1343 if (TRACE_ON(relay))
1344 TRACE_(relay)("\1Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1345 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
1346 else
1347 TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1349 return status;
1353 /*************************************************************************
1354 * process_attach
1356 * Send the process attach notification to all DLLs the given module
1357 * depends on (recursively). This is somewhat complicated due to the fact that
1359 * - we have to respect the module dependencies, i.e. modules implicitly
1360 * referenced by another module have to be initialized before the module
1361 * itself can be initialized
1363 * - the initialization routine of a DLL can itself call LoadLibrary,
1364 * thereby introducing a whole new set of dependencies (even involving
1365 * the 'old' modules) at any time during the whole process
1367 * (Note that this routine can be recursively entered not only directly
1368 * from itself, but also via LoadLibrary from one of the called initialization
1369 * routines.)
1371 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1372 * the process *detach* notifications to be sent in the correct order.
1373 * This must not only take into account module dependencies, but also
1374 * 'hidden' dependencies created by modules calling LoadLibrary in their
1375 * attach notification routine.
1377 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1378 * list after the attach notification has returned. This implies that the
1379 * detach notifications are called in the reverse of the sequence the attach
1380 * notifications *returned*.
1382 * The loader_section must be locked while calling this function.
1384 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1386 NTSTATUS status = STATUS_SUCCESS;
1387 ULONG_PTR cookie;
1388 int i;
1390 if (process_detaching) return status;
1392 /* prevent infinite recursion in case of cyclical dependencies */
1393 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1394 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1395 return status;
1397 TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1399 /* Tag current MODREF to prevent recursive loop */
1400 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1401 if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */
1402 if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1404 /* Recursively attach all DLLs this one depends on */
1405 for ( i = 0; i < wm->nDeps; i++ )
1407 if (!wm->deps[i]) continue;
1408 if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1411 if (!wm->ldr.InInitializationOrderLinks.Flink)
1412 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1413 &wm->ldr.InInitializationOrderLinks);
1415 /* Call DLL entry point */
1416 if (status == STATUS_SUCCESS)
1418 WINE_MODREF *prev = current_modref;
1419 current_modref = wm;
1421 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1422 status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1423 if (status == STATUS_SUCCESS)
1425 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1427 else
1429 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1430 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );
1432 /* point to the name so LdrInitializeThunk can print it */
1433 last_failed_modref = wm;
1434 WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1436 current_modref = prev;
1439 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1440 /* Remove recursion flag */
1441 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1443 TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1444 return status;
1448 /*************************************************************************
1449 * process_detach
1451 * Send DLL process detach notifications. See the comment about calling
1452 * sequence at process_attach.
1454 static void process_detach(void)
1456 PLIST_ENTRY mark, entry;
1457 PLDR_DATA_TABLE_ENTRY mod;
1459 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1462 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1464 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1465 InInitializationOrderLinks);
1466 /* Check whether to detach this DLL */
1467 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1468 continue;
1469 if ( mod->LoadCount && !process_detaching )
1470 continue;
1472 /* Call detach notification */
1473 mod->Flags &= ~LDR_PROCESS_ATTACHED;
1474 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1475 DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1476 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1478 /* Restart at head of WINE_MODREF list, as entries might have
1479 been added and/or removed while performing the call ... */
1480 break;
1482 } while (entry != mark);
1485 /*************************************************************************
1486 * thread_attach
1488 * Send DLL thread attach notifications. These are sent in the
1489 * reverse sequence of process detach notification.
1490 * The loader_section must be locked while calling this function.
1492 static void thread_attach(void)
1494 PLIST_ENTRY mark, entry;
1495 PLDR_DATA_TABLE_ENTRY mod;
1497 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1498 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1500 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1501 InInitializationOrderLinks);
1502 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1503 continue;
1504 if ( mod->Flags & LDR_NO_DLL_CALLS )
1505 continue;
1507 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1511 /******************************************************************
1512 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1515 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1517 WINE_MODREF *wm;
1518 NTSTATUS ret = STATUS_SUCCESS;
1520 RtlEnterCriticalSection( &loader_section );
1522 wm = get_modref( hModule );
1523 if (!wm || wm->ldr.TlsIndex != -1)
1524 ret = STATUS_DLL_NOT_FOUND;
1525 else
1526 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1528 RtlLeaveCriticalSection( &loader_section );
1530 return ret;
1533 /******************************************************************
1534 * LdrFindEntryForAddress (NTDLL.@)
1536 * The loader_section must be locked while calling this function
1538 NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
1540 PLIST_ENTRY mark, entry;
1541 PLDR_DATA_TABLE_ENTRY mod;
1543 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1544 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1546 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
1547 if (mod->DllBase <= addr &&
1548 (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
1550 *pmod = mod;
1551 return STATUS_SUCCESS;
1554 return STATUS_NO_MORE_ENTRIES;
1557 /******************************************************************
1558 * LdrEnumerateLoadedModules (NTDLL.@)
1560 NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
1562 LIST_ENTRY *mark, *entry;
1563 LDR_DATA_TABLE_ENTRY *mod;
1564 BOOLEAN stop = FALSE;
1566 TRACE( "(%p, %p, %p)\n", unknown, callback, context );
1568 if (unknown || !callback)
1569 return STATUS_INVALID_PARAMETER;
1571 RtlEnterCriticalSection( &loader_section );
1573 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1574 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1576 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
1577 callback( mod, context, &stop );
1578 if (stop) break;
1581 RtlLeaveCriticalSection( &loader_section );
1582 return STATUS_SUCCESS;
1585 /******************************************************************
1586 * LdrRegisterDllNotification (NTDLL.@)
1588 NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
1589 void *context, void **cookie)
1591 struct ldr_notification *notify;
1593 TRACE( "(%x, %p, %p, %p)\n", flags, callback, context, cookie );
1595 if (!callback || !cookie)
1596 return STATUS_INVALID_PARAMETER;
1598 if (flags)
1599 FIXME( "ignoring flags %x\n", flags );
1601 notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
1602 if (!notify) return STATUS_NO_MEMORY;
1603 notify->callback = callback;
1604 notify->context = context;
1606 RtlEnterCriticalSection( &loader_section );
1607 list_add_tail( &ldr_notifications, &notify->entry );
1608 RtlLeaveCriticalSection( &loader_section );
1610 *cookie = notify;
1611 return STATUS_SUCCESS;
1614 /******************************************************************
1615 * LdrUnregisterDllNotification (NTDLL.@)
1617 NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
1619 struct ldr_notification *notify = cookie;
1621 TRACE( "(%p)\n", cookie );
1623 if (!notify) return STATUS_INVALID_PARAMETER;
1625 RtlEnterCriticalSection( &loader_section );
1626 list_remove( &notify->entry );
1627 RtlLeaveCriticalSection( &loader_section );
1629 RtlFreeHeap( GetProcessHeap(), 0, notify );
1630 return STATUS_SUCCESS;
1633 /******************************************************************
1634 * LdrLockLoaderLock (NTDLL.@)
1636 * Note: some flags are not implemented.
1637 * Flag 0x01 is used to raise exceptions on errors.
1639 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1641 if (flags & ~0x2) FIXME( "flags %x not supported\n", flags );
1643 if (result) *result = 0;
1644 if (magic) *magic = 0;
1645 if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
1646 if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1647 if (!magic) return STATUS_INVALID_PARAMETER_3;
1649 if (flags & 0x2)
1651 if (!RtlTryEnterCriticalSection( &loader_section ))
1653 *result = 2;
1654 return STATUS_SUCCESS;
1656 *result = 1;
1658 else
1660 RtlEnterCriticalSection( &loader_section );
1661 if (result) *result = 1;
1663 *magic = GetCurrentThreadId();
1664 return STATUS_SUCCESS;
1668 /******************************************************************
1669 * LdrUnlockLoaderUnlock (NTDLL.@)
1671 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
1673 if (magic)
1675 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
1676 RtlLeaveCriticalSection( &loader_section );
1678 return STATUS_SUCCESS;
1682 /******************************************************************
1683 * LdrGetProcedureAddress (NTDLL.@)
1685 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
1686 ULONG ord, PVOID *address)
1688 IMAGE_EXPORT_DIRECTORY *exports;
1689 DWORD exp_size;
1690 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1692 RtlEnterCriticalSection( &loader_section );
1694 /* check if the module itself is invalid to return the proper error */
1695 if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
1696 else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
1697 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1699 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
1700 : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
1701 if (proc)
1703 *address = proc;
1704 ret = STATUS_SUCCESS;
1708 RtlLeaveCriticalSection( &loader_section );
1709 return ret;
1713 /***********************************************************************
1714 * set_security_cookie
1716 * Create a random security cookie for buffer overflow protection. Make
1717 * sure it does not accidentally match the default cookie value.
1719 static void set_security_cookie( void *module, SIZE_T len )
1721 static ULONG seed;
1722 IMAGE_LOAD_CONFIG_DIRECTORY *loadcfg;
1723 ULONG loadcfg_size;
1724 ULONG_PTR *cookie;
1726 loadcfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &loadcfg_size );
1727 if (!loadcfg) return;
1728 if (loadcfg_size < offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie) + sizeof(loadcfg->SecurityCookie)) return;
1729 if (!loadcfg->SecurityCookie) return;
1730 if (loadcfg->SecurityCookie < (ULONG_PTR)module ||
1731 loadcfg->SecurityCookie > (ULONG_PTR)module + len - sizeof(ULONG_PTR))
1733 WARN( "security cookie %p outside of image %p-%p\n",
1734 (void *)loadcfg->SecurityCookie, module, (char *)module + len );
1735 return;
1738 cookie = (ULONG_PTR *)loadcfg->SecurityCookie;
1739 TRACE( "initializing security cookie %p\n", cookie );
1741 if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
1742 for (;;)
1744 if (*cookie == DEFAULT_SECURITY_COOKIE_16)
1745 *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
1746 else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
1747 *cookie = RtlRandom( &seed );
1748 #ifdef DEFAULT_SECURITY_COOKIE_64
1749 else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
1751 *cookie = RtlRandom( &seed );
1752 /* fill up, but keep the highest word clear */
1753 *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
1755 #endif
1756 else
1757 break;
1761 static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
1763 char *base;
1764 IMAGE_BASE_RELOCATION *rel, *end;
1765 const IMAGE_DATA_DIRECTORY *relocs;
1766 const IMAGE_SECTION_HEADER *sec;
1767 INT_PTR delta;
1768 ULONG protect_old[96], i;
1770 base = (char *)nt->OptionalHeader.ImageBase;
1771 if (module == base) return STATUS_SUCCESS; /* nothing to do */
1773 /* no relocations are performed on non page-aligned binaries */
1774 if (nt->OptionalHeader.SectionAlignment < page_size)
1775 return STATUS_SUCCESS;
1777 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
1778 return STATUS_SUCCESS;
1780 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1782 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1784 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
1785 base, module );
1786 return STATUS_CONFLICTING_ADDRESSES;
1789 if (!relocs->Size) return STATUS_SUCCESS;
1790 if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;
1792 if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
1793 return STATUS_INVALID_IMAGE_FORMAT;
1795 sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
1796 nt->FileHeader.SizeOfOptionalHeader);
1797 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
1799 void *addr = get_rva( module, sec[i].VirtualAddress );
1800 SIZE_T size = sec[i].SizeOfRawData;
1801 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
1802 &size, PAGE_READWRITE, &protect_old[i] );
1805 TRACE( "relocating from %p-%p to %p-%p\n",
1806 base, base + len, module, (char *)module + len );
1808 rel = get_rva( module, relocs->VirtualAddress );
1809 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
1810 delta = (char *)module - base;
1812 while (rel < end - 1 && rel->SizeOfBlock)
1814 if (rel->VirtualAddress >= len)
1816 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
1817 return STATUS_ACCESS_VIOLATION;
1819 rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
1820 (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
1821 (USHORT *)(rel + 1), delta );
1822 if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
1825 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
1827 void *addr = get_rva( module, sec[i].VirtualAddress );
1828 SIZE_T size = sec[i].SizeOfRawData;
1829 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
1830 &size, protect_old[i], &protect_old[i] );
1833 return STATUS_SUCCESS;
1837 /*************************************************************************
1838 * build_module
1840 * Build the module data for a mapped dll.
1842 static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
1843 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
1844 DWORD flags, WINE_MODREF **pwm )
1846 static const char builtin_signature[] = "Wine builtin DLL";
1847 char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1);
1848 BOOL is_builtin;
1849 IMAGE_NT_HEADERS *nt;
1850 WINE_MODREF *wm;
1851 NTSTATUS status;
1852 SIZE_T map_size;
1854 if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT;
1856 map_size = (nt->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
1857 if ((status = perform_relocations( *module, nt, map_size ))) return status;
1859 is_builtin = ((char *)nt - signature >= sizeof(builtin_signature) &&
1860 !memcmp( signature, builtin_signature, sizeof(builtin_signature) ));
1862 /* create the MODREF */
1864 if (!(wm = alloc_module( *module, nt_name, is_builtin ))) return STATUS_NO_MEMORY;
1866 if (id) wm->id = *id;
1867 if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE;
1868 if (image_info->u.s.ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
1870 set_security_cookie( *module, map_size );
1872 /* fixup imports */
1874 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
1875 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
1876 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
1878 if (wm->ldr.Flags & LDR_COR_ILONLY)
1879 status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
1880 else
1881 status = fixup_imports( wm, load_path );
1882 if (status != STATUS_SUCCESS)
1884 /* the module has only be inserted in the load & memory order lists */
1885 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
1886 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
1888 /* FIXME: there are several more dangling references
1889 * left. Including dlls loaded by this dll before the
1890 * failed one. Unrolling is rather difficult with the
1891 * current structure and we can leave them lying
1892 * around with no problems, so we don't care.
1893 * As these might reference our wm, we don't free it.
1895 *module = NULL;
1896 return status;
1900 TRACE( "loaded %s %p %p\n", debugstr_us(nt_name), wm, *module );
1902 if (is_builtin)
1904 if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
1906 else
1908 if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
1911 TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module,
1912 is_builtin ? "builtin" : "native" );
1914 wm->ldr.LoadCount = 1;
1915 *pwm = wm;
1916 *module = NULL;
1917 return STATUS_SUCCESS;
1921 /*************************************************************************
1922 * build_ntdll_module
1924 * Build the module data for the initially-loaded ntdll.
1926 static void build_ntdll_module(void)
1928 MEMORY_BASIC_INFORMATION meminfo;
1929 FILE_BASIC_INFORMATION basic_info;
1930 UNICODE_STRING nt_name;
1931 OBJECT_ATTRIBUTES attr;
1932 WINE_MODREF *wm;
1934 RtlInitUnicodeString( &nt_name, L"\\??\\C:\\windows\\system32\\ntdll.dll" );
1935 InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
1936 is_prefix_bootstrap = NtQueryAttributesFile( &attr, &basic_info) != STATUS_SUCCESS;
1937 NtQueryVirtualMemory( GetCurrentProcess(), build_ntdll_module, MemoryBasicInformation,
1938 &meminfo, sizeof(meminfo), NULL );
1939 wm = alloc_module( meminfo.AllocationBase, &nt_name, TRUE );
1940 assert( wm );
1941 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1942 if (TRACE_ON(relay)) RELAY_SetupDLL( meminfo.AllocationBase );
1946 #ifdef _WIN64
1947 /* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
1948 static BOOL convert_to_pe64( HMODULE module, const SECTION_IMAGE_INFORMATION *info )
1950 static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
1951 IMAGE_DIRECTORY_ENTRY_SECURITY,
1952 IMAGE_DIRECTORY_ENTRY_BASERELOC,
1953 IMAGE_DIRECTORY_ENTRY_DEBUG,
1954 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
1955 IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
1956 IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
1957 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
1958 SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
1959 IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + hdr_size);
1960 SIZE_T size = min( nt->OptionalHeader.SizeOfHeaders, nt->OptionalHeader.SizeOfImage );
1961 void *addr = module;
1962 ULONG i, old_prot;
1964 if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return TRUE; /* already 64-bit */
1965 if (!info->ImageContainsCode) return TRUE; /* no need to convert */
1967 TRACE( "%p\n", module );
1969 if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
1970 return FALSE;
1972 if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
1974 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
1975 return FALSE;
1978 memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
1979 memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
1980 hdr64.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1981 hdr64.AddressOfEntryPoint = 0;
1982 hdr64.ImageBase = hdr32.ImageBase;
1983 hdr64.SizeOfStackReserve = hdr32.SizeOfStackReserve;
1984 hdr64.SizeOfStackCommit = hdr32.SizeOfStackCommit;
1985 hdr64.SizeOfHeapReserve = hdr32.SizeOfHeapReserve;
1986 hdr64.SizeOfHeapCommit = hdr32.SizeOfHeapCommit;
1987 hdr64.LoaderFlags = hdr32.LoaderFlags;
1988 hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
1989 for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
1990 hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];
1992 memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
1993 nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
1994 nt->OptionalHeader = hdr64;
1995 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
1996 return TRUE;
1999 /* check COM header for ILONLY flag, ignoring runtime version */
2000 static BOOL get_cor_header( HANDLE file, const SECTION_IMAGE_INFORMATION *info, IMAGE_COR20_HEADER *cor )
2002 IMAGE_DOS_HEADER mz;
2003 IMAGE_NT_HEADERS32 nt;
2004 IO_STATUS_BLOCK io;
2005 LARGE_INTEGER offset;
2006 IMAGE_SECTION_HEADER sec[96];
2007 unsigned int i, count;
2008 DWORD va, size;
2010 offset.QuadPart = 0;
2011 if (NtReadFile( file, 0, NULL, NULL, &io, &mz, sizeof(mz), &offset, NULL )) return FALSE;
2012 if (io.Information != sizeof(mz)) return FALSE;
2013 if (mz.e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
2014 offset.QuadPart = mz.e_lfanew;
2015 if (NtReadFile( file, 0, NULL, NULL, &io, &nt, sizeof(nt), &offset, NULL )) return FALSE;
2016 if (io.Information != sizeof(nt)) return FALSE;
2017 if (nt.Signature != IMAGE_NT_SIGNATURE) return FALSE;
2018 if (nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return FALSE;
2019 va = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
2020 size = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
2021 if (!va || size < sizeof(*cor)) return FALSE;
2022 offset.QuadPart += offsetof( IMAGE_NT_HEADERS32, OptionalHeader ) + nt.FileHeader.SizeOfOptionalHeader;
2023 count = min( 96, nt.FileHeader.NumberOfSections );
2024 if (NtReadFile( file, 0, NULL, NULL, &io, &sec, count * sizeof(*sec), &offset, NULL )) return FALSE;
2025 if (io.Information != count * sizeof(*sec)) return FALSE;
2026 for (i = 0; i < count; i++)
2028 if (va < sec[i].VirtualAddress) continue;
2029 if (sec[i].Misc.VirtualSize && va - sec[i].VirtualAddress >= sec[i].Misc.VirtualSize) continue;
2030 offset.QuadPart = sec->PointerToRawData + va - sec[i].VirtualAddress;
2031 if (NtReadFile( file, 0, NULL, NULL, &io, cor, sizeof(*cor), &offset, NULL )) return FALSE;
2032 return (io.Information == sizeof(*cor));
2034 return FALSE;
2036 #endif
2038 /* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
2039 /* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2040 static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2042 #ifdef __i386__
2043 return info->Machine == IMAGE_FILE_MACHINE_I386;
2044 #elif defined(__arm__)
2045 return info->Machine == IMAGE_FILE_MACHINE_ARM ||
2046 info->Machine == IMAGE_FILE_MACHINE_THUMB ||
2047 info->Machine == IMAGE_FILE_MACHINE_ARMNT;
2048 #elif defined(_WIN64) /* support 32-bit IL-only images on 64-bit */
2049 #ifdef __x86_64__
2050 if (info->Machine == IMAGE_FILE_MACHINE_AMD64) return TRUE;
2051 #else
2052 if (info->Machine == IMAGE_FILE_MACHINE_ARM64) return TRUE;
2053 #endif
2054 if (!info->ImageContainsCode) return TRUE;
2055 if (!(info->u.s.ComPlusNativeReady))
2057 IMAGE_COR20_HEADER cor_header;
2058 if (!get_cor_header( file, info, &cor_header )) return FALSE;
2059 if (!(cor_header.Flags & COMIMAGE_FLAGS_ILONLY)) return FALSE;
2061 return TRUE;
2062 #else
2063 return FALSE; /* no wow64 support on other platforms */
2064 #endif
2068 /******************************************************************
2069 * get_module_path_end
2071 * Returns the end of the directory component of the module path.
2073 static inline const WCHAR *get_module_path_end( const WCHAR *module )
2075 const WCHAR *p;
2076 const WCHAR *mod_end = module;
2078 if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
2079 if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2080 if (mod_end == module + 2 && module[1] == ':') mod_end++;
2081 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
2082 return mod_end;
2086 /******************************************************************
2087 * append_path
2089 * Append a counted string to the load path. Helper for get_dll_load_path.
2091 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
2093 if (len == -1) len = wcslen(str);
2094 if (!len) return p;
2095 memcpy( p, str, len * sizeof(WCHAR) );
2096 p[len] = ';';
2097 return p + len + 1;
2101 /******************************************************************
2102 * get_dll_load_path
2104 static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2106 const WCHAR *mod_end = module;
2107 UNICODE_STRING name, value;
2108 WCHAR *p, *ret;
2109 int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2111 if (module)
2113 mod_end = get_module_path_end( module );
2114 len += (mod_end - module) + 1;
2117 RtlInitUnicodeString( &name, L"PATH" );
2118 value.Length = 0;
2119 value.MaximumLength = 0;
2120 value.Buffer = NULL;
2121 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2122 path_len = value.Length;
2124 if (dll_dir) len += wcslen( dll_dir ) + 1;
2125 else len += 2; /* current directory */
2126 if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2127 return STATUS_NO_MEMORY;
2129 p = append_path( p, module, mod_end - module );
2130 if (dll_dir) p = append_path( p, dll_dir, -1 );
2131 else if (!safe_mode) p = append_path( p, L".", -1 );
2132 p = append_path( p, system_path, -1 );
2133 if (!dll_dir && safe_mode) p = append_path( p, L".", -1 );
2135 value.Buffer = p;
2136 value.MaximumLength = path_len;
2138 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2140 WCHAR *new_ptr;
2142 /* grow the buffer and retry */
2143 path_len = value.Length;
2144 if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
2146 RtlFreeHeap( GetProcessHeap(), 0, ret );
2147 return STATUS_NO_MEMORY;
2149 value.Buffer = new_ptr + (value.Buffer - ret);
2150 value.MaximumLength = path_len;
2151 ret = new_ptr;
2153 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
2154 *path = ret;
2155 return STATUS_SUCCESS;
2159 /******************************************************************
2160 * get_dll_load_path_search_flags
2162 static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
2164 const WCHAR *image = NULL, *mod_end, *image_end;
2165 struct dll_dir_entry *dir;
2166 WCHAR *p, *ret;
2167 int len = 1;
2169 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
2170 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
2171 LOAD_LIBRARY_SEARCH_USER_DIRS |
2172 LOAD_LIBRARY_SEARCH_SYSTEM32);
2174 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
2176 DWORD type = RtlDetermineDosPathNameType_U( module );
2177 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2178 return STATUS_INVALID_PARAMETER;
2179 mod_end = get_module_path_end( module );
2180 len += (mod_end - module) + 1;
2182 else module = NULL;
2184 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
2186 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
2187 image_end = get_module_path_end( image );
2188 len += (image_end - image) + 1;
2191 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2193 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2194 len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2195 if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
2198 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2200 if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2202 if (module) p = append_path( p, module, mod_end - module );
2203 if (image) p = append_path( p, image, image_end - image );
2204 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2206 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2207 p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
2208 p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
2210 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2211 else
2213 if (p > ret) p--;
2214 *p = 0;
2217 *path = ret;
2218 return STATUS_SUCCESS;
2222 /***********************************************************************
2223 * open_dll_file
2225 * Open a file for a new dll. Helper for find_dll_file.
2227 static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2228 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2230 FILE_BASIC_INFORMATION info;
2231 OBJECT_ATTRIBUTES attr;
2232 IO_STATUS_BLOCK io;
2233 LARGE_INTEGER size;
2234 FILE_OBJECTID_BUFFER fid;
2235 NTSTATUS status;
2236 HANDLE handle;
2238 if ((*pwm = find_fullname_module( nt_name ))) return STATUS_SUCCESS;
2240 attr.Length = sizeof(attr);
2241 attr.RootDirectory = 0;
2242 attr.Attributes = OBJ_CASE_INSENSITIVE;
2243 attr.ObjectName = nt_name;
2244 attr.SecurityDescriptor = NULL;
2245 attr.SecurityQualityOfService = NULL;
2246 if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2247 FILE_SHARE_READ | FILE_SHARE_DELETE,
2248 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
2250 if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
2251 status != STATUS_OBJECT_NAME_NOT_FOUND &&
2252 !NtQueryAttributesFile( &attr, &info ))
2254 /* if the file exists but failed to open, report the error */
2255 return status;
2257 /* otherwise continue searching */
2258 return STATUS_DLL_NOT_FOUND;
2261 if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
2263 memcpy( id, fid.ObjectId, sizeof(*id) );
2264 if ((*pwm = find_fileid_module( id )))
2266 TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2267 (*pwm)->ldr.DllBase, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2268 NtClose( handle );
2269 return STATUS_SUCCESS;
2273 size.QuadPart = 0;
2274 status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2275 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
2276 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
2277 if (!status)
2279 NtQuerySection( *mapping, SectionImageInformation, image_info, sizeof(*image_info), NULL );
2280 if (!is_valid_binary( handle, image_info ))
2282 TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->Machine );
2283 status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2284 NtClose( *mapping );
2285 *mapping = NULL;
2288 NtClose( handle );
2289 return status;
2293 /******************************************************************************
2294 * find_existing_module
2296 * Find an existing module that is the same mapping as the new module.
2298 static WINE_MODREF *find_existing_module( HMODULE module )
2300 WINE_MODREF *wm;
2301 LIST_ENTRY *mark, *entry;
2302 LDR_DATA_TABLE_ENTRY *mod;
2303 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2305 if ((wm = get_modref( module ))) return wm;
2307 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
2308 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2310 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
2311 if (mod->TimeDateStamp != nt->FileHeader.TimeDateStamp) continue;
2312 if (mod->CheckSum != nt->OptionalHeader.CheckSum) continue;
2313 if (NtAreMappedFilesTheSame( mod->DllBase, module ) != STATUS_SUCCESS) continue;
2314 return CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2316 return NULL;
2320 /******************************************************************************
2321 * load_native_dll (internal)
2323 static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping,
2324 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2325 DWORD flags, WINE_MODREF** pwm )
2327 void *module = NULL;
2328 SIZE_T len = 0;
2329 NTSTATUS status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
2330 ViewShare, 0, PAGE_EXECUTE_READ );
2332 if (status == STATUS_IMAGE_NOT_AT_BASE) status = STATUS_SUCCESS;
2333 if (status) return status;
2335 if ((*pwm = find_existing_module( module ))) /* already loaded */
2337 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2338 TRACE( "found %s for %s at %p, count=%d\n",
2339 debugstr_us(&(*pwm)->ldr.FullDllName), debugstr_us(nt_name),
2340 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
2341 if (module != (*pwm)->ldr.DllBase) NtUnmapViewOfSection( NtCurrentProcess(), module );
2342 return STATUS_SUCCESS;
2344 #ifdef _WIN64
2345 if (!convert_to_pe64( module, image_info )) status = STATUS_INVALID_IMAGE_FORMAT;
2346 #endif
2347 if (!status) status = build_module( load_path, nt_name, &module, image_info, id, flags, pwm );
2348 if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2349 return status;
2353 /***********************************************************************
2354 * load_so_dll
2356 static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2357 DWORD flags, WINE_MODREF **pwm )
2359 void *module;
2360 NTSTATUS status;
2361 WINE_MODREF *wm;
2362 UNICODE_STRING win_name = *nt_name;
2364 TRACE( "trying %s as so lib\n", debugstr_us(&win_name) );
2365 if ((status = unix_funcs->load_so_dll( &win_name, &module )))
2367 WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
2368 if (status == STATUS_INVALID_IMAGE_FORMAT) status = STATUS_INVALID_IMAGE_NOT_MZ;
2369 return status;
2372 if ((wm = get_modref( module ))) /* already loaded */
2374 TRACE( "Found %s at %p for builtin %s\n",
2375 debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
2376 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2378 else
2380 SECTION_IMAGE_INFORMATION image_info = { 0 };
2382 if ((status = build_module( load_path, &win_name, &module, &image_info, NULL, flags, &wm )))
2384 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2385 return status;
2387 TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
2389 *pwm = wm;
2390 return STATUS_SUCCESS;
2394 /*************************************************************************
2395 * build_main_module
2397 * Build the module data for the main image.
2399 static WINE_MODREF *build_main_module(void)
2401 SECTION_IMAGE_INFORMATION info;
2402 UNICODE_STRING nt_name;
2403 WINE_MODREF *wm;
2404 NTSTATUS status;
2405 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
2406 void *module = NtCurrentTeb()->Peb->ImageBaseAddress;
2408 default_load_path = params->DllPath.Buffer;
2409 if (!default_load_path)
2410 get_dll_load_path( params->ImagePathName.Buffer, NULL, dll_safe_mode, &default_load_path );
2412 NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info), NULL );
2413 if (info.ImageCharacteristics & IMAGE_FILE_DLL)
2415 MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_us(&params->ImagePathName) );
2416 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
2418 #ifdef _WIN64
2419 if (!convert_to_pe64( module, &info ))
2421 status = STATUS_INVALID_IMAGE_FORMAT;
2422 goto failed;
2424 #endif
2425 status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
2426 if (status) goto failed;
2427 status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, &wm );
2428 RtlFreeUnicodeString( &nt_name );
2429 if (!status) return wm;
2430 failed:
2431 MESSAGE( "wine: failed to create main module for %s, status %x\n",
2432 debugstr_us(&params->ImagePathName), status );
2433 NtTerminateProcess( GetCurrentProcess(), status );
2434 return NULL; /* unreached */
2438 /***********************************************************************
2439 * find_actctx_dll
2441 * Find the full path (if any) of the dll from the activation context.
2443 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
2445 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
2447 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
2448 ACTCTX_SECTION_KEYED_DATA data;
2449 UNICODE_STRING nameW;
2450 NTSTATUS status;
2451 SIZE_T needed, size = 1024;
2452 WCHAR *p;
2454 RtlInitUnicodeString( &nameW, libname );
2455 data.cbSize = sizeof(data);
2456 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2457 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
2458 &nameW, &data );
2459 if (status != STATUS_SUCCESS) return status;
2461 for (;;)
2463 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2465 status = STATUS_NO_MEMORY;
2466 goto done;
2468 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
2469 AssemblyDetailedInformationInActivationContext,
2470 info, size, &needed );
2471 if (status == STATUS_SUCCESS) break;
2472 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
2473 RtlFreeHeap( GetProcessHeap(), 0, info );
2474 size = needed;
2475 /* restart with larger buffer */
2478 if (!info->lpAssemblyManifestPath)
2480 status = STATUS_SXS_KEY_NOT_FOUND;
2481 goto done;
2484 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2486 DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2487 p++;
2488 len = wcslen( p );
2489 if (!dirlen || len <= dirlen ||
2490 RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2491 wcsicmp( p + dirlen, L".manifest" ))
2493 /* manifest name does not match directory name, so it's not a global
2494 * windows/winsxs manifest; use the manifest directory name instead */
2495 dirlen = p - info->lpAssemblyManifestPath;
2496 needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
2497 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2499 status = STATUS_NO_MEMORY;
2500 goto done;
2502 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
2503 p += dirlen;
2504 wcscpy( p, libname );
2505 goto done;
2509 if (!info->lpAssemblyDirectoryName)
2511 status = STATUS_SXS_KEY_NOT_FOUND;
2512 goto done;
2515 needed = (wcslen(windows_dir) * sizeof(WCHAR) +
2516 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2518 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2520 status = STATUS_NO_MEMORY;
2521 goto done;
2523 wcscpy( p, windows_dir );
2524 p += wcslen(p);
2525 memcpy( p, winsxsW, sizeof(winsxsW) );
2526 p += ARRAY_SIZE( winsxsW );
2527 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
2528 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2529 *p++ = '\\';
2530 wcscpy( p, libname );
2531 done:
2532 RtlFreeHeap( GetProcessHeap(), 0, info );
2533 RtlReleaseActivationContext( data.hActCtx );
2534 return status;
2538 /***********************************************************************
2539 * get_env_var
2541 static NTSTATUS get_env_var( const WCHAR *name, SIZE_T extra, UNICODE_STRING *ret )
2543 NTSTATUS status;
2544 SIZE_T len, size = 1024 + extra;
2546 for (;;)
2548 ret->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, size );
2549 status = RtlQueryEnvironmentVariable( NULL, name, wcslen(name),
2550 ret->Buffer, size - extra - 1, &len );
2551 if (!status)
2553 ret->Buffer[len] = 0;
2554 ret->Length = len * sizeof(WCHAR);
2555 ret->MaximumLength = size * sizeof(WCHAR);
2556 return status;
2558 RtlFreeHeap( GetProcessHeap(), 0, ret->Buffer );
2559 if (status != STATUS_BUFFER_TOO_SMALL) return status;
2560 size = len + 1 + extra;
2565 /***********************************************************************
2566 * find_builtin_without_file
2568 * Find a builtin dll when the corresponding file cannot be found in the prefix.
2569 * This is used during prefix bootstrap.
2571 static NTSTATUS find_builtin_without_file( const WCHAR *name, UNICODE_STRING *new_name,
2572 WINE_MODREF **pwm, HANDLE *mapping,
2573 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2575 const WCHAR *ext;
2576 WCHAR dllpath[32];
2577 DWORD i, len;
2578 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2579 BOOL found_image = FALSE;
2581 if (!get_env_var( L"WINEBUILDDIR", 20 + 2 * wcslen(name), new_name ))
2583 RtlAppendUnicodeToString( new_name, L"\\dlls\\" );
2584 RtlAppendUnicodeToString( new_name, name );
2585 if ((ext = wcsrchr( name, '.' )) && !wcscmp( ext, L".dll" )) new_name->Length -= 4 * sizeof(WCHAR);
2586 RtlAppendUnicodeToString( new_name, L"\\" );
2587 RtlAppendUnicodeToString( new_name, name );
2588 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2589 if (status != STATUS_DLL_NOT_FOUND) goto done;
2590 RtlAppendUnicodeToString( new_name, L".fake" );
2591 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2592 if (status != STATUS_DLL_NOT_FOUND) goto done;
2593 RtlFreeUnicodeString( new_name );
2595 for (i = 0; ; i++)
2597 swprintf( dllpath, ARRAY_SIZE(dllpath), L"WINEDLLDIR%u", i );
2598 if (get_env_var( dllpath, 20 + wcslen(name), new_name )) break;
2599 len = new_name->Length;
2600 RtlAppendUnicodeToString( new_name, L"\\" );
2601 RtlAppendUnicodeToString( new_name, name );
2602 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2603 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2604 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2605 new_name->Length = len;
2606 RtlAppendUnicodeToString( new_name, L"\\fakedlls\\" );
2607 RtlAppendUnicodeToString( new_name, name );
2608 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2609 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2610 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2611 RtlFreeUnicodeString( new_name );
2613 if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2615 done:
2616 RtlFreeUnicodeString( new_name );
2617 if (!status)
2619 new_name->Length = (4 + wcslen(system_dir) + wcslen(name)) * sizeof(WCHAR);
2620 new_name->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, new_name->Length + sizeof(WCHAR) );
2621 wcscpy( new_name->Buffer, L"\\??\\" );
2622 wcscat( new_name->Buffer, system_dir );
2623 wcscat( new_name->Buffer, name );
2625 return status;
2629 /***********************************************************************
2630 * search_dll_file
2632 * Search for dll in the specified paths.
2634 static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
2635 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
2636 struct file_id *id )
2638 WCHAR *name;
2639 BOOL found_image = FALSE;
2640 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2641 ULONG len;
2643 if (!paths) paths = default_load_path;
2644 len = wcslen( paths );
2646 if (len < wcslen( system_dir )) len = wcslen( system_dir );
2647 len += wcslen( search ) + 2;
2649 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2650 return STATUS_NO_MEMORY;
2652 while (*paths)
2654 LPCWSTR ptr = paths;
2656 while (*ptr && *ptr != ';') ptr++;
2657 len = ptr - paths;
2658 if (*ptr == ';') ptr++;
2659 memcpy( name, paths, len * sizeof(WCHAR) );
2660 if (len && name[len - 1] != '\\') name[len++] = '\\';
2661 wcscpy( name + len, search );
2663 nt_name->Buffer = NULL;
2664 if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
2666 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
2667 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2668 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2669 RtlFreeUnicodeString( nt_name );
2670 paths = ptr;
2673 if (found_image)
2674 status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2675 else if (is_prefix_bootstrap && !wcspbrk( search, L":/\\" ))
2676 status = find_builtin_without_file( search, nt_name, pwm, mapping, image_info, id );
2678 done:
2679 RtlFreeHeap( GetProcessHeap(), 0, name );
2680 return status;
2684 /***********************************************************************
2685 * find_dll_file
2687 * Find the file (or already loaded module) for a given dll name.
2689 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
2690 UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2691 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2693 WCHAR *ext, *dllname;
2694 NTSTATUS status;
2695 ULONG wow64_old_value = 0;
2697 *pwm = NULL;
2698 dllname = NULL;
2700 if (default_ext) /* first append default extension */
2702 if (!(ext = wcsrchr( libname, '.')) || wcschr( ext, '/' ) || wcschr( ext, '\\'))
2704 if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
2705 (wcslen(libname)+wcslen(default_ext)+1) * sizeof(WCHAR))))
2706 return STATUS_NO_MEMORY;
2707 wcscpy( dllname, libname );
2708 wcscat( dllname, default_ext );
2709 libname = dllname;
2713 /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
2714 RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
2716 nt_name->Buffer = NULL;
2718 if (!contains_path( libname ))
2720 WCHAR *fullname = NULL;
2722 status = find_actctx_dll( libname, &fullname );
2723 if (status == STATUS_SUCCESS)
2725 TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
2726 RtlFreeHeap( GetProcessHeap(), 0, dllname );
2727 libname = dllname = fullname;
2729 else
2731 if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
2732 if ((*pwm = find_basename_module( libname )) != NULL)
2734 status = STATUS_SUCCESS;
2735 goto done;
2740 if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
2741 status = search_dll_file( load_path, libname, nt_name, pwm, mapping, image_info, id );
2742 else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
2743 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
2745 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT;
2747 done:
2748 RtlFreeHeap( GetProcessHeap(), 0, dllname );
2749 if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
2750 return status;
2754 /***********************************************************************
2755 * load_dll (internal)
2757 * Load a PE style module according to the load order.
2758 * The loader_section must be locked while calling this function.
2760 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
2761 DWORD flags, WINE_MODREF** pwm )
2763 UNICODE_STRING nt_name;
2764 struct file_id id;
2765 HANDLE mapping = 0;
2766 SECTION_IMAGE_INFORMATION image_info;
2767 NTSTATUS nts;
2768 void *prev;
2770 TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
2772 nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
2774 if (*pwm) /* found already loaded module */
2776 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2778 TRACE("Found %s for %s at %p, count=%d\n",
2779 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
2780 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
2781 RtlFreeUnicodeString( &nt_name );
2782 return STATUS_SUCCESS;
2785 if (nts && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
2787 prev = NtCurrentTeb()->Tib.ArbitraryUserPointer;
2788 NtCurrentTeb()->Tib.ArbitraryUserPointer = nt_name.Buffer + 4;
2790 switch (nts)
2792 case STATUS_INVALID_IMAGE_NOT_MZ: /* not in PE format, maybe it's a .so file */
2793 nts = load_so_dll( load_path, &nt_name, flags, pwm );
2794 break;
2796 case STATUS_SUCCESS: /* valid PE file */
2797 nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, pwm );
2798 break;
2800 NtCurrentTeb()->Tib.ArbitraryUserPointer = prev;
2802 done:
2803 if (nts == STATUS_SUCCESS)
2804 TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.DllBase);
2805 else
2806 WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
2808 if (mapping) NtClose( mapping );
2809 RtlFreeUnicodeString( &nt_name );
2810 return nts;
2814 /***********************************************************************
2815 * __wine_init_unix_lib
2817 NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
2819 WINE_MODREF *wm;
2820 NTSTATUS ret;
2822 RtlEnterCriticalSection( &loader_section );
2824 if ((wm = get_modref( module ))) ret = unix_funcs->init_unix_lib( module, reason, ptr_in, ptr_out );
2825 else ret = STATUS_INVALID_HANDLE;
2827 RtlLeaveCriticalSection( &loader_section );
2828 return ret;
2832 /******************************************************************
2833 * LdrLoadDll (NTDLL.@)
2835 NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
2836 const UNICODE_STRING *libname, HMODULE* hModule)
2838 WINE_MODREF *wm;
2839 NTSTATUS nts;
2841 RtlEnterCriticalSection( &loader_section );
2843 nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm );
2845 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
2847 nts = process_attach( wm, NULL );
2848 if (nts != STATUS_SUCCESS)
2850 LdrUnloadDll(wm->ldr.DllBase);
2851 wm = NULL;
2854 *hModule = (wm) ? wm->ldr.DllBase : NULL;
2856 RtlLeaveCriticalSection( &loader_section );
2857 return nts;
2861 /******************************************************************
2862 * LdrGetDllHandle (NTDLL.@)
2864 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
2866 NTSTATUS status;
2867 UNICODE_STRING nt_name;
2868 WINE_MODREF *wm;
2869 HANDLE mapping;
2870 SECTION_IMAGE_INFORMATION image_info;
2871 struct file_id id;
2873 RtlEnterCriticalSection( &loader_section );
2875 status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id );
2877 if (wm) *base = wm->ldr.DllBase;
2878 else
2880 if (status == STATUS_SUCCESS) NtClose( mapping );
2881 status = STATUS_DLL_NOT_FOUND;
2883 RtlFreeUnicodeString( &nt_name );
2885 RtlLeaveCriticalSection( &loader_section );
2886 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
2887 return status;
2891 /******************************************************************
2892 * LdrAddRefDll (NTDLL.@)
2894 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
2896 NTSTATUS ret = STATUS_SUCCESS;
2897 WINE_MODREF *wm;
2899 if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %x not implemented\n", module, flags );
2901 RtlEnterCriticalSection( &loader_section );
2903 if ((wm = get_modref( module )))
2905 if (flags & LDR_ADDREF_DLL_PIN)
2906 wm->ldr.LoadCount = -1;
2907 else
2908 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2909 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
2911 else ret = STATUS_INVALID_PARAMETER;
2913 RtlLeaveCriticalSection( &loader_section );
2914 return ret;
2918 /***********************************************************************
2919 * LdrProcessRelocationBlock (NTDLL.@)
2921 * Apply relocations to a given page of a mapped PE image.
2923 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
2924 USHORT *relocs, INT_PTR delta )
2926 while (count--)
2928 USHORT offset = *relocs & 0xfff;
2929 int type = *relocs >> 12;
2930 switch(type)
2932 case IMAGE_REL_BASED_ABSOLUTE:
2933 break;
2934 case IMAGE_REL_BASED_HIGH:
2935 *(short *)((char *)page + offset) += HIWORD(delta);
2936 break;
2937 case IMAGE_REL_BASED_LOW:
2938 *(short *)((char *)page + offset) += LOWORD(delta);
2939 break;
2940 case IMAGE_REL_BASED_HIGHLOW:
2941 *(int *)((char *)page + offset) += delta;
2942 break;
2943 #ifdef _WIN64
2944 case IMAGE_REL_BASED_DIR64:
2945 *(INT_PTR *)((char *)page + offset) += delta;
2946 break;
2947 #elif defined(__arm__)
2948 case IMAGE_REL_BASED_THUMB_MOV32:
2950 DWORD *inst = (DWORD *)((char *)page + offset);
2951 WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
2952 ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
2953 WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
2954 ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
2955 DWORD imm = MAKELONG( lo, hi ) + delta;
2957 lo = LOWORD( imm );
2958 hi = HIWORD( imm );
2960 if ((inst[0] & 0x8000fbf0) != 0x0000f240 || (inst[1] & 0x8000fbf0) != 0x0000f2c0)
2961 ERR("wrong Thumb2 instruction @%p %08x:%08x, expected MOVW/MOVT\n",
2962 inst, inst[0], inst[1] );
2964 inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
2965 ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
2966 inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
2967 ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
2968 break;
2970 #endif
2971 default:
2972 FIXME("Unknown/unsupported fixup type %x.\n", type);
2973 return NULL;
2975 relocs++;
2977 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
2981 /******************************************************************
2982 * LdrQueryProcessModuleInformation
2985 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi,
2986 ULONG buf_size, ULONG* req_size)
2988 SYSTEM_MODULE* sm = &smi->Modules[0];
2989 ULONG size = sizeof(ULONG);
2990 NTSTATUS nts = STATUS_SUCCESS;
2991 ANSI_STRING str;
2992 char* ptr;
2993 PLIST_ENTRY mark, entry;
2994 LDR_DATA_TABLE_ENTRY *mod;
2995 WORD id = 0;
2997 smi->ModulesCount = 0;
2999 RtlEnterCriticalSection( &loader_section );
3000 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3001 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3003 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3004 size += sizeof(*sm);
3005 if (size <= buf_size)
3007 sm->Section = 0; /* FIXME */
3008 sm->MappedBaseAddress = mod->DllBase;
3009 sm->ImageBaseAddress = mod->DllBase;
3010 sm->ImageSize = mod->SizeOfImage;
3011 sm->Flags = mod->Flags;
3012 sm->LoadOrderIndex = id++;
3013 sm->InitOrderIndex = 0; /* FIXME */
3014 sm->LoadCount = mod->LoadCount;
3015 str.Length = 0;
3016 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
3017 str.Buffer = (char*)sm->Name;
3018 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
3019 ptr = strrchr(str.Buffer, '\\');
3020 sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3022 smi->ModulesCount++;
3023 sm++;
3025 else nts = STATUS_INFO_LENGTH_MISMATCH;
3027 RtlLeaveCriticalSection( &loader_section );
3029 if (req_size) *req_size = size;
3031 return nts;
3035 static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, ULONG *value )
3037 NTSTATUS status;
3038 UNICODE_STRING str;
3039 ULONG size;
3040 WCHAR buffer[64];
3041 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3043 RtlInitUnicodeString( &str, name );
3045 size = sizeof(buffer) - sizeof(WCHAR);
3046 if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
3047 return status;
3049 if (info->Type != REG_DWORD)
3051 buffer[size / sizeof(WCHAR)] = 0;
3052 *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3054 else memcpy( value, info->Data, sizeof(*value) );
3055 return status;
3058 static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
3059 void *data, ULONG in_size, ULONG *out_size )
3061 NTSTATUS status;
3062 UNICODE_STRING str;
3063 ULONG size;
3064 char *buffer;
3065 KEY_VALUE_PARTIAL_INFORMATION *info;
3066 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
3068 RtlInitUnicodeString( &str, name );
3070 size = info_size + in_size;
3071 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
3072 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3073 status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
3074 if (!status || status == STATUS_BUFFER_OVERFLOW)
3076 if (out_size) *out_size = info->DataLength;
3077 if (data && !status) memcpy( data, info->Data, info->DataLength );
3079 RtlFreeHeap( GetProcessHeap(), 0, buffer );
3080 return status;
3084 /******************************************************************
3085 * LdrQueryImageFileExecutionOptions (NTDLL.@)
3087 NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
3088 void *data, ULONG in_size, ULONG *out_size )
3090 static const WCHAR optionsW[] = {'M','a','c','h','i','n','e','\\',
3091 'S','o','f','t','w','a','r','e','\\',
3092 'M','i','c','r','o','s','o','f','t','\\',
3093 'W','i','n','d','o','w','s',' ','N','T','\\',
3094 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3095 'I','m','a','g','e',' ','F','i','l','e',' ',
3096 'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
3097 WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3098 OBJECT_ATTRIBUTES attr;
3099 UNICODE_STRING name_str;
3100 HANDLE hkey;
3101 NTSTATUS status;
3102 ULONG len;
3103 WCHAR *p;
3105 attr.Length = sizeof(attr);
3106 attr.RootDirectory = 0;
3107 attr.ObjectName = &name_str;
3108 attr.Attributes = OBJ_CASE_INSENSITIVE;
3109 attr.SecurityDescriptor = NULL;
3110 attr.SecurityQualityOfService = NULL;
3112 p = key->Buffer + key->Length / sizeof(WCHAR);
3113 while (p > key->Buffer && p[-1] != '\\') p--;
3114 len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
3115 name_str.Buffer = path;
3116 name_str.Length = sizeof(optionsW) + len;
3117 name_str.MaximumLength = name_str.Length;
3118 memcpy( path, optionsW, sizeof(optionsW) );
3119 memcpy( path + ARRAY_SIZE( optionsW ), p, len );
3120 if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
3122 if (type == REG_DWORD)
3124 if (out_size) *out_size = sizeof(ULONG);
3125 if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
3126 else status = STATUS_BUFFER_OVERFLOW;
3128 else status = query_string_option( hkey, value, type, data, in_size, out_size );
3130 NtClose( hkey );
3131 return status;
3135 /******************************************************************
3136 * RtlDllShutdownInProgress (NTDLL.@)
3138 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
3140 return process_detaching;
3143 /****************************************************************************
3144 * LdrResolveDelayLoadedAPI (NTDLL.@)
3146 void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3147 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
3148 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3149 IMAGE_THUNK_DATA* addr, ULONG flags )
3151 IMAGE_THUNK_DATA *pIAT, *pINT;
3152 DELAYLOAD_INFO delayinfo;
3153 UNICODE_STRING mod;
3154 const CHAR* name;
3155 HMODULE *phmod;
3156 NTSTATUS nts;
3157 FARPROC fp;
3158 DWORD id;
3160 TRACE( "(%p, %p, %p, %p, %p, 0x%08x)\n", base, desc, dllhook, syshook, addr, flags );
3162 phmod = get_rva(base, desc->ModuleHandleRVA);
3163 pIAT = get_rva(base, desc->ImportAddressTableRVA);
3164 pINT = get_rva(base, desc->ImportNameTableRVA);
3165 name = get_rva(base, desc->DllNameRVA);
3166 id = addr - pIAT;
3168 if (!*phmod)
3170 if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
3172 nts = STATUS_NO_MEMORY;
3173 goto fail;
3175 nts = LdrLoadDll(NULL, 0, &mod, phmod);
3176 RtlFreeUnicodeString(&mod);
3177 if (nts) goto fail;
3180 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3181 nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
3182 else
3184 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3185 ANSI_STRING fnc;
3187 RtlInitAnsiString(&fnc, (char*)iibn->Name);
3188 nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
3190 if (!nts)
3192 pIAT[id].u1.Function = (ULONG_PTR)fp;
3193 return fp;
3196 fail:
3197 delayinfo.Size = sizeof(delayinfo);
3198 delayinfo.DelayloadDescriptor = desc;
3199 delayinfo.ThunkAddress = addr;
3200 delayinfo.TargetDllName = name;
3201 delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
3202 delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
3203 delayinfo.TargetModuleBase = *phmod;
3204 delayinfo.Unused = NULL;
3205 delayinfo.LastError = nts;
3207 if (dllhook)
3208 return dllhook(4, &delayinfo);
3210 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3212 DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
3213 return syshook(name, (const char *)ord);
3215 else
3217 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3218 return syshook(name, (const char *)iibn->Name);
3222 /******************************************************************
3223 * LdrShutdownProcess (NTDLL.@)
3226 void WINAPI LdrShutdownProcess(void)
3228 BOOL detaching = process_detaching;
3230 TRACE("()\n");
3232 process_detaching = TRUE;
3233 if (!detaching)
3234 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3236 process_detach();
3240 /******************************************************************
3241 * RtlExitUserProcess (NTDLL.@)
3243 void WINAPI RtlExitUserProcess( DWORD status )
3245 RtlEnterCriticalSection( &loader_section );
3246 RtlAcquirePebLock();
3247 NtTerminateProcess( 0, status );
3248 LdrShutdownProcess();
3249 for (;;) NtTerminateProcess( GetCurrentProcess(), status );
3252 /******************************************************************
3253 * LdrShutdownThread (NTDLL.@)
3256 void WINAPI LdrShutdownThread(void)
3258 PLIST_ENTRY mark, entry;
3259 LDR_DATA_TABLE_ENTRY *mod;
3260 WINE_MODREF *wm;
3261 UINT i;
3262 void **pointers;
3264 TRACE("()\n");
3266 /* don't do any detach calls if process is exiting */
3267 if (process_detaching) return;
3269 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3271 RtlEnterCriticalSection( &loader_section );
3272 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3274 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3275 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3277 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
3278 InInitializationOrderLinks);
3279 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3280 continue;
3281 if ( mod->Flags & LDR_NO_DLL_CALLS )
3282 continue;
3284 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
3285 DLL_THREAD_DETACH, NULL );
3288 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
3290 RtlAcquirePebLock();
3291 RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3292 if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
3294 for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
3295 RtlFreeHeap( GetProcessHeap(), 0, pointers );
3297 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
3298 NtCurrentTeb()->FlsSlots = NULL;
3299 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3300 NtCurrentTeb()->TlsExpansionSlots = NULL;
3301 RtlReleasePebLock();
3303 RtlLeaveCriticalSection( &loader_section );
3304 /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */
3305 if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] );
3306 RtlFreeThreadActivationContextStack();
3310 /***********************************************************************
3311 * free_modref
3314 static void free_modref( WINE_MODREF *wm )
3316 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
3317 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
3318 if (wm->ldr.InInitializationOrderLinks.Flink)
3319 RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
3321 TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
3322 if (!TRACE_ON(module))
3323 TRACE_(loaddll)("Unloaded module %s : %s\n",
3324 debugstr_w(wm->ldr.FullDllName.Buffer),
3325 (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
3327 free_tls_slot( &wm->ldr );
3328 RtlReleaseActivationContext( wm->ldr.ActivationContext );
3329 NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
3330 if (cached_modref == wm) cached_modref = NULL;
3331 RtlFreeUnicodeString( &wm->ldr.FullDllName );
3332 RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
3333 RtlFreeHeap( GetProcessHeap(), 0, wm );
3336 /***********************************************************************
3337 * MODULE_FlushModrefs
3339 * Remove all unused modrefs and call the internal unloading routines
3340 * for the library type.
3342 * The loader_section must be locked while calling this function.
3344 static void MODULE_FlushModrefs(void)
3346 PLIST_ENTRY mark, entry, prev;
3347 LDR_DATA_TABLE_ENTRY *mod;
3348 WINE_MODREF*wm;
3350 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3351 for (entry = mark->Blink; entry != mark; entry = prev)
3353 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
3354 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3355 prev = entry->Blink;
3356 if (!mod->LoadCount) free_modref( wm );
3359 /* check load order list too for modules that haven't been initialized yet */
3360 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3361 for (entry = mark->Blink; entry != mark; entry = prev)
3363 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3364 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3365 prev = entry->Blink;
3366 if (!mod->LoadCount) free_modref( wm );
3370 /***********************************************************************
3371 * MODULE_DecRefCount
3373 * The loader_section must be locked while calling this function.
3375 static void MODULE_DecRefCount( WINE_MODREF *wm )
3377 int i;
3379 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3380 return;
3382 if ( wm->ldr.LoadCount <= 0 )
3383 return;
3385 --wm->ldr.LoadCount;
3386 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3388 if ( wm->ldr.LoadCount == 0 )
3390 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
3392 for ( i = 0; i < wm->nDeps; i++ )
3393 if ( wm->deps[i] )
3394 MODULE_DecRefCount( wm->deps[i] );
3396 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
3398 module_push_unload_trace( &wm->ldr );
3402 /******************************************************************
3403 * LdrUnloadDll (NTDLL.@)
3407 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
3409 WINE_MODREF *wm;
3410 NTSTATUS retv = STATUS_SUCCESS;
3412 if (process_detaching) return retv;
3414 TRACE("(%p)\n", hModule);
3416 RtlEnterCriticalSection( &loader_section );
3418 free_lib_count++;
3419 if ((wm = get_modref( hModule )) != NULL)
3421 TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
3423 /* Recursively decrement reference counts */
3424 MODULE_DecRefCount( wm );
3426 /* Call process detach notifications */
3427 if ( free_lib_count <= 1 )
3429 process_detach();
3430 MODULE_FlushModrefs();
3433 TRACE("END\n");
3435 else
3436 retv = STATUS_DLL_NOT_FOUND;
3438 free_lib_count--;
3440 RtlLeaveCriticalSection( &loader_section );
3442 return retv;
3445 /***********************************************************************
3446 * RtlImageNtHeader (NTDLL.@)
3448 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
3450 IMAGE_NT_HEADERS *ret;
3452 __TRY
3454 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
3456 ret = NULL;
3457 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
3459 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
3460 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
3463 __EXCEPT_PAGE_FAULT
3465 return NULL;
3467 __ENDTRY
3468 return ret;
3471 /***********************************************************************
3472 * process_breakpoint
3474 * Trigger a debug breakpoint if the process is being debugged.
3476 static void process_breakpoint(void)
3478 DWORD_PTR port = 0;
3480 NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort, &port, sizeof(port), NULL );
3481 if (!port) return;
3483 __TRY
3485 DbgBreakPoint();
3487 __EXCEPT_ALL
3489 /* do nothing */
3491 __ENDTRY
3495 /***********************************************************************
3496 * load_global_options
3498 static void load_global_options(void)
3500 OBJECT_ATTRIBUTES attr;
3501 UNICODE_STRING name_str;
3502 HANDLE hkey;
3503 ULONG value;
3505 attr.Length = sizeof(attr);
3506 attr.RootDirectory = 0;
3507 attr.ObjectName = &name_str;
3508 attr.Attributes = OBJ_CASE_INSENSITIVE;
3509 attr.SecurityDescriptor = NULL;
3510 attr.SecurityQualityOfService = NULL;
3511 RtlInitUnicodeString( &name_str, L"Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
3513 if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
3515 query_dword_option( hkey, L"GlobalFlag", &NtCurrentTeb()->Peb->NtGlobalFlag );
3516 query_dword_option( hkey, L"SafeProcessSearchMode", &path_safe_mode );
3517 query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode );
3519 if (!query_dword_option( hkey, L"CriticalSectionTimeout", &value ))
3520 NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart = (ULONGLONG)value * -10000000;
3522 if (!query_dword_option( hkey, L"HeapSegmentReserve", &value ))
3523 NtCurrentTeb()->Peb->HeapSegmentReserve = value;
3525 if (!query_dword_option( hkey, L"HeapSegmentCommit", &value ))
3526 NtCurrentTeb()->Peb->HeapSegmentCommit = value;
3528 if (!query_dword_option( hkey, L"HeapDeCommitTotalFreeThreshold", &value ))
3529 NtCurrentTeb()->Peb->HeapDeCommitTotalFreeThreshold = value;
3531 if (!query_dword_option( hkey, L"HeapDeCommitFreeBlockThreshold", &value ))
3532 NtCurrentTeb()->Peb->HeapDeCommitFreeBlockThreshold = value;
3534 NtClose( hkey );
3536 LdrQueryImageFileExecutionOptions( &NtCurrentTeb()->Peb->ProcessParameters->ImagePathName,
3537 L"GlobalFlag", REG_DWORD, &NtCurrentTeb()->Peb->NtGlobalFlag,
3538 sizeof(DWORD), NULL );
3539 heap_set_debug_flags( GetProcessHeap() );
3543 #ifndef _WIN64
3544 void *Wow64Transition = NULL;
3546 static void map_wow64cpu(void)
3548 SIZE_T size = 0;
3549 OBJECT_ATTRIBUTES attr;
3550 UNICODE_STRING string;
3551 HANDLE file, section;
3552 IO_STATUS_BLOCK io;
3553 NTSTATUS status;
3555 RtlInitUnicodeString( &string, L"\\??\\C:\\windows\\sysnative\\wow64cpu.dll" );
3556 InitializeObjectAttributes( &attr, &string, 0, NULL, NULL );
3557 if ((status = NtOpenFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ,
3558 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
3560 WARN("failed to open wow64cpu, status %#x\n", status);
3561 return;
3563 if (!NtCreateSection( &section, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
3564 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
3565 NULL, NULL, PAGE_EXECUTE_READ, SEC_COMMIT, file ))
3567 NtMapViewOfSection( section, NtCurrentProcess(), &Wow64Transition, 0,
3568 0, NULL, &size, ViewShare, 0, PAGE_EXECUTE_READ );
3569 NtClose( section );
3571 NtClose( file );
3574 static void init_wow64(void)
3576 PEB *peb = NtCurrentTeb()->Peb;
3577 PEB64 *peb64;
3579 if (!NtCurrentTeb64()) return;
3580 peb64 = UlongToPtr( NtCurrentTeb64()->Peb );
3581 peb64->ImageBaseAddress = PtrToUlong( peb->ImageBaseAddress );
3582 peb64->OSMajorVersion = peb->OSMajorVersion;
3583 peb64->OSMinorVersion = peb->OSMinorVersion;
3584 peb64->OSBuildNumber = peb->OSBuildNumber;
3585 peb64->OSPlatformId = peb->OSPlatformId;
3586 peb64->SessionId = peb->SessionId;
3588 map_wow64cpu();
3590 #endif
3593 /******************************************************************
3594 * LdrInitializeThunk (NTDLL.@)
3596 * Attach to all the loaded dlls.
3597 * If this is the first time, perform the full process initialization.
3599 void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR unknown3, ULONG_PTR unknown4 )
3601 static int attach_done;
3602 int i;
3603 NTSTATUS status;
3604 ULONG_PTR cookie;
3605 WINE_MODREF *wm;
3606 void **entry;
3608 #ifdef __i386__
3609 entry = (void **)&context->Eax;
3610 #elif defined(__x86_64__)
3611 entry = (void **)&context->Rcx;
3612 #elif defined(__arm__)
3613 entry = (void **)&context->R0;
3614 #elif defined(__aarch64__)
3615 entry = (void **)&context->u.s.X0;
3616 #endif
3618 if (process_detaching) NtTerminateThread( GetCurrentThread(), 0 );
3620 RtlEnterCriticalSection( &loader_section );
3622 if (!imports_fixup_done)
3624 ANSI_STRING func_name;
3625 WINE_MODREF *kernel32;
3626 PEB *peb = NtCurrentTeb()->Peb;
3628 peb->LdrData = &ldr;
3629 peb->FastPebLock = &peb_lock;
3630 peb->TlsBitmap = &tls_bitmap;
3631 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
3632 peb->LoaderLock = &loader_section;
3633 peb->OSMajorVersion = 5;
3634 peb->OSMinorVersion = 1;
3635 peb->OSBuildNumber = 0xA28;
3636 peb->OSPlatformId = VER_PLATFORM_WIN32_NT;
3637 peb->SessionId = 1;
3638 peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );
3640 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
3641 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
3642 sizeof(peb->TlsExpansionBitmapBits) * 8 );
3643 RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
3645 init_user_process_params();
3646 load_global_options();
3647 version_init();
3648 #ifndef _WIN64
3649 init_wow64();
3650 #endif
3651 wm = build_main_module();
3652 wm->ldr.LoadCount = -1;
3654 build_ntdll_module();
3656 if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32 )) != STATUS_SUCCESS)
3658 MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
3659 NtTerminateProcess( GetCurrentProcess(), status );
3661 kernel32_handle = kernel32->ldr.DllBase;
3662 RtlInitAnsiString( &func_name, "BaseThreadInitThunk" );
3663 if ((status = LdrGetProcedureAddress( kernel32_handle, &func_name,
3664 0, (void **)&pBaseThreadInitThunk )) != STATUS_SUCCESS)
3666 MESSAGE( "wine: could not find BaseThreadInitThunk in kernel32.dll, status %x\n", status );
3667 NtTerminateProcess( GetCurrentProcess(), status );
3670 actctx_init();
3671 if (wm->ldr.Flags & LDR_COR_ILONLY)
3672 status = fixup_imports_ilonly( wm, NULL, entry );
3673 else
3674 status = fixup_imports( wm, NULL );
3676 if (status)
3678 ERR( "Importing dlls for %s failed, status %x\n",
3679 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3680 NtTerminateProcess( GetCurrentProcess(), status );
3682 imports_fixup_done = TRUE;
3684 else wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3686 RtlAcquirePebLock();
3687 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
3688 RtlReleasePebLock();
3690 NtCurrentTeb()->FlsSlots = fls_alloc_data();
3692 if (!attach_done) /* first time around */
3694 attach_done = 1;
3695 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
3697 ERR( "TLS init failed when loading %s, status %x\n",
3698 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3699 NtTerminateProcess( GetCurrentProcess(), status );
3701 wm->ldr.Flags |= LDR_PROCESS_ATTACHED; /* don't try to attach again */
3702 if (wm->ldr.ActivationContext)
3703 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
3705 for (i = 0; i < wm->nDeps; i++)
3707 if (!wm->deps[i]) continue;
3708 if ((status = process_attach( wm->deps[i], context )) != STATUS_SUCCESS)
3710 if (last_failed_modref)
3711 ERR( "%s failed to initialize, aborting\n",
3712 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
3713 ERR( "Initializing dlls for %s failed, status %x\n",
3714 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3715 NtTerminateProcess( GetCurrentProcess(), status );
3718 unix_funcs->virtual_release_address_space();
3719 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
3720 if (wm->ldr.Flags & LDR_WINE_INTERNAL) unix_funcs->init_builtin_dll( wm->ldr.DllBase );
3721 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
3722 process_breakpoint();
3724 else
3726 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
3727 NtTerminateThread( GetCurrentThread(), status );
3728 thread_attach();
3729 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
3732 RtlLeaveCriticalSection( &loader_section );
3733 signal_start_thread( context );
3737 /***********************************************************************
3738 * RtlImageDirectoryEntryToData (NTDLL.@)
3740 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
3742 const IMAGE_NT_HEADERS *nt;
3743 DWORD addr;
3745 if ((ULONG_PTR)module & 1) image = FALSE; /* mapped as data file */
3746 module = (HMODULE)((ULONG_PTR)module & ~3);
3747 if (!(nt = RtlImageNtHeader( module ))) return NULL;
3748 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
3750 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
3752 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
3753 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
3754 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
3755 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
3757 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
3759 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
3761 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
3762 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
3763 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
3764 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
3766 else return NULL;
3768 /* not mapped as image, need to find the section containing the virtual address */
3769 return RtlImageRvaToVa( nt, module, addr, NULL );
3773 /***********************************************************************
3774 * RtlImageRvaToSection (NTDLL.@)
3776 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
3777 HMODULE module, DWORD rva )
3779 int i;
3780 const IMAGE_SECTION_HEADER *sec;
3782 sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
3783 nt->FileHeader.SizeOfOptionalHeader);
3784 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
3786 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
3787 return (PIMAGE_SECTION_HEADER)sec;
3789 return NULL;
3793 /***********************************************************************
3794 * RtlImageRvaToVa (NTDLL.@)
3796 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
3797 DWORD rva, IMAGE_SECTION_HEADER **section )
3799 IMAGE_SECTION_HEADER *sec;
3801 if (section && *section) /* try this section first */
3803 sec = *section;
3804 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
3805 goto found;
3807 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
3808 found:
3809 if (section) *section = sec;
3810 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
3814 /***********************************************************************
3815 * RtlPcToFileHeader (NTDLL.@)
3817 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
3819 LDR_DATA_TABLE_ENTRY *module;
3820 PVOID ret = NULL;
3822 RtlEnterCriticalSection( &loader_section );
3823 if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase;
3824 RtlLeaveCriticalSection( &loader_section );
3825 *address = ret;
3826 return ret;
3830 /****************************************************************************
3831 * LdrGetDllDirectory (NTDLL.@)
3833 NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
3835 NTSTATUS status = STATUS_SUCCESS;
3837 RtlEnterCriticalSection( &dlldir_section );
3838 dir->Length = dll_directory.Length + sizeof(WCHAR);
3839 if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
3840 else
3842 status = STATUS_BUFFER_TOO_SMALL;
3843 if (dir->MaximumLength) dir->Buffer[0] = 0;
3845 RtlLeaveCriticalSection( &dlldir_section );
3846 return status;
3850 /****************************************************************************
3851 * LdrSetDllDirectory (NTDLL.@)
3853 NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
3855 NTSTATUS status = STATUS_SUCCESS;
3856 UNICODE_STRING new;
3858 if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
3859 else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;
3861 RtlEnterCriticalSection( &dlldir_section );
3862 RtlFreeUnicodeString( &dll_directory );
3863 dll_directory = new;
3864 RtlLeaveCriticalSection( &dlldir_section );
3865 return status;
3869 /****************************************************************************
3870 * LdrAddDllDirectory (NTDLL.@)
3872 NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
3874 FILE_BASIC_INFORMATION info;
3875 UNICODE_STRING nt_name;
3876 NTSTATUS status;
3877 OBJECT_ATTRIBUTES attr;
3878 DWORD len;
3879 struct dll_dir_entry *ptr;
3880 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
3882 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
3883 return STATUS_INVALID_PARAMETER;
3885 status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
3886 if (status) return status;
3887 len = nt_name.Length / sizeof(WCHAR);
3888 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
3889 return STATUS_NO_MEMORY;
3890 memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );
3892 attr.Length = sizeof(attr);
3893 attr.RootDirectory = 0;
3894 attr.Attributes = OBJ_CASE_INSENSITIVE;
3895 attr.ObjectName = &nt_name;
3896 attr.SecurityDescriptor = NULL;
3897 attr.SecurityQualityOfService = NULL;
3898 status = NtQueryAttributesFile( &attr, &info );
3899 RtlFreeUnicodeString( &nt_name );
3901 if (!status)
3903 TRACE( "%s\n", debugstr_w( ptr->dir ));
3904 RtlEnterCriticalSection( &dlldir_section );
3905 list_add_head( &dll_dir_list, &ptr->entry );
3906 RtlLeaveCriticalSection( &dlldir_section );
3907 *cookie = ptr;
3909 else RtlFreeHeap( GetProcessHeap(), 0, ptr );
3910 return status;
3914 /****************************************************************************
3915 * LdrRemoveDllDirectory (NTDLL.@)
3917 NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
3919 struct dll_dir_entry *ptr = cookie;
3921 TRACE( "%s\n", debugstr_w( ptr->dir ));
3923 RtlEnterCriticalSection( &dlldir_section );
3924 list_remove( &ptr->entry );
3925 RtlFreeHeap( GetProcessHeap(), 0, ptr );
3926 RtlLeaveCriticalSection( &dlldir_section );
3927 return STATUS_SUCCESS;
3931 /*************************************************************************
3932 * LdrSetDefaultDllDirectories (NTDLL.@)
3934 NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
3936 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
3937 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
3938 LOAD_LIBRARY_SEARCH_USER_DIRS |
3939 LOAD_LIBRARY_SEARCH_SYSTEM32 |
3940 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
3942 if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
3943 default_search_flags = flags;
3944 return STATUS_SUCCESS;
3948 /******************************************************************
3949 * LdrGetDllPath (NTDLL.@)
3951 NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
3953 NTSTATUS status;
3954 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
3955 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
3956 LOAD_LIBRARY_SEARCH_USER_DIRS |
3957 LOAD_LIBRARY_SEARCH_SYSTEM32 |
3958 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
3960 if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
3962 if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
3963 if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
3965 else if (!(flags & load_library_search_flags)) flags |= default_search_flags;
3967 RtlEnterCriticalSection( &dlldir_section );
3969 if (flags & load_library_search_flags)
3971 status = get_dll_load_path_search_flags( module, flags, path );
3973 else
3975 const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
3976 if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH))
3977 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
3978 status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
3981 RtlLeaveCriticalSection( &dlldir_section );
3982 *unknown = NULL;
3983 return status;
3987 /*************************************************************************
3988 * RtlSetSearchPathMode (NTDLL.@)
3990 NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
3992 int val;
3994 switch (flags)
3996 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
3997 val = 1;
3998 break;
3999 case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
4000 val = 0;
4001 break;
4002 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4003 InterlockedExchange( (int *)&path_safe_mode, 2 );
4004 return STATUS_SUCCESS;
4005 default:
4006 return STATUS_INVALID_PARAMETER;
4009 for (;;)
4011 int prev = path_safe_mode;
4012 if (prev == 2) break; /* permanently set */
4013 if (InterlockedCompareExchange( (int *)&path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4015 return STATUS_ACCESS_DENIED;
4019 /******************************************************************
4020 * RtlGetExePath (NTDLL.@)
4022 NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
4024 const WCHAR *dlldir = L".";
4025 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4027 /* same check as NeedCurrentDirectoryForExePathW */
4028 if (!wcschr( name, '\\' ))
4030 UNICODE_STRING name, value = { 0 };
4032 RtlInitUnicodeString( &name, L"NoDefaultCurrentDirectoryInExePath" );
4033 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4034 dlldir = L"";
4036 return get_dll_load_path( module, dlldir, FALSE, path );
4040 /******************************************************************
4041 * RtlGetSearchPath (NTDLL.@)
4043 NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
4045 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4046 return get_dll_load_path( module, NULL, path_safe_mode, path );
4050 /******************************************************************
4051 * RtlReleasePath (NTDLL.@)
4053 void WINAPI RtlReleasePath( PWSTR path )
4055 RtlFreeHeap( GetProcessHeap(), 0, path );
4059 /******************************************************************
4060 * DllMain (NTDLL.@)
4062 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4064 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
4065 return TRUE;
4069 /***********************************************************************
4070 * __wine_set_unix_funcs
4072 NTSTATUS CDECL __wine_set_unix_funcs( int version, const struct unix_funcs *funcs )
4074 if (version != NTDLL_UNIXLIB_VERSION) return STATUS_REVISION_MISMATCH;
4075 unix_funcs = funcs;
4076 return STATUS_SUCCESS;