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
23 #include "wine/port.h"
27 #ifdef HAVE_SYS_MMAN_H
28 # include <sys/mman.h>
32 #define WIN32_NO_STATUS
33 #define NONAMELESSUNION
37 #include "delayloadhandler.h"
39 #include "wine/exception.h"
40 #include "wine/library.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 #include "wine/server.h"
44 #include "ntdll_misc.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
);
52 WINE_DECLARE_DEBUG_CHANNEL(pid
);
55 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
57 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
58 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
60 /* we don't want to include winuser.h */
61 #define RT_MANIFEST ((ULONG_PTR)24)
62 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
64 typedef DWORD (CALLBACK
*DLLENTRYPROC
)(HMODULE
,DWORD
,LPVOID
);
66 static BOOL process_detaching
= FALSE
; /* set on process detach to avoid deadlocks with thread detach */
67 static int free_lib_count
; /* recursion depth of LdrUnloadDll calls */
69 static const char * const reason_names
[] =
75 NULL
, NULL
, NULL
, NULL
,
79 static const WCHAR dllW
[] = {'.','d','l','l',0};
81 /* internal representation of 32bit modules. per process. */
82 typedef struct _wine_modref
86 struct _wine_modref
**deps
;
89 /* info about the current builtin dll load */
90 /* used to keep track of things across the register_dll constructor call */
91 struct builtin_load_info
93 const WCHAR
*load_path
;
94 const WCHAR
*filename
;
99 static struct builtin_load_info default_load_info
;
100 static struct builtin_load_info
*builtin_load_info
= &default_load_info
;
105 LPTHREAD_START_ROUTINE entry
;
108 static HANDLE main_exe_file
;
109 static UINT tls_module_count
; /* number of modules with TLS directory */
110 static IMAGE_TLS_DIRECTORY
*tls_dirs
; /* array of TLS directories */
111 LIST_ENTRY tls_links
= { &tls_links
, &tls_links
};
113 static RTL_CRITICAL_SECTION loader_section
;
114 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
116 0, 0, &loader_section
,
117 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
118 0, 0, { (DWORD_PTR
)(__FILE__
": loader_section") }
120 static RTL_CRITICAL_SECTION loader_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
122 static WINE_MODREF
*cached_modref
;
123 static WINE_MODREF
*current_modref
;
124 static WINE_MODREF
*last_failed_modref
;
126 static NTSTATUS
load_dll( LPCWSTR load_path
, LPCWSTR libname
, DWORD flags
, WINE_MODREF
** pwm
);
127 static NTSTATUS
process_attach( WINE_MODREF
*wm
, LPVOID lpReserved
);
128 static FARPROC
find_ordinal_export( HMODULE module
, const IMAGE_EXPORT_DIRECTORY
*exports
,
129 DWORD exp_size
, DWORD ordinal
, LPCWSTR load_path
);
130 static FARPROC
find_named_export( HMODULE module
, const IMAGE_EXPORT_DIRECTORY
*exports
,
131 DWORD exp_size
, const char *name
, int hint
, LPCWSTR load_path
);
133 /* convert PE image VirtualAddress to Real Address */
134 static inline void *get_rva( HMODULE module
, DWORD va
)
136 return (void *)((char *)module
+ va
);
139 /* check whether the file name contains a path */
140 static inline BOOL
contains_path( LPCWSTR name
)
142 return ((*name
&& (name
[1] == ':')) || strchrW(name
, '/') || strchrW(name
, '\\'));
145 /* convert from straight ASCII to Unicode without depending on the current codepage */
146 static inline void ascii_to_unicode( WCHAR
*dst
, const char *src
, size_t len
)
148 while (len
--) *dst
++ = (unsigned char)*src
++;
152 /*************************************************************************
153 * call_dll_entry_point
155 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
156 * their entry point, so we need a small asm wrapper. Testing indicates
157 * that only modifying esi leads to a crash, so use this one to backup
158 * ebp while running the dll entry proc.
161 extern BOOL
call_dll_entry_point( DLLENTRYPROC proc
, void *module
, UINT reason
, void *reserved
);
162 __ASM_GLOBAL_FUNC(call_dll_entry_point
,
164 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
165 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
167 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
169 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
171 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
173 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
175 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
179 "movl 8(%ebp),%eax\n\t"
182 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
183 "leal -12(%ebp),%esp\n\t"
185 __ASM_CFI(".cfi_same_value %edi\n\t")
187 __ASM_CFI(".cfi_same_value %esi\n\t")
189 __ASM_CFI(".cfi_same_value %ebx\n\t")
191 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
192 __ASM_CFI(".cfi_same_value %ebp\n\t")
195 static inline BOOL
call_dll_entry_point( DLLENTRYPROC proc
, void *module
,
196 UINT reason
, void *reserved
)
198 return proc( module
, reason
, reserved
);
200 #endif /* __i386__ */
203 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
204 /*************************************************************************
207 * Entry point for stub functions.
209 static void stub_entry_point( const char *dll
, const char *name
, void *ret_addr
)
211 EXCEPTION_RECORD rec
;
213 rec
.ExceptionCode
= EXCEPTION_WINE_STUB
;
214 rec
.ExceptionFlags
= EH_NONCONTINUABLE
;
215 rec
.ExceptionRecord
= NULL
;
216 rec
.ExceptionAddress
= ret_addr
;
217 rec
.NumberParameters
= 2;
218 rec
.ExceptionInformation
[0] = (ULONG_PTR
)dll
;
219 rec
.ExceptionInformation
[1] = (ULONG_PTR
)name
;
220 for (;;) RtlRaiseException( &rec
);
224 #include "pshpack1.h"
228 BYTE pushl1
; /* pushl $name */
230 BYTE pushl2
; /* pushl $dll */
232 BYTE call
; /* call stub_entry_point */
235 #elif defined(__arm__)
238 BYTE ldr_r0
[4]; /* ldr r0, $dll */
239 BYTE mov_pc_pc1
[4]; /* mov pc,pc */
241 BYTE ldr_r1
[4]; /* ldr r1, $name */
242 BYTE mov_pc_pc2
[4]; /* mov pc,pc */
244 BYTE mov_r2_lr
[4]; /* mov r2, lr */
245 BYTE ldr_pc_pc
[4]; /* ldr pc, [pc, #-4] */
251 BYTE movq_rdi
[2]; /* movq $dll,%rdi */
253 BYTE movq_rsi
[2]; /* movq $name,%rsi */
255 BYTE movq_rsp_rdx
[4]; /* movq (%rsp),%rdx */
256 BYTE movq_rax
[2]; /* movq $entry, %rax */
258 BYTE jmpq_rax
[2]; /* jmp %rax */
263 /*************************************************************************
266 * Allocate a stub entry point.
268 static ULONG_PTR
allocate_stub( const char *dll
, const char *name
)
270 #define MAX_SIZE 65536
271 static struct stub
*stubs
;
272 static unsigned int nb_stubs
;
275 if (nb_stubs
>= MAX_SIZE
/ sizeof(*stub
)) return 0xdeadbeef;
279 SIZE_T size
= MAX_SIZE
;
280 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs
, 0, &size
,
281 MEM_COMMIT
, PAGE_EXECUTE_READWRITE
) != STATUS_SUCCESS
)
284 stub
= &stubs
[nb_stubs
++];
286 stub
->pushl1
= 0x68; /* pushl $name */
288 stub
->pushl2
= 0x68; /* pushl $dll */
290 stub
->call
= 0xe8; /* call stub_entry_point */
291 stub
->entry
= (BYTE
*)stub_entry_point
- (BYTE
*)(&stub
->entry
+ 1);
292 #elif defined(__arm__)
293 stub
->ldr_r0
[0] = 0x00; /* ldr r0, $dll */
294 stub
->ldr_r0
[1] = 0x00;
295 stub
->ldr_r0
[2] = 0x9f;
296 stub
->ldr_r0
[3] = 0xe5;
297 stub
->mov_pc_pc1
[0] = 0x0f; /* mov pc,pc */
298 stub
->mov_pc_pc1
[1] = 0xf0;
299 stub
->mov_pc_pc1
[2] = 0xa0;
300 stub
->mov_pc_pc1
[3] = 0xe1;
302 stub
->ldr_r1
[0] = 0x00; /* ldr r1, $name */
303 stub
->ldr_r1
[1] = 0x10;
304 stub
->ldr_r1
[2] = 0x9f;
305 stub
->ldr_r1
[3] = 0xe5;
306 stub
->mov_pc_pc2
[0] = 0x0f; /* mov pc,pc */
307 stub
->mov_pc_pc2
[1] = 0xf0;
308 stub
->mov_pc_pc2
[2] = 0xa0;
309 stub
->mov_pc_pc2
[3] = 0xe1;
311 stub
->mov_r2_lr
[0] = 0x0e; /* mov r2, lr */
312 stub
->mov_r2_lr
[1] = 0x20;
313 stub
->mov_r2_lr
[2] = 0xa0;
314 stub
->mov_r2_lr
[3] = 0xe1;
315 stub
->ldr_pc_pc
[0] = 0x04; /* ldr pc, [pc, #-4] */
316 stub
->ldr_pc_pc
[1] = 0xf0;
317 stub
->ldr_pc_pc
[2] = 0x1f;
318 stub
->ldr_pc_pc
[3] = 0xe5;
319 stub
->entry
= stub_entry_point
;
321 stub
->movq_rdi
[0] = 0x48; /* movq $dll,%rdi */
322 stub
->movq_rdi
[1] = 0xbf;
324 stub
->movq_rsi
[0] = 0x48; /* movq $name,%rsi */
325 stub
->movq_rsi
[1] = 0xbe;
327 stub
->movq_rsp_rdx
[0] = 0x48; /* movq (%rsp),%rdx */
328 stub
->movq_rsp_rdx
[1] = 0x8b;
329 stub
->movq_rsp_rdx
[2] = 0x14;
330 stub
->movq_rsp_rdx
[3] = 0x24;
331 stub
->movq_rax
[0] = 0x48; /* movq $entry, %rax */
332 stub
->movq_rax
[1] = 0xb8;
333 stub
->entry
= stub_entry_point
;
334 stub
->jmpq_rax
[0] = 0xff; /* jmp %rax */
335 stub
->jmpq_rax
[1] = 0xe0;
337 return (ULONG_PTR
)stub
;
341 static inline ULONG_PTR
allocate_stub( const char *dll
, const char *name
) { return 0xdeadbeef; }
342 #endif /* __i386__ */
345 /*************************************************************************
348 * Looks for the referenced HMODULE in the current process
349 * The loader_section must be locked while calling this function.
351 static WINE_MODREF
*get_modref( HMODULE hmod
)
353 PLIST_ENTRY mark
, entry
;
356 if (cached_modref
&& cached_modref
->ldr
.BaseAddress
== hmod
) return cached_modref
;
358 mark
= &NtCurrentTeb()->Peb
->LdrData
->InMemoryOrderModuleList
;
359 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
361 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InMemoryOrderModuleList
);
362 if (mod
->BaseAddress
== hmod
)
363 return cached_modref
= CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
);
369 /**********************************************************************
370 * find_basename_module
372 * Find a module from its base name.
373 * The loader_section must be locked while calling this function
375 static WINE_MODREF
*find_basename_module( LPCWSTR name
)
377 PLIST_ENTRY mark
, entry
;
379 if (cached_modref
&& !strcmpiW( name
, cached_modref
->ldr
.BaseDllName
.Buffer
))
380 return cached_modref
;
382 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
383 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
385 LDR_MODULE
*mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
386 if (!strcmpiW( name
, mod
->BaseDllName
.Buffer
))
388 cached_modref
= CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
);
389 return cached_modref
;
396 /**********************************************************************
397 * find_fullname_module
399 * Find a module from its full path name.
400 * The loader_section must be locked while calling this function
402 static WINE_MODREF
*find_fullname_module( LPCWSTR name
)
404 PLIST_ENTRY mark
, entry
;
406 if (cached_modref
&& !strcmpiW( name
, cached_modref
->ldr
.FullDllName
.Buffer
))
407 return cached_modref
;
409 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
410 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
412 LDR_MODULE
*mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
413 if (!strcmpiW( name
, mod
->FullDllName
.Buffer
))
415 cached_modref
= CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
);
416 return cached_modref
;
423 /*************************************************************************
424 * find_forwarded_export
426 * Find the final function pointer for a forwarded function.
427 * The loader_section must be locked while calling this function.
429 static FARPROC
find_forwarded_export( HMODULE module
, const char *forward
, LPCWSTR load_path
)
431 const IMAGE_EXPORT_DIRECTORY
*exports
;
435 const char *end
= strrchr(forward
, '.');
438 if (!end
) return NULL
;
439 if ((end
- forward
) * sizeof(WCHAR
) >= sizeof(mod_name
)) return NULL
;
440 ascii_to_unicode( mod_name
, forward
, end
- forward
);
441 mod_name
[end
- forward
] = 0;
442 if (!strchrW( mod_name
, '.' ))
444 if ((end
- forward
) * sizeof(WCHAR
) >= sizeof(mod_name
) - sizeof(dllW
)) return NULL
;
445 memcpy( mod_name
+ (end
- forward
), dllW
, sizeof(dllW
) );
448 if (!(wm
= find_basename_module( mod_name
)))
450 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name
), forward
);
451 if (load_dll( load_path
, mod_name
, 0, &wm
) == STATUS_SUCCESS
&&
452 !(wm
->ldr
.Flags
& LDR_DONT_RESOLVE_REFS
))
454 if (process_attach( wm
, NULL
) != STATUS_SUCCESS
)
456 LdrUnloadDll( wm
->ldr
.BaseAddress
);
463 ERR( "module not found for forward '%s' used by %s\n",
464 forward
, debugstr_w(get_modref(module
)->ldr
.FullDllName
.Buffer
) );
468 if ((exports
= RtlImageDirectoryEntryToData( wm
->ldr
.BaseAddress
, TRUE
,
469 IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
)))
471 const char *name
= end
+ 1;
472 if (*name
== '#') /* ordinal */
473 proc
= find_ordinal_export( wm
->ldr
.BaseAddress
, exports
, exp_size
, atoi(name
+1), load_path
);
475 proc
= find_named_export( wm
->ldr
.BaseAddress
, exports
, exp_size
, name
, -1, load_path
);
480 ERR("function not found for forward '%s' used by %s."
481 " If you are using builtin %s, try using the native one instead.\n",
482 forward
, debugstr_w(get_modref(module
)->ldr
.FullDllName
.Buffer
),
483 debugstr_w(get_modref(module
)->ldr
.BaseDllName
.Buffer
) );
489 /*************************************************************************
490 * find_ordinal_export
492 * Find an exported function by ordinal.
493 * The exports base must have been subtracted from the ordinal already.
494 * The loader_section must be locked while calling this function.
496 static FARPROC
find_ordinal_export( HMODULE module
, const IMAGE_EXPORT_DIRECTORY
*exports
,
497 DWORD exp_size
, DWORD ordinal
, LPCWSTR load_path
)
500 const DWORD
*functions
= get_rva( module
, exports
->AddressOfFunctions
);
502 if (ordinal
>= exports
->NumberOfFunctions
)
504 TRACE(" ordinal %d out of range!\n", ordinal
+ exports
->Base
);
507 if (!functions
[ordinal
]) return NULL
;
509 proc
= get_rva( module
, functions
[ordinal
] );
511 /* if the address falls into the export dir, it's a forward */
512 if (((const char *)proc
>= (const char *)exports
) &&
513 ((const char *)proc
< (const char *)exports
+ exp_size
))
514 return find_forwarded_export( module
, (const char *)proc
, load_path
);
518 const WCHAR
*user
= current_modref
? current_modref
->ldr
.BaseDllName
.Buffer
: NULL
;
519 proc
= SNOOP_GetProcAddress( module
, exports
, exp_size
, proc
, ordinal
, user
);
523 const WCHAR
*user
= current_modref
? current_modref
->ldr
.BaseDllName
.Buffer
: NULL
;
524 proc
= RELAY_GetProcAddress( module
, exports
, exp_size
, proc
, ordinal
, user
);
530 /*************************************************************************
533 * Find an exported function by name.
534 * The loader_section must be locked while calling this function.
536 static FARPROC
find_named_export( HMODULE module
, const IMAGE_EXPORT_DIRECTORY
*exports
,
537 DWORD exp_size
, const char *name
, int hint
, LPCWSTR load_path
)
539 const WORD
*ordinals
= get_rva( module
, exports
->AddressOfNameOrdinals
);
540 const DWORD
*names
= get_rva( module
, exports
->AddressOfNames
);
541 int min
= 0, max
= exports
->NumberOfNames
- 1;
543 /* first check the hint */
544 if (hint
>= 0 && hint
<= max
)
546 char *ename
= get_rva( module
, names
[hint
] );
547 if (!strcmp( ename
, name
))
548 return find_ordinal_export( module
, exports
, exp_size
, ordinals
[hint
], load_path
);
551 /* then do a binary search */
554 int res
, pos
= (min
+ max
) / 2;
555 char *ename
= get_rva( module
, names
[pos
] );
556 if (!(res
= strcmp( ename
, name
)))
557 return find_ordinal_export( module
, exports
, exp_size
, ordinals
[pos
], load_path
);
558 if (res
> 0) max
= pos
- 1;
566 /*************************************************************************
569 * Import the dll specified by the given import descriptor.
570 * The loader_section must be locked while calling this function.
572 static BOOL
import_dll( HMODULE module
, const IMAGE_IMPORT_DESCRIPTOR
*descr
, LPCWSTR load_path
, WINE_MODREF
**pwm
)
577 const IMAGE_EXPORT_DIRECTORY
*exports
;
579 const IMAGE_THUNK_DATA
*import_list
;
580 IMAGE_THUNK_DATA
*thunk_list
;
582 const char *name
= get_rva( module
, descr
->Name
);
583 DWORD len
= strlen(name
);
585 SIZE_T protect_size
= 0;
588 thunk_list
= get_rva( module
, (DWORD
)descr
->FirstThunk
);
589 if (descr
->u
.OriginalFirstThunk
)
590 import_list
= get_rva( module
, (DWORD
)descr
->u
.OriginalFirstThunk
);
592 import_list
= thunk_list
;
594 if (!import_list
->u1
.Ordinal
)
596 WARN( "Skipping unused import %s\n", name
);
601 while (len
&& name
[len
-1] == ' ') len
--; /* remove trailing spaces */
603 if (len
* sizeof(WCHAR
) < sizeof(buffer
))
605 ascii_to_unicode( buffer
, name
, len
);
607 status
= load_dll( load_path
, buffer
, 0, &wmImp
);
609 else /* need to allocate a larger buffer */
611 WCHAR
*ptr
= RtlAllocateHeap( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) );
612 if (!ptr
) return FALSE
;
613 ascii_to_unicode( ptr
, name
, len
);
615 status
= load_dll( load_path
, ptr
, 0, &wmImp
);
616 RtlFreeHeap( GetProcessHeap(), 0, ptr
);
621 if (status
== STATUS_DLL_NOT_FOUND
)
622 ERR("Library %s (which is needed by %s) not found\n",
623 name
, debugstr_w(current_modref
->ldr
.FullDllName
.Buffer
));
625 ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
626 name
, debugstr_w(current_modref
->ldr
.FullDllName
.Buffer
), status
);
630 /* unprotect the import address table since it can be located in
631 * readonly section */
632 while (import_list
[protect_size
].u1
.Ordinal
) protect_size
++;
633 protect_base
= thunk_list
;
634 protect_size
*= sizeof(*thunk_list
);
635 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base
,
636 &protect_size
, PAGE_READWRITE
, &protect_old
);
638 imp_mod
= wmImp
->ldr
.BaseAddress
;
639 exports
= RtlImageDirectoryEntryToData( imp_mod
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
643 /* set all imported function to deadbeef */
644 while (import_list
->u1
.Ordinal
)
646 if (IMAGE_SNAP_BY_ORDINAL(import_list
->u1
.Ordinal
))
648 int ordinal
= IMAGE_ORDINAL(import_list
->u1
.Ordinal
);
649 WARN("No implementation for %s.%d", name
, ordinal
);
650 thunk_list
->u1
.Function
= allocate_stub( name
, IntToPtr(ordinal
) );
654 IMAGE_IMPORT_BY_NAME
*pe_name
= get_rva( module
, (DWORD
)import_list
->u1
.AddressOfData
);
655 WARN("No implementation for %s.%s", name
, pe_name
->Name
);
656 thunk_list
->u1
.Function
= allocate_stub( name
, (const char*)pe_name
->Name
);
658 WARN(" imported from %s, allocating stub %p\n",
659 debugstr_w(current_modref
->ldr
.FullDllName
.Buffer
),
660 (void *)thunk_list
->u1
.Function
);
667 while (import_list
->u1
.Ordinal
)
669 if (IMAGE_SNAP_BY_ORDINAL(import_list
->u1
.Ordinal
))
671 int ordinal
= IMAGE_ORDINAL(import_list
->u1
.Ordinal
);
673 thunk_list
->u1
.Function
= (ULONG_PTR
)find_ordinal_export( imp_mod
, exports
, exp_size
,
674 ordinal
- exports
->Base
, load_path
);
675 if (!thunk_list
->u1
.Function
)
677 thunk_list
->u1
.Function
= allocate_stub( name
, IntToPtr(ordinal
) );
678 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
679 name
, ordinal
, debugstr_w(current_modref
->ldr
.FullDllName
.Buffer
),
680 (void *)thunk_list
->u1
.Function
);
682 TRACE_(imports
)("--- Ordinal %s.%d = %p\n", name
, ordinal
, (void *)thunk_list
->u1
.Function
);
684 else /* import by name */
686 IMAGE_IMPORT_BY_NAME
*pe_name
;
687 pe_name
= get_rva( module
, (DWORD
)import_list
->u1
.AddressOfData
);
688 thunk_list
->u1
.Function
= (ULONG_PTR
)find_named_export( imp_mod
, exports
, exp_size
,
689 (const char*)pe_name
->Name
,
690 pe_name
->Hint
, load_path
);
691 if (!thunk_list
->u1
.Function
)
693 thunk_list
->u1
.Function
= allocate_stub( name
, (const char*)pe_name
->Name
);
694 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
695 name
, pe_name
->Name
, debugstr_w(current_modref
->ldr
.FullDllName
.Buffer
),
696 (void *)thunk_list
->u1
.Function
);
698 TRACE_(imports
)("--- %s %s.%d = %p\n",
699 pe_name
->Name
, name
, pe_name
->Hint
, (void *)thunk_list
->u1
.Function
);
706 /* restore old protection of the import address table */
707 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base
, &protect_size
, protect_old
, &protect_old
);
713 /***********************************************************************
714 * create_module_activation_context
716 static NTSTATUS
create_module_activation_context( LDR_MODULE
*module
)
719 LDR_RESOURCE_INFO info
;
720 const IMAGE_RESOURCE_DATA_ENTRY
*entry
;
722 info
.Type
= RT_MANIFEST
;
723 info
.Name
= ISOLATIONAWARE_MANIFEST_RESOURCE_ID
;
725 if (!(status
= LdrFindResource_U( module
->BaseAddress
, &info
, 3, &entry
)))
728 ctx
.cbSize
= sizeof(ctx
);
730 ctx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_HMODULE_VALID
;
731 ctx
.hModule
= module
->BaseAddress
;
732 ctx
.lpResourceName
= (LPCWSTR
)ISOLATIONAWARE_MANIFEST_RESOURCE_ID
;
733 status
= RtlCreateActivationContext( &module
->ActivationContext
, &ctx
);
739 /*************************************************************************
740 * is_dll_native_subsystem
742 * Check if dll is a proper native driver.
743 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
744 * while being perfectly normal DLLs. This heuristic should catch such breakages.
746 static BOOL
is_dll_native_subsystem( HMODULE module
, const IMAGE_NT_HEADERS
*nt
, LPCWSTR filename
)
748 static const WCHAR ntdllW
[] = {'n','t','d','l','l','.','d','l','l',0};
749 static const WCHAR kernel32W
[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
750 const IMAGE_IMPORT_DESCRIPTOR
*imports
;
754 if (nt
->OptionalHeader
.Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
) return FALSE
;
755 if (nt
->OptionalHeader
.SectionAlignment
< page_size
) return TRUE
;
757 if ((imports
= RtlImageDirectoryEntryToData( module
, TRUE
,
758 IMAGE_DIRECTORY_ENTRY_IMPORT
, &size
)))
760 for (i
= 0; imports
[i
].Name
; i
++)
762 const char *name
= get_rva( module
, imports
[i
].Name
);
763 DWORD len
= strlen(name
);
764 if (len
* sizeof(WCHAR
) >= sizeof(buffer
)) continue;
765 ascii_to_unicode( buffer
, name
, len
+ 1 );
766 if (!strcmpiW( buffer
, ntdllW
) || !strcmpiW( buffer
, kernel32W
))
768 TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename
), debugstr_w(buffer
) );
776 /*************************************************************************
779 * Allocate a TLS slot for a newly-loaded module.
780 * The loader_section must be locked while calling this function.
782 static SHORT
alloc_tls_slot( LDR_MODULE
*mod
)
784 const IMAGE_TLS_DIRECTORY
*dir
;
789 if (!(dir
= RtlImageDirectoryEntryToData( mod
->BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_TLS
, &size
)))
792 size
= dir
->EndAddressOfRawData
- dir
->StartAddressOfRawData
;
793 if (!size
&& !dir
->SizeOfZeroFill
&& !dir
->AddressOfCallBacks
) return -1;
795 for (i
= 0; i
< tls_module_count
; i
++)
797 if (!tls_dirs
[i
].StartAddressOfRawData
&& !tls_dirs
[i
].EndAddressOfRawData
&&
798 !tls_dirs
[i
].SizeOfZeroFill
&& !tls_dirs
[i
].AddressOfCallBacks
)
802 TRACE( "module %p data %p-%p zerofill %u index %p callback %p flags %x -> slot %u\n", mod
->BaseAddress
,
803 (void *)dir
->StartAddressOfRawData
, (void *)dir
->EndAddressOfRawData
, dir
->SizeOfZeroFill
,
804 (void *)dir
->AddressOfIndex
, (void *)dir
->AddressOfCallBacks
, dir
->Characteristics
, i
);
806 if (i
== tls_module_count
)
808 UINT new_count
= max( 32, tls_module_count
* 2 );
811 new_ptr
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*tls_dirs
) );
813 new_ptr
= RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, tls_dirs
,
814 new_count
* sizeof(*tls_dirs
) );
815 if (!new_ptr
) return -1;
817 /* resize the pointer block in all running threads */
818 for (entry
= tls_links
.Flink
; entry
!= &tls_links
; entry
= entry
->Flink
)
820 TEB
*teb
= CONTAINING_RECORD( entry
, TEB
, TlsLinks
);
821 void **old
= teb
->ThreadLocalStoragePointer
;
822 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*new));
825 if (old
) memcpy( new, old
, tls_module_count
* sizeof(*new) );
826 teb
->ThreadLocalStoragePointer
= new;
827 #if defined(__APPLE__) && defined(__x86_64__)
828 if (teb
->Reserved5
[0])
829 ((TEB
*)teb
->Reserved5
[0])->ThreadLocalStoragePointer
= new;
831 TRACE( "thread %04lx tls block %p -> %p\n", (ULONG_PTR
)teb
->ClientId
.UniqueThread
, old
, new );
832 /* FIXME: can't free old block here, should be freed at thread exit */
836 tls_module_count
= new_count
;
839 /* allocate the data block in all running threads */
840 for (entry
= tls_links
.Flink
; entry
!= &tls_links
; entry
= entry
->Flink
)
842 TEB
*teb
= CONTAINING_RECORD( entry
, TEB
, TlsLinks
);
844 if (!(new_ptr
= RtlAllocateHeap( GetProcessHeap(), 0, size
+ dir
->SizeOfZeroFill
))) return -1;
845 memcpy( new_ptr
, (void *)dir
->StartAddressOfRawData
, size
);
846 memset( (char *)new_ptr
+ size
, 0, dir
->SizeOfZeroFill
);
848 TRACE( "thread %04lx slot %u: %u/%u bytes at %p\n",
849 (ULONG_PTR
)teb
->ClientId
.UniqueThread
, i
, size
, dir
->SizeOfZeroFill
, new_ptr
);
851 RtlFreeHeap( GetProcessHeap(), 0,
852 interlocked_xchg_ptr( (void **)teb
->ThreadLocalStoragePointer
+ i
, new_ptr
));
855 *(DWORD
*)dir
->AddressOfIndex
= i
;
861 /*************************************************************************
864 * Free the module TLS slot on unload.
865 * The loader_section must be locked while calling this function.
867 static void free_tls_slot( LDR_MODULE
*mod
)
869 ULONG i
= (USHORT
)mod
->TlsIndex
;
871 if (mod
->TlsIndex
== -1) return;
872 assert( i
< tls_module_count
);
873 memset( &tls_dirs
[i
], 0, sizeof(tls_dirs
[i
]) );
877 /****************************************************************
880 * Fixup all imports of a given module.
881 * The loader_section must be locked while calling this function.
883 static NTSTATUS
fixup_imports( WINE_MODREF
*wm
, LPCWSTR load_path
)
886 const IMAGE_IMPORT_DESCRIPTOR
*imports
;
892 if (!(wm
->ldr
.Flags
& LDR_DONT_RESOLVE_REFS
)) return STATUS_SUCCESS
; /* already done */
893 wm
->ldr
.Flags
&= ~LDR_DONT_RESOLVE_REFS
;
895 wm
->ldr
.TlsIndex
= alloc_tls_slot( &wm
->ldr
);
897 if (!(imports
= RtlImageDirectoryEntryToData( wm
->ldr
.BaseAddress
, TRUE
,
898 IMAGE_DIRECTORY_ENTRY_IMPORT
, &size
)))
899 return STATUS_SUCCESS
;
902 while (imports
[nb_imports
].Name
&& imports
[nb_imports
].FirstThunk
) nb_imports
++;
904 if (!nb_imports
) return STATUS_SUCCESS
; /* no imports */
906 if (!create_module_activation_context( &wm
->ldr
))
907 RtlActivateActivationContext( 0, wm
->ldr
.ActivationContext
, &cookie
);
909 /* Allocate module dependency list */
910 wm
->nDeps
= nb_imports
;
911 wm
->deps
= RtlAllocateHeap( GetProcessHeap(), 0, nb_imports
*sizeof(WINE_MODREF
*) );
913 /* load the imported modules. They are automatically
914 * added to the modref list of the process.
916 prev
= current_modref
;
918 status
= STATUS_SUCCESS
;
919 for (i
= 0; i
< nb_imports
; i
++)
921 if (!import_dll( wm
->ldr
.BaseAddress
, &imports
[i
], load_path
, &wm
->deps
[i
] ))
924 status
= STATUS_DLL_NOT_FOUND
;
927 current_modref
= prev
;
928 if (wm
->ldr
.ActivationContext
) RtlDeactivateActivationContext( 0, cookie
);
933 /*************************************************************************
936 * Allocate a WINE_MODREF structure and add it to the process list
937 * The loader_section must be locked while calling this function.
939 static WINE_MODREF
*alloc_module( HMODULE hModule
, LPCWSTR filename
)
943 const IMAGE_NT_HEADERS
*nt
= RtlImageNtHeader(hModule
);
945 if (!(wm
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wm
) ))) return NULL
;
950 wm
->ldr
.BaseAddress
= hModule
;
951 wm
->ldr
.EntryPoint
= NULL
;
952 wm
->ldr
.SizeOfImage
= nt
->OptionalHeader
.SizeOfImage
;
953 wm
->ldr
.Flags
= LDR_DONT_RESOLVE_REFS
;
954 wm
->ldr
.TlsIndex
= -1;
955 wm
->ldr
.LoadCount
= 1;
956 wm
->ldr
.SectionHandle
= NULL
;
957 wm
->ldr
.CheckSum
= 0;
958 wm
->ldr
.TimeDateStamp
= 0;
959 wm
->ldr
.ActivationContext
= 0;
961 RtlCreateUnicodeString( &wm
->ldr
.FullDllName
, filename
);
962 if ((p
= strrchrW( wm
->ldr
.FullDllName
.Buffer
, '\\' ))) p
++;
963 else p
= wm
->ldr
.FullDllName
.Buffer
;
964 RtlInitUnicodeString( &wm
->ldr
.BaseDllName
, p
);
966 if (!(nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) || !is_dll_native_subsystem( hModule
, nt
, p
))
968 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
969 wm
->ldr
.Flags
|= LDR_IMAGE_IS_DLL
;
970 if (nt
->OptionalHeader
.AddressOfEntryPoint
)
971 wm
->ldr
.EntryPoint
= (char *)hModule
+ nt
->OptionalHeader
.AddressOfEntryPoint
;
974 InsertTailList(&NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
,
975 &wm
->ldr
.InLoadOrderModuleList
);
976 InsertTailList(&NtCurrentTeb()->Peb
->LdrData
->InMemoryOrderModuleList
,
977 &wm
->ldr
.InMemoryOrderModuleList
);
979 /* wait until init is called for inserting into this list */
980 wm
->ldr
.InInitializationOrderModuleList
.Flink
= NULL
;
981 wm
->ldr
.InInitializationOrderModuleList
.Blink
= NULL
;
983 if (!(nt
->OptionalHeader
.DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_NX_COMPAT
))
985 ULONG flags
= MEM_EXECUTE_OPTION_ENABLE
;
986 WARN( "disabling no-exec because of %s\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
) );
987 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags
, &flags
, sizeof(flags
) );
993 /*************************************************************************
996 * Allocate the per-thread structure for module TLS storage.
998 static NTSTATUS
alloc_thread_tls(void)
1003 if (!tls_module_count
) return STATUS_SUCCESS
;
1005 if (!(pointers
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1006 tls_module_count
* sizeof(*pointers
) )))
1007 return STATUS_NO_MEMORY
;
1009 for (i
= 0; i
< tls_module_count
; i
++)
1011 const IMAGE_TLS_DIRECTORY
*dir
= &tls_dirs
[i
];
1014 size
= dir
->EndAddressOfRawData
- dir
->StartAddressOfRawData
;
1015 if (!size
&& !dir
->SizeOfZeroFill
) continue;
1017 if (!(pointers
[i
] = RtlAllocateHeap( GetProcessHeap(), 0, size
+ dir
->SizeOfZeroFill
)))
1019 while (i
) RtlFreeHeap( GetProcessHeap(), 0, pointers
[--i
] );
1020 RtlFreeHeap( GetProcessHeap(), 0, pointers
);
1021 return STATUS_NO_MEMORY
;
1023 memcpy( pointers
[i
], (void *)dir
->StartAddressOfRawData
, size
);
1024 memset( (char *)pointers
[i
] + size
, 0, dir
->SizeOfZeroFill
);
1026 TRACE( "thread %04x slot %u: %u/%u bytes at %p\n",
1027 GetCurrentThreadId(), i
, size
, dir
->SizeOfZeroFill
, pointers
[i
] );
1029 NtCurrentTeb()->ThreadLocalStoragePointer
= pointers
;
1030 #if defined(__APPLE__) && defined(__x86_64__)
1031 __asm__
volatile (".byte 0x65\n\tmovq %0,%c1"
1033 : "r" (pointers
), "n" (FIELD_OFFSET(TEB
, ThreadLocalStoragePointer
)));
1035 return STATUS_SUCCESS
;
1039 /*************************************************************************
1040 * call_tls_callbacks
1042 static void call_tls_callbacks( HMODULE module
, UINT reason
)
1044 const IMAGE_TLS_DIRECTORY
*dir
;
1045 const PIMAGE_TLS_CALLBACK
*callback
;
1048 dir
= RtlImageDirectoryEntryToData( module
, TRUE
, IMAGE_DIRECTORY_ENTRY_TLS
, &dirsize
);
1049 if (!dir
|| !dir
->AddressOfCallBacks
) return;
1051 for (callback
= (const PIMAGE_TLS_CALLBACK
*)dir
->AddressOfCallBacks
; *callback
; callback
++)
1053 if (TRACE_ON(relay
))
1056 DPRINTF( "%04x:", GetCurrentProcessId() );
1057 DPRINTF("%04x:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1058 GetCurrentThreadId(), *callback
, module
, reason_names
[reason
] );
1062 call_dll_entry_point( (DLLENTRYPROC
)*callback
, module
, reason
, NULL
);
1066 if (TRACE_ON(relay
))
1069 DPRINTF( "%04x:", GetCurrentProcessId() );
1070 DPRINTF("%04x:exception in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1071 GetCurrentThreadId(), callback
, module
, reason_names
[reason
] );
1076 if (TRACE_ON(relay
))
1079 DPRINTF( "%04x:", GetCurrentProcessId() );
1080 DPRINTF("%04x:Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1081 GetCurrentThreadId(), *callback
, module
, reason_names
[reason
] );
1087 /*************************************************************************
1090 static NTSTATUS
MODULE_InitDLL( WINE_MODREF
*wm
, UINT reason
, LPVOID lpReserved
)
1093 NTSTATUS status
= STATUS_SUCCESS
;
1094 DLLENTRYPROC entry
= wm
->ldr
.EntryPoint
;
1095 void *module
= wm
->ldr
.BaseAddress
;
1098 /* Skip calls for modules loaded with special load flags */
1100 if (wm
->ldr
.Flags
& LDR_DONT_RESOLVE_REFS
) return STATUS_SUCCESS
;
1101 if (wm
->ldr
.TlsIndex
!= -1) call_tls_callbacks( wm
->ldr
.BaseAddress
, reason
);
1102 if (!entry
|| !(wm
->ldr
.Flags
& LDR_IMAGE_IS_DLL
)) return STATUS_SUCCESS
;
1104 if (TRACE_ON(relay
))
1106 size_t len
= min( wm
->ldr
.BaseDllName
.Length
, sizeof(mod_name
)-sizeof(WCHAR
) );
1107 memcpy( mod_name
, wm
->ldr
.BaseDllName
.Buffer
, len
);
1108 mod_name
[len
/ sizeof(WCHAR
)] = 0;
1110 DPRINTF( "%04x:", GetCurrentProcessId() );
1111 DPRINTF("%04x:Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1112 GetCurrentThreadId(), entry
, module
, debugstr_w(mod_name
),
1113 reason_names
[reason
], lpReserved
);
1115 else TRACE("(%p %s,%s,%p) - CALL\n", module
, debugstr_w(wm
->ldr
.BaseDllName
.Buffer
),
1116 reason_names
[reason
], lpReserved
);
1120 retv
= call_dll_entry_point( entry
, module
, reason
, lpReserved
);
1122 status
= STATUS_DLL_INIT_FAILED
;
1126 if (TRACE_ON(relay
))
1129 DPRINTF( "%04x:", GetCurrentProcessId() );
1130 DPRINTF("%04x:exception in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1131 GetCurrentThreadId(), entry
, module
, reason_names
[reason
], lpReserved
);
1133 status
= GetExceptionCode();
1137 /* The state of the module list may have changed due to the call
1138 to the dll. We cannot assume that this module has not been
1140 if (TRACE_ON(relay
))
1143 DPRINTF( "%04x:", GetCurrentProcessId() );
1144 DPRINTF("%04x:Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1145 GetCurrentThreadId(), entry
, module
, debugstr_w(mod_name
),
1146 reason_names
[reason
], lpReserved
, retv
);
1148 else TRACE("(%p,%s,%p) - RETURN %d\n", module
, reason_names
[reason
], lpReserved
, retv
);
1154 /*************************************************************************
1157 * Send the process attach notification to all DLLs the given module
1158 * depends on (recursively). This is somewhat complicated due to the fact that
1160 * - we have to respect the module dependencies, i.e. modules implicitly
1161 * referenced by another module have to be initialized before the module
1162 * itself can be initialized
1164 * - the initialization routine of a DLL can itself call LoadLibrary,
1165 * thereby introducing a whole new set of dependencies (even involving
1166 * the 'old' modules) at any time during the whole process
1168 * (Note that this routine can be recursively entered not only directly
1169 * from itself, but also via LoadLibrary from one of the called initialization
1172 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1173 * the process *detach* notifications to be sent in the correct order.
1174 * This must not only take into account module dependencies, but also
1175 * 'hidden' dependencies created by modules calling LoadLibrary in their
1176 * attach notification routine.
1178 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1179 * list after the attach notification has returned. This implies that the
1180 * detach notifications are called in the reverse of the sequence the attach
1181 * notifications *returned*.
1183 * The loader_section must be locked while calling this function.
1185 static NTSTATUS
process_attach( WINE_MODREF
*wm
, LPVOID lpReserved
)
1187 NTSTATUS status
= STATUS_SUCCESS
;
1191 if (process_detaching
) return status
;
1193 /* prevent infinite recursion in case of cyclical dependencies */
1194 if ( ( wm
->ldr
.Flags
& LDR_LOAD_IN_PROGRESS
)
1195 || ( wm
->ldr
.Flags
& LDR_PROCESS_ATTACHED
) )
1198 TRACE("(%s,%p) - START\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
), lpReserved
);
1200 /* Tag current MODREF to prevent recursive loop */
1201 wm
->ldr
.Flags
|= LDR_LOAD_IN_PROGRESS
;
1202 if (lpReserved
) wm
->ldr
.LoadCount
= -1; /* pin it if imported by the main exe */
1203 if (wm
->ldr
.ActivationContext
) RtlActivateActivationContext( 0, wm
->ldr
.ActivationContext
, &cookie
);
1205 /* Recursively attach all DLLs this one depends on */
1206 for ( i
= 0; i
< wm
->nDeps
; i
++ )
1208 if (!wm
->deps
[i
]) continue;
1209 if ((status
= process_attach( wm
->deps
[i
], lpReserved
)) != STATUS_SUCCESS
) break;
1212 if (!wm
->ldr
.InInitializationOrderModuleList
.Flink
)
1213 InsertTailList(&NtCurrentTeb()->Peb
->LdrData
->InInitializationOrderModuleList
,
1214 &wm
->ldr
.InInitializationOrderModuleList
);
1216 /* Call DLL entry point */
1217 if (status
== STATUS_SUCCESS
)
1219 WINE_MODREF
*prev
= current_modref
;
1220 current_modref
= wm
;
1221 status
= MODULE_InitDLL( wm
, DLL_PROCESS_ATTACH
, lpReserved
);
1222 if (status
== STATUS_SUCCESS
)
1223 wm
->ldr
.Flags
|= LDR_PROCESS_ATTACHED
;
1226 MODULE_InitDLL( wm
, DLL_PROCESS_DETACH
, lpReserved
);
1227 /* point to the name so LdrInitializeThunk can print it */
1228 last_failed_modref
= wm
;
1229 WARN("Initialization of %s failed\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
));
1231 current_modref
= prev
;
1234 if (wm
->ldr
.ActivationContext
) RtlDeactivateActivationContext( 0, cookie
);
1235 /* Remove recursion flag */
1236 wm
->ldr
.Flags
&= ~LDR_LOAD_IN_PROGRESS
;
1238 TRACE("(%s,%p) - END\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
), lpReserved
);
1243 /**********************************************************************
1244 * attach_implicitly_loaded_dlls
1246 * Attach to the (builtin) dlls that have been implicitly loaded because
1247 * of a dependency at the Unix level, but not imported at the Win32 level.
1249 static void attach_implicitly_loaded_dlls( LPVOID reserved
)
1253 PLIST_ENTRY mark
, entry
;
1255 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
1256 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
1258 LDR_MODULE
*mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
1260 if (mod
->Flags
& (LDR_LOAD_IN_PROGRESS
| LDR_PROCESS_ATTACHED
)) continue;
1261 TRACE( "found implicitly loaded %s, attaching to it\n",
1262 debugstr_w(mod
->BaseDllName
.Buffer
));
1263 process_attach( CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
), reserved
);
1264 break; /* restart the search from the start */
1266 if (entry
== mark
) break; /* nothing found */
1271 /*************************************************************************
1274 * Send DLL process detach notifications. See the comment about calling
1275 * sequence at process_attach.
1277 static void process_detach(void)
1279 PLIST_ENTRY mark
, entry
;
1282 mark
= &NtCurrentTeb()->Peb
->LdrData
->InInitializationOrderModuleList
;
1285 for (entry
= mark
->Blink
; entry
!= mark
; entry
= entry
->Blink
)
1287 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
,
1288 InInitializationOrderModuleList
);
1289 /* Check whether to detach this DLL */
1290 if ( !(mod
->Flags
& LDR_PROCESS_ATTACHED
) )
1292 if ( mod
->LoadCount
&& !process_detaching
)
1295 /* Call detach notification */
1296 mod
->Flags
&= ~LDR_PROCESS_ATTACHED
;
1297 MODULE_InitDLL( CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
),
1298 DLL_PROCESS_DETACH
, ULongToPtr(process_detaching
) );
1300 /* Restart at head of WINE_MODREF list, as entries might have
1301 been added and/or removed while performing the call ... */
1304 } while (entry
!= mark
);
1307 /*************************************************************************
1308 * MODULE_DllThreadAttach
1310 * Send DLL thread attach notifications. These are sent in the
1311 * reverse sequence of process detach notification.
1314 NTSTATUS
MODULE_DllThreadAttach( LPVOID lpReserved
)
1316 PLIST_ENTRY mark
, entry
;
1320 /* don't do any attach calls if process is exiting */
1321 if (process_detaching
) return STATUS_SUCCESS
;
1323 RtlEnterCriticalSection( &loader_section
);
1325 RtlAcquirePebLock();
1326 InsertHeadList( &tls_links
, &NtCurrentTeb()->TlsLinks
);
1327 RtlReleasePebLock();
1329 if ((status
= alloc_thread_tls()) != STATUS_SUCCESS
) goto done
;
1331 mark
= &NtCurrentTeb()->Peb
->LdrData
->InInitializationOrderModuleList
;
1332 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
1334 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
,
1335 InInitializationOrderModuleList
);
1336 if ( !(mod
->Flags
& LDR_PROCESS_ATTACHED
) )
1338 if ( mod
->Flags
& LDR_NO_DLL_CALLS
)
1341 MODULE_InitDLL( CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
),
1342 DLL_THREAD_ATTACH
, lpReserved
);
1346 RtlLeaveCriticalSection( &loader_section
);
1350 /******************************************************************
1351 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1354 NTSTATUS WINAPI
LdrDisableThreadCalloutsForDll(HMODULE hModule
)
1357 NTSTATUS ret
= STATUS_SUCCESS
;
1359 RtlEnterCriticalSection( &loader_section
);
1361 wm
= get_modref( hModule
);
1362 if (!wm
|| wm
->ldr
.TlsIndex
!= -1)
1363 ret
= STATUS_DLL_NOT_FOUND
;
1365 wm
->ldr
.Flags
|= LDR_NO_DLL_CALLS
;
1367 RtlLeaveCriticalSection( &loader_section
);
1372 /******************************************************************
1373 * LdrFindEntryForAddress (NTDLL.@)
1375 * The loader_section must be locked while calling this function
1377 NTSTATUS WINAPI
LdrFindEntryForAddress(const void* addr
, PLDR_MODULE
* pmod
)
1379 PLIST_ENTRY mark
, entry
;
1382 mark
= &NtCurrentTeb()->Peb
->LdrData
->InMemoryOrderModuleList
;
1383 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
1385 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InMemoryOrderModuleList
);
1386 if (mod
->BaseAddress
<= addr
&&
1387 (const char *)addr
< (char*)mod
->BaseAddress
+ mod
->SizeOfImage
)
1390 return STATUS_SUCCESS
;
1393 return STATUS_NO_MORE_ENTRIES
;
1396 /******************************************************************
1397 * LdrLockLoaderLock (NTDLL.@)
1399 * Note: some flags are not implemented.
1400 * Flag 0x01 is used to raise exceptions on errors.
1402 NTSTATUS WINAPI
LdrLockLoaderLock( ULONG flags
, ULONG
*result
, ULONG_PTR
*magic
)
1404 if (flags
& ~0x2) FIXME( "flags %x not supported\n", flags
);
1406 if (result
) *result
= 0;
1407 if (magic
) *magic
= 0;
1408 if (flags
& ~0x3) return STATUS_INVALID_PARAMETER_1
;
1409 if (!result
&& (flags
& 0x2)) return STATUS_INVALID_PARAMETER_2
;
1410 if (!magic
) return STATUS_INVALID_PARAMETER_3
;
1414 if (!RtlTryEnterCriticalSection( &loader_section
))
1417 return STATUS_SUCCESS
;
1423 RtlEnterCriticalSection( &loader_section
);
1424 if (result
) *result
= 1;
1426 *magic
= GetCurrentThreadId();
1427 return STATUS_SUCCESS
;
1431 /******************************************************************
1432 * LdrUnlockLoaderUnlock (NTDLL.@)
1434 NTSTATUS WINAPI
LdrUnlockLoaderLock( ULONG flags
, ULONG_PTR magic
)
1438 if (magic
!= GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2
;
1439 RtlLeaveCriticalSection( &loader_section
);
1441 return STATUS_SUCCESS
;
1445 /******************************************************************
1446 * LdrGetProcedureAddress (NTDLL.@)
1448 NTSTATUS WINAPI
LdrGetProcedureAddress(HMODULE module
, const ANSI_STRING
*name
,
1449 ULONG ord
, PVOID
*address
)
1451 IMAGE_EXPORT_DIRECTORY
*exports
;
1453 NTSTATUS ret
= STATUS_PROCEDURE_NOT_FOUND
;
1455 RtlEnterCriticalSection( &loader_section
);
1457 /* check if the module itself is invalid to return the proper error */
1458 if (!get_modref( module
)) ret
= STATUS_DLL_NOT_FOUND
;
1459 else if ((exports
= RtlImageDirectoryEntryToData( module
, TRUE
,
1460 IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
)))
1462 LPCWSTR load_path
= NtCurrentTeb()->Peb
->ProcessParameters
->DllPath
.Buffer
;
1463 void *proc
= name
? find_named_export( module
, exports
, exp_size
, name
->Buffer
, -1, load_path
)
1464 : find_ordinal_export( module
, exports
, exp_size
, ord
- exports
->Base
, load_path
);
1468 ret
= STATUS_SUCCESS
;
1472 RtlLeaveCriticalSection( &loader_section
);
1477 /***********************************************************************
1480 * Check if a loaded native dll is a Wine fake dll.
1482 static BOOL
is_fake_dll( HANDLE handle
)
1484 static const char fakedll_signature
[] = "Wine placeholder DLL";
1485 char buffer
[sizeof(IMAGE_DOS_HEADER
) + sizeof(fakedll_signature
)];
1486 const IMAGE_DOS_HEADER
*dos
= (const IMAGE_DOS_HEADER
*)buffer
;
1488 LARGE_INTEGER offset
;
1490 offset
.QuadPart
= 0;
1491 if (NtReadFile( handle
, 0, NULL
, 0, &io
, buffer
, sizeof(buffer
), &offset
, NULL
)) return FALSE
;
1492 if (io
.Information
< sizeof(buffer
)) return FALSE
;
1493 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
1494 if (dos
->e_lfanew
>= sizeof(*dos
) + sizeof(fakedll_signature
) &&
1495 !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) )) return TRUE
;
1500 /***********************************************************************
1501 * get_builtin_fullname
1503 * Build the full pathname for a builtin dll.
1505 static WCHAR
*get_builtin_fullname( const WCHAR
*path
, const char *filename
)
1507 static const WCHAR soW
[] = {'.','s','o',0};
1508 WCHAR
*p
, *fullname
;
1509 size_t i
, len
= strlen(filename
);
1511 /* check if path can correspond to the dll we have */
1512 if (path
&& (p
= strrchrW( path
, '\\' )))
1515 for (i
= 0; i
< len
; i
++)
1516 if (tolowerW(p
[i
]) != tolowerW( (WCHAR
)filename
[i
]) ) break;
1517 if (i
== len
&& (!p
[len
] || !strcmpiW( p
+ len
, soW
)))
1519 /* the filename matches, use path as the full path */
1521 if ((fullname
= RtlAllocateHeap( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) )))
1523 memcpy( fullname
, path
, len
* sizeof(WCHAR
) );
1530 if ((fullname
= RtlAllocateHeap( GetProcessHeap(), 0,
1531 system_dir
.MaximumLength
+ (len
+ 1) * sizeof(WCHAR
) )))
1533 memcpy( fullname
, system_dir
.Buffer
, system_dir
.Length
);
1534 p
= fullname
+ system_dir
.Length
/ sizeof(WCHAR
);
1535 if (p
> fullname
&& p
[-1] != '\\') *p
++ = '\\';
1536 ascii_to_unicode( p
, filename
, len
+ 1 );
1542 /*************************************************************************
1545 static BOOL
is_16bit_builtin( HMODULE module
)
1547 const IMAGE_EXPORT_DIRECTORY
*exports
;
1550 if (!(exports
= RtlImageDirectoryEntryToData( module
, TRUE
,
1551 IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
)))
1554 return find_named_export( module
, exports
, exp_size
, "__wine_spec_dos_header", -1, NULL
) != NULL
;
1558 /***********************************************************************
1559 * load_builtin_callback
1561 * Load a library in memory; callback function for wine_dll_register
1563 static void load_builtin_callback( void *module
, const char *filename
)
1565 static const WCHAR emptyW
[1];
1566 IMAGE_NT_HEADERS
*nt
;
1569 const WCHAR
*load_path
;
1573 ERR("could not map image for %s\n", filename
? filename
: "main exe" );
1576 if (!(nt
= RtlImageNtHeader( module
)))
1578 ERR( "bad module for %s\n", filename
? filename
: "main exe" );
1579 builtin_load_info
->status
= STATUS_INVALID_IMAGE_FORMAT
;
1583 virtual_create_builtin_view( module
);
1585 /* create the MODREF */
1587 if (!(fullname
= get_builtin_fullname( builtin_load_info
->filename
, filename
)))
1589 ERR( "can't load %s\n", filename
);
1590 builtin_load_info
->status
= STATUS_NO_MEMORY
;
1594 wm
= alloc_module( module
, fullname
);
1595 RtlFreeHeap( GetProcessHeap(), 0, fullname
);
1598 ERR( "can't load %s\n", filename
);
1599 builtin_load_info
->status
= STATUS_NO_MEMORY
;
1602 wm
->ldr
.Flags
|= LDR_WINE_INTERNAL
;
1604 if ((nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ||
1605 nt
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
||
1606 is_16bit_builtin( module
))
1610 load_path
= builtin_load_info
->load_path
;
1611 if (!load_path
) load_path
= NtCurrentTeb()->Peb
->ProcessParameters
->DllPath
.Buffer
;
1612 if (!load_path
) load_path
= emptyW
;
1613 if (fixup_imports( wm
, load_path
) != STATUS_SUCCESS
)
1615 /* the module has only be inserted in the load & memory order lists */
1616 RemoveEntryList(&wm
->ldr
.InLoadOrderModuleList
);
1617 RemoveEntryList(&wm
->ldr
.InMemoryOrderModuleList
);
1618 /* FIXME: free the modref */
1619 builtin_load_info
->status
= STATUS_DLL_NOT_FOUND
;
1624 builtin_load_info
->wm
= wm
;
1625 TRACE( "loaded %s %p %p\n", filename
, wm
, module
);
1627 /* send the DLL load event */
1629 SERVER_START_REQ( load_dll
)
1632 req
->base
= wine_server_client_ptr( module
);
1633 req
->size
= nt
->OptionalHeader
.SizeOfImage
;
1634 req
->dbg_offset
= nt
->FileHeader
.PointerToSymbolTable
;
1635 req
->dbg_size
= nt
->FileHeader
.NumberOfSymbols
;
1636 req
->name
= wine_server_client_ptr( &wm
->ldr
.FullDllName
.Buffer
);
1637 wine_server_add_data( req
, wm
->ldr
.FullDllName
.Buffer
, wm
->ldr
.FullDllName
.Length
);
1638 wine_server_call( req
);
1642 /* setup relay debugging entry points */
1643 if (TRACE_ON(relay
)) RELAY_SetupDLL( module
);
1647 /***********************************************************************
1648 * set_security_cookie
1650 * Create a random security cookie for buffer overflow protection. Make
1651 * sure it does not accidentally match the default cookie value.
1653 static void set_security_cookie( void *module
, SIZE_T len
)
1656 IMAGE_LOAD_CONFIG_DIRECTORY
*loadcfg
;
1660 loadcfg
= RtlImageDirectoryEntryToData( module
, TRUE
, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
, &loadcfg_size
);
1661 if (!loadcfg
) return;
1662 if (loadcfg_size
< offsetof(IMAGE_LOAD_CONFIG_DIRECTORY
, SecurityCookie
) + sizeof(loadcfg
->SecurityCookie
)) return;
1663 if (!loadcfg
->SecurityCookie
) return;
1664 if (loadcfg
->SecurityCookie
< (ULONG_PTR
)module
||
1665 loadcfg
->SecurityCookie
> (ULONG_PTR
)module
+ len
- sizeof(ULONG_PTR
))
1667 WARN( "security cookie %p outside of image %p-%p\n",
1668 (void *)loadcfg
->SecurityCookie
, module
, (char *)module
+ len
);
1672 cookie
= (ULONG_PTR
*)loadcfg
->SecurityCookie
;
1673 TRACE( "initializing security cookie %p\n", cookie
);
1675 if (!seed
) seed
= NtGetTickCount() ^ GetCurrentProcessId();
1678 if (*cookie
== DEFAULT_SECURITY_COOKIE_16
)
1679 *cookie
= RtlRandom( &seed
) >> 16; /* leave the high word clear */
1680 else if (*cookie
== DEFAULT_SECURITY_COOKIE_32
)
1681 *cookie
= RtlRandom( &seed
);
1682 #ifdef DEFAULT_SECURITY_COOKIE_64
1683 else if (*cookie
== DEFAULT_SECURITY_COOKIE_64
)
1685 *cookie
= RtlRandom( &seed
);
1686 /* fill up, but keep the highest word clear */
1687 *cookie
^= (ULONG_PTR
)RtlRandom( &seed
) << 16;
1695 static NTSTATUS
perform_relocations( void *module
, SIZE_T len
)
1697 IMAGE_NT_HEADERS
*nt
;
1699 IMAGE_BASE_RELOCATION
*rel
, *end
;
1700 const IMAGE_DATA_DIRECTORY
*relocs
;
1701 const IMAGE_SECTION_HEADER
*sec
;
1703 ULONG protect_old
[96], i
;
1705 nt
= RtlImageNtHeader( module
);
1706 base
= (char *)nt
->OptionalHeader
.ImageBase
;
1708 assert( module
!= base
);
1710 /* no relocations are performed on non page-aligned binaries */
1711 if (nt
->OptionalHeader
.SectionAlignment
< page_size
)
1712 return STATUS_SUCCESS
;
1714 if (!(nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) && NtCurrentTeb()->Peb
->ImageBaseAddress
)
1715 return STATUS_SUCCESS
;
1717 relocs
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1719 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1721 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
1723 return STATUS_CONFLICTING_ADDRESSES
;
1726 if (!relocs
->Size
) return STATUS_SUCCESS
;
1727 if (!relocs
->VirtualAddress
) return STATUS_CONFLICTING_ADDRESSES
;
1729 if (nt
->FileHeader
.NumberOfSections
> sizeof(protect_old
)/sizeof(protect_old
[0]))
1730 return STATUS_INVALID_IMAGE_FORMAT
;
1732 sec
= (const IMAGE_SECTION_HEADER
*)((const char *)&nt
->OptionalHeader
+
1733 nt
->FileHeader
.SizeOfOptionalHeader
);
1734 for (i
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++)
1736 void *addr
= get_rva( module
, sec
[i
].VirtualAddress
);
1737 SIZE_T size
= sec
[i
].SizeOfRawData
;
1738 NtProtectVirtualMemory( NtCurrentProcess(), &addr
,
1739 &size
, PAGE_READWRITE
, &protect_old
[i
] );
1742 TRACE( "relocating from %p-%p to %p-%p\n",
1743 base
, base
+ len
, module
, (char *)module
+ len
);
1745 rel
= get_rva( module
, relocs
->VirtualAddress
);
1746 end
= get_rva( module
, relocs
->VirtualAddress
+ relocs
->Size
);
1747 delta
= (char *)module
- base
;
1749 while (rel
< end
- 1 && rel
->SizeOfBlock
)
1751 if (rel
->VirtualAddress
>= len
)
1753 WARN( "invalid address %p in relocation %p\n", get_rva( module
, rel
->VirtualAddress
), rel
);
1754 return STATUS_ACCESS_VIOLATION
;
1756 rel
= LdrProcessRelocationBlock( get_rva( module
, rel
->VirtualAddress
),
1757 (rel
->SizeOfBlock
- sizeof(*rel
)) / sizeof(USHORT
),
1758 (USHORT
*)(rel
+ 1), delta
);
1759 if (!rel
) return STATUS_INVALID_IMAGE_FORMAT
;
1762 for (i
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++)
1764 void *addr
= get_rva( module
, sec
[i
].VirtualAddress
);
1765 SIZE_T size
= sec
[i
].SizeOfRawData
;
1766 NtProtectVirtualMemory( NtCurrentProcess(), &addr
,
1767 &size
, protect_old
[i
], &protect_old
[i
] );
1770 return STATUS_SUCCESS
;
1773 /******************************************************************************
1774 * load_native_dll (internal)
1776 static NTSTATUS
load_native_dll( LPCWSTR load_path
, LPCWSTR name
, HANDLE file
,
1777 DWORD flags
, WINE_MODREF
** pwm
)
1782 IMAGE_NT_HEADERS
*nt
;
1787 TRACE("Trying native dll %s\n", debugstr_w(name
));
1790 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
,
1791 NULL
, &size
, PAGE_EXECUTE_READ
, SEC_IMAGE
, file
);
1792 if (status
!= STATUS_SUCCESS
) return status
;
1795 status
= NtMapViewOfSection( mapping
, NtCurrentProcess(),
1796 &module
, 0, 0, &size
, &len
, ViewShare
, 0, PAGE_EXECUTE_READ
);
1798 /* perform base relocation, if necessary */
1800 if (status
== STATUS_IMAGE_NOT_AT_BASE
)
1801 status
= perform_relocations( module
, len
);
1803 if (status
!= STATUS_SUCCESS
)
1805 if (module
) NtUnmapViewOfSection( NtCurrentProcess(), module
);
1809 /* create the MODREF */
1811 if (!(wm
= alloc_module( module
, name
)))
1813 status
= STATUS_NO_MEMORY
;
1817 set_security_cookie( module
, len
);
1821 nt
= RtlImageNtHeader( module
);
1823 if (!(flags
& DONT_RESOLVE_DLL_REFERENCES
) &&
1824 ((nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ||
1825 nt
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
))
1827 if ((status
= fixup_imports( wm
, load_path
)) != STATUS_SUCCESS
)
1829 /* the module has only be inserted in the load & memory order lists */
1830 RemoveEntryList(&wm
->ldr
.InLoadOrderModuleList
);
1831 RemoveEntryList(&wm
->ldr
.InMemoryOrderModuleList
);
1833 /* FIXME: there are several more dangling references
1834 * left. Including dlls loaded by this dll before the
1835 * failed one. Unrolling is rather difficult with the
1836 * current structure and we can leave them lying
1837 * around with no problems, so we don't care.
1838 * As these might reference our wm, we don't free it.
1844 /* send DLL load event */
1846 SERVER_START_REQ( load_dll
)
1848 req
->mapping
= wine_server_obj_handle( mapping
);
1849 req
->base
= wine_server_client_ptr( module
);
1850 req
->size
= nt
->OptionalHeader
.SizeOfImage
;
1851 req
->dbg_offset
= nt
->FileHeader
.PointerToSymbolTable
;
1852 req
->dbg_size
= nt
->FileHeader
.NumberOfSymbols
;
1853 req
->name
= wine_server_client_ptr( &wm
->ldr
.FullDllName
.Buffer
);
1854 wine_server_add_data( req
, wm
->ldr
.FullDllName
.Buffer
, wm
->ldr
.FullDllName
.Length
);
1855 wine_server_call( req
);
1859 if ((wm
->ldr
.Flags
& LDR_IMAGE_IS_DLL
) && TRACE_ON(snoop
)) SNOOP_SetupDLL( module
);
1861 TRACE_(loaddll
)( "Loaded %s at %p: native\n", debugstr_w(wm
->ldr
.FullDllName
.Buffer
), module
);
1863 wm
->ldr
.LoadCount
= 1;
1865 status
= STATUS_SUCCESS
;
1872 /***********************************************************************
1875 static NTSTATUS
load_builtin_dll( LPCWSTR load_path
, LPCWSTR path
, HANDLE file
,
1876 DWORD flags
, WINE_MODREF
** pwm
)
1878 char error
[256], dllname
[MAX_PATH
];
1879 const WCHAR
*name
, *p
;
1882 struct builtin_load_info info
, *prev_info
;
1884 /* Fix the name in case we have a full path and extension */
1886 if ((p
= strrchrW( name
, '\\' ))) name
= p
+ 1;
1887 if ((p
= strrchrW( name
, '/' ))) name
= p
+ 1;
1889 /* load_library will modify info.status. Note also that load_library can be
1890 * called several times, if the .so file we're loading has dependencies.
1891 * info.status will gather all the errors we may get while loading all these
1894 info
.load_path
= load_path
;
1895 info
.filename
= NULL
;
1896 info
.status
= STATUS_SUCCESS
;
1899 if (file
) /* we have a real file, try to load it */
1901 UNICODE_STRING nt_name
;
1902 ANSI_STRING unix_name
;
1904 TRACE("Trying built-in %s\n", debugstr_w(path
));
1906 if (!RtlDosPathNameToNtPathName_U( path
, &nt_name
, NULL
, NULL
))
1907 return STATUS_DLL_NOT_FOUND
;
1909 if (wine_nt_to_unix_file_name( &nt_name
, &unix_name
, FILE_OPEN
, FALSE
))
1911 RtlFreeUnicodeString( &nt_name
);
1912 return STATUS_DLL_NOT_FOUND
;
1914 prev_info
= builtin_load_info
;
1915 info
.filename
= nt_name
.Buffer
+ 4; /* skip \??\ */
1916 builtin_load_info
= &info
;
1917 handle
= wine_dlopen( unix_name
.Buffer
, RTLD_NOW
, error
, sizeof(error
) );
1918 builtin_load_info
= prev_info
;
1919 RtlFreeUnicodeString( &nt_name
);
1920 RtlFreeHeap( GetProcessHeap(), 0, unix_name
.Buffer
);
1923 WARN( "failed to load .so lib for builtin %s: %s\n", debugstr_w(path
), error
);
1924 return STATUS_INVALID_IMAGE_FORMAT
;
1931 TRACE("Trying built-in %s\n", debugstr_w(name
));
1933 /* we don't want to depend on the current codepage here */
1934 len
= strlenW( name
) + 1;
1935 if (len
>= sizeof(dllname
)) return STATUS_NAME_TOO_LONG
;
1936 for (i
= 0; i
< len
; i
++)
1938 if (name
[i
] > 127) return STATUS_DLL_NOT_FOUND
;
1939 dllname
[i
] = (char)name
[i
];
1940 if (dllname
[i
] >= 'A' && dllname
[i
] <= 'Z') dllname
[i
] += 'a' - 'A';
1943 prev_info
= builtin_load_info
;
1944 builtin_load_info
= &info
;
1945 handle
= wine_dll_load( dllname
, error
, sizeof(error
), &file_exists
);
1946 builtin_load_info
= prev_info
;
1951 /* The file does not exist -> WARN() */
1952 WARN("cannot open .so lib for builtin %s: %s\n", debugstr_w(name
), error
);
1953 return STATUS_DLL_NOT_FOUND
;
1955 /* ERR() for all other errors (missing functions, ...) */
1956 ERR("failed to load .so lib for builtin %s: %s\n", debugstr_w(name
), error
);
1957 return STATUS_PROCEDURE_NOT_FOUND
;
1961 if (info
.status
!= STATUS_SUCCESS
)
1963 wine_dll_unload( handle
);
1969 PLIST_ENTRY mark
, entry
;
1971 /* The constructor wasn't called, this means the .so is already
1972 * loaded under a different name. Try to find the wm for it. */
1974 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
1975 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
1977 LDR_MODULE
*mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
1978 if (mod
->Flags
& LDR_WINE_INTERNAL
&& mod
->SectionHandle
== handle
)
1980 info
.wm
= CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
);
1981 TRACE( "Found %s at %p for builtin %s\n",
1982 debugstr_w(info
.wm
->ldr
.FullDllName
.Buffer
), info
.wm
->ldr
.BaseAddress
, debugstr_w(path
) );
1986 wine_dll_unload( handle
); /* release the libdl refcount */
1987 if (!info
.wm
) return STATUS_INVALID_IMAGE_FORMAT
;
1988 if (info
.wm
->ldr
.LoadCount
!= -1) info
.wm
->ldr
.LoadCount
++;
1992 TRACE_(loaddll
)( "Loaded %s at %p: builtin\n", debugstr_w(info
.wm
->ldr
.FullDllName
.Buffer
), info
.wm
->ldr
.BaseAddress
);
1993 info
.wm
->ldr
.LoadCount
= 1;
1994 info
.wm
->ldr
.SectionHandle
= handle
;
1998 return STATUS_SUCCESS
;
2002 /***********************************************************************
2005 * Find the full path (if any) of the dll from the activation context.
2007 static NTSTATUS
find_actctx_dll( LPCWSTR libname
, LPWSTR
*fullname
)
2009 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\'};
2010 static const WCHAR dotManifestW
[] = {'.','m','a','n','i','f','e','s','t',0};
2012 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*info
;
2013 ACTCTX_SECTION_KEYED_DATA data
;
2014 UNICODE_STRING nameW
;
2016 SIZE_T needed
, size
= 1024;
2019 RtlInitUnicodeString( &nameW
, libname
);
2020 data
.cbSize
= sizeof(data
);
2021 status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
2022 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
2024 if (status
!= STATUS_SUCCESS
) return status
;
2028 if (!(info
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
2030 status
= STATUS_NO_MEMORY
;
2033 status
= RtlQueryInformationActivationContext( 0, data
.hActCtx
, &data
.ulAssemblyRosterIndex
,
2034 AssemblyDetailedInformationInActivationContext
,
2035 info
, size
, &needed
);
2036 if (status
== STATUS_SUCCESS
) break;
2037 if (status
!= STATUS_BUFFER_TOO_SMALL
) goto done
;
2038 RtlFreeHeap( GetProcessHeap(), 0, info
);
2040 /* restart with larger buffer */
2043 if (!info
->lpAssemblyManifestPath
|| !info
->lpAssemblyDirectoryName
)
2045 status
= STATUS_SXS_KEY_NOT_FOUND
;
2049 if ((p
= strrchrW( info
->lpAssemblyManifestPath
, '\\' )))
2051 DWORD dirlen
= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
2054 if (strncmpiW( p
, info
->lpAssemblyDirectoryName
, dirlen
) || strcmpiW( p
+ dirlen
, dotManifestW
))
2056 /* manifest name does not match directory name, so it's not a global
2057 * windows/winsxs manifest; use the manifest directory name instead */
2058 dirlen
= p
- info
->lpAssemblyManifestPath
;
2059 needed
= (dirlen
+ 1) * sizeof(WCHAR
) + nameW
.Length
;
2060 if (!(*fullname
= p
= RtlAllocateHeap( GetProcessHeap(), 0, needed
)))
2062 status
= STATUS_NO_MEMORY
;
2065 memcpy( p
, info
->lpAssemblyManifestPath
, dirlen
* sizeof(WCHAR
) );
2067 strcpyW( p
, libname
);
2072 needed
= (strlenW(user_shared_data
->NtSystemRoot
) * sizeof(WCHAR
) +
2073 sizeof(winsxsW
) + info
->ulAssemblyDirectoryNameLength
+ nameW
.Length
+ 2*sizeof(WCHAR
));
2075 if (!(*fullname
= p
= RtlAllocateHeap( GetProcessHeap(), 0, needed
)))
2077 status
= STATUS_NO_MEMORY
;
2080 strcpyW( p
, user_shared_data
->NtSystemRoot
);
2082 memcpy( p
, winsxsW
, sizeof(winsxsW
) );
2083 p
+= sizeof(winsxsW
) / sizeof(WCHAR
);
2084 memcpy( p
, info
->lpAssemblyDirectoryName
, info
->ulAssemblyDirectoryNameLength
);
2085 p
+= info
->ulAssemblyDirectoryNameLength
/ sizeof(WCHAR
);
2087 strcpyW( p
, libname
);
2089 RtlFreeHeap( GetProcessHeap(), 0, info
);
2090 RtlReleaseActivationContext( data
.hActCtx
);
2095 /***********************************************************************
2098 * Find the file (or already loaded module) for a given dll name.
2100 static NTSTATUS
find_dll_file( const WCHAR
*load_path
, const WCHAR
*libname
,
2101 WCHAR
*filename
, ULONG
*size
, WINE_MODREF
**pwm
, HANDLE
*handle
)
2103 OBJECT_ATTRIBUTES attr
;
2105 UNICODE_STRING nt_name
;
2106 WCHAR
*file_part
, *ext
, *dllname
;
2109 /* first append .dll if needed */
2112 if (!(ext
= strrchrW( libname
, '.')) || strchrW( ext
, '/' ) || strchrW( ext
, '\\'))
2114 if (!(dllname
= RtlAllocateHeap( GetProcessHeap(), 0,
2115 (strlenW(libname
) * sizeof(WCHAR
)) + sizeof(dllW
) )))
2116 return STATUS_NO_MEMORY
;
2117 strcpyW( dllname
, libname
);
2118 strcatW( dllname
, dllW
);
2122 nt_name
.Buffer
= NULL
;
2124 if (!contains_path( libname
))
2127 WCHAR
*fullname
= NULL
;
2129 if ((*pwm
= find_basename_module( libname
)) != NULL
) goto found
;
2131 status
= find_actctx_dll( libname
, &fullname
);
2132 if (status
== STATUS_SUCCESS
)
2134 TRACE ("found %s for %s\n", debugstr_w(fullname
), debugstr_w(libname
) );
2135 RtlFreeHeap( GetProcessHeap(), 0, dllname
);
2136 libname
= dllname
= fullname
;
2138 else if (status
!= STATUS_SXS_KEY_NOT_FOUND
)
2140 RtlFreeHeap( GetProcessHeap(), 0, dllname
);
2145 if (RtlDetermineDosPathNameType_U( libname
) == RELATIVE_PATH
)
2147 /* we need to search for it */
2148 len
= RtlDosSearchPath_U( load_path
, libname
, NULL
, *size
, filename
, &file_part
);
2151 if (len
>= *size
) goto overflow
;
2152 if ((*pwm
= find_fullname_module( filename
)) || !handle
) goto found
;
2154 if (!RtlDosPathNameToNtPathName_U( filename
, &nt_name
, NULL
, NULL
))
2156 RtlFreeHeap( GetProcessHeap(), 0, dllname
);
2157 return STATUS_NO_MEMORY
;
2159 attr
.Length
= sizeof(attr
);
2160 attr
.RootDirectory
= 0;
2161 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2162 attr
.ObjectName
= &nt_name
;
2163 attr
.SecurityDescriptor
= NULL
;
2164 attr
.SecurityQualityOfService
= NULL
;
2165 if (NtOpenFile( handle
, GENERIC_READ
|SYNCHRONIZE
, &attr
, &io
, FILE_SHARE_READ
|FILE_SHARE_DELETE
, FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
)) *handle
= 0;
2171 if (!contains_path( libname
))
2173 /* if libname doesn't contain a path at all, we simply return the name as is,
2174 * to be loaded as builtin */
2175 len
= strlenW(libname
) * sizeof(WCHAR
);
2176 if (len
>= *size
) goto overflow
;
2177 strcpyW( filename
, libname
);
2182 /* absolute path name, or relative path name but not found above */
2184 if (!RtlDosPathNameToNtPathName_U( libname
, &nt_name
, &file_part
, NULL
))
2186 RtlFreeHeap( GetProcessHeap(), 0, dllname
);
2187 return STATUS_NO_MEMORY
;
2189 len
= nt_name
.Length
- 4*sizeof(WCHAR
); /* for \??\ prefix */
2190 if (len
>= *size
) goto overflow
;
2191 memcpy( filename
, nt_name
.Buffer
+ 4, len
+ sizeof(WCHAR
) );
2192 if (!(*pwm
= find_fullname_module( filename
)) && handle
)
2194 attr
.Length
= sizeof(attr
);
2195 attr
.RootDirectory
= 0;
2196 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2197 attr
.ObjectName
= &nt_name
;
2198 attr
.SecurityDescriptor
= NULL
;
2199 attr
.SecurityQualityOfService
= NULL
;
2200 if (NtOpenFile( handle
, GENERIC_READ
|SYNCHRONIZE
, &attr
, &io
, FILE_SHARE_READ
|FILE_SHARE_DELETE
, FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NON_DIRECTORY_FILE
)) *handle
= 0;
2203 RtlFreeUnicodeString( &nt_name
);
2204 RtlFreeHeap( GetProcessHeap(), 0, dllname
);
2205 return STATUS_SUCCESS
;
2208 RtlFreeUnicodeString( &nt_name
);
2209 RtlFreeHeap( GetProcessHeap(), 0, dllname
);
2210 *size
= len
+ sizeof(WCHAR
);
2211 return STATUS_BUFFER_TOO_SMALL
;
2215 /***********************************************************************
2216 * load_dll (internal)
2218 * Load a PE style module according to the load order.
2219 * The loader_section must be locked while calling this function.
2221 static NTSTATUS
load_dll( LPCWSTR load_path
, LPCWSTR libname
, DWORD flags
, WINE_MODREF
** pwm
)
2223 enum loadorder loadorder
;
2227 WINE_MODREF
*main_exe
;
2231 TRACE( "looking for %s in %s\n", debugstr_w(libname
), debugstr_w(load_path
) );
2235 size
= sizeof(buffer
);
2238 nts
= find_dll_file( load_path
, libname
, filename
, &size
, pwm
, &handle
);
2239 if (nts
== STATUS_SUCCESS
) break;
2240 if (filename
!= buffer
) RtlFreeHeap( GetProcessHeap(), 0, filename
);
2241 if (nts
!= STATUS_BUFFER_TOO_SMALL
) return nts
;
2242 /* grow the buffer and retry */
2243 if (!(filename
= RtlAllocateHeap( GetProcessHeap(), 0, size
))) return STATUS_NO_MEMORY
;
2246 if (*pwm
) /* found already loaded module */
2248 if ((*pwm
)->ldr
.LoadCount
!= -1) (*pwm
)->ldr
.LoadCount
++;
2250 TRACE("Found %s for %s at %p, count=%d\n",
2251 debugstr_w((*pwm
)->ldr
.FullDllName
.Buffer
), debugstr_w(libname
),
2252 (*pwm
)->ldr
.BaseAddress
, (*pwm
)->ldr
.LoadCount
);
2253 if (filename
!= buffer
) RtlFreeHeap( GetProcessHeap(), 0, filename
);
2254 return STATUS_SUCCESS
;
2257 main_exe
= get_modref( NtCurrentTeb()->Peb
->ImageBaseAddress
);
2258 loadorder
= get_load_order( main_exe
? main_exe
->ldr
.BaseDllName
.Buffer
: NULL
, filename
);
2260 if (handle
&& is_fake_dll( handle
))
2262 TRACE( "%s is a fake Wine dll\n", debugstr_w(filename
) );
2270 nts
= STATUS_NO_MEMORY
;
2273 nts
= STATUS_DLL_NOT_FOUND
;
2276 case LO_NATIVE_BUILTIN
:
2277 if (!handle
) nts
= STATUS_DLL_NOT_FOUND
;
2280 nts
= load_native_dll( load_path
, filename
, handle
, flags
, pwm
);
2281 if (nts
== STATUS_INVALID_IMAGE_NOT_MZ
)
2282 /* not in PE format, maybe it's a builtin */
2283 nts
= load_builtin_dll( load_path
, filename
, handle
, flags
, pwm
);
2285 if (nts
== STATUS_DLL_NOT_FOUND
&& loadorder
== LO_NATIVE_BUILTIN
)
2286 nts
= load_builtin_dll( load_path
, filename
, 0, flags
, pwm
);
2289 case LO_BUILTIN_NATIVE
:
2290 case LO_DEFAULT
: /* default is builtin,native */
2291 nts
= load_builtin_dll( load_path
, filename
, handle
, flags
, pwm
);
2292 if (!handle
) break; /* nothing else we can try */
2293 /* file is not a builtin library, try without using the specified file */
2294 if (nts
!= STATUS_SUCCESS
)
2295 nts
= load_builtin_dll( load_path
, filename
, 0, flags
, pwm
);
2296 if (nts
== STATUS_SUCCESS
&& loadorder
== LO_DEFAULT
&&
2297 (MODULE_InitDLL( *pwm
, DLL_WINE_PREATTACH
, NULL
) != STATUS_SUCCESS
))
2299 /* stub-only dll, try native */
2300 TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_w(filename
) );
2301 LdrUnloadDll( (*pwm
)->ldr
.BaseAddress
);
2302 nts
= STATUS_DLL_NOT_FOUND
;
2304 if (nts
== STATUS_DLL_NOT_FOUND
&& loadorder
!= LO_BUILTIN
)
2305 nts
= load_native_dll( load_path
, filename
, handle
, flags
, pwm
);
2309 if (nts
== STATUS_SUCCESS
)
2311 /* Initialize DLL just loaded */
2312 TRACE("Loaded module %s (%s) at %p\n", debugstr_w(filename
),
2313 ((*pwm
)->ldr
.Flags
& LDR_WINE_INTERNAL
) ? "builtin" : "native",
2314 (*pwm
)->ldr
.BaseAddress
);
2315 if (handle
) NtClose( handle
);
2316 if (filename
!= buffer
) RtlFreeHeap( GetProcessHeap(), 0, filename
);
2320 WARN("Failed to load module %s; status=%x\n", debugstr_w(libname
), nts
);
2321 if (handle
) NtClose( handle
);
2322 if (filename
!= buffer
) RtlFreeHeap( GetProcessHeap(), 0, filename
);
2326 /******************************************************************
2327 * LdrLoadDll (NTDLL.@)
2329 NTSTATUS WINAPI DECLSPEC_HOTPATCH
LdrLoadDll(LPCWSTR path_name
, DWORD flags
,
2330 const UNICODE_STRING
*libname
, HMODULE
* hModule
)
2335 RtlEnterCriticalSection( &loader_section
);
2337 if (!path_name
) path_name
= NtCurrentTeb()->Peb
->ProcessParameters
->DllPath
.Buffer
;
2338 nts
= load_dll( path_name
, libname
->Buffer
, flags
, &wm
);
2340 if (nts
== STATUS_SUCCESS
&& !(wm
->ldr
.Flags
& LDR_DONT_RESOLVE_REFS
))
2342 nts
= process_attach( wm
, NULL
);
2343 if (nts
!= STATUS_SUCCESS
)
2345 LdrUnloadDll(wm
->ldr
.BaseAddress
);
2349 *hModule
= (wm
) ? wm
->ldr
.BaseAddress
: NULL
;
2351 RtlLeaveCriticalSection( &loader_section
);
2356 /******************************************************************
2357 * LdrGetDllHandle (NTDLL.@)
2359 NTSTATUS WINAPI
LdrGetDllHandle( LPCWSTR load_path
, ULONG flags
, const UNICODE_STRING
*name
, HMODULE
*base
)
2367 RtlEnterCriticalSection( &loader_section
);
2369 if (!load_path
) load_path
= NtCurrentTeb()->Peb
->ProcessParameters
->DllPath
.Buffer
;
2372 size
= sizeof(buffer
);
2375 status
= find_dll_file( load_path
, name
->Buffer
, filename
, &size
, &wm
, NULL
);
2376 if (filename
!= buffer
) RtlFreeHeap( GetProcessHeap(), 0, filename
);
2377 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
2378 /* grow the buffer and retry */
2379 if (!(filename
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
2381 status
= STATUS_NO_MEMORY
;
2386 if (status
== STATUS_SUCCESS
)
2388 if (wm
) *base
= wm
->ldr
.BaseAddress
;
2389 else status
= STATUS_DLL_NOT_FOUND
;
2392 RtlLeaveCriticalSection( &loader_section
);
2393 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name
), status
? NULL
: *base
, debugstr_w(load_path
) );
2398 /******************************************************************
2399 * LdrAddRefDll (NTDLL.@)
2401 NTSTATUS WINAPI
LdrAddRefDll( ULONG flags
, HMODULE module
)
2403 NTSTATUS ret
= STATUS_SUCCESS
;
2406 if (flags
& ~LDR_ADDREF_DLL_PIN
) FIXME( "%p flags %x not implemented\n", module
, flags
);
2408 RtlEnterCriticalSection( &loader_section
);
2410 if ((wm
= get_modref( module
)))
2412 if (flags
& LDR_ADDREF_DLL_PIN
)
2413 wm
->ldr
.LoadCount
= -1;
2415 if (wm
->ldr
.LoadCount
!= -1) wm
->ldr
.LoadCount
++;
2416 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
), wm
->ldr
.LoadCount
);
2418 else ret
= STATUS_INVALID_PARAMETER
;
2420 RtlLeaveCriticalSection( &loader_section
);
2425 /***********************************************************************
2426 * LdrProcessRelocationBlock (NTDLL.@)
2428 * Apply relocations to a given page of a mapped PE image.
2430 IMAGE_BASE_RELOCATION
* WINAPI
LdrProcessRelocationBlock( void *page
, UINT count
,
2431 USHORT
*relocs
, INT_PTR delta
)
2435 USHORT offset
= *relocs
& 0xfff;
2436 int type
= *relocs
>> 12;
2439 case IMAGE_REL_BASED_ABSOLUTE
:
2441 case IMAGE_REL_BASED_HIGH
:
2442 *(short *)((char *)page
+ offset
) += HIWORD(delta
);
2444 case IMAGE_REL_BASED_LOW
:
2445 *(short *)((char *)page
+ offset
) += LOWORD(delta
);
2447 case IMAGE_REL_BASED_HIGHLOW
:
2448 *(int *)((char *)page
+ offset
) += delta
;
2451 case IMAGE_REL_BASED_DIR64
:
2452 *(INT_PTR
*)((char *)page
+ offset
) += delta
;
2454 #elif defined(__arm__)
2455 case IMAGE_REL_BASED_THUMB_MOV32
:
2457 DWORD inst
= *(INT_PTR
*)((char *)page
+ offset
);
2458 DWORD imm16
= ((inst
<< 1) & 0x0800) + ((inst
<< 12) & 0xf000) +
2459 ((inst
>> 20) & 0x0700) + ((inst
>> 16) & 0x00ff);
2462 if ((inst
& 0x8000fbf0) != 0x0000f240)
2463 ERR("wrong Thumb2 instruction %08x, expected MOVW\n", inst
);
2465 imm16
+= LOWORD(delta
);
2466 hi_delta
= HIWORD(delta
) + HIWORD(imm16
);
2467 *(INT_PTR
*)((char *)page
+ offset
) = (inst
& 0x8f00fbf0) + ((imm16
>> 1) & 0x0400) +
2468 ((imm16
>> 12) & 0x000f) +
2469 ((imm16
<< 20) & 0x70000000) +
2470 ((imm16
<< 16) & 0xff0000);
2474 inst
= *(INT_PTR
*)((char *)page
+ offset
+ 4);
2475 imm16
= ((inst
<< 1) & 0x0800) + ((inst
<< 12) & 0xf000) +
2476 ((inst
>> 20) & 0x0700) + ((inst
>> 16) & 0x00ff);
2478 if ((inst
& 0x8000fbf0) != 0x0000f2c0)
2479 ERR("wrong Thumb2 instruction %08x, expected MOVT\n", inst
);
2483 ERR("resulting immediate value won't fit: %08x\n", imm16
);
2484 *(INT_PTR
*)((char *)page
+ offset
+ 4) = (inst
& 0x8f00fbf0) +
2485 ((imm16
>> 1) & 0x0400) +
2486 ((imm16
>> 12) & 0x000f) +
2487 ((imm16
<< 20) & 0x70000000) +
2488 ((imm16
<< 16) & 0xff0000);
2494 FIXME("Unknown/unsupported fixup type %x.\n", type
);
2499 return (IMAGE_BASE_RELOCATION
*)relocs
; /* return address of next block */
2503 /******************************************************************
2504 * LdrQueryProcessModuleInformation
2507 NTSTATUS WINAPI
LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi
,
2508 ULONG buf_size
, ULONG
* req_size
)
2510 SYSTEM_MODULE
* sm
= &smi
->Modules
[0];
2511 ULONG size
= sizeof(ULONG
);
2512 NTSTATUS nts
= STATUS_SUCCESS
;
2515 PLIST_ENTRY mark
, entry
;
2519 smi
->ModulesCount
= 0;
2521 RtlEnterCriticalSection( &loader_section
);
2522 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
2523 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
2525 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
2526 size
+= sizeof(*sm
);
2527 if (size
<= buf_size
)
2529 sm
->Reserved1
= 0; /* FIXME */
2530 sm
->Reserved2
= 0; /* FIXME */
2531 sm
->ImageBaseAddress
= mod
->BaseAddress
;
2532 sm
->ImageSize
= mod
->SizeOfImage
;
2533 sm
->Flags
= mod
->Flags
;
2535 sm
->Rank
= 0; /* FIXME */
2536 sm
->Unknown
= 0; /* FIXME */
2538 str
.MaximumLength
= MAXIMUM_FILENAME_LENGTH
;
2539 str
.Buffer
= (char*)sm
->Name
;
2540 RtlUnicodeStringToAnsiString(&str
, &mod
->FullDllName
, FALSE
);
2541 ptr
= strrchr(str
.Buffer
, '\\');
2542 sm
->NameOffset
= (ptr
!= NULL
) ? (ptr
- str
.Buffer
+ 1) : 0;
2544 smi
->ModulesCount
++;
2547 else nts
= STATUS_INFO_LENGTH_MISMATCH
;
2549 RtlLeaveCriticalSection( &loader_section
);
2551 if (req_size
) *req_size
= size
;
2557 static NTSTATUS
query_dword_option( HANDLE hkey
, LPCWSTR name
, ULONG
*value
)
2563 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
2565 RtlInitUnicodeString( &str
, name
);
2567 size
= sizeof(buffer
) - sizeof(WCHAR
);
2568 if ((status
= NtQueryValueKey( hkey
, &str
, KeyValuePartialInformation
, buffer
, size
, &size
)))
2571 if (info
->Type
!= REG_DWORD
)
2573 buffer
[size
/ sizeof(WCHAR
)] = 0;
2574 *value
= strtoulW( (WCHAR
*)info
->Data
, 0, 16 );
2576 else memcpy( value
, info
->Data
, sizeof(*value
) );
2580 static NTSTATUS
query_string_option( HANDLE hkey
, LPCWSTR name
, ULONG type
,
2581 void *data
, ULONG in_size
, ULONG
*out_size
)
2587 KEY_VALUE_PARTIAL_INFORMATION
*info
;
2588 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
2590 RtlInitUnicodeString( &str
, name
);
2592 size
= info_size
+ in_size
;
2593 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, size
))) return STATUS_NO_MEMORY
;
2594 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
2595 status
= NtQueryValueKey( hkey
, &str
, KeyValuePartialInformation
, buffer
, size
, &size
);
2596 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
2598 if (out_size
) *out_size
= info
->DataLength
;
2599 if (data
&& !status
) memcpy( data
, info
->Data
, info
->DataLength
);
2601 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
2606 /******************************************************************
2607 * LdrQueryImageFileExecutionOptions (NTDLL.@)
2609 NTSTATUS WINAPI
LdrQueryImageFileExecutionOptions( const UNICODE_STRING
*key
, LPCWSTR value
, ULONG type
,
2610 void *data
, ULONG in_size
, ULONG
*out_size
)
2612 static const WCHAR optionsW
[] = {'M','a','c','h','i','n','e','\\',
2613 'S','o','f','t','w','a','r','e','\\',
2614 'M','i','c','r','o','s','o','f','t','\\',
2615 'W','i','n','d','o','w','s',' ','N','T','\\',
2616 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2617 'I','m','a','g','e',' ','F','i','l','e',' ',
2618 'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
2619 WCHAR path
[MAX_PATH
+ sizeof(optionsW
)/sizeof(WCHAR
)];
2620 OBJECT_ATTRIBUTES attr
;
2621 UNICODE_STRING name_str
;
2627 attr
.Length
= sizeof(attr
);
2628 attr
.RootDirectory
= 0;
2629 attr
.ObjectName
= &name_str
;
2630 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2631 attr
.SecurityDescriptor
= NULL
;
2632 attr
.SecurityQualityOfService
= NULL
;
2634 if ((p
= memrchrW( key
->Buffer
, '\\', key
->Length
/ sizeof(WCHAR
) ))) p
++;
2635 else p
= key
->Buffer
;
2636 len
= key
->Length
- (p
- key
->Buffer
) * sizeof(WCHAR
);
2637 name_str
.Buffer
= path
;
2638 name_str
.Length
= sizeof(optionsW
) + len
;
2639 name_str
.MaximumLength
= name_str
.Length
;
2640 memcpy( path
, optionsW
, sizeof(optionsW
) );
2641 memcpy( path
+ sizeof(optionsW
)/sizeof(WCHAR
), p
, len
);
2642 if ((status
= NtOpenKey( &hkey
, KEY_QUERY_VALUE
, &attr
))) return status
;
2644 if (type
== REG_DWORD
)
2646 if (out_size
) *out_size
= sizeof(ULONG
);
2647 if (in_size
>= sizeof(ULONG
)) status
= query_dword_option( hkey
, value
, data
);
2648 else status
= STATUS_BUFFER_OVERFLOW
;
2650 else status
= query_string_option( hkey
, value
, type
, data
, in_size
, out_size
);
2657 /******************************************************************
2658 * RtlDllShutdownInProgress (NTDLL.@)
2660 BOOLEAN WINAPI
RtlDllShutdownInProgress(void)
2662 return process_detaching
;
2665 /****************************************************************************
2666 * LdrResolveDelayLoadedAPI (NTDLL.@)
2668 void* WINAPI
LdrResolveDelayLoadedAPI( void* base
, const IMAGE_DELAYLOAD_DESCRIPTOR
* desc
,
2669 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook
, void* syshook
,
2670 IMAGE_THUNK_DATA
* addr
, ULONG flags
)
2672 IMAGE_THUNK_DATA
*pIAT
, *pINT
;
2673 DELAYLOAD_INFO delayinfo
;
2681 FIXME("(%p, %p, %p, %p, %p, 0x%08x), partial stub\n", base
, desc
, dllhook
, syshook
, addr
, flags
);
2683 phmod
= get_rva(base
, desc
->ModuleHandleRVA
);
2684 pIAT
= get_rva(base
, desc
->ImportAddressTableRVA
);
2685 pINT
= get_rva(base
, desc
->ImportNameTableRVA
);
2686 name
= get_rva(base
, desc
->DllNameRVA
);
2691 if (!RtlCreateUnicodeStringFromAsciiz(&mod
, name
))
2693 nts
= STATUS_NO_MEMORY
;
2696 nts
= LdrLoadDll(NULL
, 0, &mod
, phmod
);
2697 RtlFreeUnicodeString(&mod
);
2701 if (IMAGE_SNAP_BY_ORDINAL(pINT
[id
].u1
.Ordinal
))
2702 nts
= LdrGetProcedureAddress(*phmod
, NULL
, LOWORD(pINT
[id
].u1
.Ordinal
), (void**)&fp
);
2705 const IMAGE_IMPORT_BY_NAME
* iibn
= get_rva(base
, pINT
[id
].u1
.AddressOfData
);
2708 RtlInitAnsiString(&fnc
, (char*)iibn
->Name
);
2709 nts
= LdrGetProcedureAddress(*phmod
, &fnc
, 0, (void**)&fp
);
2713 pIAT
[id
].u1
.Function
= (ULONG_PTR
)fp
;
2718 delayinfo
.Size
= sizeof(delayinfo
);
2719 delayinfo
.DelayloadDescriptor
= desc
;
2720 delayinfo
.ThunkAddress
= addr
;
2721 delayinfo
.TargetDllName
= name
;
2722 delayinfo
.TargetApiDescriptor
.ImportDescribedByName
= !IMAGE_SNAP_BY_ORDINAL(pINT
[id
].u1
.Ordinal
);
2723 delayinfo
.TargetApiDescriptor
.Description
.Ordinal
= LOWORD(pINT
[id
].u1
.Ordinal
);
2724 delayinfo
.TargetModuleBase
= *phmod
;
2725 delayinfo
.Unused
= NULL
;
2726 delayinfo
.LastError
= nts
;
2727 return dllhook(4, &delayinfo
);
2730 /******************************************************************
2731 * LdrShutdownProcess (NTDLL.@)
2734 void WINAPI
LdrShutdownProcess(void)
2737 process_detaching
= TRUE
;
2742 /******************************************************************
2743 * RtlExitUserProcess (NTDLL.@)
2745 void WINAPI
RtlExitUserProcess( DWORD status
)
2747 RtlEnterCriticalSection( &loader_section
);
2748 RtlAcquirePebLock();
2749 NtTerminateProcess( 0, status
);
2750 LdrShutdownProcess();
2751 NtTerminateProcess( GetCurrentProcess(), status
);
2755 /******************************************************************
2756 * LdrShutdownThread (NTDLL.@)
2759 void WINAPI
LdrShutdownThread(void)
2761 PLIST_ENTRY mark
, entry
;
2768 /* don't do any detach calls if process is exiting */
2769 if (process_detaching
) return;
2771 RtlEnterCriticalSection( &loader_section
);
2773 mark
= &NtCurrentTeb()->Peb
->LdrData
->InInitializationOrderModuleList
;
2774 for (entry
= mark
->Blink
; entry
!= mark
; entry
= entry
->Blink
)
2776 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
,
2777 InInitializationOrderModuleList
);
2778 if ( !(mod
->Flags
& LDR_PROCESS_ATTACHED
) )
2780 if ( mod
->Flags
& LDR_NO_DLL_CALLS
)
2783 MODULE_InitDLL( CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
),
2784 DLL_THREAD_DETACH
, NULL
);
2787 RtlAcquirePebLock();
2788 RemoveEntryList( &NtCurrentTeb()->TlsLinks
);
2789 RtlReleasePebLock();
2791 if ((pointers
= NtCurrentTeb()->ThreadLocalStoragePointer
))
2793 for (i
= 0; i
< tls_module_count
; i
++) RtlFreeHeap( GetProcessHeap(), 0, pointers
[i
] );
2794 RtlFreeHeap( GetProcessHeap(), 0, pointers
);
2796 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->FlsSlots
);
2797 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots
);
2798 RtlLeaveCriticalSection( &loader_section
);
2802 /***********************************************************************
2806 static void free_modref( WINE_MODREF
*wm
)
2808 RemoveEntryList(&wm
->ldr
.InLoadOrderModuleList
);
2809 RemoveEntryList(&wm
->ldr
.InMemoryOrderModuleList
);
2810 if (wm
->ldr
.InInitializationOrderModuleList
.Flink
)
2811 RemoveEntryList(&wm
->ldr
.InInitializationOrderModuleList
);
2813 TRACE(" unloading %s\n", debugstr_w(wm
->ldr
.FullDllName
.Buffer
));
2814 if (!TRACE_ON(module
))
2815 TRACE_(loaddll
)("Unloaded module %s : %s\n",
2816 debugstr_w(wm
->ldr
.FullDllName
.Buffer
),
2817 (wm
->ldr
.Flags
& LDR_WINE_INTERNAL
) ? "builtin" : "native" );
2819 SERVER_START_REQ( unload_dll
)
2821 req
->base
= wine_server_client_ptr( wm
->ldr
.BaseAddress
);
2822 wine_server_call( req
);
2826 free_tls_slot( &wm
->ldr
);
2827 RtlReleaseActivationContext( wm
->ldr
.ActivationContext
);
2828 if (wm
->ldr
.Flags
& LDR_WINE_INTERNAL
) wine_dll_unload( wm
->ldr
.SectionHandle
);
2829 NtUnmapViewOfSection( NtCurrentProcess(), wm
->ldr
.BaseAddress
);
2830 if (cached_modref
== wm
) cached_modref
= NULL
;
2831 RtlFreeUnicodeString( &wm
->ldr
.FullDllName
);
2832 RtlFreeHeap( GetProcessHeap(), 0, wm
->deps
);
2833 RtlFreeHeap( GetProcessHeap(), 0, wm
);
2836 /***********************************************************************
2837 * MODULE_FlushModrefs
2839 * Remove all unused modrefs and call the internal unloading routines
2840 * for the library type.
2842 * The loader_section must be locked while calling this function.
2844 static void MODULE_FlushModrefs(void)
2846 PLIST_ENTRY mark
, entry
, prev
;
2850 mark
= &NtCurrentTeb()->Peb
->LdrData
->InInitializationOrderModuleList
;
2851 for (entry
= mark
->Blink
; entry
!= mark
; entry
= prev
)
2853 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InInitializationOrderModuleList
);
2854 wm
= CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
);
2855 prev
= entry
->Blink
;
2856 if (!mod
->LoadCount
) free_modref( wm
);
2859 /* check load order list too for modules that haven't been initialized yet */
2860 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
2861 for (entry
= mark
->Blink
; entry
!= mark
; entry
= prev
)
2863 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
2864 wm
= CONTAINING_RECORD(mod
, WINE_MODREF
, ldr
);
2865 prev
= entry
->Blink
;
2866 if (!mod
->LoadCount
) free_modref( wm
);
2870 /***********************************************************************
2871 * MODULE_DecRefCount
2873 * The loader_section must be locked while calling this function.
2875 static void MODULE_DecRefCount( WINE_MODREF
*wm
)
2879 if ( wm
->ldr
.Flags
& LDR_UNLOAD_IN_PROGRESS
)
2882 if ( wm
->ldr
.LoadCount
<= 0 )
2885 --wm
->ldr
.LoadCount
;
2886 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
), wm
->ldr
.LoadCount
);
2888 if ( wm
->ldr
.LoadCount
== 0 )
2890 wm
->ldr
.Flags
|= LDR_UNLOAD_IN_PROGRESS
;
2892 for ( i
= 0; i
< wm
->nDeps
; i
++ )
2894 MODULE_DecRefCount( wm
->deps
[i
] );
2896 wm
->ldr
.Flags
&= ~LDR_UNLOAD_IN_PROGRESS
;
2900 /******************************************************************
2901 * LdrUnloadDll (NTDLL.@)
2905 NTSTATUS WINAPI
LdrUnloadDll( HMODULE hModule
)
2908 NTSTATUS retv
= STATUS_SUCCESS
;
2910 if (process_detaching
) return retv
;
2912 TRACE("(%p)\n", hModule
);
2914 RtlEnterCriticalSection( &loader_section
);
2917 if ((wm
= get_modref( hModule
)) != NULL
)
2919 TRACE("(%s) - START\n", debugstr_w(wm
->ldr
.BaseDllName
.Buffer
));
2921 /* Recursively decrement reference counts */
2922 MODULE_DecRefCount( wm
);
2924 /* Call process detach notifications */
2925 if ( free_lib_count
<= 1 )
2928 MODULE_FlushModrefs();
2934 retv
= STATUS_DLL_NOT_FOUND
;
2938 RtlLeaveCriticalSection( &loader_section
);
2943 /***********************************************************************
2944 * RtlImageNtHeader (NTDLL.@)
2946 PIMAGE_NT_HEADERS WINAPI
RtlImageNtHeader(HMODULE hModule
)
2948 IMAGE_NT_HEADERS
*ret
;
2952 IMAGE_DOS_HEADER
*dos
= (IMAGE_DOS_HEADER
*)hModule
;
2955 if (dos
->e_magic
== IMAGE_DOS_SIGNATURE
)
2957 ret
= (IMAGE_NT_HEADERS
*)((char *)dos
+ dos
->e_lfanew
);
2958 if (ret
->Signature
!= IMAGE_NT_SIGNATURE
) ret
= NULL
;
2970 /***********************************************************************
2971 * attach_process_dlls
2973 * Initial attach to all the dlls loaded by the process.
2975 static NTSTATUS
attach_process_dlls( void *wm
)
2979 pthread_sigmask( SIG_UNBLOCK
, &server_block_set
, NULL
);
2981 RtlEnterCriticalSection( &loader_section
);
2982 if ((status
= process_attach( wm
, (LPVOID
)1 )) != STATUS_SUCCESS
)
2984 if (last_failed_modref
)
2985 ERR( "%s failed to initialize, aborting\n",
2986 debugstr_w(last_failed_modref
->ldr
.BaseDllName
.Buffer
) + 1 );
2989 attach_implicitly_loaded_dlls( (LPVOID
)1 );
2990 RtlLeaveCriticalSection( &loader_section
);
2995 /***********************************************************************
2996 * load_global_options
2998 static void load_global_options(void)
3000 static const WCHAR sessionW
[] = {'M','a','c','h','i','n','e','\\',
3001 'S','y','s','t','e','m','\\',
3002 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
3003 'C','o','n','t','r','o','l','\\',
3004 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
3005 static const WCHAR globalflagW
[] = {'G','l','o','b','a','l','F','l','a','g',0};
3006 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};
3007 static const WCHAR heapresW
[] = {'H','e','a','p','S','e','g','m','e','n','t','R','e','s','e','r','v','e',0};
3008 static const WCHAR heapcommitW
[] = {'H','e','a','p','S','e','g','m','e','n','t','C','o','m','m','i','t',0};
3009 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};
3010 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};
3012 OBJECT_ATTRIBUTES attr
;
3013 UNICODE_STRING name_str
;
3017 attr
.Length
= sizeof(attr
);
3018 attr
.RootDirectory
= 0;
3019 attr
.ObjectName
= &name_str
;
3020 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
3021 attr
.SecurityDescriptor
= NULL
;
3022 attr
.SecurityQualityOfService
= NULL
;
3023 RtlInitUnicodeString( &name_str
, sessionW
);
3025 if (NtOpenKey( &hkey
, KEY_QUERY_VALUE
, &attr
)) return;
3027 query_dword_option( hkey
, globalflagW
, &NtCurrentTeb()->Peb
->NtGlobalFlag
);
3029 query_dword_option( hkey
, critsectW
, &value
);
3030 NtCurrentTeb()->Peb
->CriticalSectionTimeout
.QuadPart
= (ULONGLONG
)value
* -10000000;
3032 query_dword_option( hkey
, heapresW
, &value
);
3033 NtCurrentTeb()->Peb
->HeapSegmentReserve
= value
;
3035 query_dword_option( hkey
, heapcommitW
, &value
);
3036 NtCurrentTeb()->Peb
->HeapSegmentCommit
= value
;
3038 query_dword_option( hkey
, decommittotalW
, &value
);
3039 NtCurrentTeb()->Peb
->HeapDeCommitTotalFreeThreshold
= value
;
3041 query_dword_option( hkey
, decommitfreeW
, &value
);
3042 NtCurrentTeb()->Peb
->HeapDeCommitFreeBlockThreshold
= value
;
3048 /***********************************************************************
3051 static void start_process( void *arg
)
3053 struct start_params
*start_params
= (struct start_params
*)arg
;
3054 call_thread_entry_point( start_params
->kernel_start
, start_params
->entry
);
3057 /******************************************************************
3058 * LdrInitializeThunk (NTDLL.@)
3061 void WINAPI
LdrInitializeThunk( void *kernel_start
, ULONG_PTR unknown2
,
3062 ULONG_PTR unknown3
, ULONG_PTR unknown4
)
3064 static const WCHAR globalflagW
[] = {'G','l','o','b','a','l','F','l','a','g',0};
3068 PEB
*peb
= NtCurrentTeb()->Peb
;
3069 struct start_params start_params
;
3071 if (main_exe_file
) NtClose( main_exe_file
); /* at this point the main module is created */
3073 /* allocate the modref for the main exe (if not already done) */
3074 wm
= get_modref( peb
->ImageBaseAddress
);
3076 if (wm
->ldr
.Flags
& LDR_IMAGE_IS_DLL
)
3078 ERR("%s is a dll, not an executable\n", debugstr_w(wm
->ldr
.FullDllName
.Buffer
) );
3082 peb
->LoaderLock
= &loader_section
;
3083 peb
->ProcessParameters
->ImagePathName
= wm
->ldr
.FullDllName
;
3084 if (!peb
->ProcessParameters
->WindowTitle
.Buffer
)
3085 peb
->ProcessParameters
->WindowTitle
= wm
->ldr
.FullDllName
;
3086 version_init( wm
->ldr
.FullDllName
.Buffer
);
3087 virtual_set_large_address_space();
3089 LdrQueryImageFileExecutionOptions( &peb
->ProcessParameters
->ImagePathName
, globalflagW
,
3090 REG_DWORD
, &peb
->NtGlobalFlag
, sizeof(peb
->NtGlobalFlag
), NULL
);
3092 /* the main exe needs to be the first in the load order list */
3093 RemoveEntryList( &wm
->ldr
.InLoadOrderModuleList
);
3094 InsertHeadList( &peb
->LdrData
->InLoadOrderModuleList
, &wm
->ldr
.InLoadOrderModuleList
);
3095 RemoveEntryList( &wm
->ldr
.InMemoryOrderModuleList
);
3096 InsertHeadList( &peb
->LdrData
->InMemoryOrderModuleList
, &wm
->ldr
.InMemoryOrderModuleList
);
3098 if ((status
= virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS
) goto error
;
3099 if ((status
= server_init_process_done()) != STATUS_SUCCESS
) goto error
;
3102 load_path
= NtCurrentTeb()->Peb
->ProcessParameters
->DllPath
.Buffer
;
3103 if ((status
= fixup_imports( wm
, load_path
)) != STATUS_SUCCESS
) goto error
;
3104 heap_set_debug_flags( GetProcessHeap() );
3106 /* Store original entrypoint (in case it gets corrupted) */
3107 start_params
.kernel_start
= kernel_start
;
3108 start_params
.entry
= wm
->ldr
.EntryPoint
;
3110 status
= wine_call_on_stack( attach_process_dlls
, wm
, NtCurrentTeb()->Tib
.StackBase
);
3111 if (status
!= STATUS_SUCCESS
) goto error
;
3113 virtual_release_address_space();
3114 virtual_clear_thread_stack();
3115 wine_switch_to_stack( start_process
, &start_params
, NtCurrentTeb()->Tib
.StackBase
);
3118 ERR( "Main exe initialization for %s failed, status %x\n",
3119 debugstr_w(peb
->ProcessParameters
->ImagePathName
.Buffer
), status
);
3120 NtTerminateProcess( GetCurrentProcess(), status
);
3124 /***********************************************************************
3125 * RtlImageDirectoryEntryToData (NTDLL.@)
3127 PVOID WINAPI
RtlImageDirectoryEntryToData( HMODULE module
, BOOL image
, WORD dir
, ULONG
*size
)
3129 const IMAGE_NT_HEADERS
*nt
;
3132 if ((ULONG_PTR
)module
& 1) /* mapped as data file */
3134 module
= (HMODULE
)((ULONG_PTR
)module
& ~1);
3137 if (!(nt
= RtlImageNtHeader( module
))) return NULL
;
3138 if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
3140 const IMAGE_NT_HEADERS64
*nt64
= (const IMAGE_NT_HEADERS64
*)nt
;
3142 if (dir
>= nt64
->OptionalHeader
.NumberOfRvaAndSizes
) return NULL
;
3143 if (!(addr
= nt64
->OptionalHeader
.DataDirectory
[dir
].VirtualAddress
)) return NULL
;
3144 *size
= nt64
->OptionalHeader
.DataDirectory
[dir
].Size
;
3145 if (image
|| addr
< nt64
->OptionalHeader
.SizeOfHeaders
) return (char *)module
+ addr
;
3147 else if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
)
3149 const IMAGE_NT_HEADERS32
*nt32
= (const IMAGE_NT_HEADERS32
*)nt
;
3151 if (dir
>= nt32
->OptionalHeader
.NumberOfRvaAndSizes
) return NULL
;
3152 if (!(addr
= nt32
->OptionalHeader
.DataDirectory
[dir
].VirtualAddress
)) return NULL
;
3153 *size
= nt32
->OptionalHeader
.DataDirectory
[dir
].Size
;
3154 if (image
|| addr
< nt32
->OptionalHeader
.SizeOfHeaders
) return (char *)module
+ addr
;
3158 /* not mapped as image, need to find the section containing the virtual address */
3159 return RtlImageRvaToVa( nt
, module
, addr
, NULL
);
3163 /***********************************************************************
3164 * RtlImageRvaToSection (NTDLL.@)
3166 PIMAGE_SECTION_HEADER WINAPI
RtlImageRvaToSection( const IMAGE_NT_HEADERS
*nt
,
3167 HMODULE module
, DWORD rva
)
3170 const IMAGE_SECTION_HEADER
*sec
;
3172 sec
= (const IMAGE_SECTION_HEADER
*)((const char*)&nt
->OptionalHeader
+
3173 nt
->FileHeader
.SizeOfOptionalHeader
);
3174 for (i
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++, sec
++)
3176 if ((sec
->VirtualAddress
<= rva
) && (sec
->VirtualAddress
+ sec
->SizeOfRawData
> rva
))
3177 return (PIMAGE_SECTION_HEADER
)sec
;
3183 /***********************************************************************
3184 * RtlImageRvaToVa (NTDLL.@)
3186 PVOID WINAPI
RtlImageRvaToVa( const IMAGE_NT_HEADERS
*nt
, HMODULE module
,
3187 DWORD rva
, IMAGE_SECTION_HEADER
**section
)
3189 IMAGE_SECTION_HEADER
*sec
;
3191 if (section
&& *section
) /* try this section first */
3194 if ((sec
->VirtualAddress
<= rva
) && (sec
->VirtualAddress
+ sec
->SizeOfRawData
> rva
))
3197 if (!(sec
= RtlImageRvaToSection( nt
, module
, rva
))) return NULL
;
3199 if (section
) *section
= sec
;
3200 return (char *)module
+ sec
->PointerToRawData
+ (rva
- sec
->VirtualAddress
);
3204 /***********************************************************************
3205 * RtlPcToFileHeader (NTDLL.@)
3207 PVOID WINAPI
RtlPcToFileHeader( PVOID pc
, PVOID
*address
)
3212 RtlEnterCriticalSection( &loader_section
);
3213 if (!LdrFindEntryForAddress( pc
, &module
)) ret
= module
->BaseAddress
;
3214 RtlLeaveCriticalSection( &loader_section
);
3220 /***********************************************************************
3221 * NtLoadDriver (NTDLL.@)
3222 * ZwLoadDriver (NTDLL.@)
3224 NTSTATUS WINAPI
NtLoadDriver( const UNICODE_STRING
*DriverServiceName
)
3226 FIXME("(%p), stub!\n",DriverServiceName
);
3227 return STATUS_NOT_IMPLEMENTED
;
3231 /***********************************************************************
3232 * NtUnloadDriver (NTDLL.@)
3233 * ZwUnloadDriver (NTDLL.@)
3235 NTSTATUS WINAPI
NtUnloadDriver( const UNICODE_STRING
*DriverServiceName
)
3237 FIXME("(%p), stub!\n",DriverServiceName
);
3238 return STATUS_NOT_IMPLEMENTED
;
3242 /******************************************************************
3245 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, LPVOID reserved
)
3247 if (reason
== DLL_PROCESS_ATTACH
) LdrDisableThreadCalloutsForDll( inst
);
3252 /******************************************************************
3253 * __wine_init_windows_dir (NTDLL.@)
3255 * Windows and system dir initialization once kernel32 has been loaded.
3257 void CDECL
__wine_init_windows_dir( const WCHAR
*windir
, const WCHAR
*sysdir
)
3259 PLIST_ENTRY mark
, entry
;
3262 strcpyW( user_shared_data
->NtSystemRoot
, windir
);
3263 DIR_init_windows_dir( windir
, sysdir
);
3265 /* prepend the system dir to the name of the already created modules */
3266 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
3267 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
3269 LDR_MODULE
*mod
= CONTAINING_RECORD( entry
, LDR_MODULE
, InLoadOrderModuleList
);
3271 assert( mod
->Flags
& LDR_WINE_INTERNAL
);
3273 buffer
= RtlAllocateHeap( GetProcessHeap(), 0,
3274 system_dir
.Length
+ mod
->FullDllName
.Length
+ 2*sizeof(WCHAR
) );
3275 if (!buffer
) continue;
3276 strcpyW( buffer
, system_dir
.Buffer
);
3277 p
= buffer
+ strlenW( buffer
);
3278 if (p
> buffer
&& p
[-1] != '\\') *p
++ = '\\';
3279 strcpyW( p
, mod
->FullDllName
.Buffer
);
3280 RtlInitUnicodeString( &mod
->FullDllName
, buffer
);
3281 RtlInitUnicodeString( &mod
->BaseDllName
, p
);
3286 /***********************************************************************
3287 * __wine_process_init
3289 void __wine_process_init(void)
3291 static const WCHAR kernel32W
[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
3295 ANSI_STRING func_name
;
3296 void (* DECLSPEC_NORETURN CDECL init_func
)(void);
3298 main_exe_file
= thread_init();
3300 /* retrieve current umask */
3301 FILE_umask
= umask(0777);
3302 umask( FILE_umask
);
3304 load_global_options();
3306 /* setup the load callback and create ntdll modref */
3307 wine_dll_set_callback( load_builtin_callback
);
3309 if ((status
= load_builtin_dll( NULL
, kernel32W
, 0, 0, &wm
)) != STATUS_SUCCESS
)
3311 MESSAGE( "wine: could not load kernel32.dll, status %x\n", status
);
3314 RtlInitAnsiString( &func_name
, "UnhandledExceptionFilter" );
3315 LdrGetProcedureAddress( wm
->ldr
.BaseAddress
, &func_name
, 0, (void **)&unhandled_exception_filter
);
3317 RtlInitAnsiString( &func_name
, "__wine_kernel_init" );
3318 if ((status
= LdrGetProcedureAddress( wm
->ldr
.BaseAddress
, &func_name
,
3319 0, (void **)&init_func
)) != STATUS_SUCCESS
)
3321 MESSAGE( "wine: could not find __wine_kernel_init in kernel32.dll, status %x\n", status
);