ntdll: Make sure we don't try to attach the main exe a second time.
[wine/zf.git] / dlls / ntdll / loader.c
blob4868919b0b5028522f3f71091a5059800f7ba27e
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 "config.h"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <stdarg.h>
27 #ifdef HAVE_LINK_H
28 # include <link.h>
29 #endif
30 #ifdef HAVE_SYS_MMAN_H
31 # include <sys/mman.h>
32 #endif
34 #if defined(__APPLE__)
35 # include <mach-o/getsect.h>
36 #endif
38 #include "ntstatus.h"
39 #define WIN32_NO_STATUS
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winnt.h"
44 #include "winternl.h"
45 #include "delayloadhandler.h"
47 #include "wine/exception.h"
48 #include "wine/library.h"
49 #include "wine/debug.h"
50 #include "wine/list.h"
51 #include "wine/server.h"
52 #include "ntdll_misc.h"
53 #include "ddk/wdm.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(module);
56 WINE_DECLARE_DEBUG_CHANNEL(relay);
57 WINE_DECLARE_DEBUG_CHANNEL(snoop);
58 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
59 WINE_DECLARE_DEBUG_CHANNEL(imports);
61 #ifdef _WIN64
62 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
63 #endif
64 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
65 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
67 /* we don't want to include winuser.h */
68 #define RT_MANIFEST ((ULONG_PTR)24)
69 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
71 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
72 typedef void (CALLBACK *LDRENUMPROC)(LDR_MODULE *, void *, BOOLEAN *);
74 /* system directory with trailing backslash */
75 const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
76 's','y','s','t','e','m','3','2','\\',0};
77 const WCHAR syswow64_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
78 's','y','s','w','o','w','6','4','\\',0};
80 /* system search path */
81 static const WCHAR system_path[] =
82 {'C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m','3','2',';',
83 'C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m',';',
84 'C',':','\\','w','i','n','d','o','w','s',0};
86 static const WCHAR dotW[] = {'.',0};
88 static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
89 static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
90 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
91 static ULONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
92 static ULONG dll_safe_mode = 1; /* dll search mode */
93 static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
94 static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
96 struct dll_dir_entry
98 struct list entry;
99 WCHAR dir[1];
102 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
104 struct ldr_notification
106 struct list entry;
107 PLDR_DLL_NOTIFICATION_FUNCTION callback;
108 void *context;
111 static struct list ldr_notifications = LIST_INIT( ldr_notifications );
113 static const char * const reason_names[] =
115 "PROCESS_DETACH",
116 "PROCESS_ATTACH",
117 "THREAD_ATTACH",
118 "THREAD_DETACH",
119 NULL, NULL, NULL, NULL,
120 "WINE_PREATTACH"
123 static const WCHAR dllW[] = {'.','d','l','l',0};
125 /* internal representation of 32bit modules. per process. */
126 typedef struct _wine_modref
128 LDR_MODULE ldr;
129 dev_t dev;
130 ino_t ino;
131 void *so_handle;
132 int alloc_deps;
133 int nDeps;
134 struct _wine_modref **deps;
135 } WINE_MODREF;
137 /* info about the current builtin dll load */
138 /* used to keep track of things across the register_dll constructor call */
139 struct builtin_load_info
141 const WCHAR *load_path;
142 const UNICODE_STRING *filename;
143 NTSTATUS status;
144 WINE_MODREF *wm;
147 static struct builtin_load_info default_load_info;
148 static struct builtin_load_info *builtin_load_info = &default_load_info;
150 static UINT tls_module_count; /* number of modules with TLS directory */
151 static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
152 LIST_ENTRY tls_links = { &tls_links, &tls_links };
154 static RTL_CRITICAL_SECTION loader_section;
155 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
157 0, 0, &loader_section,
158 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
159 0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
161 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
163 static CRITICAL_SECTION dlldir_section;
164 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
166 0, 0, &dlldir_section,
167 { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
168 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
170 static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };
172 static WINE_MODREF *cached_modref;
173 static WINE_MODREF *current_modref;
174 static WINE_MODREF *last_failed_modref;
176 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
177 DWORD flags, WINE_MODREF** pwm );
178 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
179 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
180 DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
181 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
182 DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
184 /* convert PE image VirtualAddress to Real Address */
185 static inline void *get_rva( HMODULE module, DWORD va )
187 return (void *)((char *)module + va);
190 /* check whether the file name contains a path */
191 static inline BOOL contains_path( LPCWSTR name )
193 return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
196 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
198 typedef struct _RTL_UNLOAD_EVENT_TRACE
200 void *BaseAddress;
201 SIZE_T SizeOfImage;
202 ULONG Sequence;
203 ULONG TimeDateStamp;
204 ULONG CheckSum;
205 WCHAR ImageName[32];
206 } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
208 static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
209 static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
210 static unsigned int unload_trace_seq;
212 static void module_push_unload_trace( const LDR_MODULE *ldr )
214 RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
215 unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
217 ptr->BaseAddress = ldr->BaseAddress;
218 ptr->SizeOfImage = ldr->SizeOfImage;
219 ptr->Sequence = unload_trace_seq;
220 ptr->TimeDateStamp = ldr->TimeDateStamp;
221 ptr->CheckSum = ldr->CheckSum;
222 memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
223 ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;
225 unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
226 unload_trace_ptr = unload_traces;
229 /*********************************************************************
230 * RtlGetUnloadEventTrace [NTDLL.@]
232 RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
234 return unload_traces;
237 /*********************************************************************
238 * RtlGetUnloadEventTraceEx [NTDLL.@]
240 void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
242 static unsigned int element_size = sizeof(*unload_traces);
243 static unsigned int element_count = ARRAY_SIZE(unload_traces);
245 *size = &element_size;
246 *count = &element_count;
247 *trace = &unload_trace_ptr;
250 /*************************************************************************
251 * call_dll_entry_point
253 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
254 * their entry point, so we need a small asm wrapper. Testing indicates
255 * that only modifying esi leads to a crash, so use this one to backup
256 * ebp while running the dll entry proc.
258 #ifdef __i386__
259 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
260 __ASM_GLOBAL_FUNC(call_dll_entry_point,
261 "pushl %ebp\n\t"
262 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
263 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
264 "movl %esp,%ebp\n\t"
265 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
266 "pushl %ebx\n\t"
267 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
268 "pushl %esi\n\t"
269 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
270 "pushl %edi\n\t"
271 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
272 "movl %ebp,%esi\n\t"
273 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
274 "pushl 20(%ebp)\n\t"
275 "pushl 16(%ebp)\n\t"
276 "pushl 12(%ebp)\n\t"
277 "movl 8(%ebp),%eax\n\t"
278 "call *%eax\n\t"
279 "movl %esi,%ebp\n\t"
280 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
281 "leal -12(%ebp),%esp\n\t"
282 "popl %edi\n\t"
283 __ASM_CFI(".cfi_same_value %edi\n\t")
284 "popl %esi\n\t"
285 __ASM_CFI(".cfi_same_value %esi\n\t")
286 "popl %ebx\n\t"
287 __ASM_CFI(".cfi_same_value %ebx\n\t")
288 "popl %ebp\n\t"
289 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
290 __ASM_CFI(".cfi_same_value %ebp\n\t")
291 "ret" )
292 #else /* __i386__ */
293 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
294 UINT reason, void *reserved )
296 return proc( module, reason, reserved );
298 #endif /* __i386__ */
301 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
302 /*************************************************************************
303 * stub_entry_point
305 * Entry point for stub functions.
307 static void stub_entry_point( const char *dll, const char *name, void *ret_addr )
309 EXCEPTION_RECORD rec;
311 rec.ExceptionCode = EXCEPTION_WINE_STUB;
312 rec.ExceptionFlags = EH_NONCONTINUABLE;
313 rec.ExceptionRecord = NULL;
314 rec.ExceptionAddress = ret_addr;
315 rec.NumberParameters = 2;
316 rec.ExceptionInformation[0] = (ULONG_PTR)dll;
317 rec.ExceptionInformation[1] = (ULONG_PTR)name;
318 for (;;) RtlRaiseException( &rec );
322 #include "pshpack1.h"
323 #ifdef __i386__
324 struct stub
326 BYTE pushl1; /* pushl $name */
327 const char *name;
328 BYTE pushl2; /* pushl $dll */
329 const char *dll;
330 BYTE call; /* call stub_entry_point */
331 DWORD entry;
333 #elif defined(__arm__)
334 struct stub
336 DWORD ldr_r0; /* ldr r0, $dll */
337 DWORD ldr_r1; /* ldr r1, $name */
338 DWORD mov_r2_lr; /* mov r2, lr */
339 DWORD ldr_pc_pc; /* ldr pc, [pc, #4] */
340 const char *dll;
341 const char *name;
342 const void* entry;
344 #elif defined(__aarch64__)
345 struct stub
347 DWORD ldr_x0; /* ldr x0, $dll */
348 DWORD ldr_x1; /* ldr x1, $name */
349 DWORD mov_x2_lr; /* mov x2, lr */
350 DWORD ldr_x16; /* ldr x16, $entry */
351 DWORD br_x16; /* br x16 */
352 const char *dll;
353 const char *name;
354 const void *entry;
356 #else
357 struct stub
359 BYTE movq_rdi[2]; /* movq $dll,%rdi */
360 const char *dll;
361 BYTE movq_rsi[2]; /* movq $name,%rsi */
362 const char *name;
363 BYTE movq_rsp_rdx[4]; /* movq (%rsp),%rdx */
364 BYTE movq_rax[2]; /* movq $entry, %rax */
365 const void* entry;
366 BYTE jmpq_rax[2]; /* jmp %rax */
368 #endif
369 #include "poppack.h"
371 /*************************************************************************
372 * allocate_stub
374 * Allocate a stub entry point.
376 static ULONG_PTR allocate_stub( const char *dll, const char *name )
378 #define MAX_SIZE 65536
379 static struct stub *stubs;
380 static unsigned int nb_stubs;
381 struct stub *stub;
383 if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
385 if (!stubs)
387 SIZE_T size = MAX_SIZE;
388 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
389 MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
390 return 0xdeadbeef;
392 stub = &stubs[nb_stubs++];
393 #ifdef __i386__
394 stub->pushl1 = 0x68; /* pushl $name */
395 stub->name = name;
396 stub->pushl2 = 0x68; /* pushl $dll */
397 stub->dll = dll;
398 stub->call = 0xe8; /* call stub_entry_point */
399 stub->entry = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
400 #elif defined(__arm__)
401 stub->ldr_r0 = 0xe59f0008; /* ldr r0, [pc, #8] ($dll) */
402 stub->ldr_r1 = 0xe59f1008; /* ldr r1, [pc, #8] ($name) */
403 stub->mov_r2_lr = 0xe1a0200e; /* mov r2, lr */
404 stub->ldr_pc_pc = 0xe59ff004; /* ldr pc, [pc, #4] */
405 stub->dll = dll;
406 stub->name = name;
407 stub->entry = stub_entry_point;
408 #elif defined(__aarch64__)
409 stub->ldr_x0 = 0x580000a0; /* ldr x0, #20 ($dll) */
410 stub->ldr_x1 = 0x580000c1; /* ldr x1, #24 ($name) */
411 stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
412 stub->ldr_x16 = 0x580000d0; /* ldr x16, #24 ($entry) */
413 stub->br_x16 = 0xd61f0200; /* br x16 */
414 stub->dll = dll;
415 stub->name = name;
416 stub->entry = stub_entry_point;
417 #else
418 stub->movq_rdi[0] = 0x48; /* movq $dll,%rdi */
419 stub->movq_rdi[1] = 0xbf;
420 stub->dll = dll;
421 stub->movq_rsi[0] = 0x48; /* movq $name,%rsi */
422 stub->movq_rsi[1] = 0xbe;
423 stub->name = name;
424 stub->movq_rsp_rdx[0] = 0x48; /* movq (%rsp),%rdx */
425 stub->movq_rsp_rdx[1] = 0x8b;
426 stub->movq_rsp_rdx[2] = 0x14;
427 stub->movq_rsp_rdx[3] = 0x24;
428 stub->movq_rax[0] = 0x48; /* movq $entry, %rax */
429 stub->movq_rax[1] = 0xb8;
430 stub->entry = stub_entry_point;
431 stub->jmpq_rax[0] = 0xff; /* jmp %rax */
432 stub->jmpq_rax[1] = 0xe0;
433 #endif
434 return (ULONG_PTR)stub;
437 #else /* __i386__ */
438 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
439 #endif /* __i386__ */
441 /* call ldr notifications */
442 static void call_ldr_notifications( ULONG reason, LDR_MODULE *module )
444 struct ldr_notification *notify, *notify_next;
445 LDR_DLL_NOTIFICATION_DATA data;
447 data.Loaded.Flags = 0;
448 data.Loaded.FullDllName = &module->FullDllName;
449 data.Loaded.BaseDllName = &module->BaseDllName;
450 data.Loaded.DllBase = module->BaseAddress;
451 data.Loaded.SizeOfImage = module->SizeOfImage;
453 LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
455 TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
456 notify->callback, reason, &data, notify->context );
458 notify->callback(reason, &data, notify->context);
460 TRACE_(relay)("\1Ret LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
461 notify->callback, reason, &data, notify->context );
465 /*************************************************************************
466 * get_modref
468 * Looks for the referenced HMODULE in the current process
469 * The loader_section must be locked while calling this function.
471 static WINE_MODREF *get_modref( HMODULE hmod )
473 PLIST_ENTRY mark, entry;
474 PLDR_MODULE mod;
476 if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
478 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
479 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
481 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
482 if (mod->BaseAddress == hmod)
483 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
485 return NULL;
489 /**********************************************************************
490 * find_basename_module
492 * Find a module from its base name.
493 * The loader_section must be locked while calling this function
495 static WINE_MODREF *find_basename_module( LPCWSTR name )
497 PLIST_ENTRY mark, entry;
498 UNICODE_STRING name_str;
500 RtlInitUnicodeString( &name_str, name );
502 if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
503 return cached_modref;
505 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
506 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
508 LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
509 if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE ))
511 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
512 return cached_modref;
515 return NULL;
519 /**********************************************************************
520 * find_fullname_module
522 * Find a module from its full path name.
523 * The loader_section must be locked while calling this function
525 static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
527 PLIST_ENTRY mark, entry;
528 UNICODE_STRING name = *nt_name;
530 if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
531 name.Length -= 4 * sizeof(WCHAR); /* for \??\ prefix */
532 name.Buffer += 4;
534 if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
535 return cached_modref;
537 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
538 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
540 LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
541 if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
543 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
544 return cached_modref;
547 return NULL;
551 /**********************************************************************
552 * find_fileid_module
554 * Find a module from its file id.
555 * The loader_section must be locked while calling this function
557 static WINE_MODREF *find_fileid_module( struct stat *st )
559 LIST_ENTRY *mark, *entry;
561 if (cached_modref && cached_modref->dev == st->st_dev && cached_modref->ino == st->st_ino)
562 return cached_modref;
564 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
565 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
567 LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );
568 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
570 if (wm->dev == st->st_dev && wm->ino == st->st_ino)
572 cached_modref = wm;
573 return wm;
576 return NULL;
580 /**********************************************************************
581 * find_so_module
583 * Find a module from its so file handle.
584 * The loader_section must be locked while calling this function
586 static WINE_MODREF *find_so_module( void *handle )
588 LIST_ENTRY *mark, *entry;
590 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
591 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
593 LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );
594 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
596 if (wm->so_handle == handle) return wm;
598 return NULL;
602 /*************************************************************************
603 * find_forwarded_export
605 * Find the final function pointer for a forwarded function.
606 * The loader_section must be locked while calling this function.
608 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
610 const IMAGE_EXPORT_DIRECTORY *exports;
611 DWORD exp_size;
612 WINE_MODREF *wm;
613 WCHAR mod_name[32];
614 const char *end = strrchr(forward, '.');
615 FARPROC proc = NULL;
617 if (!end) return NULL;
618 if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL;
619 ascii_to_unicode( mod_name, forward, end - forward );
620 mod_name[end - forward] = 0;
621 if (!wcschr( mod_name, '.' ))
623 if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name) - sizeof(dllW)) return NULL;
624 memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
627 if (!(wm = find_basename_module( mod_name )))
629 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
630 if (load_dll( load_path, mod_name, dllW, 0, &wm ) == STATUS_SUCCESS &&
631 !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
633 if (!imports_fixup_done && current_modref)
635 WINE_MODREF **deps;
636 if (current_modref->alloc_deps)
637 deps = RtlReAllocateHeap( GetProcessHeap(), 0, current_modref->deps,
638 (current_modref->alloc_deps + 1) * sizeof(*deps) );
639 else
640 deps = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*deps) );
641 if (deps)
643 deps[current_modref->nDeps++] = wm;
644 current_modref->deps = deps;
645 current_modref->alloc_deps++;
648 else if (process_attach( wm, NULL ) != STATUS_SUCCESS)
650 LdrUnloadDll( wm->ldr.BaseAddress );
651 wm = NULL;
655 if (!wm)
657 ERR( "module not found for forward '%s' used by %s\n",
658 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
659 return NULL;
662 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
663 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
665 const char *name = end + 1;
666 if (*name == '#') /* ordinal */
667 proc = find_ordinal_export( wm->ldr.BaseAddress, exports, exp_size, atoi(name+1), load_path );
668 else
669 proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, name, -1, load_path );
672 if (!proc)
674 ERR("function not found for forward '%s' used by %s."
675 " If you are using builtin %s, try using the native one instead.\n",
676 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
677 debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
679 return proc;
683 /*************************************************************************
684 * find_ordinal_export
686 * Find an exported function by ordinal.
687 * The exports base must have been subtracted from the ordinal already.
688 * The loader_section must be locked while calling this function.
690 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
691 DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
693 FARPROC proc;
694 const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
696 if (ordinal >= exports->NumberOfFunctions)
698 TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
699 return NULL;
701 if (!functions[ordinal]) return NULL;
703 proc = get_rva( module, functions[ordinal] );
705 /* if the address falls into the export dir, it's a forward */
706 if (((const char *)proc >= (const char *)exports) &&
707 ((const char *)proc < (const char *)exports + exp_size))
708 return find_forwarded_export( module, (const char *)proc, load_path );
710 if (TRACE_ON(snoop))
712 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
713 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
715 if (TRACE_ON(relay))
717 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
718 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
720 return proc;
724 /*************************************************************************
725 * find_named_export
727 * Find an exported function by name.
728 * The loader_section must be locked while calling this function.
730 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
731 DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
733 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
734 const DWORD *names = get_rva( module, exports->AddressOfNames );
735 int min = 0, max = exports->NumberOfNames - 1;
737 /* first check the hint */
738 if (hint >= 0 && hint <= max)
740 char *ename = get_rva( module, names[hint] );
741 if (!strcmp( ename, name ))
742 return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
745 /* then do a binary search */
746 while (min <= max)
748 int res, pos = (min + max) / 2;
749 char *ename = get_rva( module, names[pos] );
750 if (!(res = strcmp( ename, name )))
751 return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
752 if (res > 0) max = pos - 1;
753 else min = pos + 1;
755 return NULL;
760 /*************************************************************************
761 * import_dll
763 * Import the dll specified by the given import descriptor.
764 * The loader_section must be locked while calling this function.
766 static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
768 NTSTATUS status;
769 WINE_MODREF *wmImp;
770 HMODULE imp_mod;
771 const IMAGE_EXPORT_DIRECTORY *exports;
772 DWORD exp_size;
773 const IMAGE_THUNK_DATA *import_list;
774 IMAGE_THUNK_DATA *thunk_list;
775 WCHAR buffer[32];
776 const char *name = get_rva( module, descr->Name );
777 DWORD len = strlen(name);
778 PVOID protect_base;
779 SIZE_T protect_size = 0;
780 DWORD protect_old;
782 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
783 if (descr->u.OriginalFirstThunk)
784 import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
785 else
786 import_list = thunk_list;
788 if (!import_list->u1.Ordinal)
790 WARN( "Skipping unused import %s\n", name );
791 *pwm = NULL;
792 return TRUE;
795 while (len && name[len-1] == ' ') len--; /* remove trailing spaces */
797 if (len * sizeof(WCHAR) < sizeof(buffer))
799 ascii_to_unicode( buffer, name, len );
800 buffer[len] = 0;
801 status = load_dll( load_path, buffer, dllW, 0, &wmImp );
803 else /* need to allocate a larger buffer */
805 WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
806 if (!ptr) return FALSE;
807 ascii_to_unicode( ptr, name, len );
808 ptr[len] = 0;
809 status = load_dll( load_path, ptr, dllW, 0, &wmImp );
810 RtlFreeHeap( GetProcessHeap(), 0, ptr );
813 if (status)
815 if (status == STATUS_DLL_NOT_FOUND)
816 ERR("Library %s (which is needed by %s) not found\n",
817 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
818 else
819 ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
820 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
821 return FALSE;
824 /* unprotect the import address table since it can be located in
825 * readonly section */
826 while (import_list[protect_size].u1.Ordinal) protect_size++;
827 protect_base = thunk_list;
828 protect_size *= sizeof(*thunk_list);
829 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
830 &protect_size, PAGE_READWRITE, &protect_old );
832 imp_mod = wmImp->ldr.BaseAddress;
833 exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
835 if (!exports)
837 /* set all imported function to deadbeef */
838 while (import_list->u1.Ordinal)
840 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
842 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
843 WARN("No implementation for %s.%d", name, ordinal );
844 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
846 else
848 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
849 WARN("No implementation for %s.%s", name, pe_name->Name );
850 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
852 WARN(" imported from %s, allocating stub %p\n",
853 debugstr_w(current_modref->ldr.FullDllName.Buffer),
854 (void *)thunk_list->u1.Function );
855 import_list++;
856 thunk_list++;
858 goto done;
861 while (import_list->u1.Ordinal)
863 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
865 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
867 thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
868 ordinal - exports->Base, load_path );
869 if (!thunk_list->u1.Function)
871 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
872 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
873 name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
874 (void *)thunk_list->u1.Function );
876 TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
878 else /* import by name */
880 IMAGE_IMPORT_BY_NAME *pe_name;
881 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
882 thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
883 (const char*)pe_name->Name,
884 pe_name->Hint, load_path );
885 if (!thunk_list->u1.Function)
887 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
888 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
889 name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
890 (void *)thunk_list->u1.Function );
892 TRACE_(imports)("--- %s %s.%d = %p\n",
893 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
895 import_list++;
896 thunk_list++;
899 done:
900 /* restore old protection of the import address table */
901 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
902 *pwm = wmImp;
903 return TRUE;
907 /***********************************************************************
908 * create_module_activation_context
910 static NTSTATUS create_module_activation_context( LDR_MODULE *module )
912 NTSTATUS status;
913 LDR_RESOURCE_INFO info;
914 const IMAGE_RESOURCE_DATA_ENTRY *entry;
916 info.Type = RT_MANIFEST;
917 info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
918 info.Language = 0;
919 if (!(status = LdrFindResource_U( module->BaseAddress, &info, 3, &entry )))
921 ACTCTXW ctx;
922 ctx.cbSize = sizeof(ctx);
923 ctx.lpSource = NULL;
924 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
925 ctx.hModule = module->BaseAddress;
926 ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
927 status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
929 return status;
933 /*************************************************************************
934 * is_dll_native_subsystem
936 * Check if dll is a proper native driver.
937 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
938 * while being perfectly normal DLLs. This heuristic should catch such breakages.
940 static BOOL is_dll_native_subsystem( LDR_MODULE *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
942 static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
943 static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
944 const IMAGE_IMPORT_DESCRIPTOR *imports;
945 DWORD i, size;
946 WCHAR buffer[16];
948 if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
949 if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
950 if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
952 if ((imports = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
953 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
955 for (i = 0; imports[i].Name; i++)
957 const char *name = get_rva( mod->BaseAddress, imports[i].Name );
958 DWORD len = strlen(name);
959 if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
960 ascii_to_unicode( buffer, name, len + 1 );
961 if (!wcsicmp( buffer, ntdllW ) || !wcsicmp( buffer, kernel32W ))
963 TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
964 return FALSE;
968 return TRUE;
971 /*************************************************************************
972 * alloc_tls_slot
974 * Allocate a TLS slot for a newly-loaded module.
975 * The loader_section must be locked while calling this function.
977 static SHORT alloc_tls_slot( LDR_MODULE *mod )
979 const IMAGE_TLS_DIRECTORY *dir;
980 ULONG i, size;
981 void *new_ptr;
982 LIST_ENTRY *entry;
984 if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
985 return -1;
987 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
988 if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1;
990 for (i = 0; i < tls_module_count; i++)
992 if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
993 !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
994 break;
997 TRACE( "module %p data %p-%p zerofill %u index %p callback %p flags %x -> slot %u\n", mod->BaseAddress,
998 (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
999 (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );
1001 if (i == tls_module_count)
1003 UINT new_count = max( 32, tls_module_count * 2 );
1005 if (!tls_dirs)
1006 new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
1007 else
1008 new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
1009 new_count * sizeof(*tls_dirs) );
1010 if (!new_ptr) return -1;
1012 /* resize the pointer block in all running threads */
1013 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1015 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1016 void **old = teb->ThreadLocalStoragePointer;
1017 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
1019 if (!new) return -1;
1020 if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
1021 teb->ThreadLocalStoragePointer = new;
1022 #if defined(__APPLE__) && defined(__x86_64__)
1023 if (teb->Reserved5[0])
1024 ((TEB*)teb->Reserved5[0])->ThreadLocalStoragePointer = new;
1025 #endif
1026 TRACE( "thread %04lx tls block %p -> %p\n", (ULONG_PTR)teb->ClientId.UniqueThread, old, new );
1027 /* FIXME: can't free old block here, should be freed at thread exit */
1030 tls_dirs = new_ptr;
1031 tls_module_count = new_count;
1034 /* allocate the data block in all running threads */
1035 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1037 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1039 if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
1040 memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
1041 memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
1043 TRACE( "thread %04lx slot %u: %u/%u bytes at %p\n",
1044 (ULONG_PTR)teb->ClientId.UniqueThread, i, size, dir->SizeOfZeroFill, new_ptr );
1046 RtlFreeHeap( GetProcessHeap(), 0,
1047 interlocked_xchg_ptr( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1050 *(DWORD *)dir->AddressOfIndex = i;
1051 tls_dirs[i] = *dir;
1052 return i;
1056 /*************************************************************************
1057 * free_tls_slot
1059 * Free the module TLS slot on unload.
1060 * The loader_section must be locked while calling this function.
1062 static void free_tls_slot( LDR_MODULE *mod )
1064 ULONG i = (USHORT)mod->TlsIndex;
1066 if (mod->TlsIndex == -1) return;
1067 assert( i < tls_module_count );
1068 memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1072 /****************************************************************
1073 * fixup_imports_ilonly
1075 * Fixup imports for an IL-only module. All we do is import mscoree.
1076 * The loader_section must be locked while calling this function.
1078 static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
1080 static const WCHAR mscoreeW[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
1081 IMAGE_EXPORT_DIRECTORY *exports;
1082 DWORD exp_size;
1083 NTSTATUS status;
1084 void *proc = NULL;
1085 WINE_MODREF *prev, *imp;
1087 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1088 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1090 wm->nDeps = 1;
1091 wm->alloc_deps = 1;
1092 wm->deps = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(WINE_MODREF *) );
1094 prev = current_modref;
1095 current_modref = wm;
1096 if (!(status = load_dll( load_path, mscoreeW, NULL, 0, &imp ))) wm->deps[0] = imp;
1097 current_modref = prev;
1098 if (status)
1100 ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
1101 debugstr_w(wm->ldr.BaseDllName.Buffer) );
1102 return status;
1105 TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
1107 if ((exports = RtlImageDirectoryEntryToData( imp->ldr.BaseAddress, TRUE,
1108 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1110 const char *name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
1111 proc = find_named_export( imp->ldr.BaseAddress, exports, exp_size, name, -1, load_path );
1113 if (!proc) return STATUS_PROCEDURE_NOT_FOUND;
1114 *entry = proc;
1115 return STATUS_SUCCESS;
1119 /****************************************************************
1120 * fixup_imports
1122 * Fixup all imports of a given module.
1123 * The loader_section must be locked while calling this function.
1125 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
1127 int i, dep, nb_imports;
1128 const IMAGE_IMPORT_DESCRIPTOR *imports;
1129 WINE_MODREF *prev, *imp;
1130 DWORD size;
1131 NTSTATUS status;
1132 ULONG_PTR cookie;
1134 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1135 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1137 wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr );
1139 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
1140 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1141 return STATUS_SUCCESS;
1143 nb_imports = 0;
1144 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
1146 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
1148 if (!create_module_activation_context( &wm->ldr ))
1149 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1151 /* Allocate module dependency list */
1152 wm->alloc_deps = nb_imports;
1153 wm->deps = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
1155 /* load the imported modules. They are automatically
1156 * added to the modref list of the process.
1158 prev = current_modref;
1159 current_modref = wm;
1160 status = STATUS_SUCCESS;
1161 for (i = 0; i < nb_imports; i++)
1163 dep = wm->nDeps++;
1165 if (!import_dll( wm->ldr.BaseAddress, &imports[i], load_path, &imp ))
1167 imp = NULL;
1168 status = STATUS_DLL_NOT_FOUND;
1170 wm->deps[dep] = imp;
1172 current_modref = prev;
1173 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1174 return status;
1178 /*************************************************************************
1179 * alloc_module
1181 * Allocate a WINE_MODREF structure and add it to the process list
1182 * The loader_section must be locked while calling this function.
1184 static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1186 WCHAR *buffer;
1187 WINE_MODREF *wm;
1188 const WCHAR *p;
1189 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1191 if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1193 wm->ldr.BaseAddress = hModule;
1194 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
1195 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1196 wm->ldr.TlsIndex = -1;
1197 wm->ldr.LoadCount = 1;
1199 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
1201 RtlFreeHeap( GetProcessHeap(), 0, wm );
1202 return NULL;
1204 memcpy( buffer, nt_name->Buffer + 4 /* \??\ prefix */, nt_name->Length - 4 * sizeof(WCHAR) );
1205 buffer[nt_name->Length/sizeof(WCHAR) - 4] = 0;
1206 if ((p = wcsrchr( buffer, '\\' ))) p++;
1207 else p = buffer;
1208 RtlInitUnicodeString( &wm->ldr.FullDllName, buffer );
1209 RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
1211 if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1213 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
1214 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1215 if (nt->OptionalHeader.AddressOfEntryPoint)
1216 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1219 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1220 &wm->ldr.InLoadOrderModuleList);
1221 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1222 &wm->ldr.InMemoryOrderModuleList);
1223 /* wait until init is called for inserting into InInitializationOrderModuleList */
1225 if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
1227 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1228 WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1229 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1231 return wm;
1235 /*************************************************************************
1236 * alloc_thread_tls
1238 * Allocate the per-thread structure for module TLS storage.
1240 static NTSTATUS alloc_thread_tls(void)
1242 void **pointers;
1243 UINT i, size;
1245 if (!tls_module_count) return STATUS_SUCCESS;
1247 if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
1248 tls_module_count * sizeof(*pointers) )))
1249 return STATUS_NO_MEMORY;
1251 for (i = 0; i < tls_module_count; i++)
1253 const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1255 if (!dir) continue;
1256 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1257 if (!size && !dir->SizeOfZeroFill) continue;
1259 if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
1261 while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
1262 RtlFreeHeap( GetProcessHeap(), 0, pointers );
1263 return STATUS_NO_MEMORY;
1265 memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
1266 memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1268 TRACE( "thread %04x slot %u: %u/%u bytes at %p\n",
1269 GetCurrentThreadId(), i, size, dir->SizeOfZeroFill, pointers[i] );
1271 NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1272 #if defined(__APPLE__) && defined(__x86_64__)
1273 __asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
1275 : "r" (pointers), "n" (FIELD_OFFSET(TEB, ThreadLocalStoragePointer)));
1276 #endif
1277 return STATUS_SUCCESS;
1281 /*************************************************************************
1282 * call_tls_callbacks
1284 static void call_tls_callbacks( HMODULE module, UINT reason )
1286 const IMAGE_TLS_DIRECTORY *dir;
1287 const PIMAGE_TLS_CALLBACK *callback;
1288 ULONG dirsize;
1290 if (reason == DLL_WINE_PREATTACH) return;
1292 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
1293 if (!dir || !dir->AddressOfCallBacks) return;
1295 for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1297 TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1298 *callback, module, reason_names[reason] );
1299 __TRY
1301 call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1303 __EXCEPT_ALL
1305 TRACE_(relay)("\1exception %08x in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1306 GetExceptionCode(), callback, module, reason_names[reason] );
1307 return;
1309 __ENDTRY
1310 TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1311 *callback, module, reason_names[reason] );
1316 /*************************************************************************
1317 * call_constructors
1319 static void call_constructors( WINE_MODREF *wm )
1321 #ifdef HAVE_DLINFO
1322 extern char **__wine_main_environ;
1323 struct link_map *map;
1324 void (*init_func)(int, char **, char **) = NULL;
1325 void (**init_array)(int, char **, char **) = NULL;
1326 ULONG_PTR i, init_arraysz = 0;
1327 #ifdef _WIN64
1328 const Elf64_Dyn *dyn;
1329 #else
1330 const Elf32_Dyn *dyn;
1331 #endif
1333 if (dlinfo( wm->so_handle, RTLD_DI_LINKMAP, &map ) == -1) return;
1334 for (dyn = map->l_ld; dyn->d_tag; dyn++)
1336 switch (dyn->d_tag)
1338 case 0x60009990: init_array = (void *)((char *)map->l_addr + dyn->d_un.d_val); break;
1339 case 0x60009991: init_arraysz = dyn->d_un.d_val; break;
1340 case 0x60009992: init_func = (void *)((char *)map->l_addr + dyn->d_un.d_val); break;
1344 TRACE( "%s: got init_func %p init_array %p %lu\n", debugstr_us( &wm->ldr.BaseDllName ),
1345 init_func, init_array, init_arraysz );
1347 if (init_func) init_func( __wine_main_argc, __wine_main_argv, __wine_main_environ );
1349 if (init_array)
1350 for (i = 0; i < init_arraysz / sizeof(*init_array); i++)
1351 init_array[i]( __wine_main_argc, __wine_main_argv, __wine_main_environ );
1352 #endif
1356 /*************************************************************************
1357 * MODULE_InitDLL
1359 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1361 WCHAR mod_name[32];
1362 NTSTATUS status = STATUS_SUCCESS;
1363 DLLENTRYPROC entry = wm->ldr.EntryPoint;
1364 void *module = wm->ldr.BaseAddress;
1365 BOOL retv = FALSE;
1367 /* Skip calls for modules loaded with special load flags */
1369 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1370 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
1371 if (wm->so_handle && reason == DLL_PROCESS_ATTACH) call_constructors( wm );
1372 if (!entry) return STATUS_SUCCESS;
1374 if (TRACE_ON(relay))
1376 size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1377 memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
1378 mod_name[len / sizeof(WCHAR)] = 0;
1379 TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1380 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1382 else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
1383 reason_names[reason], lpReserved );
1385 __TRY
1387 retv = call_dll_entry_point( entry, module, reason, lpReserved );
1388 if (!retv)
1389 status = STATUS_DLL_INIT_FAILED;
1391 __EXCEPT_ALL
1393 status = GetExceptionCode();
1394 TRACE_(relay)("\1exception %08x in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1395 status, entry, module, reason_names[reason], lpReserved );
1397 __ENDTRY
1399 /* The state of the module list may have changed due to the call
1400 to the dll. We cannot assume that this module has not been
1401 deleted. */
1402 if (TRACE_ON(relay))
1403 TRACE_(relay)("\1Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1404 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
1405 else
1406 TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1408 return status;
1412 /*************************************************************************
1413 * process_attach
1415 * Send the process attach notification to all DLLs the given module
1416 * depends on (recursively). This is somewhat complicated due to the fact that
1418 * - we have to respect the module dependencies, i.e. modules implicitly
1419 * referenced by another module have to be initialized before the module
1420 * itself can be initialized
1422 * - the initialization routine of a DLL can itself call LoadLibrary,
1423 * thereby introducing a whole new set of dependencies (even involving
1424 * the 'old' modules) at any time during the whole process
1426 * (Note that this routine can be recursively entered not only directly
1427 * from itself, but also via LoadLibrary from one of the called initialization
1428 * routines.)
1430 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1431 * the process *detach* notifications to be sent in the correct order.
1432 * This must not only take into account module dependencies, but also
1433 * 'hidden' dependencies created by modules calling LoadLibrary in their
1434 * attach notification routine.
1436 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1437 * list after the attach notification has returned. This implies that the
1438 * detach notifications are called in the reverse of the sequence the attach
1439 * notifications *returned*.
1441 * The loader_section must be locked while calling this function.
1443 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1445 NTSTATUS status = STATUS_SUCCESS;
1446 ULONG_PTR cookie;
1447 int i;
1449 if (process_detaching) return status;
1451 /* prevent infinite recursion in case of cyclical dependencies */
1452 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1453 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1454 return status;
1456 TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1458 /* Tag current MODREF to prevent recursive loop */
1459 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1460 if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */
1461 if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1463 /* Recursively attach all DLLs this one depends on */
1464 for ( i = 0; i < wm->nDeps; i++ )
1466 if (!wm->deps[i]) continue;
1467 if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1470 if (!wm->ldr.InInitializationOrderModuleList.Flink)
1471 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1472 &wm->ldr.InInitializationOrderModuleList);
1474 /* Call DLL entry point */
1475 if (status == STATUS_SUCCESS)
1477 WINE_MODREF *prev = current_modref;
1478 current_modref = wm;
1480 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1481 status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1482 if (status == STATUS_SUCCESS)
1484 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1486 else
1488 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1489 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );
1491 /* point to the name so LdrInitializeThunk can print it */
1492 last_failed_modref = wm;
1493 WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1495 current_modref = prev;
1498 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1499 /* Remove recursion flag */
1500 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1502 TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1503 return status;
1507 /**********************************************************************
1508 * attach_implicitly_loaded_dlls
1510 * Attach to the (builtin) dlls that have been implicitly loaded because
1511 * of a dependency at the Unix level, but not imported at the Win32 level.
1513 static void attach_implicitly_loaded_dlls( LPVOID reserved )
1515 for (;;)
1517 PLIST_ENTRY mark, entry;
1519 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
1520 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1522 LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
1524 if (!(mod->Flags & LDR_IMAGE_IS_DLL)) continue;
1525 if (mod->Flags & (LDR_LOAD_IN_PROGRESS | LDR_PROCESS_ATTACHED)) continue;
1526 TRACE( "found implicitly loaded %s, attaching to it\n",
1527 debugstr_w(mod->BaseDllName.Buffer));
1528 process_attach( CONTAINING_RECORD(mod, WINE_MODREF, ldr), reserved );
1529 break; /* restart the search from the start */
1531 if (entry == mark) break; /* nothing found */
1536 /*************************************************************************
1537 * process_detach
1539 * Send DLL process detach notifications. See the comment about calling
1540 * sequence at process_attach.
1542 static void process_detach(void)
1544 PLIST_ENTRY mark, entry;
1545 PLDR_MODULE mod;
1547 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1550 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1552 mod = CONTAINING_RECORD(entry, LDR_MODULE,
1553 InInitializationOrderModuleList);
1554 /* Check whether to detach this DLL */
1555 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1556 continue;
1557 if ( mod->LoadCount && !process_detaching )
1558 continue;
1560 /* Call detach notification */
1561 mod->Flags &= ~LDR_PROCESS_ATTACHED;
1562 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1563 DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1564 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1566 /* Restart at head of WINE_MODREF list, as entries might have
1567 been added and/or removed while performing the call ... */
1568 break;
1570 } while (entry != mark);
1573 /*************************************************************************
1574 * thread_attach
1576 * Send DLL thread attach notifications. These are sent in the
1577 * reverse sequence of process detach notification.
1578 * The loader_section must be locked while calling this function.
1580 static void thread_attach(void)
1582 PLIST_ENTRY mark, entry;
1583 PLDR_MODULE mod;
1585 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1586 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1588 mod = CONTAINING_RECORD(entry, LDR_MODULE,
1589 InInitializationOrderModuleList);
1590 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1591 continue;
1592 if ( mod->Flags & LDR_NO_DLL_CALLS )
1593 continue;
1595 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1599 /******************************************************************
1600 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1603 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1605 WINE_MODREF *wm;
1606 NTSTATUS ret = STATUS_SUCCESS;
1608 RtlEnterCriticalSection( &loader_section );
1610 wm = get_modref( hModule );
1611 if (!wm || wm->ldr.TlsIndex != -1)
1612 ret = STATUS_DLL_NOT_FOUND;
1613 else
1614 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1616 RtlLeaveCriticalSection( &loader_section );
1618 return ret;
1621 /******************************************************************
1622 * LdrFindEntryForAddress (NTDLL.@)
1624 * The loader_section must be locked while calling this function
1626 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
1628 PLIST_ENTRY mark, entry;
1629 PLDR_MODULE mod;
1631 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1632 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1634 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
1635 if (mod->BaseAddress <= addr &&
1636 (const char *)addr < (char*)mod->BaseAddress + mod->SizeOfImage)
1638 *pmod = mod;
1639 return STATUS_SUCCESS;
1642 return STATUS_NO_MORE_ENTRIES;
1645 /******************************************************************
1646 * LdrEnumerateLoadedModules (NTDLL.@)
1648 NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
1650 LIST_ENTRY *mark, *entry;
1651 LDR_MODULE *mod;
1652 BOOLEAN stop = FALSE;
1654 TRACE( "(%p, %p, %p)\n", unknown, callback, context );
1656 if (unknown || !callback)
1657 return STATUS_INVALID_PARAMETER;
1659 RtlEnterCriticalSection( &loader_section );
1661 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1662 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1664 mod = CONTAINING_RECORD( entry, LDR_MODULE, InMemoryOrderModuleList );
1665 callback( mod, context, &stop );
1666 if (stop) break;
1669 RtlLeaveCriticalSection( &loader_section );
1670 return STATUS_SUCCESS;
1673 /******************************************************************
1674 * LdrRegisterDllNotification (NTDLL.@)
1676 NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
1677 void *context, void **cookie)
1679 struct ldr_notification *notify;
1681 TRACE( "(%x, %p, %p, %p)\n", flags, callback, context, cookie );
1683 if (!callback || !cookie)
1684 return STATUS_INVALID_PARAMETER;
1686 if (flags)
1687 FIXME( "ignoring flags %x\n", flags );
1689 notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
1690 if (!notify) return STATUS_NO_MEMORY;
1691 notify->callback = callback;
1692 notify->context = context;
1694 RtlEnterCriticalSection( &loader_section );
1695 list_add_tail( &ldr_notifications, &notify->entry );
1696 RtlLeaveCriticalSection( &loader_section );
1698 *cookie = notify;
1699 return STATUS_SUCCESS;
1702 /******************************************************************
1703 * LdrUnregisterDllNotification (NTDLL.@)
1705 NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
1707 struct ldr_notification *notify = cookie;
1709 TRACE( "(%p)\n", cookie );
1711 if (!notify) return STATUS_INVALID_PARAMETER;
1713 RtlEnterCriticalSection( &loader_section );
1714 list_remove( &notify->entry );
1715 RtlLeaveCriticalSection( &loader_section );
1717 RtlFreeHeap( GetProcessHeap(), 0, notify );
1718 return STATUS_SUCCESS;
1721 /******************************************************************
1722 * LdrLockLoaderLock (NTDLL.@)
1724 * Note: some flags are not implemented.
1725 * Flag 0x01 is used to raise exceptions on errors.
1727 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1729 if (flags & ~0x2) FIXME( "flags %x not supported\n", flags );
1731 if (result) *result = 0;
1732 if (magic) *magic = 0;
1733 if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
1734 if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1735 if (!magic) return STATUS_INVALID_PARAMETER_3;
1737 if (flags & 0x2)
1739 if (!RtlTryEnterCriticalSection( &loader_section ))
1741 *result = 2;
1742 return STATUS_SUCCESS;
1744 *result = 1;
1746 else
1748 RtlEnterCriticalSection( &loader_section );
1749 if (result) *result = 1;
1751 *magic = GetCurrentThreadId();
1752 return STATUS_SUCCESS;
1756 /******************************************************************
1757 * LdrUnlockLoaderUnlock (NTDLL.@)
1759 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
1761 if (magic)
1763 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
1764 RtlLeaveCriticalSection( &loader_section );
1766 return STATUS_SUCCESS;
1770 /******************************************************************
1771 * LdrGetProcedureAddress (NTDLL.@)
1773 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
1774 ULONG ord, PVOID *address)
1776 IMAGE_EXPORT_DIRECTORY *exports;
1777 DWORD exp_size;
1778 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1780 RtlEnterCriticalSection( &loader_section );
1782 /* check if the module itself is invalid to return the proper error */
1783 if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
1784 else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
1785 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1787 LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1788 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path )
1789 : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path );
1790 if (proc)
1792 *address = proc;
1793 ret = STATUS_SUCCESS;
1797 RtlLeaveCriticalSection( &loader_section );
1798 return ret;
1802 /*************************************************************************
1803 * is_16bit_builtin
1805 static BOOL is_16bit_builtin( HMODULE module )
1807 const IMAGE_EXPORT_DIRECTORY *exports;
1808 DWORD exp_size;
1810 if (!(exports = RtlImageDirectoryEntryToData( module, TRUE,
1811 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1812 return FALSE;
1814 return find_named_export( module, exports, exp_size, "__wine_spec_dos_header", -1, NULL ) != NULL;
1818 /* adjust an array of pointers to make them into RVAs */
1819 static inline void fixup_rva_ptrs( void *array, BYTE *base, unsigned int count )
1821 BYTE **src = array;
1822 DWORD *dst = array;
1824 for ( ; count; count--, src++, dst++) *dst = *src ? *src - base : 0;
1827 /* fixup an array of RVAs by adding the specified delta */
1828 static inline void fixup_rva_dwords( DWORD *ptr, int delta, unsigned int count )
1830 for ( ; count; count--, ptr++) if (*ptr) *ptr += delta;
1834 /* fixup an array of name/ordinal RVAs by adding the specified delta */
1835 static inline void fixup_rva_names( UINT_PTR *ptr, int delta )
1837 for ( ; *ptr; ptr++) if (!(*ptr & IMAGE_ORDINAL_FLAG)) *ptr += delta;
1841 /* fixup RVAs in the resource directory */
1842 static void fixup_so_resources( IMAGE_RESOURCE_DIRECTORY *dir, BYTE *root, int delta )
1844 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
1845 unsigned int i;
1847 for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
1849 void *ptr = root + entry->u2.s2.OffsetToDirectory;
1850 if (entry->u2.s2.DataIsDirectory) fixup_so_resources( ptr, root, delta );
1851 else fixup_rva_dwords( &((IMAGE_RESOURCE_DATA_ENTRY *)ptr)->OffsetToData, delta, 1 );
1855 /*************************************************************************
1856 * map_so_dll
1858 * Map a builtin dll in memory and fixup RVAs.
1860 static NTSTATUS map_so_dll( const IMAGE_NT_HEADERS *nt_descr, HMODULE module )
1862 static const char builtin_signature[32] = "Wine builtin DLL";
1863 IMAGE_DATA_DIRECTORY *dir;
1864 IMAGE_DOS_HEADER *dos;
1865 IMAGE_NT_HEADERS *nt;
1866 IMAGE_SECTION_HEADER *sec;
1867 BYTE *addr = (BYTE *)module;
1868 DWORD code_start, code_end, data_start, data_end, align_mask;
1869 int delta, nb_sections = 2; /* code + data */
1870 unsigned int i;
1871 DWORD size = (sizeof(IMAGE_DOS_HEADER)
1872 + sizeof(builtin_signature)
1873 + sizeof(IMAGE_NT_HEADERS)
1874 + nb_sections * sizeof(IMAGE_SECTION_HEADER));
1876 if (wine_anon_mmap( addr, size, PROT_READ | PROT_WRITE, MAP_FIXED ) != addr) return STATUS_NO_MEMORY;
1878 dos = (IMAGE_DOS_HEADER *)addr;
1879 nt = (IMAGE_NT_HEADERS *)((BYTE *)(dos + 1) + sizeof(builtin_signature));
1880 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
1882 /* build the DOS and NT headers */
1884 dos->e_magic = IMAGE_DOS_SIGNATURE;
1885 dos->e_cblp = 0x90;
1886 dos->e_cp = 3;
1887 dos->e_cparhdr = (sizeof(*dos) + 0xf) / 0x10;
1888 dos->e_minalloc = 0;
1889 dos->e_maxalloc = 0xffff;
1890 dos->e_ss = 0x0000;
1891 dos->e_sp = 0x00b8;
1892 dos->e_lfanew = sizeof(*dos) + sizeof(builtin_signature);
1894 *nt = *nt_descr;
1896 delta = (const BYTE *)nt_descr - addr;
1897 align_mask = nt->OptionalHeader.SectionAlignment - 1;
1898 code_start = (size + align_mask) & ~align_mask;
1899 data_start = delta & ~align_mask;
1900 #ifdef __APPLE__
1902 Dl_info dli;
1903 unsigned long data_size;
1904 /* need the mach_header, not the PE header, to give to getsegmentdata(3) */
1905 dladdr(addr, &dli);
1906 code_end = getsegmentdata(dli.dli_fbase, "__DATA", &data_size) - addr;
1907 data_end = (code_end + data_size + align_mask) & ~align_mask;
1909 #else
1910 code_end = data_start;
1911 data_end = (nt->OptionalHeader.SizeOfImage + delta + align_mask) & ~align_mask;
1912 #endif
1914 fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
1916 nt->FileHeader.NumberOfSections = nb_sections;
1917 nt->OptionalHeader.BaseOfCode = code_start;
1918 #ifndef _WIN64
1919 nt->OptionalHeader.BaseOfData = data_start;
1920 #endif
1921 nt->OptionalHeader.SizeOfCode = code_end - code_start;
1922 nt->OptionalHeader.SizeOfInitializedData = data_end - data_start;
1923 nt->OptionalHeader.SizeOfUninitializedData = 0;
1924 nt->OptionalHeader.SizeOfImage = data_end;
1925 nt->OptionalHeader.ImageBase = (ULONG_PTR)addr;
1927 /* build the code section */
1929 memcpy( sec->Name, ".text", sizeof(".text") );
1930 sec->SizeOfRawData = code_end - code_start;
1931 sec->Misc.VirtualSize = sec->SizeOfRawData;
1932 sec->VirtualAddress = code_start;
1933 sec->PointerToRawData = code_start;
1934 sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
1935 sec++;
1937 /* build the data section */
1939 memcpy( sec->Name, ".data", sizeof(".data") );
1940 sec->SizeOfRawData = data_end - data_start;
1941 sec->Misc.VirtualSize = sec->SizeOfRawData;
1942 sec->VirtualAddress = data_start;
1943 sec->PointerToRawData = data_start;
1944 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
1945 IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
1946 sec++;
1948 for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
1949 fixup_rva_dwords( &nt->OptionalHeader.DataDirectory[i].VirtualAddress, delta, 1 );
1951 /* build the import directory */
1953 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
1954 if (dir->Size)
1956 IMAGE_IMPORT_DESCRIPTOR *imports = (IMAGE_IMPORT_DESCRIPTOR *)(addr + dir->VirtualAddress);
1958 while (imports->Name)
1960 fixup_rva_dwords( &imports->u.OriginalFirstThunk, delta, 1 );
1961 fixup_rva_dwords( &imports->Name, delta, 1 );
1962 fixup_rva_dwords( &imports->FirstThunk, delta, 1 );
1963 if (imports->u.OriginalFirstThunk)
1964 fixup_rva_names( (UINT_PTR *)(addr + imports->u.OriginalFirstThunk), delta );
1965 if (imports->FirstThunk)
1966 fixup_rva_names( (UINT_PTR *)(addr + imports->FirstThunk), delta );
1967 imports++;
1971 /* build the resource directory */
1973 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
1974 if (dir->Size)
1976 void *ptr = addr + dir->VirtualAddress;
1977 fixup_so_resources( ptr, ptr, delta );
1980 /* build the export directory */
1982 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
1983 if (dir->Size)
1985 IMAGE_EXPORT_DIRECTORY *exports = (IMAGE_EXPORT_DIRECTORY *)(addr + dir->VirtualAddress);
1987 fixup_rva_dwords( &exports->Name, delta, 1 );
1988 fixup_rva_dwords( &exports->AddressOfFunctions, delta, 1 );
1989 fixup_rva_dwords( &exports->AddressOfNames, delta, 1 );
1990 fixup_rva_dwords( &exports->AddressOfNameOrdinals, delta, 1 );
1991 fixup_rva_dwords( (DWORD *)(addr + exports->AddressOfNames), delta, exports->NumberOfNames );
1992 fixup_rva_ptrs( addr + exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
1994 return STATUS_SUCCESS;
1998 /*************************************************************************
1999 * build_so_dll_module
2001 * Build the module for a .so builtin library.
2003 static NTSTATUS build_so_dll_module( const WCHAR *load_path, const UNICODE_STRING *nt_name,
2004 HMODULE module, DWORD flags, WINE_MODREF **pwm )
2006 IMAGE_NT_HEADERS *nt;
2007 WINE_MODREF *wm;
2008 NTSTATUS status;
2010 if (!(nt = RtlImageNtHeader( module ))) return STATUS_INVALID_IMAGE_FORMAT;
2012 if (!(wm = alloc_module( module, nt_name, TRUE ))) return STATUS_NO_MEMORY;
2014 virtual_create_builtin_view( module );
2016 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
2017 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
2018 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE ||
2019 is_16bit_builtin( module )))
2021 if ((status = fixup_imports( wm, load_path )))
2023 /* the module has only been inserted in the load & memory order lists */
2024 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
2025 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
2026 /* FIXME: free the modref */
2027 return status;
2031 TRACE( "loaded %s %p %p\n", debugstr_us(nt_name), wm, module );
2033 /* send the DLL load event */
2035 SERVER_START_REQ( load_dll )
2037 req->base = wine_server_client_ptr( module );
2038 req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
2039 req->dbg_size = nt->FileHeader.NumberOfSymbols;
2040 req->name = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
2041 wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
2042 wine_server_call( req );
2044 SERVER_END_REQ;
2046 /* setup relay debugging entry points */
2047 if (TRACE_ON(relay)) RELAY_SetupDLL( module );
2049 *pwm = wm;
2050 return STATUS_SUCCESS;
2054 /***********************************************************************
2055 * load_builtin_callback
2057 * Load a library in memory; callback function for wine_dll_register
2059 static void load_builtin_callback( void *module, const char *filename )
2061 static const WCHAR emptyW[1];
2062 const WCHAR *load_path;
2064 if (!module)
2066 ERR("could not map image for %s\n", debugstr_us(builtin_load_info->filename) );
2067 builtin_load_info->status = STATUS_NO_MEMORY;
2068 return;
2071 load_path = builtin_load_info->load_path;
2072 if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
2073 if (!load_path) load_path = emptyW;
2075 builtin_load_info->status = build_so_dll_module( load_path, builtin_load_info->filename, module,
2076 0, &builtin_load_info->wm );
2080 /***********************************************************************
2081 * set_security_cookie
2083 * Create a random security cookie for buffer overflow protection. Make
2084 * sure it does not accidentally match the default cookie value.
2086 static void set_security_cookie( void *module, SIZE_T len )
2088 static ULONG seed;
2089 IMAGE_LOAD_CONFIG_DIRECTORY *loadcfg;
2090 ULONG loadcfg_size;
2091 ULONG_PTR *cookie;
2093 loadcfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &loadcfg_size );
2094 if (!loadcfg) return;
2095 if (loadcfg_size < offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie) + sizeof(loadcfg->SecurityCookie)) return;
2096 if (!loadcfg->SecurityCookie) return;
2097 if (loadcfg->SecurityCookie < (ULONG_PTR)module ||
2098 loadcfg->SecurityCookie > (ULONG_PTR)module + len - sizeof(ULONG_PTR))
2100 WARN( "security cookie %p outside of image %p-%p\n",
2101 (void *)loadcfg->SecurityCookie, module, (char *)module + len );
2102 return;
2105 cookie = (ULONG_PTR *)loadcfg->SecurityCookie;
2106 TRACE( "initializing security cookie %p\n", cookie );
2108 if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
2109 for (;;)
2111 if (*cookie == DEFAULT_SECURITY_COOKIE_16)
2112 *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
2113 else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
2114 *cookie = RtlRandom( &seed );
2115 #ifdef DEFAULT_SECURITY_COOKIE_64
2116 else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
2118 *cookie = RtlRandom( &seed );
2119 /* fill up, but keep the highest word clear */
2120 *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
2122 #endif
2123 else
2124 break;
2128 static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
2130 char *base;
2131 IMAGE_BASE_RELOCATION *rel, *end;
2132 const IMAGE_DATA_DIRECTORY *relocs;
2133 const IMAGE_SECTION_HEADER *sec;
2134 INT_PTR delta;
2135 ULONG protect_old[96], i;
2137 base = (char *)nt->OptionalHeader.ImageBase;
2138 if (module == base) return STATUS_SUCCESS; /* nothing to do */
2140 /* no relocations are performed on non page-aligned binaries */
2141 if (nt->OptionalHeader.SectionAlignment < page_size)
2142 return STATUS_SUCCESS;
2144 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
2145 return STATUS_SUCCESS;
2147 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2149 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
2151 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
2152 base, module );
2153 return STATUS_CONFLICTING_ADDRESSES;
2156 if (!relocs->Size) return STATUS_SUCCESS;
2157 if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;
2159 if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
2160 return STATUS_INVALID_IMAGE_FORMAT;
2162 sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
2163 nt->FileHeader.SizeOfOptionalHeader);
2164 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2166 void *addr = get_rva( module, sec[i].VirtualAddress );
2167 SIZE_T size = sec[i].SizeOfRawData;
2168 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2169 &size, PAGE_READWRITE, &protect_old[i] );
2172 TRACE( "relocating from %p-%p to %p-%p\n",
2173 base, base + len, module, (char *)module + len );
2175 rel = get_rva( module, relocs->VirtualAddress );
2176 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
2177 delta = (char *)module - base;
2179 while (rel < end - 1 && rel->SizeOfBlock)
2181 if (rel->VirtualAddress >= len)
2183 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
2184 return STATUS_ACCESS_VIOLATION;
2186 rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
2187 (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
2188 (USHORT *)(rel + 1), delta );
2189 if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
2192 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2194 void *addr = get_rva( module, sec[i].VirtualAddress );
2195 SIZE_T size = sec[i].SizeOfRawData;
2196 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2197 &size, protect_old[i], &protect_old[i] );
2200 return STATUS_SUCCESS;
2203 #ifdef _WIN64
2204 /* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
2205 static BOOL convert_to_pe64( HMODULE module, const pe_image_info_t *info )
2207 static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
2208 IMAGE_DIRECTORY_ENTRY_SECURITY,
2209 IMAGE_DIRECTORY_ENTRY_BASERELOC,
2210 IMAGE_DIRECTORY_ENTRY_DEBUG,
2211 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
2212 IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
2213 IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
2214 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2215 SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
2216 IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + hdr_size);
2217 SIZE_T size = info->header_size;
2218 void *addr = module;
2219 ULONG i, old_prot;
2221 TRACE( "%p\n", module );
2223 if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
2224 return FALSE;
2226 if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
2228 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2229 return FALSE;
2232 memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
2233 memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
2234 hdr64.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2235 hdr64.AddressOfEntryPoint = 0;
2236 hdr64.ImageBase = hdr32.ImageBase;
2237 hdr64.SizeOfStackReserve = hdr32.SizeOfStackReserve;
2238 hdr64.SizeOfStackCommit = hdr32.SizeOfStackCommit;
2239 hdr64.SizeOfHeapReserve = hdr32.SizeOfHeapReserve;
2240 hdr64.SizeOfHeapCommit = hdr32.SizeOfHeapCommit;
2241 hdr64.LoaderFlags = hdr32.LoaderFlags;
2242 hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
2243 for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
2244 hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];
2246 memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
2247 nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
2248 nt->OptionalHeader = hdr64;
2249 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2250 return TRUE;
2252 #endif
2254 /* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
2255 /* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2256 static BOOL is_valid_binary( HMODULE module, const pe_image_info_t *info )
2258 #ifdef __i386__
2259 return info->machine == IMAGE_FILE_MACHINE_I386;
2260 #elif defined(__arm__)
2261 return info->machine == IMAGE_FILE_MACHINE_ARM ||
2262 info->machine == IMAGE_FILE_MACHINE_THUMB ||
2263 info->machine == IMAGE_FILE_MACHINE_ARMNT;
2264 #elif defined(_WIN64) /* support 32-bit IL-only images on 64-bit */
2265 #ifdef __x86_64__
2266 if (info->machine == IMAGE_FILE_MACHINE_AMD64) return TRUE;
2267 #else
2268 if (info->machine == IMAGE_FILE_MACHINE_ARM64) return TRUE;
2269 #endif
2270 if (!info->contains_code) return TRUE;
2271 if (!(info->image_flags & IMAGE_FLAGS_ComPlusNativeReady))
2273 /* check COM header directly, ignoring runtime version */
2274 DWORD size;
2275 const IMAGE_COR20_HEADER *cor_header = RtlImageDirectoryEntryToData( module, TRUE,
2276 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &size );
2277 if (!cor_header || !(cor_header->Flags & COMIMAGE_FLAGS_ILONLY)) return FALSE;
2279 return convert_to_pe64( module, info );
2280 #else
2281 return FALSE; /* no wow64 support on other platforms */
2282 #endif
2286 /******************************************************************
2287 * get_module_path_end
2289 * Returns the end of the directory component of the module path.
2291 static inline const WCHAR *get_module_path_end( const WCHAR *module )
2293 const WCHAR *p;
2294 const WCHAR *mod_end = module;
2296 if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
2297 if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2298 if (mod_end == module + 2 && module[1] == ':') mod_end++;
2299 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
2300 return mod_end;
2304 /******************************************************************
2305 * append_path
2307 * Append a counted string to the load path. Helper for get_dll_load_path.
2309 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
2311 if (len == -1) len = wcslen(str);
2312 if (!len) return p;
2313 memcpy( p, str, len * sizeof(WCHAR) );
2314 p[len] = ';';
2315 return p + len + 1;
2319 /******************************************************************
2320 * get_dll_load_path
2322 static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2324 static const WCHAR pathW[] = {'P','A','T','H',0};
2326 const WCHAR *mod_end = module;
2327 UNICODE_STRING name, value;
2328 WCHAR *p, *ret;
2329 int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2331 if (module)
2333 mod_end = get_module_path_end( module );
2334 len += (mod_end - module) + 1;
2337 RtlInitUnicodeString( &name, pathW );
2338 value.Length = 0;
2339 value.MaximumLength = 0;
2340 value.Buffer = NULL;
2341 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2342 path_len = value.Length;
2344 if (dll_dir) len += wcslen( dll_dir ) + 1;
2345 else len += 2; /* current directory */
2346 if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2347 return STATUS_NO_MEMORY;
2349 p = append_path( p, module, mod_end - module );
2350 if (dll_dir) p = append_path( p, dll_dir, -1 );
2351 else if (!safe_mode) p = append_path( p, dotW, -1 );
2352 p = append_path( p, system_path, -1 );
2353 if (!dll_dir && safe_mode) p = append_path( p, dotW, -1 );
2355 value.Buffer = p;
2356 value.MaximumLength = path_len;
2358 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2360 WCHAR *new_ptr;
2362 /* grow the buffer and retry */
2363 path_len = value.Length;
2364 if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
2366 RtlFreeHeap( GetProcessHeap(), 0, ret );
2367 return STATUS_NO_MEMORY;
2369 value.Buffer = new_ptr + (value.Buffer - ret);
2370 value.MaximumLength = path_len;
2371 ret = new_ptr;
2373 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
2374 *path = ret;
2375 return STATUS_SUCCESS;
2379 /******************************************************************
2380 * get_dll_load_path_search_flags
2382 static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
2384 const WCHAR *image = NULL, *mod_end, *image_end;
2385 struct dll_dir_entry *dir;
2386 WCHAR *p, *ret;
2387 int len = 1;
2389 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
2390 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
2391 LOAD_LIBRARY_SEARCH_USER_DIRS |
2392 LOAD_LIBRARY_SEARCH_SYSTEM32);
2394 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
2396 DWORD type = RtlDetermineDosPathNameType_U( module );
2397 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2398 return STATUS_INVALID_PARAMETER;
2399 mod_end = get_module_path_end( module );
2400 len += (mod_end - module) + 1;
2402 else module = NULL;
2404 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
2406 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
2407 image_end = get_module_path_end( image );
2408 len += (image_end - image) + 1;
2411 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2413 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2414 len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2415 if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
2418 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2420 if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2422 if (module) p = append_path( p, module, mod_end - module );
2423 if (image) p = append_path( p, image, image_end - image );
2424 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2426 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2427 p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
2428 p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
2430 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2431 else
2433 if (p > ret) p--;
2434 *p = 0;
2437 *path = ret;
2438 return STATUS_SUCCESS;
2442 /***********************************************************************
2443 * open_dll_file
2445 * Open a file for a new dll. Helper for find_dll_file.
2447 static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm,
2448 void **module, pe_image_info_t *image_info, struct stat *st )
2450 FILE_BASIC_INFORMATION info;
2451 OBJECT_ATTRIBUTES attr;
2452 IO_STATUS_BLOCK io;
2453 LARGE_INTEGER size;
2454 SIZE_T len = 0;
2455 NTSTATUS status;
2456 HANDLE handle, mapping;
2457 int fd, needs_close;
2459 if ((*pwm = find_fullname_module( nt_name )))
2461 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2462 *module = NULL;
2463 return STATUS_SUCCESS;
2466 attr.Length = sizeof(attr);
2467 attr.RootDirectory = 0;
2468 attr.Attributes = OBJ_CASE_INSENSITIVE;
2469 attr.ObjectName = nt_name;
2470 attr.SecurityDescriptor = NULL;
2471 attr.SecurityQualityOfService = NULL;
2472 if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2473 FILE_SHARE_READ | FILE_SHARE_DELETE,
2474 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
2476 if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
2477 status != STATUS_OBJECT_NAME_NOT_FOUND &&
2478 !NtQueryAttributesFile( &attr, &info ))
2480 /* if the file exists but failed to open, report the error */
2481 return status;
2483 /* otherwise continue searching */
2484 return STATUS_DLL_NOT_FOUND;
2487 if (!server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))
2489 fstat( fd, st );
2490 if (needs_close) close( fd );
2491 if ((*pwm = find_fileid_module( st )))
2493 TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2494 (*pwm)->ldr.BaseAddress, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2495 NtClose( handle );
2496 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2497 *module = NULL;
2498 return STATUS_SUCCESS;
2502 size.QuadPart = 0;
2503 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2504 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
2505 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
2506 NtClose( handle );
2508 if (!status)
2510 if (*module)
2512 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2513 *module = NULL;
2515 status = virtual_map_section( mapping, module, 0, 0, NULL, &len,
2516 0, PAGE_EXECUTE_READ, image_info );
2517 if (status == STATUS_IMAGE_NOT_AT_BASE) status = STATUS_SUCCESS;
2518 NtClose( mapping );
2520 if (!status && !is_valid_binary( *module, image_info ))
2522 TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->machine );
2523 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2524 *module = NULL;
2525 status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2527 return status;
2531 /******************************************************************************
2532 * load_native_dll (internal)
2534 static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
2535 const pe_image_info_t *image_info, DWORD flags, WINE_MODREF** pwm,
2536 struct stat *st )
2538 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( *module );
2539 WINE_MODREF *wm;
2540 NTSTATUS status;
2541 const char *dll_type = (image_info->image_flags & IMAGE_FLAGS_WineBuiltin) ? "PE builtin" : "native";
2543 TRACE("Trying %s dll %s\n", dll_type, debugstr_us(nt_name) );
2545 /* perform base relocation, if necessary */
2547 if ((status = perform_relocations( *module, nt, image_info->map_size ))) return status;
2549 /* create the MODREF */
2551 if (!(wm = alloc_module( *module, nt_name, (image_info->image_flags & IMAGE_FLAGS_WineBuiltin) )))
2552 return STATUS_NO_MEMORY;
2554 wm->dev = st->st_dev;
2555 wm->ino = st->st_ino;
2556 if (image_info->loader_flags) wm->ldr.Flags |= LDR_COR_IMAGE;
2557 if (image_info->image_flags & IMAGE_FLAGS_ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
2559 set_security_cookie( *module, image_info->map_size );
2561 /* fixup imports */
2563 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
2564 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
2565 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
2567 if (wm->ldr.Flags & LDR_COR_ILONLY)
2568 status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
2569 else
2570 status = fixup_imports( wm, load_path );
2571 if (status != STATUS_SUCCESS)
2573 /* the module has only be inserted in the load & memory order lists */
2574 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
2575 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
2577 /* FIXME: there are several more dangling references
2578 * left. Including dlls loaded by this dll before the
2579 * failed one. Unrolling is rather difficult with the
2580 * current structure and we can leave them lying
2581 * around with no problems, so we don't care.
2582 * As these might reference our wm, we don't free it.
2584 *module = NULL;
2585 return status;
2589 /* send DLL load event */
2591 SERVER_START_REQ( load_dll )
2593 req->base = wine_server_client_ptr( *module );
2594 req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
2595 req->dbg_size = nt->FileHeader.NumberOfSymbols;
2596 req->name = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
2597 wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
2598 wine_server_call( req );
2600 SERVER_END_REQ;
2602 if (image_info->image_flags & IMAGE_FLAGS_WineBuiltin)
2604 if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
2606 else
2608 if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
2611 TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module, dll_type );
2613 wm->ldr.LoadCount = 1;
2614 *pwm = wm;
2615 *module = NULL;
2616 return STATUS_SUCCESS;
2620 /* check if the library is the correct architecture */
2621 /* only returns false for a valid library of the wrong arch */
2622 static int check_library_arch( int fd )
2624 #ifdef __APPLE__
2625 struct /* Mach-O header */
2627 unsigned int magic;
2628 unsigned int cputype;
2629 } header;
2631 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
2632 if (header.magic != 0xfeedface) return 1;
2633 if (sizeof(void *) == sizeof(int)) return !(header.cputype >> 24);
2634 else return (header.cputype >> 24) == 1; /* CPU_ARCH_ABI64 */
2635 #else
2636 struct /* ELF header */
2638 unsigned char magic[4];
2639 unsigned char class;
2640 unsigned char data;
2641 unsigned char version;
2642 } header;
2644 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
2645 if (memcmp( header.magic, "\177ELF", 4 )) return 1;
2646 if (header.version != 1 /* EV_CURRENT */) return 1;
2647 #ifdef WORDS_BIGENDIAN
2648 if (header.data != 2 /* ELFDATA2MSB */) return 1;
2649 #else
2650 if (header.data != 1 /* ELFDATA2LSB */) return 1;
2651 #endif
2652 if (sizeof(void *) == sizeof(int)) return header.class == 1; /* ELFCLASS32 */
2653 else return header.class == 2; /* ELFCLASS64 */
2654 #endif
2657 static inline char *prepend( char *buffer, const char *str, size_t len )
2659 return memcpy( buffer - len, str, len );
2662 /***********************************************************************
2663 * open_builtin_file
2665 static NTSTATUS open_builtin_file( char *name, WINE_MODREF **pwm, void **module,
2666 pe_image_info_t *image_info, struct stat *st, char **so_name )
2668 ANSI_STRING strA;
2669 UNICODE_STRING nt_name;
2670 NTSTATUS status;
2671 int fd;
2673 nt_name.Buffer = NULL;
2674 RtlInitString( &strA, name );
2675 if ((status = wine_unix_to_nt_file_name( &strA, &nt_name ))) return status;
2677 status = open_dll_file( &nt_name, pwm, module, image_info, st );
2678 RtlFreeUnicodeString( &nt_name );
2680 /* ignore non-builtins */
2681 if (!status && !*pwm && !(image_info->image_flags & IMAGE_FLAGS_WineBuiltin))
2683 WARN( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_a(name) );
2684 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2685 *module = NULL;
2686 status = STATUS_DLL_NOT_FOUND;
2689 if (status != STATUS_DLL_NOT_FOUND) return status;
2691 /* try .so file */
2693 strcat( name, ".so" );
2694 if ((fd = open( name, O_RDONLY )) != -1)
2696 if (check_library_arch( fd ))
2698 if ((*so_name = RtlAllocateHeap( GetProcessHeap(), 0, strlen(name) + 1 )))
2699 strcpy( *so_name, name );
2700 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2701 *module = NULL;
2702 status = STATUS_SUCCESS;
2704 else status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2705 close( fd );
2707 return status;
2711 /***********************************************************************
2712 * find_builtin_dll
2714 static NTSTATUS find_builtin_dll( const WCHAR *name, WINE_MODREF **pwm,
2715 void **module, pe_image_info_t *image_info, struct stat *st,
2716 char **so_name )
2718 const char *path, *build_dir = wine_get_build_dir();
2719 unsigned int i, pos, len, namelen, maxlen = 0;
2720 char *ptr, *file;
2721 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2722 BOOL found_image = FALSE;
2724 len = wcslen( name );
2725 if (build_dir) maxlen = strlen(build_dir) + sizeof("/programs/") + len;
2726 for (i = 0; (path = wine_dll_enum_load_path( i )); i++) maxlen = max( maxlen, strlen(path)+1 );
2727 maxlen += len + sizeof(".so");
2729 if (!(file = RtlAllocateHeap( GetProcessHeap(), 0, maxlen ))) return STATUS_NO_MEMORY;
2731 pos = maxlen - len - sizeof(".so");
2732 /* we don't want to depend on the current codepage here */
2733 for (i = 0; i < len; i++)
2735 if (name[i] > 127) goto done;
2736 file[pos + i] = (char)name[i];
2737 if (file[pos + i] >= 'A' && file[pos + i] <= 'Z') file[pos + i] += 'a' - 'A';
2739 file[--pos] = '/';
2741 if (build_dir)
2743 /* try as a dll */
2744 ptr = file + pos;
2745 namelen = len + 1;
2746 file[pos + len + 1] = 0;
2747 if (namelen > 4 && !memcmp( ptr + namelen - 4, ".dll", 4 )) namelen -= 4;
2748 ptr = prepend( ptr, ptr, namelen );
2749 ptr = prepend( ptr, "/dlls", sizeof("/dlls") - 1 );
2750 ptr = prepend( ptr, build_dir, strlen(build_dir) );
2751 status = open_builtin_file( ptr, pwm, module, image_info, st, so_name );
2752 if (status != STATUS_DLL_NOT_FOUND) goto done;
2754 /* now as a program */
2755 ptr = file + pos;
2756 namelen = len + 1;
2757 file[pos + len + 1] = 0;
2758 if (namelen > 4 && !memcmp( ptr + namelen - 4, ".exe", 4 )) namelen -= 4;
2759 ptr = prepend( ptr, ptr, namelen );
2760 ptr = prepend( ptr, "/programs", sizeof("/programs") - 1 );
2761 ptr = prepend( ptr, build_dir, strlen(build_dir) );
2762 status = open_builtin_file( ptr, pwm, module, image_info, st, so_name );
2763 if (status != STATUS_DLL_NOT_FOUND) goto done;
2766 for (i = 0; (path = wine_dll_enum_load_path( i )); i++)
2768 file[pos + len + 1] = 0;
2769 ptr = prepend( file + pos, path, strlen(path) );
2770 status = open_builtin_file( ptr, pwm, module, image_info, st, so_name );
2771 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2772 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2775 if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2776 WARN( "cannot find builtin library for %s\n", debugstr_w(name) );
2778 done:
2779 RtlFreeHeap( GetProcessHeap(), 0, file );
2780 return status;
2784 /***********************************************************************
2785 * load_so_dll
2787 static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2788 const char *so_name, DWORD flags, WINE_MODREF** pwm )
2790 static const WCHAR soW[] = {'.','s','o',0};
2791 DWORD len;
2792 void *handle;
2793 const IMAGE_NT_HEADERS *nt;
2794 struct builtin_load_info info, *prev_info;
2795 ANSI_STRING unix_name;
2796 UNICODE_STRING win_name = *nt_name;
2798 unix_name.Buffer = NULL;
2799 info.load_path = load_path;
2800 info.filename = &win_name;
2801 info.status = STATUS_SUCCESS;
2802 info.wm = NULL;
2804 if (!so_name)
2806 if (wine_nt_to_unix_file_name( nt_name, &unix_name, FILE_OPEN, FALSE ))
2807 return STATUS_DLL_NOT_FOUND;
2809 /* remove .so extension from Windows name */
2810 len = nt_name->Length / sizeof(WCHAR);
2811 if (len > 3 && !wcsicmp( nt_name->Buffer + len - 3, soW )) win_name.Length -= 3 * sizeof(WCHAR);
2814 TRACE( "loading %s from so lib %s\n", debugstr_us(&win_name),
2815 debugstr_a( so_name ? so_name : unix_name.Buffer ));
2817 prev_info = builtin_load_info;
2818 builtin_load_info = &info;
2819 handle = dlopen( so_name ? so_name : unix_name.Buffer, RTLD_NOW );
2820 builtin_load_info = prev_info;
2821 RtlFreeHeap( GetProcessHeap(), 0, unix_name.Buffer );
2823 if (!handle)
2825 if (so_name)
2827 ERR("failed to load .so lib %s: %s\n", debugstr_a(so_name), dlerror() );
2828 info.status = STATUS_PROCEDURE_NOT_FOUND;
2830 else
2832 WARN( "failed to load .so lib %s: %s\n", debugstr_us(nt_name), dlerror() );
2833 info.status = STATUS_INVALID_IMAGE_FORMAT;
2837 if (info.status != STATUS_SUCCESS) goto failed;
2839 if (!info.wm && (nt = dlsym( handle, "__wine_spec_nt_header" )))
2841 HMODULE module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
2842 if ((info.wm = get_modref( module ))) /* already loaded */
2844 TRACE( "Found %s at %p for builtin %s\n",
2845 debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress,
2846 debugstr_us(nt_name) );
2847 if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
2848 dlclose( handle );
2850 else
2852 if ((info.status = map_so_dll( nt, module ))) goto failed;
2853 if ((info.status = build_so_dll_module( load_path, &win_name, module, flags, &info.wm )))
2854 goto failed;
2855 TRACE_(loaddll)( "Loaded %s at %p: builtin\n",
2856 debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress );
2857 info.wm->ldr.LoadCount = 1;
2858 info.wm->so_handle = handle;
2861 else if (!info.wm)
2863 /* The constructor wasn't called, this means the .so is already
2864 * loaded under a different name. Try to find the wm for it. */
2866 if (!(info.wm = find_so_module( handle )))
2868 info.status = STATUS_INVALID_IMAGE_FORMAT;
2869 goto failed;
2871 TRACE( "Found %s at %p for builtin %s\n",
2872 debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress,
2873 debugstr_us(nt_name) );
2874 if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
2875 dlclose( handle ); /* release the libdl refcount */
2877 else
2879 TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress );
2880 info.wm->ldr.LoadCount = 1;
2881 info.wm->so_handle = handle;
2884 *pwm = info.wm;
2885 return STATUS_SUCCESS;
2887 failed:
2888 if (handle) dlclose( handle );
2889 return info.status;
2893 /***********************************************************************
2894 * load_builtin_dll
2896 static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module_ptr,
2897 DWORD flags, WINE_MODREF** pwm )
2899 const WCHAR *name, *p;
2900 NTSTATUS status;
2901 void *module = NULL;
2902 pe_image_info_t image_info;
2903 struct stat st;
2904 char *so_name;
2906 /* Fix the name in case we have a full path and extension */
2907 name = nt_name->Buffer;
2908 if ((p = wcsrchr( name, '\\' ))) name = p + 1;
2909 if ((p = wcsrchr( name, '/' ))) name = p + 1;
2911 TRACE("Trying built-in %s\n", debugstr_w(name));
2913 if (!module_ptr) module_ptr = &module;
2915 status = find_builtin_dll( name, pwm, module_ptr, &image_info, &st, &so_name );
2916 if (status) return status;
2918 if (*pwm)
2920 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2921 TRACE( "Found %s for %s at %p, count=%d\n",
2922 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(name),
2923 (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
2924 return STATUS_SUCCESS;
2927 if (*module_ptr)
2929 TRACE( "loading %s from PE builtin %s\n", debugstr_w(name), debugstr_us(nt_name) );
2930 return load_native_dll( load_path, nt_name, module_ptr, &image_info, flags, pwm, &st );
2933 status = load_so_dll( load_path, nt_name, so_name, flags, pwm );
2934 RtlFreeHeap( GetProcessHeap(), 0, so_name );
2935 return status;
2939 /***********************************************************************
2940 * find_actctx_dll
2942 * Find the full path (if any) of the dll from the activation context.
2944 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
2946 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
2947 static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
2949 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
2950 ACTCTX_SECTION_KEYED_DATA data;
2951 UNICODE_STRING nameW;
2952 NTSTATUS status;
2953 SIZE_T needed, size = 1024;
2954 WCHAR *p;
2956 RtlInitUnicodeString( &nameW, libname );
2957 data.cbSize = sizeof(data);
2958 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2959 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
2960 &nameW, &data );
2961 if (status != STATUS_SUCCESS) return status;
2963 for (;;)
2965 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2967 status = STATUS_NO_MEMORY;
2968 goto done;
2970 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
2971 AssemblyDetailedInformationInActivationContext,
2972 info, size, &needed );
2973 if (status == STATUS_SUCCESS) break;
2974 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
2975 RtlFreeHeap( GetProcessHeap(), 0, info );
2976 size = needed;
2977 /* restart with larger buffer */
2980 if (!info->lpAssemblyManifestPath)
2982 status = STATUS_SXS_KEY_NOT_FOUND;
2983 goto done;
2986 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2988 DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2989 p++;
2990 len = wcslen( p );
2991 if (!dirlen || len <= dirlen ||
2992 RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2993 wcsicmp( p + dirlen, dotManifestW ))
2995 /* manifest name does not match directory name, so it's not a global
2996 * windows/winsxs manifest; use the manifest directory name instead */
2997 dirlen = p - info->lpAssemblyManifestPath;
2998 needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
2999 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
3001 status = STATUS_NO_MEMORY;
3002 goto done;
3004 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
3005 p += dirlen;
3006 wcscpy( p, libname );
3007 goto done;
3011 if (!info->lpAssemblyDirectoryName)
3013 status = STATUS_SXS_KEY_NOT_FOUND;
3014 goto done;
3017 needed = (wcslen(user_shared_data->NtSystemRoot) * sizeof(WCHAR) +
3018 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
3020 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
3022 status = STATUS_NO_MEMORY;
3023 goto done;
3025 wcscpy( p, user_shared_data->NtSystemRoot );
3026 p += wcslen(p);
3027 memcpy( p, winsxsW, sizeof(winsxsW) );
3028 p += ARRAY_SIZE( winsxsW );
3029 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
3030 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
3031 *p++ = '\\';
3032 wcscpy( p, libname );
3033 done:
3034 RtlFreeHeap( GetProcessHeap(), 0, info );
3035 RtlReleaseActivationContext( data.hActCtx );
3036 return status;
3040 /***********************************************************************
3041 * search_dll_file
3043 * Search for dll in the specified paths.
3045 static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
3046 WINE_MODREF **pwm, void **module, pe_image_info_t *image_info,
3047 struct stat *st )
3049 WCHAR *name;
3050 BOOL found_image = FALSE;
3051 NTSTATUS status = STATUS_DLL_NOT_FOUND;
3052 ULONG len = wcslen( paths );
3054 if (len < wcslen( system_dir )) len = wcslen( system_dir );
3055 len += wcslen( search ) + 2;
3057 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
3058 return STATUS_NO_MEMORY;
3060 while (*paths)
3062 LPCWSTR ptr = paths;
3064 while (*ptr && *ptr != ';') ptr++;
3065 len = ptr - paths;
3066 if (*ptr == ';') ptr++;
3067 memcpy( name, paths, len * sizeof(WCHAR) );
3068 if (len && name[len - 1] != '\\') name[len++] = '\\';
3069 wcscpy( name + len, search );
3071 nt_name->Buffer = NULL;
3072 if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
3074 status = open_dll_file( nt_name, pwm, module, image_info, st );
3075 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
3076 else if (status != STATUS_DLL_NOT_FOUND) goto done;
3077 RtlFreeUnicodeString( nt_name );
3078 paths = ptr;
3081 if (!found_image)
3083 /* not found, return file in the system dir to be loaded as builtin */
3084 wcscpy( name, system_dir );
3085 wcscat( name, search );
3086 if (!RtlDosPathNameToNtPathName_U( name, nt_name, NULL, NULL )) status = STATUS_NO_MEMORY;
3088 else status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
3090 done:
3091 RtlFreeHeap( GetProcessHeap(), 0, name );
3092 return status;
3096 /***********************************************************************
3097 * find_dll_file
3099 * Find the file (or already loaded module) for a given dll name.
3101 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
3102 UNICODE_STRING *nt_name, WINE_MODREF **pwm,
3103 void **module, pe_image_info_t *image_info, struct stat *st )
3105 WCHAR *ext, *dllname;
3106 NTSTATUS status;
3107 ULONG wow64_old_value = 0;
3109 *pwm = NULL;
3110 *module = NULL;
3111 dllname = NULL;
3113 if (default_ext) /* first append default extension */
3115 if (!(ext = wcsrchr( libname, '.')) || wcschr( ext, '/' ) || wcschr( ext, '\\'))
3117 if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
3118 (wcslen(libname)+wcslen(default_ext)+1) * sizeof(WCHAR))))
3119 return STATUS_NO_MEMORY;
3120 wcscpy( dllname, libname );
3121 wcscat( dllname, default_ext );
3122 libname = dllname;
3126 /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
3127 if (is_wow64) RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
3129 nt_name->Buffer = NULL;
3131 if (!contains_path( libname ))
3133 WCHAR *fullname = NULL;
3135 status = find_actctx_dll( libname, &fullname );
3136 if (status == STATUS_SUCCESS)
3138 TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
3139 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3140 libname = dllname = fullname;
3142 else
3144 if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
3145 if ((*pwm = find_basename_module( libname )) != NULL)
3147 status = STATUS_SUCCESS;
3148 goto done;
3153 if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
3154 status = search_dll_file( load_path, libname, nt_name, pwm, module, image_info, st );
3155 else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
3156 status = open_dll_file( nt_name, pwm, module, image_info, st );
3158 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT;
3160 done:
3161 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3162 if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
3163 return status;
3167 /***********************************************************************
3168 * load_dll (internal)
3170 * Load a PE style module according to the load order.
3171 * The loader_section must be locked while calling this function.
3173 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
3174 DWORD flags, WINE_MODREF** pwm )
3176 enum loadorder loadorder;
3177 WINE_MODREF *main_exe;
3178 UNICODE_STRING nt_name;
3179 struct stat st;
3180 void *module;
3181 pe_image_info_t image_info;
3182 NTSTATUS nts;
3184 TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
3186 nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &module, &image_info, &st );
3188 if (*pwm) /* found already loaded module */
3190 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
3192 TRACE("Found %s for %s at %p, count=%d\n",
3193 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
3194 (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
3195 RtlFreeUnicodeString( &nt_name );
3196 return STATUS_SUCCESS;
3199 if (nts && nts != STATUS_DLL_NOT_FOUND && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
3201 main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3202 loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, &nt_name );
3204 switch (nts)
3206 case STATUS_INVALID_IMAGE_NOT_MZ: /* not in PE format, maybe it's a .so file */
3207 switch (loadorder)
3209 case LO_NATIVE:
3210 case LO_NATIVE_BUILTIN:
3211 case LO_BUILTIN:
3212 case LO_BUILTIN_NATIVE:
3213 case LO_DEFAULT:
3214 if (!load_so_dll( load_path, &nt_name, NULL, flags, pwm )) nts = STATUS_SUCCESS;
3215 break;
3216 default:
3217 nts = STATUS_DLL_NOT_FOUND;
3218 break;
3220 break;
3222 case STATUS_SUCCESS: /* valid PE file */
3223 if (image_info.image_flags & IMAGE_FLAGS_WineBuiltin)
3225 switch (loadorder)
3227 case LO_NATIVE_BUILTIN:
3228 case LO_BUILTIN:
3229 case LO_BUILTIN_NATIVE:
3230 case LO_DEFAULT:
3231 nts = load_builtin_dll( load_path, &nt_name, &module, flags, pwm );
3232 if (nts == STATUS_DLL_NOT_FOUND)
3233 nts = load_native_dll( load_path, &nt_name, &module, &image_info, flags, pwm, &st );
3234 break;
3235 default:
3236 nts = STATUS_DLL_NOT_FOUND;
3237 break;
3239 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
3240 break;
3242 if (!(image_info.image_flags & IMAGE_FLAGS_WineFakeDll))
3244 switch (loadorder)
3246 case LO_NATIVE:
3247 case LO_NATIVE_BUILTIN:
3248 nts = load_native_dll( load_path, &nt_name, &module, &image_info, flags, pwm, &st );
3249 break;
3250 case LO_BUILTIN:
3251 nts = load_builtin_dll( load_path, &nt_name, &module, flags, pwm );
3252 break;
3253 case LO_BUILTIN_NATIVE:
3254 case LO_DEFAULT:
3255 nts = load_builtin_dll( load_path, &nt_name, &module, flags, pwm );
3256 if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT &&
3257 (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS))
3259 /* stub-only dll, try native */
3260 TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_us(&nt_name) );
3261 LdrUnloadDll( (*pwm)->ldr.BaseAddress );
3262 nts = STATUS_DLL_NOT_FOUND;
3263 /* map the dll again if it was unmapped */
3264 if (!module && open_dll_file( &nt_name, pwm, &module, &image_info, &st )) break;
3266 if (nts == STATUS_DLL_NOT_FOUND)
3267 nts = load_native_dll( load_path, &nt_name, &module, &image_info, flags, pwm, &st );
3268 break;
3269 default:
3270 nts = STATUS_DLL_NOT_FOUND;
3271 break;
3273 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
3274 break;
3276 TRACE( "%s is a fake Wine dll\n", debugstr_us(&nt_name) );
3277 NtUnmapViewOfSection( NtCurrentProcess(), module );
3278 /* fall through */
3280 case STATUS_DLL_NOT_FOUND: /* no file found, try builtin */
3281 switch (loadorder)
3283 case LO_NATIVE_BUILTIN:
3284 case LO_BUILTIN:
3285 case LO_BUILTIN_NATIVE:
3286 case LO_DEFAULT:
3287 nts = load_builtin_dll( load_path, &nt_name, NULL, flags, pwm );
3288 break;
3289 default:
3290 nts = STATUS_DLL_NOT_FOUND;
3291 break;
3293 break;
3296 done:
3297 if (nts == STATUS_SUCCESS)
3298 TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.BaseAddress);
3299 else
3300 WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
3302 RtlFreeUnicodeString( &nt_name );
3303 return nts;
3306 /******************************************************************
3307 * LdrLoadDll (NTDLL.@)
3309 NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
3310 const UNICODE_STRING *libname, HMODULE* hModule)
3312 WINE_MODREF *wm;
3313 NTSTATUS nts;
3315 RtlEnterCriticalSection( &loader_section );
3317 if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
3318 nts = load_dll( path_name, libname->Buffer, dllW, flags, &wm );
3320 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
3322 nts = process_attach( wm, NULL );
3323 if (nts != STATUS_SUCCESS)
3325 LdrUnloadDll(wm->ldr.BaseAddress);
3326 wm = NULL;
3329 *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
3331 RtlLeaveCriticalSection( &loader_section );
3332 return nts;
3336 /******************************************************************
3337 * LdrGetDllHandle (NTDLL.@)
3339 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
3341 NTSTATUS status;
3342 UNICODE_STRING nt_name;
3343 WINE_MODREF *wm;
3344 void *module;
3345 pe_image_info_t image_info;
3346 struct stat st;
3348 RtlEnterCriticalSection( &loader_section );
3350 if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
3352 status = find_dll_file( load_path, name->Buffer, dllW, &nt_name, &wm, &module, &image_info, &st );
3354 if (wm) *base = wm->ldr.BaseAddress;
3355 else
3357 if (status == STATUS_SUCCESS) NtUnmapViewOfSection( NtCurrentProcess(), module );
3358 status = STATUS_DLL_NOT_FOUND;
3360 RtlFreeUnicodeString( &nt_name );
3362 RtlLeaveCriticalSection( &loader_section );
3363 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
3364 return status;
3368 /******************************************************************
3369 * LdrAddRefDll (NTDLL.@)
3371 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
3373 NTSTATUS ret = STATUS_SUCCESS;
3374 WINE_MODREF *wm;
3376 if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %x not implemented\n", module, flags );
3378 RtlEnterCriticalSection( &loader_section );
3380 if ((wm = get_modref( module )))
3382 if (flags & LDR_ADDREF_DLL_PIN)
3383 wm->ldr.LoadCount = -1;
3384 else
3385 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3386 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3388 else ret = STATUS_INVALID_PARAMETER;
3390 RtlLeaveCriticalSection( &loader_section );
3391 return ret;
3395 /***********************************************************************
3396 * LdrProcessRelocationBlock (NTDLL.@)
3398 * Apply relocations to a given page of a mapped PE image.
3400 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3401 USHORT *relocs, INT_PTR delta )
3403 while (count--)
3405 USHORT offset = *relocs & 0xfff;
3406 int type = *relocs >> 12;
3407 switch(type)
3409 case IMAGE_REL_BASED_ABSOLUTE:
3410 break;
3411 case IMAGE_REL_BASED_HIGH:
3412 *(short *)((char *)page + offset) += HIWORD(delta);
3413 break;
3414 case IMAGE_REL_BASED_LOW:
3415 *(short *)((char *)page + offset) += LOWORD(delta);
3416 break;
3417 case IMAGE_REL_BASED_HIGHLOW:
3418 *(int *)((char *)page + offset) += delta;
3419 break;
3420 #ifdef _WIN64
3421 case IMAGE_REL_BASED_DIR64:
3422 *(INT_PTR *)((char *)page + offset) += delta;
3423 break;
3424 #elif defined(__arm__)
3425 case IMAGE_REL_BASED_THUMB_MOV32:
3427 DWORD inst = *(INT_PTR *)((char *)page + offset);
3428 DWORD imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
3429 ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
3430 DWORD hi_delta;
3432 if ((inst & 0x8000fbf0) != 0x0000f240)
3433 ERR("wrong Thumb2 instruction %08x, expected MOVW\n", inst);
3435 imm16 += LOWORD(delta);
3436 hi_delta = HIWORD(delta) + HIWORD(imm16);
3437 *(INT_PTR *)((char *)page + offset) = (inst & 0x8f00fbf0) + ((imm16 >> 1) & 0x0400) +
3438 ((imm16 >> 12) & 0x000f) +
3439 ((imm16 << 20) & 0x70000000) +
3440 ((imm16 << 16) & 0xff0000);
3442 if (hi_delta != 0)
3444 inst = *(INT_PTR *)((char *)page + offset + 4);
3445 imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
3446 ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
3448 if ((inst & 0x8000fbf0) != 0x0000f2c0)
3449 ERR("wrong Thumb2 instruction %08x, expected MOVT\n", inst);
3451 imm16 += hi_delta;
3452 if (imm16 > 0xffff)
3453 ERR("resulting immediate value won't fit: %08x\n", imm16);
3454 *(INT_PTR *)((char *)page + offset + 4) = (inst & 0x8f00fbf0) +
3455 ((imm16 >> 1) & 0x0400) +
3456 ((imm16 >> 12) & 0x000f) +
3457 ((imm16 << 20) & 0x70000000) +
3458 ((imm16 << 16) & 0xff0000);
3461 break;
3462 #endif
3463 default:
3464 FIXME("Unknown/unsupported fixup type %x.\n", type);
3465 return NULL;
3467 relocs++;
3469 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
3473 /******************************************************************
3474 * LdrQueryProcessModuleInformation
3477 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi,
3478 ULONG buf_size, ULONG* req_size)
3480 SYSTEM_MODULE* sm = &smi->Modules[0];
3481 ULONG size = sizeof(ULONG);
3482 NTSTATUS nts = STATUS_SUCCESS;
3483 ANSI_STRING str;
3484 char* ptr;
3485 PLIST_ENTRY mark, entry;
3486 PLDR_MODULE mod;
3487 WORD id = 0;
3489 smi->ModulesCount = 0;
3491 RtlEnterCriticalSection( &loader_section );
3492 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3493 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3495 mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
3496 size += sizeof(*sm);
3497 if (size <= buf_size)
3499 sm->Section = 0; /* FIXME */
3500 sm->MappedBaseAddress = mod->BaseAddress;
3501 sm->ImageBaseAddress = mod->BaseAddress;
3502 sm->ImageSize = mod->SizeOfImage;
3503 sm->Flags = mod->Flags;
3504 sm->LoadOrderIndex = id++;
3505 sm->InitOrderIndex = 0; /* FIXME */
3506 sm->LoadCount = mod->LoadCount;
3507 str.Length = 0;
3508 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
3509 str.Buffer = (char*)sm->Name;
3510 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
3511 ptr = strrchr(str.Buffer, '\\');
3512 sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3514 smi->ModulesCount++;
3515 sm++;
3517 else nts = STATUS_INFO_LENGTH_MISMATCH;
3519 RtlLeaveCriticalSection( &loader_section );
3521 if (req_size) *req_size = size;
3523 return nts;
3527 static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, ULONG *value )
3529 NTSTATUS status;
3530 UNICODE_STRING str;
3531 ULONG size;
3532 WCHAR buffer[64];
3533 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3535 RtlInitUnicodeString( &str, name );
3537 size = sizeof(buffer) - sizeof(WCHAR);
3538 if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
3539 return status;
3541 if (info->Type != REG_DWORD)
3543 buffer[size / sizeof(WCHAR)] = 0;
3544 *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3546 else memcpy( value, info->Data, sizeof(*value) );
3547 return status;
3550 static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
3551 void *data, ULONG in_size, ULONG *out_size )
3553 NTSTATUS status;
3554 UNICODE_STRING str;
3555 ULONG size;
3556 char *buffer;
3557 KEY_VALUE_PARTIAL_INFORMATION *info;
3558 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
3560 RtlInitUnicodeString( &str, name );
3562 size = info_size + in_size;
3563 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
3564 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3565 status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
3566 if (!status || status == STATUS_BUFFER_OVERFLOW)
3568 if (out_size) *out_size = info->DataLength;
3569 if (data && !status) memcpy( data, info->Data, info->DataLength );
3571 RtlFreeHeap( GetProcessHeap(), 0, buffer );
3572 return status;
3576 /******************************************************************
3577 * LdrQueryImageFileExecutionOptions (NTDLL.@)
3579 NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
3580 void *data, ULONG in_size, ULONG *out_size )
3582 static const WCHAR optionsW[] = {'M','a','c','h','i','n','e','\\',
3583 'S','o','f','t','w','a','r','e','\\',
3584 'M','i','c','r','o','s','o','f','t','\\',
3585 'W','i','n','d','o','w','s',' ','N','T','\\',
3586 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3587 'I','m','a','g','e',' ','F','i','l','e',' ',
3588 'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
3589 WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3590 OBJECT_ATTRIBUTES attr;
3591 UNICODE_STRING name_str;
3592 HANDLE hkey;
3593 NTSTATUS status;
3594 ULONG len;
3595 WCHAR *p;
3597 attr.Length = sizeof(attr);
3598 attr.RootDirectory = 0;
3599 attr.ObjectName = &name_str;
3600 attr.Attributes = OBJ_CASE_INSENSITIVE;
3601 attr.SecurityDescriptor = NULL;
3602 attr.SecurityQualityOfService = NULL;
3604 p = key->Buffer + key->Length / sizeof(WCHAR);
3605 while (p > key->Buffer && p[-1] != '\\') p--;
3606 len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
3607 name_str.Buffer = path;
3608 name_str.Length = sizeof(optionsW) + len;
3609 name_str.MaximumLength = name_str.Length;
3610 memcpy( path, optionsW, sizeof(optionsW) );
3611 memcpy( path + ARRAY_SIZE( optionsW ), p, len );
3612 if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
3614 if (type == REG_DWORD)
3616 if (out_size) *out_size = sizeof(ULONG);
3617 if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
3618 else status = STATUS_BUFFER_OVERFLOW;
3620 else status = query_string_option( hkey, value, type, data, in_size, out_size );
3622 NtClose( hkey );
3623 return status;
3627 /******************************************************************
3628 * RtlDllShutdownInProgress (NTDLL.@)
3630 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
3632 return process_detaching;
3635 /****************************************************************************
3636 * LdrResolveDelayLoadedAPI (NTDLL.@)
3638 void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3639 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
3640 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3641 IMAGE_THUNK_DATA* addr, ULONG flags )
3643 IMAGE_THUNK_DATA *pIAT, *pINT;
3644 DELAYLOAD_INFO delayinfo;
3645 UNICODE_STRING mod;
3646 const CHAR* name;
3647 HMODULE *phmod;
3648 NTSTATUS nts;
3649 FARPROC fp;
3650 DWORD id;
3652 TRACE( "(%p, %p, %p, %p, %p, 0x%08x)\n", base, desc, dllhook, syshook, addr, flags );
3654 phmod = get_rva(base, desc->ModuleHandleRVA);
3655 pIAT = get_rva(base, desc->ImportAddressTableRVA);
3656 pINT = get_rva(base, desc->ImportNameTableRVA);
3657 name = get_rva(base, desc->DllNameRVA);
3658 id = addr - pIAT;
3660 if (!*phmod)
3662 if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
3664 nts = STATUS_NO_MEMORY;
3665 goto fail;
3667 nts = LdrLoadDll(NULL, 0, &mod, phmod);
3668 RtlFreeUnicodeString(&mod);
3669 if (nts) goto fail;
3672 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3673 nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
3674 else
3676 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3677 ANSI_STRING fnc;
3679 RtlInitAnsiString(&fnc, (char*)iibn->Name);
3680 nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
3682 if (!nts)
3684 pIAT[id].u1.Function = (ULONG_PTR)fp;
3685 return fp;
3688 fail:
3689 delayinfo.Size = sizeof(delayinfo);
3690 delayinfo.DelayloadDescriptor = desc;
3691 delayinfo.ThunkAddress = addr;
3692 delayinfo.TargetDllName = name;
3693 delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
3694 delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
3695 delayinfo.TargetModuleBase = *phmod;
3696 delayinfo.Unused = NULL;
3697 delayinfo.LastError = nts;
3699 if (dllhook)
3700 return dllhook(4, &delayinfo);
3702 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3704 DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
3705 return syshook(name, (const char *)ord);
3707 else
3709 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3710 return syshook(name, (const char *)iibn->Name);
3714 /******************************************************************
3715 * LdrShutdownProcess (NTDLL.@)
3718 void WINAPI LdrShutdownProcess(void)
3720 TRACE("()\n");
3721 process_detaching = TRUE;
3722 process_detach();
3726 /******************************************************************
3727 * RtlExitUserProcess (NTDLL.@)
3729 void WINAPI RtlExitUserProcess( DWORD status )
3731 RtlEnterCriticalSection( &loader_section );
3732 RtlAcquirePebLock();
3733 NtTerminateProcess( 0, status );
3734 LdrShutdownProcess();
3735 NtTerminateProcess( GetCurrentProcess(), status );
3736 exit( get_unix_exit_code( status ));
3739 /******************************************************************
3740 * LdrShutdownThread (NTDLL.@)
3743 void WINAPI LdrShutdownThread(void)
3745 PLIST_ENTRY mark, entry;
3746 PLDR_MODULE mod;
3747 UINT i;
3748 void **pointers;
3750 TRACE("()\n");
3752 /* don't do any detach calls if process is exiting */
3753 if (process_detaching) return;
3755 RtlEnterCriticalSection( &loader_section );
3757 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3758 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3760 mod = CONTAINING_RECORD(entry, LDR_MODULE,
3761 InInitializationOrderModuleList);
3762 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3763 continue;
3764 if ( mod->Flags & LDR_NO_DLL_CALLS )
3765 continue;
3767 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
3768 DLL_THREAD_DETACH, NULL );
3771 RtlAcquirePebLock();
3772 RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3773 RtlReleasePebLock();
3775 if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
3777 for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
3778 RtlFreeHeap( GetProcessHeap(), 0, pointers );
3780 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->FlsSlots );
3781 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3782 RtlLeaveCriticalSection( &loader_section );
3786 /***********************************************************************
3787 * free_modref
3790 static void free_modref( WINE_MODREF *wm )
3792 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
3793 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
3794 if (wm->ldr.InInitializationOrderModuleList.Flink)
3795 RemoveEntryList(&wm->ldr.InInitializationOrderModuleList);
3797 TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
3798 if (!TRACE_ON(module))
3799 TRACE_(loaddll)("Unloaded module %s : %s\n",
3800 debugstr_w(wm->ldr.FullDllName.Buffer),
3801 (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
3803 SERVER_START_REQ( unload_dll )
3805 req->base = wine_server_client_ptr( wm->ldr.BaseAddress );
3806 wine_server_call( req );
3808 SERVER_END_REQ;
3810 free_tls_slot( &wm->ldr );
3811 RtlReleaseActivationContext( wm->ldr.ActivationContext );
3812 if (wm->so_handle) dlclose( wm->so_handle );
3813 NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
3814 if (cached_modref == wm) cached_modref = NULL;
3815 RtlFreeUnicodeString( &wm->ldr.FullDllName );
3816 RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
3817 RtlFreeHeap( GetProcessHeap(), 0, wm );
3820 /***********************************************************************
3821 * MODULE_FlushModrefs
3823 * Remove all unused modrefs and call the internal unloading routines
3824 * for the library type.
3826 * The loader_section must be locked while calling this function.
3828 static void MODULE_FlushModrefs(void)
3830 PLIST_ENTRY mark, entry, prev;
3831 PLDR_MODULE mod;
3832 WINE_MODREF*wm;
3834 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3835 for (entry = mark->Blink; entry != mark; entry = prev)
3837 mod = CONTAINING_RECORD(entry, LDR_MODULE, InInitializationOrderModuleList);
3838 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3839 prev = entry->Blink;
3840 if (!mod->LoadCount) free_modref( wm );
3843 /* check load order list too for modules that haven't been initialized yet */
3844 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3845 for (entry = mark->Blink; entry != mark; entry = prev)
3847 mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
3848 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3849 prev = entry->Blink;
3850 if (!mod->LoadCount) free_modref( wm );
3854 /***********************************************************************
3855 * MODULE_DecRefCount
3857 * The loader_section must be locked while calling this function.
3859 static void MODULE_DecRefCount( WINE_MODREF *wm )
3861 int i;
3863 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3864 return;
3866 if ( wm->ldr.LoadCount <= 0 )
3867 return;
3869 --wm->ldr.LoadCount;
3870 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3872 if ( wm->ldr.LoadCount == 0 )
3874 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
3876 for ( i = 0; i < wm->nDeps; i++ )
3877 if ( wm->deps[i] )
3878 MODULE_DecRefCount( wm->deps[i] );
3880 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
3882 module_push_unload_trace( &wm->ldr );
3886 /******************************************************************
3887 * LdrUnloadDll (NTDLL.@)
3891 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
3893 WINE_MODREF *wm;
3894 NTSTATUS retv = STATUS_SUCCESS;
3896 if (process_detaching) return retv;
3898 TRACE("(%p)\n", hModule);
3900 RtlEnterCriticalSection( &loader_section );
3902 free_lib_count++;
3903 if ((wm = get_modref( hModule )) != NULL)
3905 TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
3907 /* Recursively decrement reference counts */
3908 MODULE_DecRefCount( wm );
3910 /* Call process detach notifications */
3911 if ( free_lib_count <= 1 )
3913 process_detach();
3914 MODULE_FlushModrefs();
3917 TRACE("END\n");
3919 else
3920 retv = STATUS_DLL_NOT_FOUND;
3922 free_lib_count--;
3924 RtlLeaveCriticalSection( &loader_section );
3926 return retv;
3929 /***********************************************************************
3930 * RtlImageNtHeader (NTDLL.@)
3932 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
3934 IMAGE_NT_HEADERS *ret;
3936 __TRY
3938 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
3940 ret = NULL;
3941 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
3943 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
3944 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
3947 __EXCEPT_PAGE_FAULT
3949 return NULL;
3951 __ENDTRY
3952 return ret;
3956 /******************************************************************
3957 * LdrInitializeThunk (NTDLL.@)
3959 * Attach to all the loaded dlls.
3960 * If this is the first time, perform the full process initialization.
3962 void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknown3, ULONG_PTR unknown4 )
3964 static const LARGE_INTEGER zero;
3965 static int attach_done;
3966 int i;
3967 NTSTATUS status;
3968 ULONG_PTR cookie;
3969 WINE_MODREF *wm;
3970 LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
3972 pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
3974 if (process_detaching) return;
3976 RtlEnterCriticalSection( &loader_section );
3978 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3979 assert( wm );
3981 if (!imports_fixup_done)
3983 actctx_init();
3984 if (wm->ldr.Flags & LDR_COR_ILONLY)
3985 status = fixup_imports_ilonly( wm, load_path, entry );
3986 else
3987 status = fixup_imports( wm, load_path );
3989 if (status)
3991 ERR( "Importing dlls for %s failed, status %x\n",
3992 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3993 NtTerminateProcess( GetCurrentProcess(), status );
3995 imports_fixup_done = TRUE;
3998 RtlAcquirePebLock();
3999 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
4000 RtlReleasePebLock();
4002 if (!attach_done) /* first time around */
4004 attach_done = 1;
4005 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4007 ERR( "TLS init failed when loading %s, status %x\n",
4008 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4009 NtTerminateProcess( GetCurrentProcess(), status );
4011 wm->ldr.LoadCount = -1;
4012 wm->ldr.Flags |= LDR_PROCESS_ATTACHED; /* don't try to attach again */
4013 if (wm->ldr.ActivationContext)
4014 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
4016 for (i = 0; i < wm->nDeps; i++)
4018 if (!wm->deps[i]) continue;
4019 if ((status = process_attach( wm->deps[i], context )) != STATUS_SUCCESS)
4021 if (last_failed_modref)
4022 ERR( "%s failed to initialize, aborting\n",
4023 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
4024 ERR( "Initializing dlls for %s failed, status %x\n",
4025 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4026 NtTerminateProcess( GetCurrentProcess(), status );
4029 attach_implicitly_loaded_dlls( context );
4030 virtual_release_address_space();
4031 if (wm->so_handle) call_constructors( wm );
4032 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
4034 else
4036 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4037 NtTerminateThread( GetCurrentThread(), status );
4038 thread_attach();
4041 RtlLeaveCriticalSection( &loader_section );
4043 NtDelayExecution( TRUE, &zero );
4047 /***********************************************************************
4048 * load_global_options
4050 static void load_global_options(void)
4052 static const WCHAR sessionW[] = {'M','a','c','h','i','n','e','\\',
4053 'S','y','s','t','e','m','\\',
4054 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4055 'C','o','n','t','r','o','l','\\',
4056 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
4057 static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
4058 static const WCHAR safesearchW[] = {'S','a','f','e','P','r','o','c','e','s','s','S','e','a','r','c','h','M','o','d','e',0};
4059 static const WCHAR safedllmodeW[] = {'S','a','f','e','D','l','l','S','e','a','r','c','h','M','o','d','e',0};
4060 static const WCHAR critsectW[] = {'C','r','i','t','i','c','a','l','S','e','c','t','i','o','n','T','i','m','e','o','u','t',0};
4061 static const WCHAR heapresW[] = {'H','e','a','p','S','e','g','m','e','n','t','R','e','s','e','r','v','e',0};
4062 static const WCHAR heapcommitW[] = {'H','e','a','p','S','e','g','m','e','n','t','C','o','m','m','i','t',0};
4063 static const WCHAR decommittotalW[] = {'H','e','a','p','D','e','C','o','m','m','i','t','T','o','t','a','l','F','r','e','e','T','h','r','e','s','h','o','l','d',0};
4064 static const WCHAR decommitfreeW[] = {'H','e','a','p','D','e','C','o','m','m','i','t','F','r','e','e','B','l','o','c','k','T','h','r','e','s','h','o','l','d',0};
4066 OBJECT_ATTRIBUTES attr;
4067 UNICODE_STRING name_str;
4068 HANDLE hkey;
4069 ULONG value;
4071 attr.Length = sizeof(attr);
4072 attr.RootDirectory = 0;
4073 attr.ObjectName = &name_str;
4074 attr.Attributes = OBJ_CASE_INSENSITIVE;
4075 attr.SecurityDescriptor = NULL;
4076 attr.SecurityQualityOfService = NULL;
4077 RtlInitUnicodeString( &name_str, sessionW );
4079 if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
4081 query_dword_option( hkey, globalflagW, &NtCurrentTeb()->Peb->NtGlobalFlag );
4082 query_dword_option( hkey, safesearchW, &path_safe_mode );
4083 query_dword_option( hkey, safedllmodeW, &dll_safe_mode );
4085 if (!query_dword_option( hkey, critsectW, &value ))
4086 NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart = (ULONGLONG)value * -10000000;
4088 if (!query_dword_option( hkey, heapresW, &value ))
4089 NtCurrentTeb()->Peb->HeapSegmentReserve = value;
4091 if (!query_dword_option( hkey, heapcommitW, &value ))
4092 NtCurrentTeb()->Peb->HeapSegmentCommit = value;
4094 if (!query_dword_option( hkey, decommittotalW, &value ))
4095 NtCurrentTeb()->Peb->HeapDeCommitTotalFreeThreshold = value;
4097 if (!query_dword_option( hkey, decommitfreeW, &value ))
4098 NtCurrentTeb()->Peb->HeapDeCommitFreeBlockThreshold = value;
4100 NtClose( hkey );
4102 LdrQueryImageFileExecutionOptions( &NtCurrentTeb()->Peb->ProcessParameters->ImagePathName,
4103 globalflagW, REG_DWORD, &NtCurrentTeb()->Peb->NtGlobalFlag,
4104 sizeof(DWORD), NULL );
4105 heap_set_debug_flags( GetProcessHeap() );
4109 /***********************************************************************
4110 * RtlImageDirectoryEntryToData (NTDLL.@)
4112 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
4114 const IMAGE_NT_HEADERS *nt;
4115 DWORD addr;
4117 if ((ULONG_PTR)module & 1) image = FALSE; /* mapped as data file */
4118 module = (HMODULE)((ULONG_PTR)module & ~3);
4119 if (!(nt = RtlImageNtHeader( module ))) return NULL;
4120 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
4122 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
4124 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4125 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4126 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
4127 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4129 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
4131 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
4133 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4134 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4135 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
4136 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4138 else return NULL;
4140 /* not mapped as image, need to find the section containing the virtual address */
4141 return RtlImageRvaToVa( nt, module, addr, NULL );
4145 /***********************************************************************
4146 * RtlImageRvaToSection (NTDLL.@)
4148 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
4149 HMODULE module, DWORD rva )
4151 int i;
4152 const IMAGE_SECTION_HEADER *sec;
4154 sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
4155 nt->FileHeader.SizeOfOptionalHeader);
4156 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
4158 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4159 return (PIMAGE_SECTION_HEADER)sec;
4161 return NULL;
4165 /***********************************************************************
4166 * RtlImageRvaToVa (NTDLL.@)
4168 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
4169 DWORD rva, IMAGE_SECTION_HEADER **section )
4171 IMAGE_SECTION_HEADER *sec;
4173 if (section && *section) /* try this section first */
4175 sec = *section;
4176 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4177 goto found;
4179 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
4180 found:
4181 if (section) *section = sec;
4182 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
4186 /***********************************************************************
4187 * RtlPcToFileHeader (NTDLL.@)
4189 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
4191 LDR_MODULE *module;
4192 PVOID ret = NULL;
4194 RtlEnterCriticalSection( &loader_section );
4195 if (!LdrFindEntryForAddress( pc, &module )) ret = module->BaseAddress;
4196 RtlLeaveCriticalSection( &loader_section );
4197 *address = ret;
4198 return ret;
4202 /****************************************************************************
4203 * LdrGetDllDirectory (NTDLL.@)
4205 NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
4207 NTSTATUS status = STATUS_SUCCESS;
4209 RtlEnterCriticalSection( &dlldir_section );
4210 dir->Length = dll_directory.Length + sizeof(WCHAR);
4211 if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
4212 else
4214 status = STATUS_BUFFER_TOO_SMALL;
4215 if (dir->MaximumLength) dir->Buffer[0] = 0;
4217 RtlLeaveCriticalSection( &dlldir_section );
4218 return status;
4222 /****************************************************************************
4223 * LdrSetDllDirectory (NTDLL.@)
4225 NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
4227 NTSTATUS status = STATUS_SUCCESS;
4228 UNICODE_STRING new;
4230 if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
4231 else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;
4233 RtlEnterCriticalSection( &dlldir_section );
4234 RtlFreeUnicodeString( &dll_directory );
4235 dll_directory = new;
4236 RtlLeaveCriticalSection( &dlldir_section );
4237 return status;
4241 /****************************************************************************
4242 * LdrAddDllDirectory (NTDLL.@)
4244 NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
4246 FILE_BASIC_INFORMATION info;
4247 UNICODE_STRING nt_name;
4248 NTSTATUS status;
4249 OBJECT_ATTRIBUTES attr;
4250 DWORD len;
4251 struct dll_dir_entry *ptr;
4252 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
4254 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
4255 return STATUS_INVALID_PARAMETER;
4257 status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
4258 if (status) return status;
4259 len = nt_name.Length / sizeof(WCHAR);
4260 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
4261 return STATUS_NO_MEMORY;
4262 memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );
4264 attr.Length = sizeof(attr);
4265 attr.RootDirectory = 0;
4266 attr.Attributes = OBJ_CASE_INSENSITIVE;
4267 attr.ObjectName = &nt_name;
4268 attr.SecurityDescriptor = NULL;
4269 attr.SecurityQualityOfService = NULL;
4270 status = NtQueryAttributesFile( &attr, &info );
4271 RtlFreeUnicodeString( &nt_name );
4273 if (!status)
4275 TRACE( "%s\n", debugstr_w( ptr->dir ));
4276 RtlEnterCriticalSection( &dlldir_section );
4277 list_add_head( &dll_dir_list, &ptr->entry );
4278 RtlLeaveCriticalSection( &dlldir_section );
4279 *cookie = ptr;
4281 else RtlFreeHeap( GetProcessHeap(), 0, ptr );
4282 return status;
4286 /****************************************************************************
4287 * LdrRemoveDllDirectory (NTDLL.@)
4289 NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
4291 struct dll_dir_entry *ptr = cookie;
4293 TRACE( "%s\n", debugstr_w( ptr->dir ));
4295 RtlEnterCriticalSection( &dlldir_section );
4296 list_remove( &ptr->entry );
4297 RtlFreeHeap( GetProcessHeap(), 0, ptr );
4298 RtlLeaveCriticalSection( &dlldir_section );
4299 return STATUS_SUCCESS;
4303 /*************************************************************************
4304 * LdrSetDefaultDllDirectories (NTDLL.@)
4306 NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
4308 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
4309 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4310 LOAD_LIBRARY_SEARCH_USER_DIRS |
4311 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4312 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4314 if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
4315 default_search_flags = flags;
4316 return STATUS_SUCCESS;
4320 /******************************************************************
4321 * LdrGetDllPath (NTDLL.@)
4323 NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
4325 NTSTATUS status;
4326 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
4327 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4328 LOAD_LIBRARY_SEARCH_USER_DIRS |
4329 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4330 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4332 if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
4334 if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
4335 if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
4337 else if (!(flags & load_library_search_flags)) flags |= default_search_flags;
4339 RtlEnterCriticalSection( &dlldir_section );
4341 if (flags & load_library_search_flags)
4343 status = get_dll_load_path_search_flags( module, flags, path );
4345 else
4347 const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
4348 if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH))
4349 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4350 status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
4353 RtlLeaveCriticalSection( &dlldir_section );
4354 *unknown = NULL;
4355 return status;
4359 /*************************************************************************
4360 * RtlSetSearchPathMode (NTDLL.@)
4362 NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
4364 int val;
4366 switch (flags)
4368 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
4369 val = 1;
4370 break;
4371 case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
4372 val = 0;
4373 break;
4374 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4375 interlocked_xchg( (int *)&path_safe_mode, 2 );
4376 return STATUS_SUCCESS;
4377 default:
4378 return STATUS_INVALID_PARAMETER;
4381 for (;;)
4383 int prev = path_safe_mode;
4384 if (prev == 2) break; /* permanently set */
4385 if (interlocked_cmpxchg( (int *)&path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4387 return STATUS_ACCESS_DENIED;
4391 /******************************************************************
4392 * RtlGetExePath (NTDLL.@)
4394 NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
4396 static const WCHAR emptyW[1];
4397 const WCHAR *dlldir = dotW;
4398 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4400 /* same check as NeedCurrentDirectoryForExePathW */
4401 if (!wcschr( name, '\\' ))
4403 static const WCHAR env_name[] = {'N','o','D','e','f','a','u','l','t','C','u','r','r','e','n','t',
4404 'D','i','r','e','c','t','o','r','y','I','n',
4405 'E','x','e','P','a','t','h',0};
4406 UNICODE_STRING name, value = { 0 };
4408 RtlInitUnicodeString( &name, env_name );
4409 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4410 dlldir = emptyW;
4412 return get_dll_load_path( module, dlldir, FALSE, path );
4416 /******************************************************************
4417 * RtlGetSearchPath (NTDLL.@)
4419 NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
4421 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4422 return get_dll_load_path( module, NULL, path_safe_mode, path );
4426 /******************************************************************
4427 * RtlReleasePath (NTDLL.@)
4429 void WINAPI RtlReleasePath( PWSTR path )
4431 RtlFreeHeap( GetProcessHeap(), 0, path );
4435 /***********************************************************************
4436 * NtLoadDriver (NTDLL.@)
4437 * ZwLoadDriver (NTDLL.@)
4439 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *DriverServiceName )
4441 FIXME("(%p), stub!\n",DriverServiceName);
4442 return STATUS_NOT_IMPLEMENTED;
4446 /***********************************************************************
4447 * NtUnloadDriver (NTDLL.@)
4448 * ZwUnloadDriver (NTDLL.@)
4450 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *DriverServiceName )
4452 FIXME("(%p), stub!\n",DriverServiceName);
4453 return STATUS_NOT_IMPLEMENTED;
4457 /******************************************************************
4458 * DllMain (NTDLL.@)
4460 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4462 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
4463 return TRUE;
4467 /***********************************************************************
4468 * __wine_process_init
4470 void __wine_process_init(void)
4472 static const WCHAR ntdllW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
4473 's','y','s','t','e','m','3','2','\\',
4474 'n','t','d','l','l','.','d','l','l',0};
4475 static const WCHAR kernel32W[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
4476 's','y','s','t','e','m','3','2','\\',
4477 'k','e','r','n','e','l','3','2','.','d','l','l',0};
4478 RTL_USER_PROCESS_PARAMETERS *params;
4479 WINE_MODREF *wm;
4480 NTSTATUS status;
4481 ANSI_STRING func_name;
4482 UNICODE_STRING nt_name;
4483 INITIAL_TEB stack;
4484 BOOL suspend;
4485 SIZE_T info_size;
4486 TEB *teb = thread_init();
4487 PEB *peb = teb->Peb;
4489 /* setup the server connection */
4490 server_init_process();
4491 info_size = server_init_thread( peb, &suspend );
4493 peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );
4494 peb->LoaderLock = &loader_section;
4496 init_unix_codepage();
4497 init_directories();
4498 init_user_process_params( info_size );
4500 NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 );
4502 /* retrieve current umask */
4503 FILE_umask = umask(0777);
4504 umask( FILE_umask );
4506 load_global_options();
4507 version_init();
4509 /* setup the load callback and create ntdll modref */
4510 RtlInitUnicodeString( &nt_name, ntdllW );
4511 default_load_info.filename = &nt_name;
4512 wine_dll_set_callback( load_builtin_callback );
4514 RtlInitUnicodeString( &nt_name, kernel32W );
4515 if ((status = load_builtin_dll( NULL, &nt_name, NULL, 0, &wm )) != STATUS_SUCCESS)
4517 MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
4518 exit(1);
4520 RtlInitAnsiString( &func_name, "__wine_start_process" );
4521 if ((status = LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name,
4522 0, (void **)&kernel32_start_process )) != STATUS_SUCCESS)
4524 MESSAGE( "wine: could not find __wine_start_process in kernel32.dll, status %x\n", status );
4525 exit(1);
4528 init_locale( wm->ldr.BaseAddress );
4530 params = peb->ProcessParameters;
4531 if (!(status = load_dll( params->DllPath.Buffer, params->ImagePathName.Buffer, NULL,
4532 DONT_RESOLVE_DLL_REFERENCES, &wm )))
4534 peb->ImageBaseAddress = wm->ldr.BaseAddress;
4535 TRACE( "main exe loaded %s at %p\n", debugstr_us(&params->ImagePathName), peb->ImageBaseAddress );
4536 if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
4538 MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
4539 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
4542 else
4544 if (!info_size) status = restart_process( params, status );
4545 switch (status)
4547 case STATUS_INVALID_IMAGE_WIN_64:
4548 ERR( "%s 64-bit application not supported in 32-bit prefix\n",
4549 debugstr_us(&params->ImagePathName) );
4550 break;
4551 case STATUS_INVALID_IMAGE_WIN_16:
4552 case STATUS_INVALID_IMAGE_NE_FORMAT:
4553 case STATUS_INVALID_IMAGE_PROTECT:
4554 ERR( "%s 16-bit application not supported on this system\n",
4555 debugstr_us(&params->ImagePathName) );
4556 break;
4557 case STATUS_INVALID_IMAGE_FORMAT:
4558 ERR( "%s not supported on this system\n", debugstr_us(&params->ImagePathName) );
4559 break;
4560 case STATUS_DLL_NOT_FOUND:
4561 ERR( "%s not found\n", debugstr_us(&params->ImagePathName) );
4562 break;
4563 default:
4564 ERR( "failed to load %s, error %x\n", debugstr_us(&params->ImagePathName), status );
4565 break;
4567 NtTerminateProcess( GetCurrentProcess(), status );
4570 virtual_set_large_address_space();
4572 /* the main exe needs to be the first in the load order list */
4573 RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
4574 InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
4575 RemoveEntryList( &wm->ldr.InMemoryOrderModuleList );
4576 InsertHeadList( &peb->LdrData->InMemoryOrderModuleList, &wm->ldr.InMemoryOrderModuleList );
4578 virtual_alloc_thread_stack( &stack, 0, 0, NULL );
4579 teb->Tib.StackBase = stack.StackBase;
4580 teb->Tib.StackLimit = stack.StackLimit;
4581 teb->DeallocationStack = stack.DeallocationStack;
4583 server_init_process_done();