dbghelp: Use local declarations of r_debug and link_map structs.
[wine.git] / dlls / ntdll / loader.c
blobb946416734ad14526a54ed38ea9764292146a9c5
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_SYS_MMAN_H
28 # include <sys/mman.h>
29 #endif
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #define NONAMELESSUNION
34 #include "windef.h"
35 #include "winnt.h"
36 #include "winternl.h"
37 #include "delayloadhandler.h"
39 #include "wine/exception.h"
40 #include "wine/library.h"
41 #include "wine/debug.h"
42 #include "wine/list.h"
43 #include "wine/server.h"
44 #include "ntdll_misc.h"
45 #include "ddk/wdm.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(module);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
49 WINE_DECLARE_DEBUG_CHANNEL(snoop);
50 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
51 WINE_DECLARE_DEBUG_CHANNEL(imports);
53 #ifdef _WIN64
54 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
55 #endif
56 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
57 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
59 /* we don't want to include winuser.h */
60 #define RT_MANIFEST ((ULONG_PTR)24)
61 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
63 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
64 typedef void (CALLBACK *LDRENUMPROC)(LDR_MODULE *, void *, BOOLEAN *);
66 /* system directory with trailing backslash */
67 const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
68 's','y','s','t','e','m','3','2','\\',0};
69 const WCHAR syswow64_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
70 's','y','s','w','o','w','6','4','\\',0};
72 /* system search path */
73 static const WCHAR system_path[] =
74 {'C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m','3','2',';',
75 'C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m',';',
76 'C',':','\\','w','i','n','d','o','w','s',0};
78 static const WCHAR dotW[] = {'.',0};
80 static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
81 static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
82 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
83 static ULONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
84 static ULONG dll_safe_mode = 1; /* dll search mode */
85 static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
86 static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
88 struct dll_dir_entry
90 struct list entry;
91 WCHAR dir[1];
94 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
96 struct ldr_notification
98 struct list entry;
99 PLDR_DLL_NOTIFICATION_FUNCTION callback;
100 void *context;
103 static struct list ldr_notifications = LIST_INIT( ldr_notifications );
105 static const char * const reason_names[] =
107 "PROCESS_DETACH",
108 "PROCESS_ATTACH",
109 "THREAD_ATTACH",
110 "THREAD_DETACH",
111 NULL, NULL, NULL, NULL,
112 "WINE_PREATTACH"
115 static const WCHAR dllW[] = {'.','d','l','l',0};
117 /* internal representation of 32bit modules. per process. */
118 typedef struct _wine_modref
120 LDR_MODULE ldr;
121 dev_t dev;
122 ino_t ino;
123 int alloc_deps;
124 int nDeps;
125 struct _wine_modref **deps;
126 } WINE_MODREF;
128 /* info about the current builtin dll load */
129 /* used to keep track of things across the register_dll constructor call */
130 struct builtin_load_info
132 const WCHAR *load_path;
133 const UNICODE_STRING *filename;
134 NTSTATUS status;
135 WINE_MODREF *wm;
138 static struct builtin_load_info default_load_info;
139 static struct builtin_load_info *builtin_load_info = &default_load_info;
141 static UINT tls_module_count; /* number of modules with TLS directory */
142 static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
143 LIST_ENTRY tls_links = { &tls_links, &tls_links };
145 static RTL_CRITICAL_SECTION loader_section;
146 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
148 0, 0, &loader_section,
149 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
150 0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
152 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
154 static CRITICAL_SECTION dlldir_section;
155 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
157 0, 0, &dlldir_section,
158 { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
159 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
161 static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };
163 static WINE_MODREF *cached_modref;
164 static WINE_MODREF *current_modref;
165 static WINE_MODREF *last_failed_modref;
167 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
168 DWORD flags, WINE_MODREF** pwm );
169 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
170 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
171 DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
172 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
173 DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
175 /* convert PE image VirtualAddress to Real Address */
176 static inline void *get_rva( HMODULE module, DWORD va )
178 return (void *)((char *)module + va);
181 /* check whether the file name contains a path */
182 static inline BOOL contains_path( LPCWSTR name )
184 return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
187 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
189 typedef struct _RTL_UNLOAD_EVENT_TRACE
191 void *BaseAddress;
192 SIZE_T SizeOfImage;
193 ULONG Sequence;
194 ULONG TimeDateStamp;
195 ULONG CheckSum;
196 WCHAR ImageName[32];
197 } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
199 static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
200 static unsigned int unload_trace_seq;
202 static void module_push_unload_trace( const LDR_MODULE *ldr )
204 RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
205 unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
207 ptr->BaseAddress = ldr->BaseAddress;
208 ptr->SizeOfImage = ldr->SizeOfImage;
209 ptr->Sequence = unload_trace_seq;
210 ptr->TimeDateStamp = ldr->TimeDateStamp;
211 ptr->CheckSum = ldr->CheckSum;
212 memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
213 ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;
215 unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
218 /*********************************************************************
219 * RtlGetUnloadEventTrace [NTDLL.@]
221 RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
223 return unload_traces;
226 /*********************************************************************
227 * RtlGetUnloadEventTraceEx [NTDLL.@]
229 void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
231 static unsigned int element_size = sizeof(*unload_traces);
232 static unsigned int element_count = ARRAY_SIZE(unload_traces);
234 *size = &element_size;
235 *count = &element_count;
236 *trace = unload_traces;
239 /*************************************************************************
240 * call_dll_entry_point
242 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
243 * their entry point, so we need a small asm wrapper. Testing indicates
244 * that only modifying esi leads to a crash, so use this one to backup
245 * ebp while running the dll entry proc.
247 #ifdef __i386__
248 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
249 __ASM_GLOBAL_FUNC(call_dll_entry_point,
250 "pushl %ebp\n\t"
251 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
252 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
253 "movl %esp,%ebp\n\t"
254 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
255 "pushl %ebx\n\t"
256 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
257 "pushl %esi\n\t"
258 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
259 "pushl %edi\n\t"
260 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
261 "movl %ebp,%esi\n\t"
262 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
263 "pushl 20(%ebp)\n\t"
264 "pushl 16(%ebp)\n\t"
265 "pushl 12(%ebp)\n\t"
266 "movl 8(%ebp),%eax\n\t"
267 "call *%eax\n\t"
268 "movl %esi,%ebp\n\t"
269 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
270 "leal -12(%ebp),%esp\n\t"
271 "popl %edi\n\t"
272 __ASM_CFI(".cfi_same_value %edi\n\t")
273 "popl %esi\n\t"
274 __ASM_CFI(".cfi_same_value %esi\n\t")
275 "popl %ebx\n\t"
276 __ASM_CFI(".cfi_same_value %ebx\n\t")
277 "popl %ebp\n\t"
278 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
279 __ASM_CFI(".cfi_same_value %ebp\n\t")
280 "ret" )
281 #else /* __i386__ */
282 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
283 UINT reason, void *reserved )
285 return proc( module, reason, reserved );
287 #endif /* __i386__ */
290 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
291 /*************************************************************************
292 * stub_entry_point
294 * Entry point for stub functions.
296 static void stub_entry_point( const char *dll, const char *name, void *ret_addr )
298 EXCEPTION_RECORD rec;
300 rec.ExceptionCode = EXCEPTION_WINE_STUB;
301 rec.ExceptionFlags = EH_NONCONTINUABLE;
302 rec.ExceptionRecord = NULL;
303 rec.ExceptionAddress = ret_addr;
304 rec.NumberParameters = 2;
305 rec.ExceptionInformation[0] = (ULONG_PTR)dll;
306 rec.ExceptionInformation[1] = (ULONG_PTR)name;
307 for (;;) RtlRaiseException( &rec );
311 #include "pshpack1.h"
312 #ifdef __i386__
313 struct stub
315 BYTE pushl1; /* pushl $name */
316 const char *name;
317 BYTE pushl2; /* pushl $dll */
318 const char *dll;
319 BYTE call; /* call stub_entry_point */
320 DWORD entry;
322 #elif defined(__arm__)
323 struct stub
325 DWORD ldr_r0; /* ldr r0, $dll */
326 DWORD ldr_r1; /* ldr r1, $name */
327 DWORD mov_r2_lr; /* mov r2, lr */
328 DWORD ldr_pc_pc; /* ldr pc, [pc, #4] */
329 const char *dll;
330 const char *name;
331 const void* entry;
333 #elif defined(__aarch64__)
334 struct stub
336 DWORD ldr_x0; /* ldr x0, $dll */
337 DWORD ldr_x1; /* ldr x1, $name */
338 DWORD mov_x2_lr; /* mov x2, lr */
339 DWORD ldr_x16; /* ldr x16, $entry */
340 DWORD br_x16; /* br x16 */
341 const char *dll;
342 const char *name;
343 const void *entry;
345 #else
346 struct stub
348 BYTE movq_rdi[2]; /* movq $dll,%rdi */
349 const char *dll;
350 BYTE movq_rsi[2]; /* movq $name,%rsi */
351 const char *name;
352 BYTE movq_rsp_rdx[4]; /* movq (%rsp),%rdx */
353 BYTE movq_rax[2]; /* movq $entry, %rax */
354 const void* entry;
355 BYTE jmpq_rax[2]; /* jmp %rax */
357 #endif
358 #include "poppack.h"
360 /*************************************************************************
361 * allocate_stub
363 * Allocate a stub entry point.
365 static ULONG_PTR allocate_stub( const char *dll, const char *name )
367 #define MAX_SIZE 65536
368 static struct stub *stubs;
369 static unsigned int nb_stubs;
370 struct stub *stub;
372 if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
374 if (!stubs)
376 SIZE_T size = MAX_SIZE;
377 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
378 MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
379 return 0xdeadbeef;
381 stub = &stubs[nb_stubs++];
382 #ifdef __i386__
383 stub->pushl1 = 0x68; /* pushl $name */
384 stub->name = name;
385 stub->pushl2 = 0x68; /* pushl $dll */
386 stub->dll = dll;
387 stub->call = 0xe8; /* call stub_entry_point */
388 stub->entry = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
389 #elif defined(__arm__)
390 stub->ldr_r0 = 0xe59f0008; /* ldr r0, [pc, #8] ($dll) */
391 stub->ldr_r1 = 0xe59f1008; /* ldr r1, [pc, #8] ($name) */
392 stub->mov_r2_lr = 0xe1a0200e; /* mov r2, lr */
393 stub->ldr_pc_pc = 0xe59ff004; /* ldr pc, [pc, #4] */
394 stub->dll = dll;
395 stub->name = name;
396 stub->entry = stub_entry_point;
397 #elif defined(__aarch64__)
398 stub->ldr_x0 = 0x580000a0; /* ldr x0, #20 ($dll) */
399 stub->ldr_x1 = 0x580000c1; /* ldr x1, #24 ($name) */
400 stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
401 stub->ldr_x16 = 0x580000d0; /* ldr x16, #24 ($entry) */
402 stub->br_x16 = 0xd61f0200; /* br x16 */
403 stub->dll = dll;
404 stub->name = name;
405 stub->entry = stub_entry_point;
406 #else
407 stub->movq_rdi[0] = 0x48; /* movq $dll,%rdi */
408 stub->movq_rdi[1] = 0xbf;
409 stub->dll = dll;
410 stub->movq_rsi[0] = 0x48; /* movq $name,%rsi */
411 stub->movq_rsi[1] = 0xbe;
412 stub->name = name;
413 stub->movq_rsp_rdx[0] = 0x48; /* movq (%rsp),%rdx */
414 stub->movq_rsp_rdx[1] = 0x8b;
415 stub->movq_rsp_rdx[2] = 0x14;
416 stub->movq_rsp_rdx[3] = 0x24;
417 stub->movq_rax[0] = 0x48; /* movq $entry, %rax */
418 stub->movq_rax[1] = 0xb8;
419 stub->entry = stub_entry_point;
420 stub->jmpq_rax[0] = 0xff; /* jmp %rax */
421 stub->jmpq_rax[1] = 0xe0;
422 #endif
423 return (ULONG_PTR)stub;
426 #else /* __i386__ */
427 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
428 #endif /* __i386__ */
430 /* call ldr notifications */
431 static void call_ldr_notifications( ULONG reason, LDR_MODULE *module )
433 struct ldr_notification *notify, *notify_next;
434 LDR_DLL_NOTIFICATION_DATA data;
436 data.Loaded.Flags = 0;
437 data.Loaded.FullDllName = &module->FullDllName;
438 data.Loaded.BaseDllName = &module->BaseDllName;
439 data.Loaded.DllBase = module->BaseAddress;
440 data.Loaded.SizeOfImage = module->SizeOfImage;
442 LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
444 TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
445 notify->callback, reason, &data, notify->context );
447 notify->callback(reason, &data, notify->context);
449 TRACE_(relay)("\1Ret LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
450 notify->callback, reason, &data, notify->context );
454 /*************************************************************************
455 * get_modref
457 * Looks for the referenced HMODULE in the current process
458 * The loader_section must be locked while calling this function.
460 static WINE_MODREF *get_modref( HMODULE hmod )
462 PLIST_ENTRY mark, entry;
463 PLDR_MODULE mod;
465 if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
467 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
468 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
470 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
471 if (mod->BaseAddress == hmod)
472 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
474 return NULL;
478 /**********************************************************************
479 * find_basename_module
481 * Find a module from its base name.
482 * The loader_section must be locked while calling this function
484 static WINE_MODREF *find_basename_module( LPCWSTR name )
486 PLIST_ENTRY mark, entry;
487 UNICODE_STRING name_str;
489 RtlInitUnicodeString( &name_str, name );
491 if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
492 return cached_modref;
494 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
495 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
497 LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
498 if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE ))
500 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
501 return cached_modref;
504 return NULL;
508 /**********************************************************************
509 * find_fullname_module
511 * Find a module from its full path name.
512 * The loader_section must be locked while calling this function
514 static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
516 PLIST_ENTRY mark, entry;
517 UNICODE_STRING name = *nt_name;
519 if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
520 name.Length -= 4 * sizeof(WCHAR); /* for \??\ prefix */
521 name.Buffer += 4;
523 if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
524 return cached_modref;
526 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
527 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
529 LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
530 if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
532 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
533 return cached_modref;
536 return NULL;
540 /**********************************************************************
541 * find_fileid_module
543 * Find a module from its file id.
544 * The loader_section must be locked while calling this function
546 static WINE_MODREF *find_fileid_module( struct stat *st )
548 LIST_ENTRY *mark, *entry;
550 if (cached_modref && cached_modref->dev == st->st_dev && cached_modref->ino == st->st_ino)
551 return cached_modref;
553 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
554 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
556 LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );
557 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
559 if (wm->dev == st->st_dev && wm->ino == st->st_ino)
561 cached_modref = wm;
562 return wm;
565 return NULL;
569 /**********************************************************************
570 * find_so_module
572 * Find a module from its so file handle.
573 * The loader_section must be locked while calling this function
575 static WINE_MODREF *find_so_module( void *handle )
577 LIST_ENTRY *mark, *entry;
579 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
580 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
582 LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );
583 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
585 if (mod->Flags & LDR_WINE_INTERNAL && mod->SectionHandle == handle) return wm;
587 return NULL;
591 /*************************************************************************
592 * find_forwarded_export
594 * Find the final function pointer for a forwarded function.
595 * The loader_section must be locked while calling this function.
597 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
599 const IMAGE_EXPORT_DIRECTORY *exports;
600 DWORD exp_size;
601 WINE_MODREF *wm;
602 WCHAR mod_name[32];
603 const char *end = strrchr(forward, '.');
604 FARPROC proc = NULL;
606 if (!end) return NULL;
607 if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL;
608 ascii_to_unicode( mod_name, forward, end - forward );
609 mod_name[end - forward] = 0;
610 if (!wcschr( mod_name, '.' ))
612 if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name) - sizeof(dllW)) return NULL;
613 memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
616 if (!(wm = find_basename_module( mod_name )))
618 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
619 if (load_dll( load_path, mod_name, dllW, 0, &wm ) == STATUS_SUCCESS &&
620 !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
622 if (!imports_fixup_done && current_modref)
624 WINE_MODREF **deps;
625 if (current_modref->alloc_deps)
626 deps = RtlReAllocateHeap( GetProcessHeap(), 0, current_modref->deps,
627 (current_modref->alloc_deps + 1) * sizeof(*deps) );
628 else
629 deps = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*deps) );
630 if (deps)
632 deps[current_modref->nDeps++] = wm;
633 current_modref->deps = deps;
634 current_modref->alloc_deps++;
637 else if (process_attach( wm, NULL ) != STATUS_SUCCESS)
639 LdrUnloadDll( wm->ldr.BaseAddress );
640 wm = NULL;
644 if (!wm)
646 ERR( "module not found for forward '%s' used by %s\n",
647 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
648 return NULL;
651 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
652 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
654 const char *name = end + 1;
655 if (*name == '#') /* ordinal */
656 proc = find_ordinal_export( wm->ldr.BaseAddress, exports, exp_size, atoi(name+1), load_path );
657 else
658 proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, name, -1, load_path );
661 if (!proc)
663 ERR("function not found for forward '%s' used by %s."
664 " If you are using builtin %s, try using the native one instead.\n",
665 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
666 debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
668 return proc;
672 /*************************************************************************
673 * find_ordinal_export
675 * Find an exported function by ordinal.
676 * The exports base must have been subtracted from the ordinal already.
677 * The loader_section must be locked while calling this function.
679 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
680 DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
682 FARPROC proc;
683 const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
685 if (ordinal >= exports->NumberOfFunctions)
687 TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
688 return NULL;
690 if (!functions[ordinal]) return NULL;
692 proc = get_rva( module, functions[ordinal] );
694 /* if the address falls into the export dir, it's a forward */
695 if (((const char *)proc >= (const char *)exports) &&
696 ((const char *)proc < (const char *)exports + exp_size))
697 return find_forwarded_export( module, (const char *)proc, load_path );
699 if (TRACE_ON(snoop))
701 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
702 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
704 if (TRACE_ON(relay))
706 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
707 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
709 return proc;
713 /*************************************************************************
714 * find_named_export
716 * Find an exported function by name.
717 * The loader_section must be locked while calling this function.
719 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
720 DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
722 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
723 const DWORD *names = get_rva( module, exports->AddressOfNames );
724 int min = 0, max = exports->NumberOfNames - 1;
726 /* first check the hint */
727 if (hint >= 0 && hint <= max)
729 char *ename = get_rva( module, names[hint] );
730 if (!strcmp( ename, name ))
731 return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
734 /* then do a binary search */
735 while (min <= max)
737 int res, pos = (min + max) / 2;
738 char *ename = get_rva( module, names[pos] );
739 if (!(res = strcmp( ename, name )))
740 return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
741 if (res > 0) max = pos - 1;
742 else min = pos + 1;
744 return NULL;
749 /*************************************************************************
750 * import_dll
752 * Import the dll specified by the given import descriptor.
753 * The loader_section must be locked while calling this function.
755 static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
757 NTSTATUS status;
758 WINE_MODREF *wmImp;
759 HMODULE imp_mod;
760 const IMAGE_EXPORT_DIRECTORY *exports;
761 DWORD exp_size;
762 const IMAGE_THUNK_DATA *import_list;
763 IMAGE_THUNK_DATA *thunk_list;
764 WCHAR buffer[32];
765 const char *name = get_rva( module, descr->Name );
766 DWORD len = strlen(name);
767 PVOID protect_base;
768 SIZE_T protect_size = 0;
769 DWORD protect_old;
771 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
772 if (descr->u.OriginalFirstThunk)
773 import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
774 else
775 import_list = thunk_list;
777 if (!import_list->u1.Ordinal)
779 WARN( "Skipping unused import %s\n", name );
780 *pwm = NULL;
781 return TRUE;
784 while (len && name[len-1] == ' ') len--; /* remove trailing spaces */
786 if (len * sizeof(WCHAR) < sizeof(buffer))
788 ascii_to_unicode( buffer, name, len );
789 buffer[len] = 0;
790 status = load_dll( load_path, buffer, dllW, 0, &wmImp );
792 else /* need to allocate a larger buffer */
794 WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
795 if (!ptr) return FALSE;
796 ascii_to_unicode( ptr, name, len );
797 ptr[len] = 0;
798 status = load_dll( load_path, ptr, dllW, 0, &wmImp );
799 RtlFreeHeap( GetProcessHeap(), 0, ptr );
802 if (status)
804 if (status == STATUS_DLL_NOT_FOUND)
805 ERR("Library %s (which is needed by %s) not found\n",
806 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
807 else
808 ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
809 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
810 return FALSE;
813 /* unprotect the import address table since it can be located in
814 * readonly section */
815 while (import_list[protect_size].u1.Ordinal) protect_size++;
816 protect_base = thunk_list;
817 protect_size *= sizeof(*thunk_list);
818 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
819 &protect_size, PAGE_READWRITE, &protect_old );
821 imp_mod = wmImp->ldr.BaseAddress;
822 exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
824 if (!exports)
826 /* set all imported function to deadbeef */
827 while (import_list->u1.Ordinal)
829 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
831 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
832 WARN("No implementation for %s.%d", name, ordinal );
833 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
835 else
837 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
838 WARN("No implementation for %s.%s", name, pe_name->Name );
839 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
841 WARN(" imported from %s, allocating stub %p\n",
842 debugstr_w(current_modref->ldr.FullDllName.Buffer),
843 (void *)thunk_list->u1.Function );
844 import_list++;
845 thunk_list++;
847 goto done;
850 while (import_list->u1.Ordinal)
852 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
854 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
856 thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
857 ordinal - exports->Base, load_path );
858 if (!thunk_list->u1.Function)
860 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
861 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
862 name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
863 (void *)thunk_list->u1.Function );
865 TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
867 else /* import by name */
869 IMAGE_IMPORT_BY_NAME *pe_name;
870 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
871 thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
872 (const char*)pe_name->Name,
873 pe_name->Hint, load_path );
874 if (!thunk_list->u1.Function)
876 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
877 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
878 name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
879 (void *)thunk_list->u1.Function );
881 TRACE_(imports)("--- %s %s.%d = %p\n",
882 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
884 import_list++;
885 thunk_list++;
888 done:
889 /* restore old protection of the import address table */
890 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
891 *pwm = wmImp;
892 return TRUE;
896 /***********************************************************************
897 * create_module_activation_context
899 static NTSTATUS create_module_activation_context( LDR_MODULE *module )
901 NTSTATUS status;
902 LDR_RESOURCE_INFO info;
903 const IMAGE_RESOURCE_DATA_ENTRY *entry;
905 info.Type = RT_MANIFEST;
906 info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
907 info.Language = 0;
908 if (!(status = LdrFindResource_U( module->BaseAddress, &info, 3, &entry )))
910 ACTCTXW ctx;
911 ctx.cbSize = sizeof(ctx);
912 ctx.lpSource = NULL;
913 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
914 ctx.hModule = module->BaseAddress;
915 ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
916 status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
918 return status;
922 /*************************************************************************
923 * is_dll_native_subsystem
925 * Check if dll is a proper native driver.
926 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
927 * while being perfectly normal DLLs. This heuristic should catch such breakages.
929 static BOOL is_dll_native_subsystem( LDR_MODULE *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
931 static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
932 static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
933 const IMAGE_IMPORT_DESCRIPTOR *imports;
934 DWORD i, size;
935 WCHAR buffer[16];
937 if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
938 if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
939 if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
941 if ((imports = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
942 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
944 for (i = 0; imports[i].Name; i++)
946 const char *name = get_rva( mod->BaseAddress, imports[i].Name );
947 DWORD len = strlen(name);
948 if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
949 ascii_to_unicode( buffer, name, len + 1 );
950 if (!wcsicmp( buffer, ntdllW ) || !wcsicmp( buffer, kernel32W ))
952 TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
953 return FALSE;
957 return TRUE;
960 /*************************************************************************
961 * alloc_tls_slot
963 * Allocate a TLS slot for a newly-loaded module.
964 * The loader_section must be locked while calling this function.
966 static SHORT alloc_tls_slot( LDR_MODULE *mod )
968 const IMAGE_TLS_DIRECTORY *dir;
969 ULONG i, size;
970 void *new_ptr;
971 LIST_ENTRY *entry;
973 if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
974 return -1;
976 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
977 if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1;
979 for (i = 0; i < tls_module_count; i++)
981 if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
982 !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
983 break;
986 TRACE( "module %p data %p-%p zerofill %u index %p callback %p flags %x -> slot %u\n", mod->BaseAddress,
987 (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
988 (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );
990 if (i == tls_module_count)
992 UINT new_count = max( 32, tls_module_count * 2 );
994 if (!tls_dirs)
995 new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
996 else
997 new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
998 new_count * sizeof(*tls_dirs) );
999 if (!new_ptr) return -1;
1001 /* resize the pointer block in all running threads */
1002 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1004 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1005 void **old = teb->ThreadLocalStoragePointer;
1006 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
1008 if (!new) return -1;
1009 if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
1010 teb->ThreadLocalStoragePointer = new;
1011 #if defined(__APPLE__) && defined(__x86_64__)
1012 if (teb->Reserved5[0])
1013 ((TEB*)teb->Reserved5[0])->ThreadLocalStoragePointer = new;
1014 #endif
1015 TRACE( "thread %04lx tls block %p -> %p\n", (ULONG_PTR)teb->ClientId.UniqueThread, old, new );
1016 /* FIXME: can't free old block here, should be freed at thread exit */
1019 tls_dirs = new_ptr;
1020 tls_module_count = new_count;
1023 /* allocate the data block in all running threads */
1024 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1026 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1028 if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
1029 memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
1030 memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
1032 TRACE( "thread %04lx slot %u: %u/%u bytes at %p\n",
1033 (ULONG_PTR)teb->ClientId.UniqueThread, i, size, dir->SizeOfZeroFill, new_ptr );
1035 RtlFreeHeap( GetProcessHeap(), 0,
1036 interlocked_xchg_ptr( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1039 *(DWORD *)dir->AddressOfIndex = i;
1040 tls_dirs[i] = *dir;
1041 return i;
1045 /*************************************************************************
1046 * free_tls_slot
1048 * Free the module TLS slot on unload.
1049 * The loader_section must be locked while calling this function.
1051 static void free_tls_slot( LDR_MODULE *mod )
1053 ULONG i = (USHORT)mod->TlsIndex;
1055 if (mod->TlsIndex == -1) return;
1056 assert( i < tls_module_count );
1057 memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1061 /****************************************************************
1062 * fixup_imports_ilonly
1064 * Fixup imports for an IL-only module. All we do is import mscoree.
1065 * The loader_section must be locked while calling this function.
1067 static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
1069 static const WCHAR mscoreeW[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
1070 IMAGE_EXPORT_DIRECTORY *exports;
1071 DWORD exp_size;
1072 NTSTATUS status;
1073 void *proc = NULL;
1074 WINE_MODREF *prev, *imp;
1076 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1077 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1079 wm->nDeps = 1;
1080 wm->alloc_deps = 1;
1081 wm->deps = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(WINE_MODREF *) );
1083 prev = current_modref;
1084 current_modref = wm;
1085 if (!(status = load_dll( load_path, mscoreeW, NULL, 0, &imp ))) wm->deps[0] = imp;
1086 current_modref = prev;
1087 if (status)
1089 ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
1090 debugstr_w(wm->ldr.BaseDllName.Buffer) );
1091 return status;
1094 TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
1096 if ((exports = RtlImageDirectoryEntryToData( imp->ldr.BaseAddress, TRUE,
1097 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1099 const char *name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
1100 proc = find_named_export( imp->ldr.BaseAddress, exports, exp_size, name, -1, load_path );
1102 if (!proc) return STATUS_PROCEDURE_NOT_FOUND;
1103 *entry = proc;
1104 return STATUS_SUCCESS;
1108 /****************************************************************
1109 * fixup_imports
1111 * Fixup all imports of a given module.
1112 * The loader_section must be locked while calling this function.
1114 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
1116 int i, dep, nb_imports;
1117 const IMAGE_IMPORT_DESCRIPTOR *imports;
1118 WINE_MODREF *prev, *imp;
1119 DWORD size;
1120 NTSTATUS status;
1121 ULONG_PTR cookie;
1123 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1124 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1126 wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr );
1128 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
1129 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1130 return STATUS_SUCCESS;
1132 nb_imports = 0;
1133 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
1135 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
1137 if (!create_module_activation_context( &wm->ldr ))
1138 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1140 /* Allocate module dependency list */
1141 wm->alloc_deps = nb_imports;
1142 wm->deps = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
1144 /* load the imported modules. They are automatically
1145 * added to the modref list of the process.
1147 prev = current_modref;
1148 current_modref = wm;
1149 status = STATUS_SUCCESS;
1150 for (i = 0; i < nb_imports; i++)
1152 dep = wm->nDeps++;
1154 if (!import_dll( wm->ldr.BaseAddress, &imports[i], load_path, &imp ))
1156 imp = NULL;
1157 status = STATUS_DLL_NOT_FOUND;
1159 wm->deps[dep] = imp;
1161 current_modref = prev;
1162 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1163 return status;
1167 /*************************************************************************
1168 * alloc_module
1170 * Allocate a WINE_MODREF structure and add it to the process list
1171 * The loader_section must be locked while calling this function.
1173 static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1175 WINE_MODREF *wm;
1176 const WCHAR *p;
1177 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1179 if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1181 wm->ldr.BaseAddress = hModule;
1182 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
1183 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1184 wm->ldr.TlsIndex = -1;
1185 wm->ldr.LoadCount = 1;
1187 RtlCreateUnicodeString( &wm->ldr.FullDllName, nt_name->Buffer + 4 /* \??\ prefix */ );
1188 if ((p = wcsrchr( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
1189 else p = wm->ldr.FullDllName.Buffer;
1190 RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
1192 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) || !is_dll_native_subsystem( &wm->ldr, nt, p ))
1194 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
1195 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1196 if (nt->OptionalHeader.AddressOfEntryPoint)
1197 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1200 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1201 &wm->ldr.InLoadOrderModuleList);
1202 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1203 &wm->ldr.InMemoryOrderModuleList);
1204 /* wait until init is called for inserting into InInitializationOrderModuleList */
1206 if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
1208 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1209 WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1210 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1212 return wm;
1216 /*************************************************************************
1217 * alloc_thread_tls
1219 * Allocate the per-thread structure for module TLS storage.
1221 static NTSTATUS alloc_thread_tls(void)
1223 void **pointers;
1224 UINT i, size;
1226 if (!tls_module_count) return STATUS_SUCCESS;
1228 if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
1229 tls_module_count * sizeof(*pointers) )))
1230 return STATUS_NO_MEMORY;
1232 for (i = 0; i < tls_module_count; i++)
1234 const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1236 if (!dir) continue;
1237 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1238 if (!size && !dir->SizeOfZeroFill) continue;
1240 if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
1242 while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
1243 RtlFreeHeap( GetProcessHeap(), 0, pointers );
1244 return STATUS_NO_MEMORY;
1246 memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
1247 memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1249 TRACE( "thread %04x slot %u: %u/%u bytes at %p\n",
1250 GetCurrentThreadId(), i, size, dir->SizeOfZeroFill, pointers[i] );
1252 NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1253 #if defined(__APPLE__) && defined(__x86_64__)
1254 __asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
1256 : "r" (pointers), "n" (FIELD_OFFSET(TEB, ThreadLocalStoragePointer)));
1257 #endif
1258 return STATUS_SUCCESS;
1262 /*************************************************************************
1263 * call_tls_callbacks
1265 static void call_tls_callbacks( HMODULE module, UINT reason )
1267 const IMAGE_TLS_DIRECTORY *dir;
1268 const PIMAGE_TLS_CALLBACK *callback;
1269 ULONG dirsize;
1271 if (reason == DLL_WINE_PREATTACH) return;
1273 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
1274 if (!dir || !dir->AddressOfCallBacks) return;
1276 for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1278 TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1279 *callback, module, reason_names[reason] );
1280 __TRY
1282 call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1284 __EXCEPT_ALL
1286 TRACE_(relay)("\1exception %08x in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1287 GetExceptionCode(), callback, module, reason_names[reason] );
1288 return;
1290 __ENDTRY
1291 TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1292 *callback, module, reason_names[reason] );
1297 /*************************************************************************
1298 * MODULE_InitDLL
1300 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1302 WCHAR mod_name[32];
1303 NTSTATUS status = STATUS_SUCCESS;
1304 DLLENTRYPROC entry = wm->ldr.EntryPoint;
1305 void *module = wm->ldr.BaseAddress;
1306 BOOL retv = FALSE;
1308 /* Skip calls for modules loaded with special load flags */
1310 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1311 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
1312 if (!entry || !(wm->ldr.Flags & LDR_IMAGE_IS_DLL)) return STATUS_SUCCESS;
1314 if (TRACE_ON(relay))
1316 size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1317 memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
1318 mod_name[len / sizeof(WCHAR)] = 0;
1319 TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1320 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1322 else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
1323 reason_names[reason], lpReserved );
1325 __TRY
1327 retv = call_dll_entry_point( entry, module, reason, lpReserved );
1328 if (!retv)
1329 status = STATUS_DLL_INIT_FAILED;
1331 __EXCEPT_ALL
1333 status = GetExceptionCode();
1334 TRACE_(relay)("\1exception %08x in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1335 status, entry, module, reason_names[reason], lpReserved );
1337 __ENDTRY
1339 /* The state of the module list may have changed due to the call
1340 to the dll. We cannot assume that this module has not been
1341 deleted. */
1342 if (TRACE_ON(relay))
1343 TRACE_(relay)("\1Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1344 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
1345 else
1346 TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1348 return status;
1352 /*************************************************************************
1353 * process_attach
1355 * Send the process attach notification to all DLLs the given module
1356 * depends on (recursively). This is somewhat complicated due to the fact that
1358 * - we have to respect the module dependencies, i.e. modules implicitly
1359 * referenced by another module have to be initialized before the module
1360 * itself can be initialized
1362 * - the initialization routine of a DLL can itself call LoadLibrary,
1363 * thereby introducing a whole new set of dependencies (even involving
1364 * the 'old' modules) at any time during the whole process
1366 * (Note that this routine can be recursively entered not only directly
1367 * from itself, but also via LoadLibrary from one of the called initialization
1368 * routines.)
1370 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1371 * the process *detach* notifications to be sent in the correct order.
1372 * This must not only take into account module dependencies, but also
1373 * 'hidden' dependencies created by modules calling LoadLibrary in their
1374 * attach notification routine.
1376 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1377 * list after the attach notification has returned. This implies that the
1378 * detach notifications are called in the reverse of the sequence the attach
1379 * notifications *returned*.
1381 * The loader_section must be locked while calling this function.
1383 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1385 NTSTATUS status = STATUS_SUCCESS;
1386 ULONG_PTR cookie;
1387 int i;
1389 if (process_detaching) return status;
1391 /* prevent infinite recursion in case of cyclical dependencies */
1392 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1393 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1394 return status;
1396 TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1398 /* Tag current MODREF to prevent recursive loop */
1399 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1400 if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */
1401 if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1403 /* Recursively attach all DLLs this one depends on */
1404 for ( i = 0; i < wm->nDeps; i++ )
1406 if (!wm->deps[i]) continue;
1407 if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1410 if (!wm->ldr.InInitializationOrderModuleList.Flink)
1411 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1412 &wm->ldr.InInitializationOrderModuleList);
1414 /* Call DLL entry point */
1415 if (status == STATUS_SUCCESS)
1417 WINE_MODREF *prev = current_modref;
1418 current_modref = wm;
1420 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1421 status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1422 if (status == STATUS_SUCCESS)
1424 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1426 else
1428 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1429 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );
1431 /* point to the name so LdrInitializeThunk can print it */
1432 last_failed_modref = wm;
1433 WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1435 current_modref = prev;
1438 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1439 /* Remove recursion flag */
1440 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1442 TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1443 return status;
1447 /**********************************************************************
1448 * attach_implicitly_loaded_dlls
1450 * Attach to the (builtin) dlls that have been implicitly loaded because
1451 * of a dependency at the Unix level, but not imported at the Win32 level.
1453 static void attach_implicitly_loaded_dlls( LPVOID reserved )
1455 for (;;)
1457 PLIST_ENTRY mark, entry;
1459 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
1460 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1462 LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
1464 if (mod->Flags & (LDR_LOAD_IN_PROGRESS | LDR_PROCESS_ATTACHED)) continue;
1465 TRACE( "found implicitly loaded %s, attaching to it\n",
1466 debugstr_w(mod->BaseDllName.Buffer));
1467 process_attach( CONTAINING_RECORD(mod, WINE_MODREF, ldr), reserved );
1468 break; /* restart the search from the start */
1470 if (entry == mark) break; /* nothing found */
1475 /*************************************************************************
1476 * process_detach
1478 * Send DLL process detach notifications. See the comment about calling
1479 * sequence at process_attach.
1481 static void process_detach(void)
1483 PLIST_ENTRY mark, entry;
1484 PLDR_MODULE mod;
1486 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1489 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1491 mod = CONTAINING_RECORD(entry, LDR_MODULE,
1492 InInitializationOrderModuleList);
1493 /* Check whether to detach this DLL */
1494 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1495 continue;
1496 if ( mod->LoadCount && !process_detaching )
1497 continue;
1499 /* Call detach notification */
1500 mod->Flags &= ~LDR_PROCESS_ATTACHED;
1501 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1502 DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1503 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1505 /* Restart at head of WINE_MODREF list, as entries might have
1506 been added and/or removed while performing the call ... */
1507 break;
1509 } while (entry != mark);
1512 /*************************************************************************
1513 * thread_attach
1515 * Send DLL thread attach notifications. These are sent in the
1516 * reverse sequence of process detach notification.
1517 * The loader_section must be locked while calling this function.
1519 static void thread_attach(void)
1521 PLIST_ENTRY mark, entry;
1522 PLDR_MODULE mod;
1524 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1525 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1527 mod = CONTAINING_RECORD(entry, LDR_MODULE,
1528 InInitializationOrderModuleList);
1529 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1530 continue;
1531 if ( mod->Flags & LDR_NO_DLL_CALLS )
1532 continue;
1534 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1538 /******************************************************************
1539 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1542 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1544 WINE_MODREF *wm;
1545 NTSTATUS ret = STATUS_SUCCESS;
1547 RtlEnterCriticalSection( &loader_section );
1549 wm = get_modref( hModule );
1550 if (!wm || wm->ldr.TlsIndex != -1)
1551 ret = STATUS_DLL_NOT_FOUND;
1552 else
1553 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1555 RtlLeaveCriticalSection( &loader_section );
1557 return ret;
1560 /******************************************************************
1561 * LdrFindEntryForAddress (NTDLL.@)
1563 * The loader_section must be locked while calling this function
1565 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
1567 PLIST_ENTRY mark, entry;
1568 PLDR_MODULE mod;
1570 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1571 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1573 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
1574 if (mod->BaseAddress <= addr &&
1575 (const char *)addr < (char*)mod->BaseAddress + mod->SizeOfImage)
1577 *pmod = mod;
1578 return STATUS_SUCCESS;
1581 return STATUS_NO_MORE_ENTRIES;
1584 /******************************************************************
1585 * LdrEnumerateLoadedModules (NTDLL.@)
1587 NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
1589 LIST_ENTRY *mark, *entry;
1590 LDR_MODULE *mod;
1591 BOOLEAN stop = FALSE;
1593 TRACE( "(%p, %p, %p)\n", unknown, callback, context );
1595 if (unknown || !callback)
1596 return STATUS_INVALID_PARAMETER;
1598 RtlEnterCriticalSection( &loader_section );
1600 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1601 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1603 mod = CONTAINING_RECORD( entry, LDR_MODULE, InMemoryOrderModuleList );
1604 callback( mod, context, &stop );
1605 if (stop) break;
1608 RtlLeaveCriticalSection( &loader_section );
1609 return STATUS_SUCCESS;
1612 /******************************************************************
1613 * LdrRegisterDllNotification (NTDLL.@)
1615 NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
1616 void *context, void **cookie)
1618 struct ldr_notification *notify;
1620 TRACE( "(%x, %p, %p, %p)\n", flags, callback, context, cookie );
1622 if (!callback || !cookie)
1623 return STATUS_INVALID_PARAMETER;
1625 if (flags)
1626 FIXME( "ignoring flags %x\n", flags );
1628 notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
1629 if (!notify) return STATUS_NO_MEMORY;
1630 notify->callback = callback;
1631 notify->context = context;
1633 RtlEnterCriticalSection( &loader_section );
1634 list_add_tail( &ldr_notifications, &notify->entry );
1635 RtlLeaveCriticalSection( &loader_section );
1637 *cookie = notify;
1638 return STATUS_SUCCESS;
1641 /******************************************************************
1642 * LdrUnregisterDllNotification (NTDLL.@)
1644 NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
1646 struct ldr_notification *notify = cookie;
1648 TRACE( "(%p)\n", cookie );
1650 if (!notify) return STATUS_INVALID_PARAMETER;
1652 RtlEnterCriticalSection( &loader_section );
1653 list_remove( &notify->entry );
1654 RtlLeaveCriticalSection( &loader_section );
1656 RtlFreeHeap( GetProcessHeap(), 0, notify );
1657 return STATUS_SUCCESS;
1660 /******************************************************************
1661 * LdrLockLoaderLock (NTDLL.@)
1663 * Note: some flags are not implemented.
1664 * Flag 0x01 is used to raise exceptions on errors.
1666 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1668 if (flags & ~0x2) FIXME( "flags %x not supported\n", flags );
1670 if (result) *result = 0;
1671 if (magic) *magic = 0;
1672 if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
1673 if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1674 if (!magic) return STATUS_INVALID_PARAMETER_3;
1676 if (flags & 0x2)
1678 if (!RtlTryEnterCriticalSection( &loader_section ))
1680 *result = 2;
1681 return STATUS_SUCCESS;
1683 *result = 1;
1685 else
1687 RtlEnterCriticalSection( &loader_section );
1688 if (result) *result = 1;
1690 *magic = GetCurrentThreadId();
1691 return STATUS_SUCCESS;
1695 /******************************************************************
1696 * LdrUnlockLoaderUnlock (NTDLL.@)
1698 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
1700 if (magic)
1702 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
1703 RtlLeaveCriticalSection( &loader_section );
1705 return STATUS_SUCCESS;
1709 /******************************************************************
1710 * LdrGetProcedureAddress (NTDLL.@)
1712 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
1713 ULONG ord, PVOID *address)
1715 IMAGE_EXPORT_DIRECTORY *exports;
1716 DWORD exp_size;
1717 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1719 RtlEnterCriticalSection( &loader_section );
1721 /* check if the module itself is invalid to return the proper error */
1722 if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
1723 else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
1724 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1726 LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1727 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path )
1728 : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path );
1729 if (proc)
1731 *address = proc;
1732 ret = STATUS_SUCCESS;
1736 RtlLeaveCriticalSection( &loader_section );
1737 return ret;
1741 /***********************************************************************
1742 * get_builtin_fullname
1744 * Build the full pathname for a builtin dll.
1746 static BOOL get_builtin_fullname( UNICODE_STRING *nt_name, const UNICODE_STRING *path,
1747 const char *filename )
1749 static const WCHAR nt_prefixW[] = {'\\','?','?','\\',0};
1750 static const WCHAR soW[] = {'.','s','o',0};
1751 WCHAR *p, *fullname, filenameW[256];
1752 size_t len = strlen(filename);
1754 if (len >= ARRAY_SIZE(filenameW)) return FALSE;
1755 ascii_to_unicode( filenameW, filename, len + 1 );
1757 /* check if path can correspond to the dll we have */
1758 if (path && (p = wcsrchr( path->Buffer, '\\' )))
1760 p++;
1761 if (!wcsnicmp( p, filenameW, len ) && (!p[len] || !wcsicmp( p + len, soW )))
1763 /* the filename matches, use path as the full path */
1764 len += p - path->Buffer;
1765 if (!(fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
1766 return FALSE;
1767 memcpy( fullname, path->Buffer, len * sizeof(WCHAR) );
1768 fullname[len] = 0;
1769 goto done;
1773 if (!(fullname = RtlAllocateHeap( GetProcessHeap(), 0,
1774 (wcslen(system_dir) + len + 5) * sizeof(WCHAR) )))
1775 return FALSE;
1776 wcscpy( fullname, nt_prefixW );
1777 wcscat( fullname, system_dir );
1778 wcscat( fullname, filenameW );
1779 done:
1780 RtlInitUnicodeString( nt_name, fullname );
1781 return TRUE;
1785 /*************************************************************************
1786 * is_16bit_builtin
1788 static BOOL is_16bit_builtin( HMODULE module )
1790 const IMAGE_EXPORT_DIRECTORY *exports;
1791 DWORD exp_size;
1793 if (!(exports = RtlImageDirectoryEntryToData( module, TRUE,
1794 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1795 return FALSE;
1797 return find_named_export( module, exports, exp_size, "__wine_spec_dos_header", -1, NULL ) != NULL;
1801 /***********************************************************************
1802 * load_builtin_callback
1804 * Load a library in memory; callback function for wine_dll_register
1806 static void load_builtin_callback( void *module, const char *filename )
1808 static const WCHAR emptyW[1];
1809 IMAGE_NT_HEADERS *nt;
1810 WINE_MODREF *wm;
1811 UNICODE_STRING nt_name;
1812 const WCHAR *load_path;
1814 if (!module)
1816 ERR("could not map image for %s\n", filename ? filename : "main exe" );
1817 return;
1819 if (!(nt = RtlImageNtHeader( module )))
1821 ERR( "bad module for %s\n", filename ? filename : "main exe" );
1822 builtin_load_info->status = STATUS_INVALID_IMAGE_FORMAT;
1823 return;
1826 virtual_create_builtin_view( module );
1828 /* create the MODREF */
1830 if (!get_builtin_fullname( &nt_name, builtin_load_info->filename, filename ))
1832 ERR( "can't load %s\n", filename );
1833 builtin_load_info->status = STATUS_NO_MEMORY;
1834 return;
1837 wm = alloc_module( module, &nt_name, TRUE );
1838 RtlFreeUnicodeString( &nt_name );
1839 if (!wm)
1841 ERR( "can't load %s\n", filename );
1842 builtin_load_info->status = STATUS_NO_MEMORY;
1843 return;
1846 if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
1847 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE ||
1848 is_16bit_builtin( module ))
1850 /* fixup imports */
1852 load_path = builtin_load_info->load_path;
1853 if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1854 if (!load_path) load_path = emptyW;
1855 if (fixup_imports( wm, load_path ) != STATUS_SUCCESS)
1857 /* the module has only be inserted in the load & memory order lists */
1858 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
1859 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
1860 /* FIXME: free the modref */
1861 builtin_load_info->status = STATUS_DLL_NOT_FOUND;
1862 return;
1866 builtin_load_info->wm = wm;
1867 TRACE( "loaded %s %p %p\n", filename, wm, module );
1869 /* send the DLL load event */
1871 SERVER_START_REQ( load_dll )
1873 req->base = wine_server_client_ptr( module );
1874 req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
1875 req->dbg_size = nt->FileHeader.NumberOfSymbols;
1876 req->name = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1877 wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1878 wine_server_call( req );
1880 SERVER_END_REQ;
1882 /* setup relay debugging entry points */
1883 if (TRACE_ON(relay)) RELAY_SetupDLL( module );
1887 /***********************************************************************
1888 * set_security_cookie
1890 * Create a random security cookie for buffer overflow protection. Make
1891 * sure it does not accidentally match the default cookie value.
1893 static void set_security_cookie( void *module, SIZE_T len )
1895 static ULONG seed;
1896 IMAGE_LOAD_CONFIG_DIRECTORY *loadcfg;
1897 ULONG loadcfg_size;
1898 ULONG_PTR *cookie;
1900 loadcfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &loadcfg_size );
1901 if (!loadcfg) return;
1902 if (loadcfg_size < offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie) + sizeof(loadcfg->SecurityCookie)) return;
1903 if (!loadcfg->SecurityCookie) return;
1904 if (loadcfg->SecurityCookie < (ULONG_PTR)module ||
1905 loadcfg->SecurityCookie > (ULONG_PTR)module + len - sizeof(ULONG_PTR))
1907 WARN( "security cookie %p outside of image %p-%p\n",
1908 (void *)loadcfg->SecurityCookie, module, (char *)module + len );
1909 return;
1912 cookie = (ULONG_PTR *)loadcfg->SecurityCookie;
1913 TRACE( "initializing security cookie %p\n", cookie );
1915 if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
1916 for (;;)
1918 if (*cookie == DEFAULT_SECURITY_COOKIE_16)
1919 *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
1920 else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
1921 *cookie = RtlRandom( &seed );
1922 #ifdef DEFAULT_SECURITY_COOKIE_64
1923 else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
1925 *cookie = RtlRandom( &seed );
1926 /* fill up, but keep the highest word clear */
1927 *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
1929 #endif
1930 else
1931 break;
1935 static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
1937 char *base;
1938 IMAGE_BASE_RELOCATION *rel, *end;
1939 const IMAGE_DATA_DIRECTORY *relocs;
1940 const IMAGE_SECTION_HEADER *sec;
1941 INT_PTR delta;
1942 ULONG protect_old[96], i;
1944 base = (char *)nt->OptionalHeader.ImageBase;
1945 if (module == base) return STATUS_SUCCESS; /* nothing to do */
1947 /* no relocations are performed on non page-aligned binaries */
1948 if (nt->OptionalHeader.SectionAlignment < page_size)
1949 return STATUS_SUCCESS;
1951 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
1952 return STATUS_SUCCESS;
1954 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1956 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1958 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
1959 base, module );
1960 return STATUS_CONFLICTING_ADDRESSES;
1963 if (!relocs->Size) return STATUS_SUCCESS;
1964 if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;
1966 if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
1967 return STATUS_INVALID_IMAGE_FORMAT;
1969 sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
1970 nt->FileHeader.SizeOfOptionalHeader);
1971 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
1973 void *addr = get_rva( module, sec[i].VirtualAddress );
1974 SIZE_T size = sec[i].SizeOfRawData;
1975 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
1976 &size, PAGE_READWRITE, &protect_old[i] );
1979 TRACE( "relocating from %p-%p to %p-%p\n",
1980 base, base + len, module, (char *)module + len );
1982 rel = get_rva( module, relocs->VirtualAddress );
1983 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
1984 delta = (char *)module - base;
1986 while (rel < end - 1 && rel->SizeOfBlock)
1988 if (rel->VirtualAddress >= len)
1990 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
1991 return STATUS_ACCESS_VIOLATION;
1993 rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
1994 (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
1995 (USHORT *)(rel + 1), delta );
1996 if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
1999 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2001 void *addr = get_rva( module, sec[i].VirtualAddress );
2002 SIZE_T size = sec[i].SizeOfRawData;
2003 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2004 &size, protect_old[i], &protect_old[i] );
2007 return STATUS_SUCCESS;
2010 #ifdef _WIN64
2011 /* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
2012 static BOOL convert_to_pe64( HMODULE module, const pe_image_info_t *info )
2014 static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
2015 IMAGE_DIRECTORY_ENTRY_SECURITY,
2016 IMAGE_DIRECTORY_ENTRY_BASERELOC,
2017 IMAGE_DIRECTORY_ENTRY_DEBUG,
2018 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
2019 IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
2020 IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
2021 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2022 SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
2023 IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + hdr_size);
2024 SIZE_T size = info->header_size;
2025 void *addr = module;
2026 ULONG i, old_prot;
2028 TRACE( "%p\n", module );
2030 if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
2031 return FALSE;
2033 if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
2035 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2036 return FALSE;
2039 memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
2040 memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
2041 hdr64.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2042 hdr64.AddressOfEntryPoint = 0;
2043 hdr64.ImageBase = hdr32.ImageBase;
2044 hdr64.SizeOfStackReserve = hdr32.SizeOfStackReserve;
2045 hdr64.SizeOfStackCommit = hdr32.SizeOfStackCommit;
2046 hdr64.SizeOfHeapReserve = hdr32.SizeOfHeapReserve;
2047 hdr64.SizeOfHeapCommit = hdr32.SizeOfHeapCommit;
2048 hdr64.LoaderFlags = hdr32.LoaderFlags;
2049 hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
2050 for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
2051 hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];
2053 memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
2054 nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
2055 nt->OptionalHeader = hdr64;
2056 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2057 return TRUE;
2059 #endif
2061 /* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
2062 /* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2063 static BOOL is_valid_binary( HMODULE module, const pe_image_info_t *info )
2065 #ifdef __i386__
2066 return info->machine == IMAGE_FILE_MACHINE_I386;
2067 #elif defined(__arm__)
2068 return info->machine == IMAGE_FILE_MACHINE_ARM ||
2069 info->machine == IMAGE_FILE_MACHINE_THUMB ||
2070 info->machine == IMAGE_FILE_MACHINE_ARMNT;
2071 #elif defined(_WIN64) /* support 32-bit IL-only images on 64-bit */
2072 #ifdef __x86_64__
2073 if (info->machine == IMAGE_FILE_MACHINE_AMD64) return TRUE;
2074 #else
2075 if (info->machine == IMAGE_FILE_MACHINE_ARM64) return TRUE;
2076 #endif
2077 if (!info->contains_code) return TRUE;
2078 if (!(info->image_flags & IMAGE_FLAGS_ComPlusNativeReady))
2080 /* check COM header directly, ignoring runtime version */
2081 DWORD size;
2082 const IMAGE_COR20_HEADER *cor_header = RtlImageDirectoryEntryToData( module, TRUE,
2083 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &size );
2084 if (!cor_header || !(cor_header->Flags & COMIMAGE_FLAGS_ILONLY)) return FALSE;
2086 return convert_to_pe64( module, info );
2087 #else
2088 return FALSE; /* no wow64 support on other platforms */
2089 #endif
2093 /******************************************************************
2094 * get_module_path_end
2096 * Returns the end of the directory component of the module path.
2098 static inline const WCHAR *get_module_path_end( const WCHAR *module )
2100 const WCHAR *p;
2101 const WCHAR *mod_end = module;
2103 if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
2104 if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2105 if (mod_end == module + 2 && module[1] == ':') mod_end++;
2106 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
2107 return mod_end;
2111 /******************************************************************
2112 * append_path
2114 * Append a counted string to the load path. Helper for get_dll_load_path.
2116 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
2118 if (len == -1) len = wcslen(str);
2119 if (!len) return p;
2120 memcpy( p, str, len * sizeof(WCHAR) );
2121 p[len] = ';';
2122 return p + len + 1;
2126 /******************************************************************
2127 * get_dll_load_path
2129 static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2131 static const WCHAR pathW[] = {'P','A','T','H',0};
2133 const WCHAR *mod_end = module;
2134 UNICODE_STRING name, value;
2135 WCHAR *p, *ret;
2136 int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2138 if (module)
2140 mod_end = get_module_path_end( module );
2141 len += (mod_end - module) + 1;
2144 RtlInitUnicodeString( &name, pathW );
2145 value.Length = 0;
2146 value.MaximumLength = 0;
2147 value.Buffer = NULL;
2148 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2149 path_len = value.Length;
2151 if (dll_dir) len += wcslen( dll_dir ) + 1;
2152 else len += 2; /* current directory */
2153 if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2154 return STATUS_NO_MEMORY;
2156 p = append_path( p, module, mod_end - module );
2157 if (dll_dir) p = append_path( p, dll_dir, -1 );
2158 else if (!safe_mode) p = append_path( p, dotW, -1 );
2159 p = append_path( p, system_path, -1 );
2160 if (!dll_dir && safe_mode) p = append_path( p, dotW, -1 );
2162 value.Buffer = p;
2163 value.MaximumLength = path_len;
2165 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2167 WCHAR *new_ptr;
2169 /* grow the buffer and retry */
2170 path_len = value.Length;
2171 if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
2173 RtlFreeHeap( GetProcessHeap(), 0, ret );
2174 return STATUS_NO_MEMORY;
2176 value.Buffer = new_ptr + (value.Buffer - ret);
2177 value.MaximumLength = path_len;
2178 ret = new_ptr;
2180 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
2181 *path = ret;
2182 return STATUS_SUCCESS;
2186 /******************************************************************
2187 * get_dll_load_path_search_flags
2189 static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
2191 const WCHAR *image = NULL, *mod_end, *image_end;
2192 struct dll_dir_entry *dir;
2193 WCHAR *p, *ret;
2194 int len = 1;
2196 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
2197 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
2198 LOAD_LIBRARY_SEARCH_USER_DIRS |
2199 LOAD_LIBRARY_SEARCH_SYSTEM32);
2201 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
2203 DWORD type = RtlDetermineDosPathNameType_U( module );
2204 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2205 return STATUS_INVALID_PARAMETER;
2206 mod_end = get_module_path_end( module );
2207 len += (mod_end - module) + 1;
2209 else module = NULL;
2211 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
2213 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
2214 image_end = get_module_path_end( image );
2215 len += (image_end - image) + 1;
2218 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2220 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2221 len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2222 if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
2225 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2227 if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2229 if (module) p = append_path( p, module, mod_end - module );
2230 if (image) p = append_path( p, image, image_end - image );
2231 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2233 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2234 p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
2235 p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
2237 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2238 else
2240 if (p > ret) p--;
2241 *p = 0;
2244 *path = ret;
2245 return STATUS_SUCCESS;
2249 /***********************************************************************
2250 * open_dll_file
2252 * Open a file for a new dll. Helper for find_dll_file.
2254 static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm,
2255 void **module, pe_image_info_t *image_info, struct stat *st )
2257 FILE_BASIC_INFORMATION info;
2258 OBJECT_ATTRIBUTES attr;
2259 IO_STATUS_BLOCK io;
2260 LARGE_INTEGER size;
2261 SIZE_T len = 0;
2262 NTSTATUS status;
2263 HANDLE handle, mapping;
2264 int fd, needs_close;
2266 if ((*pwm = find_fullname_module( nt_name )))
2268 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2269 *module = NULL;
2270 return STATUS_SUCCESS;
2273 attr.Length = sizeof(attr);
2274 attr.RootDirectory = 0;
2275 attr.Attributes = OBJ_CASE_INSENSITIVE;
2276 attr.ObjectName = nt_name;
2277 attr.SecurityDescriptor = NULL;
2278 attr.SecurityQualityOfService = NULL;
2279 if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2280 FILE_SHARE_READ | FILE_SHARE_DELETE,
2281 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
2283 if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
2284 status != STATUS_OBJECT_NAME_NOT_FOUND &&
2285 !NtQueryAttributesFile( &attr, &info ))
2287 /* if the file exists but failed to open, report the error */
2288 return status;
2290 /* otherwise continue searching */
2291 return STATUS_DLL_NOT_FOUND;
2294 if (!server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))
2296 fstat( fd, st );
2297 if (needs_close) close( fd );
2298 if ((*pwm = find_fileid_module( st )))
2300 TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2301 (*pwm)->ldr.BaseAddress, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2302 NtClose( handle );
2303 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2304 *module = NULL;
2305 return STATUS_SUCCESS;
2309 size.QuadPart = 0;
2310 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2311 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
2312 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
2313 NtClose( handle );
2315 if (!status)
2317 if (*module)
2319 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2320 *module = NULL;
2322 status = virtual_map_section( mapping, module, 0, 0, NULL, &len,
2323 0, PAGE_EXECUTE_READ, image_info );
2324 if (status == STATUS_IMAGE_NOT_AT_BASE) status = STATUS_SUCCESS;
2325 NtClose( mapping );
2327 if (!status && !is_valid_binary( *module, image_info ))
2329 TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->machine );
2330 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2331 *module = NULL;
2332 status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2334 return status;
2338 /******************************************************************************
2339 * load_native_dll (internal)
2341 static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
2342 const pe_image_info_t *image_info, DWORD flags, WINE_MODREF** pwm,
2343 struct stat *st )
2345 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( *module );
2346 WINE_MODREF *wm;
2347 NTSTATUS status;
2348 const char *dll_type = (image_info->image_flags & IMAGE_FLAGS_WineBuiltin) ? "PE builtin" : "native";
2350 TRACE("Trying %s dll %s\n", dll_type, debugstr_us(nt_name) );
2352 /* perform base relocation, if necessary */
2354 if ((status = perform_relocations( *module, nt, image_info->map_size ))) return status;
2356 /* create the MODREF */
2358 if (!(wm = alloc_module( *module, nt_name, (image_info->image_flags & IMAGE_FLAGS_WineBuiltin) )))
2359 return STATUS_NO_MEMORY;
2361 wm->dev = st->st_dev;
2362 wm->ino = st->st_ino;
2363 if (image_info->loader_flags) wm->ldr.Flags |= LDR_COR_IMAGE;
2364 if (image_info->image_flags & IMAGE_FLAGS_ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
2366 set_security_cookie( *module, image_info->map_size );
2368 /* fixup imports */
2370 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
2371 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
2372 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
2374 if (wm->ldr.Flags & LDR_COR_ILONLY)
2375 status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
2376 else
2377 status = fixup_imports( wm, load_path );
2378 if (status != STATUS_SUCCESS)
2380 /* the module has only be inserted in the load & memory order lists */
2381 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
2382 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
2384 /* FIXME: there are several more dangling references
2385 * left. Including dlls loaded by this dll before the
2386 * failed one. Unrolling is rather difficult with the
2387 * current structure and we can leave them lying
2388 * around with no problems, so we don't care.
2389 * As these might reference our wm, we don't free it.
2391 *module = NULL;
2392 return status;
2396 /* send DLL load event */
2398 SERVER_START_REQ( load_dll )
2400 req->base = wine_server_client_ptr( *module );
2401 req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
2402 req->dbg_size = nt->FileHeader.NumberOfSymbols;
2403 req->name = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
2404 wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
2405 wine_server_call( req );
2407 SERVER_END_REQ;
2409 if (image_info->image_flags & IMAGE_FLAGS_WineBuiltin)
2411 if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
2413 else
2415 if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
2418 TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module, dll_type );
2420 wm->ldr.LoadCount = 1;
2421 *pwm = wm;
2422 *module = NULL;
2423 return STATUS_SUCCESS;
2427 /* check if the library is the correct architecture */
2428 /* only returns false for a valid library of the wrong arch */
2429 static int check_library_arch( int fd )
2431 #ifdef __APPLE__
2432 struct /* Mach-O header */
2434 unsigned int magic;
2435 unsigned int cputype;
2436 } header;
2438 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
2439 if (header.magic != 0xfeedface) return 1;
2440 if (sizeof(void *) == sizeof(int)) return !(header.cputype >> 24);
2441 else return (header.cputype >> 24) == 1; /* CPU_ARCH_ABI64 */
2442 #else
2443 struct /* ELF header */
2445 unsigned char magic[4];
2446 unsigned char class;
2447 unsigned char data;
2448 unsigned char version;
2449 } header;
2451 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
2452 if (memcmp( header.magic, "\177ELF", 4 )) return 1;
2453 if (header.version != 1 /* EV_CURRENT */) return 1;
2454 #ifdef WORDS_BIGENDIAN
2455 if (header.data != 2 /* ELFDATA2MSB */) return 1;
2456 #else
2457 if (header.data != 1 /* ELFDATA2LSB */) return 1;
2458 #endif
2459 if (sizeof(void *) == sizeof(int)) return header.class == 1; /* ELFCLASS32 */
2460 else return header.class == 2; /* ELFCLASS64 */
2461 #endif
2464 static inline char *prepend( char *buffer, const char *str, size_t len )
2466 return memcpy( buffer - len, str, len );
2469 /***********************************************************************
2470 * open_builtin_file
2472 static NTSTATUS open_builtin_file( char *name, WINE_MODREF **pwm, void **module,
2473 pe_image_info_t *image_info, struct stat *st, char **so_name )
2475 ANSI_STRING strA;
2476 UNICODE_STRING nt_name;
2477 NTSTATUS status;
2478 int fd;
2480 nt_name.Buffer = NULL;
2481 RtlInitString( &strA, name );
2482 if ((status = wine_unix_to_nt_file_name( &strA, &nt_name ))) return status;
2484 status = open_dll_file( &nt_name, pwm, module, image_info, st );
2485 RtlFreeUnicodeString( &nt_name );
2487 /* ignore non-builtins */
2488 if (!status && !*pwm && !(image_info->image_flags & IMAGE_FLAGS_WineBuiltin))
2490 WARN( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_a(name) );
2491 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2492 *module = NULL;
2493 status = STATUS_DLL_NOT_FOUND;
2496 if (status != STATUS_DLL_NOT_FOUND) return status;
2498 /* try .so file */
2500 strcat( name, ".so" );
2501 if ((fd = open( name, O_RDONLY )) != -1)
2503 if (check_library_arch( fd ))
2505 if ((*so_name = RtlAllocateHeap( GetProcessHeap(), 0, strlen(name) + 1 )))
2506 strcpy( *so_name, name );
2507 NtUnmapViewOfSection( NtCurrentProcess(), *module );
2508 *module = NULL;
2509 status = STATUS_SUCCESS;
2511 else status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2512 close( fd );
2514 return status;
2518 /***********************************************************************
2519 * find_builtin_dll
2521 static NTSTATUS find_builtin_dll( const WCHAR *name, WINE_MODREF **pwm,
2522 void **module, pe_image_info_t *image_info, struct stat *st,
2523 char **so_name )
2525 const char *path, *build_dir = wine_get_build_dir();
2526 unsigned int i, pos, len, namelen, maxlen = 0;
2527 char *ptr, *file;
2528 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2529 BOOL found_image = FALSE;
2531 len = wcslen( name );
2532 if (build_dir) maxlen = strlen(build_dir) + sizeof("/programs/") + len;
2533 for (i = 0; (path = wine_dll_enum_load_path( i )); i++) maxlen = max( maxlen, strlen(path)+1 );
2534 maxlen += len + sizeof(".so");
2536 if (!(file = RtlAllocateHeap( GetProcessHeap(), 0, maxlen ))) return STATUS_NO_MEMORY;
2538 pos = maxlen - len - sizeof(".so");
2539 /* we don't want to depend on the current codepage here */
2540 for (i = 0; i < len; i++)
2542 if (name[i] > 127) goto done;
2543 file[pos + i] = (char)name[i];
2544 if (file[pos + i] >= 'A' && file[pos + i] <= 'Z') file[pos + i] += 'a' - 'A';
2546 file[--pos] = '/';
2548 if (build_dir)
2550 /* try as a dll */
2551 ptr = file + pos;
2552 namelen = len + 1;
2553 file[pos + len + 1] = 0;
2554 if (namelen > 4 && !memcmp( ptr + namelen - 4, ".dll", 4 )) namelen -= 4;
2555 ptr = prepend( ptr, ptr, namelen );
2556 ptr = prepend( ptr, "/dlls", sizeof("/dlls") - 1 );
2557 ptr = prepend( ptr, build_dir, strlen(build_dir) );
2558 status = open_builtin_file( ptr, pwm, module, image_info, st, so_name );
2559 if (status != STATUS_DLL_NOT_FOUND) goto done;
2561 /* now as a program */
2562 ptr = file + pos;
2563 namelen = len + 1;
2564 file[pos + len + 1] = 0;
2565 if (namelen > 4 && !memcmp( ptr + namelen - 4, ".exe", 4 )) namelen -= 4;
2566 ptr = prepend( ptr, ptr, namelen );
2567 ptr = prepend( ptr, "/programs", sizeof("/programs") - 1 );
2568 ptr = prepend( ptr, build_dir, strlen(build_dir) );
2569 status = open_builtin_file( ptr, pwm, module, image_info, st, so_name );
2570 if (status != STATUS_DLL_NOT_FOUND) goto done;
2573 for (i = 0; (path = wine_dll_enum_load_path( i )); i++)
2575 file[pos + len + 1] = 0;
2576 ptr = prepend( file + pos, path, strlen(path) );
2577 status = open_builtin_file( ptr, pwm, module, image_info, st, so_name );
2578 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2579 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2582 if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2583 WARN( "cannot find builtin library for %s\n", debugstr_w(name) );
2585 done:
2586 RtlFreeHeap( GetProcessHeap(), 0, file );
2587 return status;
2591 /***********************************************************************
2592 * load_so_dll
2594 static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2595 const char *so_name, WINE_MODREF** pwm )
2597 char error[256];
2598 void *handle;
2599 struct builtin_load_info info, *prev_info;
2600 ANSI_STRING unix_name;
2602 if (so_name)
2604 TRACE( "loading %s from so lib %s\n", debugstr_us(nt_name), debugstr_a(so_name) );
2605 unix_name.Buffer = NULL;
2607 else
2609 TRACE( "loading %s as so lib\n", debugstr_us(nt_name) );
2610 if (wine_nt_to_unix_file_name( nt_name, &unix_name, FILE_OPEN, FALSE ))
2611 return STATUS_DLL_NOT_FOUND;
2614 info.load_path = load_path;
2615 info.filename = nt_name;
2616 info.status = STATUS_SUCCESS;
2617 info.wm = NULL;
2619 prev_info = builtin_load_info;
2620 builtin_load_info = &info;
2621 handle = wine_dlopen( so_name ? so_name : unix_name.Buffer, RTLD_NOW, error, sizeof(error) );
2622 builtin_load_info = prev_info;
2623 RtlFreeHeap( GetProcessHeap(), 0, unix_name.Buffer );
2625 if (!handle)
2627 if (so_name)
2629 ERR("failed to load .so lib %s: %s\n", debugstr_a(so_name), error );
2630 return STATUS_PROCEDURE_NOT_FOUND;
2632 WARN( "failed to load .so lib %s: %s\n", debugstr_us(nt_name), error );
2633 return STATUS_INVALID_IMAGE_FORMAT;
2636 if (info.status != STATUS_SUCCESS) goto failed;
2638 if (!info.wm)
2640 /* The constructor wasn't called, this means the .so is already
2641 * loaded under a different name. Try to find the wm for it. */
2643 if (!(info.wm = find_so_module( handle )))
2645 info.status = STATUS_INVALID_IMAGE_FORMAT;
2646 goto failed;
2648 TRACE( "Found %s at %p for builtin %s\n",
2649 debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress,
2650 debugstr_us(nt_name) );
2651 if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
2652 wine_dlclose( handle, NULL, 0 ); /* release the libdl refcount */
2654 else
2656 TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress );
2657 info.wm->ldr.LoadCount = 1;
2658 info.wm->ldr.SectionHandle = handle;
2661 *pwm = info.wm;
2662 return STATUS_SUCCESS;
2664 failed:
2665 wine_dlclose( handle, NULL, 0 );
2666 return info.status;
2670 /***********************************************************************
2671 * load_builtin_dll
2673 static NTSTATUS load_builtin_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module_ptr,
2674 DWORD flags, WINE_MODREF** pwm )
2676 const WCHAR *name, *p;
2677 NTSTATUS status;
2678 void *module = NULL;
2679 pe_image_info_t image_info;
2680 struct stat st;
2681 char *so_name;
2683 /* Fix the name in case we have a full path and extension */
2684 name = nt_name->Buffer;
2685 if ((p = wcsrchr( name, '\\' ))) name = p + 1;
2686 if ((p = wcsrchr( name, '/' ))) name = p + 1;
2688 TRACE("Trying built-in %s\n", debugstr_w(name));
2690 if (!module_ptr) module_ptr = &module;
2692 status = find_builtin_dll( name, pwm, module_ptr, &image_info, &st, &so_name );
2693 if (status) return status;
2695 if (*pwm)
2697 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2698 TRACE( "Found %s for %s at %p, count=%d\n",
2699 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(name),
2700 (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
2701 return STATUS_SUCCESS;
2704 if (*module_ptr)
2706 TRACE( "loading %s from PE builtin %s\n", debugstr_w(name), debugstr_us(nt_name) );
2707 return load_native_dll( load_path, nt_name, module_ptr, &image_info, flags, pwm, &st );
2710 status = load_so_dll( load_path, nt_name, so_name, pwm );
2711 RtlFreeHeap( GetProcessHeap(), 0, so_name );
2712 return status;
2716 /***********************************************************************
2717 * find_actctx_dll
2719 * Find the full path (if any) of the dll from the activation context.
2721 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
2723 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
2724 static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
2726 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
2727 ACTCTX_SECTION_KEYED_DATA data;
2728 UNICODE_STRING nameW;
2729 NTSTATUS status;
2730 SIZE_T needed, size = 1024;
2731 WCHAR *p;
2733 RtlInitUnicodeString( &nameW, libname );
2734 data.cbSize = sizeof(data);
2735 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2736 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
2737 &nameW, &data );
2738 if (status != STATUS_SUCCESS) return status;
2740 for (;;)
2742 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2744 status = STATUS_NO_MEMORY;
2745 goto done;
2747 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
2748 AssemblyDetailedInformationInActivationContext,
2749 info, size, &needed );
2750 if (status == STATUS_SUCCESS) break;
2751 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
2752 RtlFreeHeap( GetProcessHeap(), 0, info );
2753 size = needed;
2754 /* restart with larger buffer */
2757 if (!info->lpAssemblyManifestPath)
2759 status = STATUS_SXS_KEY_NOT_FOUND;
2760 goto done;
2763 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2765 DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2766 p++;
2767 len = wcslen( p );
2768 if (!dirlen || len <= dirlen ||
2769 RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2770 wcsicmp( p + dirlen, dotManifestW ))
2772 /* manifest name does not match directory name, so it's not a global
2773 * windows/winsxs manifest; use the manifest directory name instead */
2774 dirlen = p - info->lpAssemblyManifestPath;
2775 needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
2776 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2778 status = STATUS_NO_MEMORY;
2779 goto done;
2781 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
2782 p += dirlen;
2783 wcscpy( p, libname );
2784 goto done;
2788 if (!info->lpAssemblyDirectoryName)
2790 status = STATUS_SXS_KEY_NOT_FOUND;
2791 goto done;
2794 needed = (wcslen(user_shared_data->NtSystemRoot) * sizeof(WCHAR) +
2795 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2797 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2799 status = STATUS_NO_MEMORY;
2800 goto done;
2802 wcscpy( p, user_shared_data->NtSystemRoot );
2803 p += wcslen(p);
2804 memcpy( p, winsxsW, sizeof(winsxsW) );
2805 p += ARRAY_SIZE( winsxsW );
2806 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
2807 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2808 *p++ = '\\';
2809 wcscpy( p, libname );
2810 done:
2811 RtlFreeHeap( GetProcessHeap(), 0, info );
2812 RtlReleaseActivationContext( data.hActCtx );
2813 return status;
2817 /***********************************************************************
2818 * search_dll_file
2820 * Search for dll in the specified paths.
2822 static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
2823 WINE_MODREF **pwm, void **module, pe_image_info_t *image_info,
2824 struct stat *st )
2826 WCHAR *name;
2827 BOOL found_image = FALSE;
2828 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2829 ULONG len = wcslen( paths );
2831 if (len < wcslen( system_dir )) len = wcslen( system_dir );
2832 len += wcslen( search ) + 2;
2834 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2835 return STATUS_NO_MEMORY;
2837 while (*paths)
2839 LPCWSTR ptr = paths;
2841 while (*ptr && *ptr != ';') ptr++;
2842 len = ptr - paths;
2843 if (*ptr == ';') ptr++;
2844 memcpy( name, paths, len * sizeof(WCHAR) );
2845 if (len && name[len - 1] != '\\') name[len++] = '\\';
2846 wcscpy( name + len, search );
2848 nt_name->Buffer = NULL;
2849 if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
2851 status = open_dll_file( nt_name, pwm, module, image_info, st );
2852 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2853 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2854 RtlFreeUnicodeString( nt_name );
2855 paths = ptr;
2858 if (!found_image)
2860 /* not found, return file in the system dir to be loaded as builtin */
2861 wcscpy( name, system_dir );
2862 wcscat( name, search );
2863 if (!RtlDosPathNameToNtPathName_U( name, nt_name, NULL, NULL )) status = STATUS_NO_MEMORY;
2865 else status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2867 done:
2868 RtlFreeHeap( GetProcessHeap(), 0, name );
2869 return status;
2873 /***********************************************************************
2874 * find_dll_file
2876 * Find the file (or already loaded module) for a given dll name.
2878 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
2879 UNICODE_STRING *nt_name, WINE_MODREF **pwm,
2880 void **module, pe_image_info_t *image_info, struct stat *st )
2882 WCHAR *ext, *dllname;
2883 NTSTATUS status;
2884 ULONG wow64_old_value = 0;
2886 *pwm = NULL;
2887 *module = NULL;
2888 dllname = NULL;
2890 if (default_ext) /* first append default extension */
2892 if (!(ext = wcsrchr( libname, '.')) || wcschr( ext, '/' ) || wcschr( ext, '\\'))
2894 if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
2895 (wcslen(libname)+wcslen(default_ext)+1) * sizeof(WCHAR))))
2896 return STATUS_NO_MEMORY;
2897 wcscpy( dllname, libname );
2898 wcscat( dllname, default_ext );
2899 libname = dllname;
2903 /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
2904 if (is_wow64) RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
2906 nt_name->Buffer = NULL;
2908 if (!contains_path( libname ))
2910 WCHAR *fullname = NULL;
2912 status = find_actctx_dll( libname, &fullname );
2913 if (status == STATUS_SUCCESS)
2915 TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
2916 RtlFreeHeap( GetProcessHeap(), 0, dllname );
2917 libname = dllname = fullname;
2919 else
2921 if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
2922 if ((*pwm = find_basename_module( libname )) != NULL)
2924 status = STATUS_SUCCESS;
2925 goto done;
2930 if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
2931 status = search_dll_file( load_path, libname, nt_name, pwm, module, image_info, st );
2932 else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
2933 status = open_dll_file( nt_name, pwm, module, image_info, st );
2935 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT;
2937 done:
2938 RtlFreeHeap( GetProcessHeap(), 0, dllname );
2939 if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
2940 return status;
2944 /***********************************************************************
2945 * load_dll (internal)
2947 * Load a PE style module according to the load order.
2948 * The loader_section must be locked while calling this function.
2950 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
2951 DWORD flags, WINE_MODREF** pwm )
2953 enum loadorder loadorder;
2954 WINE_MODREF *main_exe;
2955 UNICODE_STRING nt_name;
2956 struct stat st;
2957 void *module;
2958 pe_image_info_t image_info;
2959 NTSTATUS nts;
2961 TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
2963 nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &module, &image_info, &st );
2965 if (*pwm) /* found already loaded module */
2967 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2969 TRACE("Found %s for %s at %p, count=%d\n",
2970 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
2971 (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
2972 RtlFreeUnicodeString( &nt_name );
2973 return STATUS_SUCCESS;
2976 if (nts && nts != STATUS_DLL_NOT_FOUND && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
2978 main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
2979 loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, &nt_name );
2981 switch (nts)
2983 case STATUS_INVALID_IMAGE_NOT_MZ: /* not in PE format, maybe it's a .so file */
2984 switch (loadorder)
2986 case LO_NATIVE:
2987 case LO_NATIVE_BUILTIN:
2988 case LO_BUILTIN:
2989 case LO_BUILTIN_NATIVE:
2990 case LO_DEFAULT:
2991 if (!load_so_dll( load_path, &nt_name, NULL, pwm )) nts = STATUS_SUCCESS;
2992 break;
2993 default:
2994 nts = STATUS_DLL_NOT_FOUND;
2995 break;
2997 break;
2999 case STATUS_SUCCESS: /* valid PE file */
3000 if (image_info.image_flags & IMAGE_FLAGS_WineBuiltin)
3002 switch (loadorder)
3004 case LO_NATIVE_BUILTIN:
3005 case LO_BUILTIN:
3006 case LO_BUILTIN_NATIVE:
3007 case LO_DEFAULT:
3008 nts = load_builtin_dll( load_path, &nt_name, &module, flags, pwm );
3009 if (nts == STATUS_DLL_NOT_FOUND)
3010 nts = load_native_dll( load_path, &nt_name, &module, &image_info, flags, pwm, &st );
3011 break;
3012 default:
3013 nts = STATUS_DLL_NOT_FOUND;
3014 break;
3016 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
3017 break;
3019 if (!(image_info.image_flags & IMAGE_FLAGS_WineFakeDll))
3021 switch (loadorder)
3023 case LO_NATIVE:
3024 case LO_NATIVE_BUILTIN:
3025 nts = load_native_dll( load_path, &nt_name, &module, &image_info, flags, pwm, &st );
3026 break;
3027 case LO_BUILTIN:
3028 nts = load_builtin_dll( load_path, &nt_name, &module, flags, pwm );
3029 break;
3030 case LO_BUILTIN_NATIVE:
3031 case LO_DEFAULT:
3032 nts = load_builtin_dll( load_path, &nt_name, &module, flags, pwm );
3033 if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT &&
3034 (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS))
3036 /* stub-only dll, try native */
3037 TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_us(&nt_name) );
3038 LdrUnloadDll( (*pwm)->ldr.BaseAddress );
3039 nts = STATUS_DLL_NOT_FOUND;
3040 /* map the dll again if it was unmapped */
3041 if (!module && open_dll_file( &nt_name, pwm, &module, &image_info, &st )) break;
3043 if (nts == STATUS_DLL_NOT_FOUND)
3044 nts = load_native_dll( load_path, &nt_name, &module, &image_info, flags, pwm, &st );
3045 break;
3046 default:
3047 nts = STATUS_DLL_NOT_FOUND;
3048 break;
3050 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
3051 break;
3053 TRACE( "%s is a fake Wine dll\n", debugstr_us(&nt_name) );
3054 NtUnmapViewOfSection( NtCurrentProcess(), module );
3055 /* fall through */
3057 case STATUS_DLL_NOT_FOUND: /* no file found, try builtin */
3058 switch (loadorder)
3060 case LO_NATIVE_BUILTIN:
3061 case LO_BUILTIN:
3062 case LO_BUILTIN_NATIVE:
3063 case LO_DEFAULT:
3064 nts = load_builtin_dll( load_path, &nt_name, NULL, flags, pwm );
3065 break;
3066 default:
3067 nts = STATUS_DLL_NOT_FOUND;
3068 break;
3070 break;
3073 done:
3074 if (nts == STATUS_SUCCESS)
3075 TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.BaseAddress);
3076 else
3077 WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
3079 RtlFreeUnicodeString( &nt_name );
3080 return nts;
3083 /******************************************************************
3084 * LdrLoadDll (NTDLL.@)
3086 NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
3087 const UNICODE_STRING *libname, HMODULE* hModule)
3089 WINE_MODREF *wm;
3090 NTSTATUS nts;
3092 RtlEnterCriticalSection( &loader_section );
3094 if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
3095 nts = load_dll( path_name, libname->Buffer, dllW, flags, &wm );
3097 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
3099 nts = process_attach( wm, NULL );
3100 if (nts != STATUS_SUCCESS)
3102 LdrUnloadDll(wm->ldr.BaseAddress);
3103 wm = NULL;
3106 *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
3108 RtlLeaveCriticalSection( &loader_section );
3109 return nts;
3113 /******************************************************************
3114 * LdrGetDllHandle (NTDLL.@)
3116 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
3118 NTSTATUS status;
3119 UNICODE_STRING nt_name;
3120 WINE_MODREF *wm;
3121 void *module;
3122 pe_image_info_t image_info;
3123 struct stat st;
3125 RtlEnterCriticalSection( &loader_section );
3127 if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
3129 status = find_dll_file( load_path, name->Buffer, dllW, &nt_name, &wm, &module, &image_info, &st );
3131 if (wm) *base = wm->ldr.BaseAddress;
3132 else
3134 if (status == STATUS_SUCCESS) NtUnmapViewOfSection( NtCurrentProcess(), module );
3135 status = STATUS_DLL_NOT_FOUND;
3137 RtlFreeUnicodeString( &nt_name );
3139 RtlLeaveCriticalSection( &loader_section );
3140 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
3141 return status;
3145 /******************************************************************
3146 * LdrAddRefDll (NTDLL.@)
3148 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
3150 NTSTATUS ret = STATUS_SUCCESS;
3151 WINE_MODREF *wm;
3153 if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %x not implemented\n", module, flags );
3155 RtlEnterCriticalSection( &loader_section );
3157 if ((wm = get_modref( module )))
3159 if (flags & LDR_ADDREF_DLL_PIN)
3160 wm->ldr.LoadCount = -1;
3161 else
3162 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3163 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3165 else ret = STATUS_INVALID_PARAMETER;
3167 RtlLeaveCriticalSection( &loader_section );
3168 return ret;
3172 /***********************************************************************
3173 * LdrProcessRelocationBlock (NTDLL.@)
3175 * Apply relocations to a given page of a mapped PE image.
3177 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3178 USHORT *relocs, INT_PTR delta )
3180 while (count--)
3182 USHORT offset = *relocs & 0xfff;
3183 int type = *relocs >> 12;
3184 switch(type)
3186 case IMAGE_REL_BASED_ABSOLUTE:
3187 break;
3188 case IMAGE_REL_BASED_HIGH:
3189 *(short *)((char *)page + offset) += HIWORD(delta);
3190 break;
3191 case IMAGE_REL_BASED_LOW:
3192 *(short *)((char *)page + offset) += LOWORD(delta);
3193 break;
3194 case IMAGE_REL_BASED_HIGHLOW:
3195 *(int *)((char *)page + offset) += delta;
3196 break;
3197 #ifdef _WIN64
3198 case IMAGE_REL_BASED_DIR64:
3199 *(INT_PTR *)((char *)page + offset) += delta;
3200 break;
3201 #elif defined(__arm__)
3202 case IMAGE_REL_BASED_THUMB_MOV32:
3204 DWORD inst = *(INT_PTR *)((char *)page + offset);
3205 DWORD imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
3206 ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
3207 DWORD hi_delta;
3209 if ((inst & 0x8000fbf0) != 0x0000f240)
3210 ERR("wrong Thumb2 instruction %08x, expected MOVW\n", inst);
3212 imm16 += LOWORD(delta);
3213 hi_delta = HIWORD(delta) + HIWORD(imm16);
3214 *(INT_PTR *)((char *)page + offset) = (inst & 0x8f00fbf0) + ((imm16 >> 1) & 0x0400) +
3215 ((imm16 >> 12) & 0x000f) +
3216 ((imm16 << 20) & 0x70000000) +
3217 ((imm16 << 16) & 0xff0000);
3219 if (hi_delta != 0)
3221 inst = *(INT_PTR *)((char *)page + offset + 4);
3222 imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
3223 ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
3225 if ((inst & 0x8000fbf0) != 0x0000f2c0)
3226 ERR("wrong Thumb2 instruction %08x, expected MOVT\n", inst);
3228 imm16 += hi_delta;
3229 if (imm16 > 0xffff)
3230 ERR("resulting immediate value won't fit: %08x\n", imm16);
3231 *(INT_PTR *)((char *)page + offset + 4) = (inst & 0x8f00fbf0) +
3232 ((imm16 >> 1) & 0x0400) +
3233 ((imm16 >> 12) & 0x000f) +
3234 ((imm16 << 20) & 0x70000000) +
3235 ((imm16 << 16) & 0xff0000);
3238 break;
3239 #endif
3240 default:
3241 FIXME("Unknown/unsupported fixup type %x.\n", type);
3242 return NULL;
3244 relocs++;
3246 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
3250 /******************************************************************
3251 * LdrQueryProcessModuleInformation
3254 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi,
3255 ULONG buf_size, ULONG* req_size)
3257 SYSTEM_MODULE* sm = &smi->Modules[0];
3258 ULONG size = sizeof(ULONG);
3259 NTSTATUS nts = STATUS_SUCCESS;
3260 ANSI_STRING str;
3261 char* ptr;
3262 PLIST_ENTRY mark, entry;
3263 PLDR_MODULE mod;
3264 WORD id = 0;
3266 smi->ModulesCount = 0;
3268 RtlEnterCriticalSection( &loader_section );
3269 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3270 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3272 mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
3273 size += sizeof(*sm);
3274 if (size <= buf_size)
3276 sm->Section = 0; /* FIXME */
3277 sm->MappedBaseAddress = mod->BaseAddress;
3278 sm->ImageBaseAddress = mod->BaseAddress;
3279 sm->ImageSize = mod->SizeOfImage;
3280 sm->Flags = mod->Flags;
3281 sm->LoadOrderIndex = id++;
3282 sm->InitOrderIndex = 0; /* FIXME */
3283 sm->LoadCount = mod->LoadCount;
3284 str.Length = 0;
3285 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
3286 str.Buffer = (char*)sm->Name;
3287 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
3288 ptr = strrchr(str.Buffer, '\\');
3289 sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3291 smi->ModulesCount++;
3292 sm++;
3294 else nts = STATUS_INFO_LENGTH_MISMATCH;
3296 RtlLeaveCriticalSection( &loader_section );
3298 if (req_size) *req_size = size;
3300 return nts;
3304 static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, ULONG *value )
3306 NTSTATUS status;
3307 UNICODE_STRING str;
3308 ULONG size;
3309 WCHAR buffer[64];
3310 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3312 RtlInitUnicodeString( &str, name );
3314 size = sizeof(buffer) - sizeof(WCHAR);
3315 if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
3316 return status;
3318 if (info->Type != REG_DWORD)
3320 buffer[size / sizeof(WCHAR)] = 0;
3321 *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3323 else memcpy( value, info->Data, sizeof(*value) );
3324 return status;
3327 static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
3328 void *data, ULONG in_size, ULONG *out_size )
3330 NTSTATUS status;
3331 UNICODE_STRING str;
3332 ULONG size;
3333 char *buffer;
3334 KEY_VALUE_PARTIAL_INFORMATION *info;
3335 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
3337 RtlInitUnicodeString( &str, name );
3339 size = info_size + in_size;
3340 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
3341 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3342 status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
3343 if (!status || status == STATUS_BUFFER_OVERFLOW)
3345 if (out_size) *out_size = info->DataLength;
3346 if (data && !status) memcpy( data, info->Data, info->DataLength );
3348 RtlFreeHeap( GetProcessHeap(), 0, buffer );
3349 return status;
3353 /******************************************************************
3354 * LdrQueryImageFileExecutionOptions (NTDLL.@)
3356 NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
3357 void *data, ULONG in_size, ULONG *out_size )
3359 static const WCHAR optionsW[] = {'M','a','c','h','i','n','e','\\',
3360 'S','o','f','t','w','a','r','e','\\',
3361 'M','i','c','r','o','s','o','f','t','\\',
3362 'W','i','n','d','o','w','s',' ','N','T','\\',
3363 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3364 'I','m','a','g','e',' ','F','i','l','e',' ',
3365 'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
3366 WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3367 OBJECT_ATTRIBUTES attr;
3368 UNICODE_STRING name_str;
3369 HANDLE hkey;
3370 NTSTATUS status;
3371 ULONG len;
3372 WCHAR *p;
3374 attr.Length = sizeof(attr);
3375 attr.RootDirectory = 0;
3376 attr.ObjectName = &name_str;
3377 attr.Attributes = OBJ_CASE_INSENSITIVE;
3378 attr.SecurityDescriptor = NULL;
3379 attr.SecurityQualityOfService = NULL;
3381 p = key->Buffer + key->Length / sizeof(WCHAR);
3382 while (p > key->Buffer && p[-1] != '\\') p--;
3383 len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
3384 name_str.Buffer = path;
3385 name_str.Length = sizeof(optionsW) + len;
3386 name_str.MaximumLength = name_str.Length;
3387 memcpy( path, optionsW, sizeof(optionsW) );
3388 memcpy( path + ARRAY_SIZE( optionsW ), p, len );
3389 if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
3391 if (type == REG_DWORD)
3393 if (out_size) *out_size = sizeof(ULONG);
3394 if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
3395 else status = STATUS_BUFFER_OVERFLOW;
3397 else status = query_string_option( hkey, value, type, data, in_size, out_size );
3399 NtClose( hkey );
3400 return status;
3404 /******************************************************************
3405 * RtlDllShutdownInProgress (NTDLL.@)
3407 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
3409 return process_detaching;
3412 /****************************************************************************
3413 * LdrResolveDelayLoadedAPI (NTDLL.@)
3415 void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3416 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
3417 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3418 IMAGE_THUNK_DATA* addr, ULONG flags )
3420 IMAGE_THUNK_DATA *pIAT, *pINT;
3421 DELAYLOAD_INFO delayinfo;
3422 UNICODE_STRING mod;
3423 const CHAR* name;
3424 HMODULE *phmod;
3425 NTSTATUS nts;
3426 FARPROC fp;
3427 DWORD id;
3429 TRACE( "(%p, %p, %p, %p, %p, 0x%08x)\n", base, desc, dllhook, syshook, addr, flags );
3431 phmod = get_rva(base, desc->ModuleHandleRVA);
3432 pIAT = get_rva(base, desc->ImportAddressTableRVA);
3433 pINT = get_rva(base, desc->ImportNameTableRVA);
3434 name = get_rva(base, desc->DllNameRVA);
3435 id = addr - pIAT;
3437 if (!*phmod)
3439 if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
3441 nts = STATUS_NO_MEMORY;
3442 goto fail;
3444 nts = LdrLoadDll(NULL, 0, &mod, phmod);
3445 RtlFreeUnicodeString(&mod);
3446 if (nts) goto fail;
3449 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3450 nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
3451 else
3453 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3454 ANSI_STRING fnc;
3456 RtlInitAnsiString(&fnc, (char*)iibn->Name);
3457 nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
3459 if (!nts)
3461 pIAT[id].u1.Function = (ULONG_PTR)fp;
3462 return fp;
3465 fail:
3466 delayinfo.Size = sizeof(delayinfo);
3467 delayinfo.DelayloadDescriptor = desc;
3468 delayinfo.ThunkAddress = addr;
3469 delayinfo.TargetDllName = name;
3470 delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
3471 delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
3472 delayinfo.TargetModuleBase = *phmod;
3473 delayinfo.Unused = NULL;
3474 delayinfo.LastError = nts;
3476 if (dllhook)
3477 return dllhook(4, &delayinfo);
3479 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3481 DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
3482 return syshook(name, (const char *)ord);
3484 else
3486 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3487 return syshook(name, (const char *)iibn->Name);
3491 /******************************************************************
3492 * LdrShutdownProcess (NTDLL.@)
3495 void WINAPI LdrShutdownProcess(void)
3497 TRACE("()\n");
3498 process_detaching = TRUE;
3499 process_detach();
3503 /******************************************************************
3504 * RtlExitUserProcess (NTDLL.@)
3506 void WINAPI RtlExitUserProcess( DWORD status )
3508 RtlEnterCriticalSection( &loader_section );
3509 RtlAcquirePebLock();
3510 NtTerminateProcess( 0, status );
3511 LdrShutdownProcess();
3512 NtTerminateProcess( GetCurrentProcess(), status );
3513 exit( get_unix_exit_code( status ));
3516 /******************************************************************
3517 * LdrShutdownThread (NTDLL.@)
3520 void WINAPI LdrShutdownThread(void)
3522 PLIST_ENTRY mark, entry;
3523 PLDR_MODULE mod;
3524 UINT i;
3525 void **pointers;
3527 TRACE("()\n");
3529 /* don't do any detach calls if process is exiting */
3530 if (process_detaching) return;
3532 RtlEnterCriticalSection( &loader_section );
3534 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3535 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3537 mod = CONTAINING_RECORD(entry, LDR_MODULE,
3538 InInitializationOrderModuleList);
3539 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3540 continue;
3541 if ( mod->Flags & LDR_NO_DLL_CALLS )
3542 continue;
3544 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
3545 DLL_THREAD_DETACH, NULL );
3548 RtlAcquirePebLock();
3549 RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3550 RtlReleasePebLock();
3552 if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
3554 for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
3555 RtlFreeHeap( GetProcessHeap(), 0, pointers );
3557 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->FlsSlots );
3558 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3559 RtlLeaveCriticalSection( &loader_section );
3563 /***********************************************************************
3564 * free_modref
3567 static void free_modref( WINE_MODREF *wm )
3569 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
3570 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
3571 if (wm->ldr.InInitializationOrderModuleList.Flink)
3572 RemoveEntryList(&wm->ldr.InInitializationOrderModuleList);
3574 TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
3575 if (!TRACE_ON(module))
3576 TRACE_(loaddll)("Unloaded module %s : %s\n",
3577 debugstr_w(wm->ldr.FullDllName.Buffer),
3578 (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
3580 SERVER_START_REQ( unload_dll )
3582 req->base = wine_server_client_ptr( wm->ldr.BaseAddress );
3583 wine_server_call( req );
3585 SERVER_END_REQ;
3587 free_tls_slot( &wm->ldr );
3588 RtlReleaseActivationContext( wm->ldr.ActivationContext );
3589 if ((wm->ldr.Flags & LDR_WINE_INTERNAL) && wm->ldr.SectionHandle)
3590 wine_dlclose( wm->ldr.SectionHandle, NULL, 0 );
3591 NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
3592 if (cached_modref == wm) cached_modref = NULL;
3593 RtlFreeUnicodeString( &wm->ldr.FullDllName );
3594 RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
3595 RtlFreeHeap( GetProcessHeap(), 0, wm );
3598 /***********************************************************************
3599 * MODULE_FlushModrefs
3601 * Remove all unused modrefs and call the internal unloading routines
3602 * for the library type.
3604 * The loader_section must be locked while calling this function.
3606 static void MODULE_FlushModrefs(void)
3608 PLIST_ENTRY mark, entry, prev;
3609 PLDR_MODULE mod;
3610 WINE_MODREF*wm;
3612 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3613 for (entry = mark->Blink; entry != mark; entry = prev)
3615 mod = CONTAINING_RECORD(entry, LDR_MODULE, InInitializationOrderModuleList);
3616 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3617 prev = entry->Blink;
3618 if (!mod->LoadCount) free_modref( wm );
3621 /* check load order list too for modules that haven't been initialized yet */
3622 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3623 for (entry = mark->Blink; entry != mark; entry = prev)
3625 mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
3626 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3627 prev = entry->Blink;
3628 if (!mod->LoadCount) free_modref( wm );
3632 /***********************************************************************
3633 * MODULE_DecRefCount
3635 * The loader_section must be locked while calling this function.
3637 static void MODULE_DecRefCount( WINE_MODREF *wm )
3639 int i;
3641 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3642 return;
3644 if ( wm->ldr.LoadCount <= 0 )
3645 return;
3647 --wm->ldr.LoadCount;
3648 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3650 if ( wm->ldr.LoadCount == 0 )
3652 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
3654 for ( i = 0; i < wm->nDeps; i++ )
3655 if ( wm->deps[i] )
3656 MODULE_DecRefCount( wm->deps[i] );
3658 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
3660 module_push_unload_trace( &wm->ldr );
3664 /******************************************************************
3665 * LdrUnloadDll (NTDLL.@)
3669 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
3671 WINE_MODREF *wm;
3672 NTSTATUS retv = STATUS_SUCCESS;
3674 if (process_detaching) return retv;
3676 TRACE("(%p)\n", hModule);
3678 RtlEnterCriticalSection( &loader_section );
3680 free_lib_count++;
3681 if ((wm = get_modref( hModule )) != NULL)
3683 TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
3685 /* Recursively decrement reference counts */
3686 MODULE_DecRefCount( wm );
3688 /* Call process detach notifications */
3689 if ( free_lib_count <= 1 )
3691 process_detach();
3692 MODULE_FlushModrefs();
3695 TRACE("END\n");
3697 else
3698 retv = STATUS_DLL_NOT_FOUND;
3700 free_lib_count--;
3702 RtlLeaveCriticalSection( &loader_section );
3704 return retv;
3707 /***********************************************************************
3708 * RtlImageNtHeader (NTDLL.@)
3710 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
3712 IMAGE_NT_HEADERS *ret;
3714 __TRY
3716 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
3718 ret = NULL;
3719 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
3721 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
3722 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
3725 __EXCEPT_PAGE_FAULT
3727 return NULL;
3729 __ENDTRY
3730 return ret;
3734 /******************************************************************
3735 * LdrInitializeThunk (NTDLL.@)
3737 * Attach to all the loaded dlls.
3738 * If this is the first time, perform the full process initialization.
3740 void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknown3, ULONG_PTR unknown4 )
3742 static const LARGE_INTEGER zero;
3743 NTSTATUS status;
3744 WINE_MODREF *wm;
3745 LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
3747 pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
3749 if (process_detaching) return;
3751 RtlEnterCriticalSection( &loader_section );
3753 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3754 assert( wm );
3756 if (!imports_fixup_done)
3758 actctx_init();
3759 if (wm->ldr.Flags & LDR_COR_ILONLY)
3760 status = fixup_imports_ilonly( wm, load_path, entry );
3761 else
3762 status = fixup_imports( wm, load_path );
3764 if (status)
3766 ERR( "Importing dlls for %s failed, status %x\n",
3767 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3768 NtTerminateProcess( GetCurrentProcess(), status );
3770 imports_fixup_done = TRUE;
3773 RtlAcquirePebLock();
3774 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
3775 RtlReleasePebLock();
3777 if (!(wm->ldr.Flags & LDR_PROCESS_ATTACHED)) /* first time around */
3779 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
3781 ERR( "TLS init failed when loading %s, status %x\n",
3782 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3783 NtTerminateProcess( GetCurrentProcess(), status );
3785 if ((status = process_attach( wm, context )) != STATUS_SUCCESS)
3787 if (last_failed_modref)
3788 ERR( "%s failed to initialize, aborting\n",
3789 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
3790 ERR( "Initializing dlls for %s failed, status %x\n",
3791 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
3792 NtTerminateProcess( GetCurrentProcess(), status );
3794 attach_implicitly_loaded_dlls( context );
3795 virtual_release_address_space();
3797 else
3799 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
3800 NtTerminateThread( GetCurrentThread(), status );
3801 thread_attach();
3804 RtlLeaveCriticalSection( &loader_section );
3806 NtDelayExecution( TRUE, &zero );
3810 /***********************************************************************
3811 * load_global_options
3813 static void load_global_options(void)
3815 static const WCHAR sessionW[] = {'M','a','c','h','i','n','e','\\',
3816 'S','y','s','t','e','m','\\',
3817 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
3818 'C','o','n','t','r','o','l','\\',
3819 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
3820 static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
3821 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};
3822 static const WCHAR safedllmodeW[] = {'S','a','f','e','D','l','l','S','e','a','r','c','h','M','o','d','e',0};
3823 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};
3824 static const WCHAR heapresW[] = {'H','e','a','p','S','e','g','m','e','n','t','R','e','s','e','r','v','e',0};
3825 static const WCHAR heapcommitW[] = {'H','e','a','p','S','e','g','m','e','n','t','C','o','m','m','i','t',0};
3826 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};
3827 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};
3829 OBJECT_ATTRIBUTES attr;
3830 UNICODE_STRING name_str;
3831 HANDLE hkey;
3832 ULONG value;
3834 attr.Length = sizeof(attr);
3835 attr.RootDirectory = 0;
3836 attr.ObjectName = &name_str;
3837 attr.Attributes = OBJ_CASE_INSENSITIVE;
3838 attr.SecurityDescriptor = NULL;
3839 attr.SecurityQualityOfService = NULL;
3840 RtlInitUnicodeString( &name_str, sessionW );
3842 if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
3844 query_dword_option( hkey, globalflagW, &NtCurrentTeb()->Peb->NtGlobalFlag );
3845 query_dword_option( hkey, safesearchW, &path_safe_mode );
3846 query_dword_option( hkey, safedllmodeW, &dll_safe_mode );
3848 if (!query_dword_option( hkey, critsectW, &value ))
3849 NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart = (ULONGLONG)value * -10000000;
3851 if (!query_dword_option( hkey, heapresW, &value ))
3852 NtCurrentTeb()->Peb->HeapSegmentReserve = value;
3854 if (!query_dword_option( hkey, heapcommitW, &value ))
3855 NtCurrentTeb()->Peb->HeapSegmentCommit = value;
3857 if (!query_dword_option( hkey, decommittotalW, &value ))
3858 NtCurrentTeb()->Peb->HeapDeCommitTotalFreeThreshold = value;
3860 if (!query_dword_option( hkey, decommitfreeW, &value ))
3861 NtCurrentTeb()->Peb->HeapDeCommitFreeBlockThreshold = value;
3863 NtClose( hkey );
3865 LdrQueryImageFileExecutionOptions( &NtCurrentTeb()->Peb->ProcessParameters->ImagePathName,
3866 globalflagW, REG_DWORD, &NtCurrentTeb()->Peb->NtGlobalFlag,
3867 sizeof(DWORD), NULL );
3868 heap_set_debug_flags( GetProcessHeap() );
3872 /***********************************************************************
3873 * RtlImageDirectoryEntryToData (NTDLL.@)
3875 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
3877 const IMAGE_NT_HEADERS *nt;
3878 DWORD addr;
3880 if ((ULONG_PTR)module & 1) image = FALSE; /* mapped as data file */
3881 module = (HMODULE)((ULONG_PTR)module & ~3);
3882 if (!(nt = RtlImageNtHeader( module ))) return NULL;
3883 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
3885 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
3887 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
3888 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
3889 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
3890 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
3892 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
3894 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
3896 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
3897 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
3898 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
3899 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
3901 else return NULL;
3903 /* not mapped as image, need to find the section containing the virtual address */
3904 return RtlImageRvaToVa( nt, module, addr, NULL );
3908 /***********************************************************************
3909 * RtlImageRvaToSection (NTDLL.@)
3911 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
3912 HMODULE module, DWORD rva )
3914 int i;
3915 const IMAGE_SECTION_HEADER *sec;
3917 sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
3918 nt->FileHeader.SizeOfOptionalHeader);
3919 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
3921 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
3922 return (PIMAGE_SECTION_HEADER)sec;
3924 return NULL;
3928 /***********************************************************************
3929 * RtlImageRvaToVa (NTDLL.@)
3931 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
3932 DWORD rva, IMAGE_SECTION_HEADER **section )
3934 IMAGE_SECTION_HEADER *sec;
3936 if (section && *section) /* try this section first */
3938 sec = *section;
3939 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
3940 goto found;
3942 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
3943 found:
3944 if (section) *section = sec;
3945 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
3949 /***********************************************************************
3950 * RtlPcToFileHeader (NTDLL.@)
3952 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
3954 LDR_MODULE *module;
3955 PVOID ret = NULL;
3957 RtlEnterCriticalSection( &loader_section );
3958 if (!LdrFindEntryForAddress( pc, &module )) ret = module->BaseAddress;
3959 RtlLeaveCriticalSection( &loader_section );
3960 *address = ret;
3961 return ret;
3965 /****************************************************************************
3966 * LdrGetDllDirectory (NTDLL.@)
3968 NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
3970 NTSTATUS status = STATUS_SUCCESS;
3972 RtlEnterCriticalSection( &dlldir_section );
3973 dir->Length = dll_directory.Length + sizeof(WCHAR);
3974 if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
3975 else
3977 status = STATUS_BUFFER_TOO_SMALL;
3978 if (dir->MaximumLength) dir->Buffer[0] = 0;
3980 RtlLeaveCriticalSection( &dlldir_section );
3981 return status;
3985 /****************************************************************************
3986 * LdrSetDllDirectory (NTDLL.@)
3988 NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
3990 NTSTATUS status = STATUS_SUCCESS;
3991 UNICODE_STRING new;
3993 if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
3994 else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;
3996 RtlEnterCriticalSection( &dlldir_section );
3997 RtlFreeUnicodeString( &dll_directory );
3998 dll_directory = new;
3999 RtlLeaveCriticalSection( &dlldir_section );
4000 return status;
4004 /****************************************************************************
4005 * LdrAddDllDirectory (NTDLL.@)
4007 NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
4009 FILE_BASIC_INFORMATION info;
4010 UNICODE_STRING nt_name;
4011 NTSTATUS status;
4012 OBJECT_ATTRIBUTES attr;
4013 DWORD len;
4014 struct dll_dir_entry *ptr;
4015 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
4017 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
4018 return STATUS_INVALID_PARAMETER;
4020 status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
4021 if (status) return status;
4022 len = nt_name.Length / sizeof(WCHAR);
4023 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
4024 return STATUS_NO_MEMORY;
4025 memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );
4027 attr.Length = sizeof(attr);
4028 attr.RootDirectory = 0;
4029 attr.Attributes = OBJ_CASE_INSENSITIVE;
4030 attr.ObjectName = &nt_name;
4031 attr.SecurityDescriptor = NULL;
4032 attr.SecurityQualityOfService = NULL;
4033 status = NtQueryAttributesFile( &attr, &info );
4034 RtlFreeUnicodeString( &nt_name );
4036 if (!status)
4038 TRACE( "%s\n", debugstr_w( ptr->dir ));
4039 RtlEnterCriticalSection( &dlldir_section );
4040 list_add_head( &dll_dir_list, &ptr->entry );
4041 RtlLeaveCriticalSection( &dlldir_section );
4042 *cookie = ptr;
4044 else RtlFreeHeap( GetProcessHeap(), 0, ptr );
4045 return status;
4049 /****************************************************************************
4050 * LdrRemoveDllDirectory (NTDLL.@)
4052 NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
4054 struct dll_dir_entry *ptr = cookie;
4056 TRACE( "%s\n", debugstr_w( ptr->dir ));
4058 RtlEnterCriticalSection( &dlldir_section );
4059 list_remove( &ptr->entry );
4060 RtlFreeHeap( GetProcessHeap(), 0, ptr );
4061 RtlLeaveCriticalSection( &dlldir_section );
4062 return STATUS_SUCCESS;
4066 /*************************************************************************
4067 * LdrSetDefaultDllDirectories (NTDLL.@)
4069 NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
4071 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
4072 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4073 LOAD_LIBRARY_SEARCH_USER_DIRS |
4074 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4075 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4077 if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
4078 default_search_flags = flags;
4079 return STATUS_SUCCESS;
4083 /******************************************************************
4084 * LdrGetDllPath (NTDLL.@)
4086 NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
4088 NTSTATUS status;
4089 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
4090 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4091 LOAD_LIBRARY_SEARCH_USER_DIRS |
4092 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4093 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4095 if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
4097 if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
4098 if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
4100 else if (!(flags & load_library_search_flags)) flags |= default_search_flags;
4102 RtlEnterCriticalSection( &dlldir_section );
4104 if (flags & load_library_search_flags)
4106 status = get_dll_load_path_search_flags( module, flags, path );
4108 else
4110 const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
4111 if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH))
4112 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4113 status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
4116 RtlLeaveCriticalSection( &dlldir_section );
4117 *unknown = NULL;
4118 return status;
4122 /*************************************************************************
4123 * RtlSetSearchPathMode (NTDLL.@)
4125 NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
4127 int val;
4129 switch (flags)
4131 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
4132 val = 1;
4133 break;
4134 case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
4135 val = 0;
4136 break;
4137 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4138 interlocked_xchg( (int *)&path_safe_mode, 2 );
4139 return STATUS_SUCCESS;
4140 default:
4141 return STATUS_INVALID_PARAMETER;
4144 for (;;)
4146 int prev = path_safe_mode;
4147 if (prev == 2) break; /* permanently set */
4148 if (interlocked_cmpxchg( (int *)&path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4150 return STATUS_ACCESS_DENIED;
4154 /******************************************************************
4155 * RtlGetExePath (NTDLL.@)
4157 NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
4159 static const WCHAR emptyW[1];
4160 const WCHAR *dlldir = dotW;
4161 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4163 /* same check as NeedCurrentDirectoryForExePathW */
4164 if (!wcschr( name, '\\' ))
4166 static const WCHAR env_name[] = {'N','o','D','e','f','a','u','l','t','C','u','r','r','e','n','t',
4167 'D','i','r','e','c','t','o','r','y','I','n',
4168 'E','x','e','P','a','t','h',0};
4169 UNICODE_STRING name, value = { 0 };
4171 RtlInitUnicodeString( &name, env_name );
4172 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4173 dlldir = emptyW;
4175 return get_dll_load_path( module, dlldir, FALSE, path );
4179 /******************************************************************
4180 * RtlGetSearchPath (NTDLL.@)
4182 NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
4184 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4185 return get_dll_load_path( module, NULL, path_safe_mode, path );
4189 /******************************************************************
4190 * RtlReleasePath (NTDLL.@)
4192 void WINAPI RtlReleasePath( PWSTR path )
4194 RtlFreeHeap( GetProcessHeap(), 0, path );
4198 /***********************************************************************
4199 * NtLoadDriver (NTDLL.@)
4200 * ZwLoadDriver (NTDLL.@)
4202 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *DriverServiceName )
4204 FIXME("(%p), stub!\n",DriverServiceName);
4205 return STATUS_NOT_IMPLEMENTED;
4209 /***********************************************************************
4210 * NtUnloadDriver (NTDLL.@)
4211 * ZwUnloadDriver (NTDLL.@)
4213 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *DriverServiceName )
4215 FIXME("(%p), stub!\n",DriverServiceName);
4216 return STATUS_NOT_IMPLEMENTED;
4220 /******************************************************************
4221 * DllMain (NTDLL.@)
4223 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4225 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
4226 return TRUE;
4230 /***********************************************************************
4231 * __wine_process_init
4233 void __wine_process_init(void)
4235 static const WCHAR kernel32W[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
4236 's','y','s','t','e','m','3','2','\\',
4237 'k','e','r','n','e','l','3','2','.','d','l','l',0};
4238 RTL_USER_PROCESS_PARAMETERS *params;
4239 WINE_MODREF *wm;
4240 NTSTATUS status;
4241 ANSI_STRING func_name;
4242 UNICODE_STRING nt_name;
4243 INITIAL_TEB stack;
4244 BOOL suspend;
4245 SIZE_T info_size;
4246 TEB *teb = thread_init();
4247 PEB *peb = teb->Peb;
4249 /* setup the server connection */
4250 server_init_process();
4251 info_size = server_init_thread( peb, &suspend );
4253 peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );
4254 peb->LoaderLock = &loader_section;
4256 init_unix_codepage();
4257 init_directories();
4258 init_user_process_params( info_size );
4260 NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 );
4262 /* retrieve current umask */
4263 FILE_umask = umask(0777);
4264 umask( FILE_umask );
4266 load_global_options();
4267 version_init();
4269 /* setup the load callback and create ntdll modref */
4270 wine_dll_set_callback( load_builtin_callback );
4272 RtlInitUnicodeString( &nt_name, kernel32W );
4273 if ((status = load_builtin_dll( NULL, &nt_name, NULL, 0, &wm )) != STATUS_SUCCESS)
4275 MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
4276 exit(1);
4278 RtlInitAnsiString( &func_name, "__wine_start_process" );
4279 if ((status = LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name,
4280 0, (void **)&kernel32_start_process )) != STATUS_SUCCESS)
4282 MESSAGE( "wine: could not find __wine_start_process in kernel32.dll, status %x\n", status );
4283 exit(1);
4286 init_locale( wm->ldr.BaseAddress );
4288 params = peb->ProcessParameters;
4289 if (!(status = load_dll( params->DllPath.Buffer, params->ImagePathName.Buffer, NULL,
4290 DONT_RESOLVE_DLL_REFERENCES, &wm )))
4292 peb->ImageBaseAddress = wm->ldr.BaseAddress;
4293 TRACE( "main exe loaded %s at %p\n", debugstr_us(&params->ImagePathName), peb->ImageBaseAddress );
4294 if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
4296 MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
4297 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
4300 else
4302 if (!info_size) status = restart_process( params, status );
4303 switch (status)
4305 case STATUS_INVALID_IMAGE_WIN_64:
4306 ERR( "%s 64-bit application not supported in 32-bit prefix\n",
4307 debugstr_us(&params->ImagePathName) );
4308 break;
4309 case STATUS_INVALID_IMAGE_WIN_16:
4310 case STATUS_INVALID_IMAGE_NE_FORMAT:
4311 case STATUS_INVALID_IMAGE_PROTECT:
4312 ERR( "%s 16-bit application not supported on this system\n",
4313 debugstr_us(&params->ImagePathName) );
4314 break;
4315 case STATUS_INVALID_IMAGE_FORMAT:
4316 ERR( "%s not supported on this system\n", debugstr_us(&params->ImagePathName) );
4317 break;
4318 case STATUS_DLL_NOT_FOUND:
4319 ERR( "%s not found\n", debugstr_us(&params->ImagePathName) );
4320 break;
4321 default:
4322 ERR( "failed to load %s, error %x\n", debugstr_us(&params->ImagePathName), status );
4323 break;
4325 NtTerminateProcess( GetCurrentProcess(), status );
4328 virtual_set_large_address_space();
4330 /* the main exe needs to be the first in the load order list */
4331 RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
4332 InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
4333 RemoveEntryList( &wm->ldr.InMemoryOrderModuleList );
4334 InsertHeadList( &peb->LdrData->InMemoryOrderModuleList, &wm->ldr.InMemoryOrderModuleList );
4336 virtual_alloc_thread_stack( &stack, 0, 0, NULL );
4337 teb->Tib.StackBase = stack.StackBase;
4338 teb->Tib.StackLimit = stack.StackLimit;
4339 teb->DeallocationStack = stack.DeallocationStack;
4341 server_init_process_done();