loader.c 166 KB
Newer Older
1
/*
2 3
 * Loader functions
 *
4
 * Copyright 1995, 2003 Alexandre Julliard
5
 * Copyright 2002 Dmitry Timoshkov for CodeWeavers
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22
#include <assert.h>
23
#include <stdarg.h>
24
#include <stdlib.h>
25

26 27
#include "ntstatus.h"
#define WIN32_NO_STATUS
28
#include "windef.h"
29
#include "winnt.h"
30
#include "winioctl.h"
31
#include "winternl.h"
32
#include "delayloadhandler.h"
33

34
#include "wine/exception.h"
35
#include "wine/debug.h"
36
#include "wine/list.h"
37
#include "ntdll_misc.h"
38
#include "ddk/ntddk.h"
39
#include "ddk/wdm.h"
40

41 42
WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay);
43
WINE_DECLARE_DEBUG_CHANNEL(snoop);
44
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
45
WINE_DECLARE_DEBUG_CHANNEL(imports);
46

47 48 49 50 51 52
#ifdef _WIN64
#define DEFAULT_SECURITY_COOKIE_64  (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
#endif
#define DEFAULT_SECURITY_COOKIE_32  0xbb40e64e
#define DEFAULT_SECURITY_COOKIE_16  (DEFAULT_SECURITY_COOKIE_32 >> 16)

53 54 55 56 57 58 59 60 61 62 63 64
#ifdef __i386__
static const WCHAR pe_dir[] = L"\\i386-windows";
#elif defined __x86_64__
static const WCHAR pe_dir[] = L"\\x86_64-windows";
#elif defined __arm__
static const WCHAR pe_dir[] = L"\\arm-windows";
#elif defined __aarch64__
static const WCHAR pe_dir[] = L"\\aarch64-windows";
#else
static const WCHAR pe_dir[] = L"";
#endif

65 66 67 68
/* we don't want to include winuser.h */
#define RT_MANIFEST                         ((ULONG_PTR)24)
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)

69
typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
70
typedef void  (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *);
71

72
void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
73
NTSTATUS (WINAPI *__wine_unix_call_dispatcher)( unixlib_handle_t, unsigned int, void * ) = __wine_unix_call;
74

75 76
static DWORD (WINAPI *pCtrlRoutine)(void *);

77 78
SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock = { 0xf0 };

79
void *__wine_syscall_dispatcher = NULL;
80
unixlib_handle_t __wine_unixlib_handle = 0;
81

82
/* windows directory */
83
const WCHAR windows_dir[] = L"C:\\windows";
84
/* system directory with trailing backslash */
85
const WCHAR system_dir[] = L"C:\\windows\\system32\\";
86

87
/* system search path */
88
static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows";
89

90
static BOOL is_prefix_bootstrap;  /* are we bootstrapping the prefix? */
91
static BOOL imports_fixup_done = FALSE;  /* set once the imports have been fixed up, before attaching them */
92
static BOOL process_detaching = FALSE;  /* set on process detach to avoid deadlocks with thread detach */
93
static int free_lib_count;   /* recursion depth of LdrUnloadDll calls */
94 95
static LONG path_safe_mode;  /* path mode set by RtlSetSearchPathMode */
static LONG dll_safe_mode = 1;  /* dll search mode */
96
static UNICODE_STRING dll_directory;  /* extra path for LdrSetDllDirectory */
97
static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */
98
static DWORD default_search_flags;  /* default flags set by LdrSetDefaultDllDirectories */
99
static WCHAR *default_load_path;    /* default dll search path */
100 101 102 103 104 105 106 107

struct dll_dir_entry
{
    struct list entry;
    WCHAR       dir[1];
};

static struct list dll_dir_list = LIST_INIT( dll_dir_list );  /* extra dirs from LdrAddDllDirectory */
108

109 110 111 112 113 114 115 116 117
struct ldr_notification
{
    struct list                    entry;
    PLDR_DLL_NOTIFICATION_FUNCTION callback;
    void                           *context;
};

static struct list ldr_notifications = LIST_INIT( ldr_notifications );

118 119 120 121 122
static const char * const reason_names[] =
{
    "PROCESS_DETACH",
    "PROCESS_ATTACH",
    "THREAD_ATTACH",
123
    "THREAD_DETACH",
124 125
};

126 127 128 129 130 131
struct file_id
{
    BYTE ObjectId[16];
};

/* internal representation of loaded modules */
132
typedef struct _wine_modref
133
{
134
    LDR_DATA_TABLE_ENTRY  ldr;
135
    struct file_id        id;
136
    ULONG                 CheckSum;
137
    BOOL                  system;
138
} WINE_MODREF;
139

140
static UINT tls_module_count;      /* number of modules with TLS directory */
141
static IMAGE_TLS_DIRECTORY *tls_dirs;  /* array of TLS directories */
142
static LIST_ENTRY tls_links = { &tls_links, &tls_links };
143

144 145
static RTL_CRITICAL_SECTION loader_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
146 147 148
{
    0, 0, &loader_section,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
149
      0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
150
};
151
static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
152

153 154 155 156 157 158 159 160 161
static CRITICAL_SECTION dlldir_section;
static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
{
    0, 0, &dlldir_section,
    { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
};
static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };

162 163 164 165 166 167 168 169 170
static RTL_CRITICAL_SECTION peb_lock;
static RTL_CRITICAL_SECTION_DEBUG peb_critsect_debug =
{
    0, 0, &peb_lock,
    { &peb_critsect_debug.ProcessLocksList, &peb_critsect_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
};
static RTL_CRITICAL_SECTION peb_lock = { &peb_critsect_debug, -1, 0, 0, 0, 0 };

171 172 173 174 175 176 177 178
static PEB_LDR_DATA ldr =
{
    sizeof(ldr), TRUE, NULL,
    { &ldr.InLoadOrderModuleList, &ldr.InLoadOrderModuleList },
    { &ldr.InMemoryOrderModuleList, &ldr.InMemoryOrderModuleList },
    { &ldr.InInitializationOrderModuleList, &ldr.InInitializationOrderModuleList }
};

179 180 181
static RTL_BITMAP tls_bitmap;
static RTL_BITMAP tls_expansion_bitmap;

182
static WINE_MODREF *cached_modref;
183
static WINE_MODREF *current_modref;
184
static WINE_MODREF *last_failed_modref;
185

186 187
static LDR_DDAG_NODE *node_ntdll, *node_kernel32;

188
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system );
189
static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved );
190 191
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
Eric Pouech's avatar
Eric Pouech committed
192
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
193
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
194 195

/* convert PE image VirtualAddress to Real Address */
196
static inline void *get_rva( HMODULE module, DWORD va )
197 198 199
{
    return (void *)((char *)module + va);
}
200

201
/* check whether the file name contains a path */
202
static inline BOOL contains_path( LPCWSTR name )
203
{
204
    return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
205 206
}

207 208 209 210 211 212 213 214 215 216 217 218 219
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64

typedef struct _RTL_UNLOAD_EVENT_TRACE
{
    void *BaseAddress;
    SIZE_T SizeOfImage;
    ULONG Sequence;
    ULONG TimeDateStamp;
    ULONG CheckSum;
    WCHAR ImageName[32];
} RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;

static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
220
static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
221 222
static unsigned int unload_trace_seq;

223
static void module_push_unload_trace( const WINE_MODREF *wm )
224 225
{
    RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
226
    const LDR_DATA_TABLE_ENTRY *ldr = &wm->ldr;
227
    unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
228

229
    ptr->BaseAddress = ldr->DllBase;
230 231 232
    ptr->SizeOfImage = ldr->SizeOfImage;
    ptr->Sequence = unload_trace_seq;
    ptr->TimeDateStamp = ldr->TimeDateStamp;
233
    ptr->CheckSum = wm->CheckSum;
234 235 236 237
    memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
    ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;

    unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
238
    unload_trace_ptr = unload_traces;
239 240
}

241 242
#ifdef __arm64ec__

243 244 245 246 247 248 249 250 251 252 253
static void update_hybrid_pointer( void *module, const IMAGE_SECTION_HEADER *sec, UINT rva, void *ptr )
{
    if (!rva) return;

    if (rva < sec->VirtualAddress || rva >= sec->VirtualAddress + sec->Misc.VirtualSize)
        ERR( "rva %x outside of section %s (%lx-%lx)\n", rva,
             sec->Name, sec->VirtualAddress, sec->VirtualAddress + sec->Misc.VirtualSize );
    else
        *(void **)get_rva( module, rva ) = ptr;
}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
static void update_hybrid_metadata( void *module, IMAGE_NT_HEADERS *nt,
                                    const IMAGE_ARM64EC_METADATA *metadata )
{
    DWORD i, protect_old;
    const IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );

    /* assume that all pointers are in the same section */

    for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
    {
        if ((sec->VirtualAddress <= metadata->__os_arm64x_dispatch_call) &&
            (sec->VirtualAddress + sec->Misc.VirtualSize > metadata->__os_arm64x_dispatch_call))
        {
            void *base = get_rva( module, sec->VirtualAddress );
            SIZE_T size = sec->Misc.VirtualSize;

            NtProtectVirtualMemory( NtCurrentProcess(), &base, &size, PAGE_READWRITE, &protect_old );

272
#define SET_FUNC(func,val) update_hybrid_pointer( module, sec, metadata->func, val )
273 274 275 276 277 278
            SET_FUNC( __os_arm64x_dispatch_call, __os_arm64x_check_call );
            SET_FUNC( __os_arm64x_dispatch_call_no_redirect, __os_arm64x_dispatch_call_no_redirect );
            SET_FUNC( __os_arm64x_dispatch_fptr, __os_arm64x_dispatch_fptr );
            SET_FUNC( __os_arm64x_dispatch_icall, __os_arm64x_check_icall );
            SET_FUNC( __os_arm64x_dispatch_icall_cfg, __os_arm64x_check_icall_cfg );
            SET_FUNC( __os_arm64x_dispatch_ret, __os_arm64x_dispatch_ret );
279 280 281 282 283 284 285 286 287
            SET_FUNC( __os_arm64x_helper0, __os_arm64x_helper0 );
            SET_FUNC( __os_arm64x_helper1, __os_arm64x_helper1 );
            SET_FUNC( __os_arm64x_helper2, __os_arm64x_helper2 );
            SET_FUNC( __os_arm64x_helper3, __os_arm64x_helper3 );
            SET_FUNC( __os_arm64x_helper4, __os_arm64x_helper4 );
            SET_FUNC( __os_arm64x_helper5, __os_arm64x_helper5 );
            SET_FUNC( __os_arm64x_helper6, __os_arm64x_helper6 );
            SET_FUNC( __os_arm64x_helper7, __os_arm64x_helper7 );
            SET_FUNC( __os_arm64x_helper8, __os_arm64x_helper8 );
288 289 290 291 292 293 294 295 296 297 298 299 300
            SET_FUNC( GetX64InformationFunctionPointer, __os_arm64x_get_x64_information );
            SET_FUNC( SetX64InformationFunctionPointer, __os_arm64x_set_x64_information );
#undef SET_FUNC

            NtProtectVirtualMemory( NtCurrentProcess(), &base, &size, protect_old, &protect_old );
            return;
        }
    }
    ERR( "module %p no section found for %lx\n", module, metadata->__os_arm64x_dispatch_call );
}

#endif

301 302 303 304 305 306 307 308 309 310 311 312 313
/*********************************************************************
 *           RtlGetUnloadEventTrace [NTDLL.@]
 */
RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
{
    return unload_traces;
}

/*********************************************************************
 *           RtlGetUnloadEventTraceEx [NTDLL.@]
 */
void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
{
314 315
    static ULONG element_size = sizeof(*unload_traces);
    static ULONG element_count = ARRAY_SIZE(unload_traces);
316 317 318

    *size = &element_size;
    *count = &element_count;
319
    *trace = &unload_trace_ptr;
320
}
321 322 323 324 325

/*************************************************************************
 *		call_dll_entry_point
 *
 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
326 327 328
 * their entry point, so we need a small asm wrapper. Testing indicates
 * that only modifying esi leads to a crash, so use this one to backup
 * ebp while running the dll entry proc.
329
 */
330
#if defined(__i386__)
331 332 333
extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
__ASM_GLOBAL_FUNC(call_dll_entry_point,
                  "pushl %ebp\n\t"
334 335
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
                  __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
336
                  "movl %esp,%ebp\n\t"
337
                  __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
338
                  "pushl %ebx\n\t"
339
                  __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
340 341 342 343 344 345
                  "pushl %esi\n\t"
                  __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
                  "pushl %edi\n\t"
                  __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
                  "movl %ebp,%esi\n\t"
                  __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
346 347 348 349 350
                  "pushl 20(%ebp)\n\t"
                  "pushl 16(%ebp)\n\t"
                  "pushl 12(%ebp)\n\t"
                  "movl 8(%ebp),%eax\n\t"
                  "call *%eax\n\t"
351 352 353 354 355 356 357
                  "movl %esi,%ebp\n\t"
                  __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
                  "leal -12(%ebp),%esp\n\t"
                  "popl %edi\n\t"
                  __ASM_CFI(".cfi_same_value %edi\n\t")
                  "popl %esi\n\t"
                  __ASM_CFI(".cfi_same_value %esi\n\t")
358
                  "popl %ebx\n\t"
359
                  __ASM_CFI(".cfi_same_value %ebx\n\t")
360
                  "popl %ebp\n\t"
361 362
                  __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
                  __ASM_CFI(".cfi_same_value %ebp\n\t")
363
                  "ret" )
364
#elif defined(__x86_64__) && !defined(__arm64ec__)
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
extern BOOL CDECL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
/* Some apps modify rbx in TLS entry point. */
__ASM_GLOBAL_FUNC(call_dll_entry_point,
                  "pushq %rbx\n\t"
                  __ASM_SEH(".seh_pushreg %rbx\n\t")
                  __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
                  __ASM_CFI(".cfi_rel_offset %rbx,0\n\t")
                  "subq $48,%rsp\n\t"
                  __ASM_SEH(".seh_stackalloc 48\n\t")
                  __ASM_SEH(".seh_endprologue\n\t")
                  __ASM_CFI(".cfi_adjust_cfa_offset 48\n\t")
                  "mov %rcx,%r10\n\t"
                  "mov %rdx,%rcx\n\t"
                  "mov %r8d,%edx\n\t"
                  "mov %r9,%r8\n\t"
                  "call *%r10\n\t"
                  "addq $48,%rsp\n\t"
                  __ASM_CFI(".cfi_adjust_cfa_offset -48\n\t")
                  "popq %rbx\n\t"
                   __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
                   __ASM_CFI(".cfi_same_value %rbx\n\t")
                  "ret" )
#else
388 389 390 391 392
static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
                                         UINT reason, void *reserved )
{
    return proc( module, reason, reserved );
}
393
#endif
394 395


396
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
397 398 399 400 401
/*************************************************************************
 *		stub_entry_point
 *
 * Entry point for stub functions.
 */
402
static void WINAPI stub_entry_point( const char *dll, const char *name, void *ret_addr )
403 404 405 406
{
    EXCEPTION_RECORD rec;

    rec.ExceptionCode           = EXCEPTION_WINE_STUB;
407
    rec.ExceptionFlags          = EXCEPTION_NONCONTINUABLE;
408
    rec.ExceptionRecord         = NULL;
409
    rec.ExceptionAddress        = ret_addr;
410
    rec.NumberParameters        = 2;
411 412
    rec.ExceptionInformation[0] = (ULONG_PTR)dll;
    rec.ExceptionInformation[1] = (ULONG_PTR)name;
413 414 415 416
    for (;;) RtlRaiseException( &rec );
}


417
#include "pshpack1.h"
418
#ifdef __i386__
419 420 421 422 423 424
struct stub
{
    BYTE        pushl1;     /* pushl $name */
    const char *name;
    BYTE        pushl2;     /* pushl $dll */
    const char *dll;
425
    BYTE        call;       /* call stub_entry_point */
426 427
    DWORD       entry;
};
428 429 430
#elif defined(__arm__)
struct stub
{
431 432 433 434
    DWORD ldr_r0;        /* ldr r0, $dll */
    DWORD ldr_r1;        /* ldr r1, $name */
    DWORD mov_r2_lr;     /* mov r2, lr */
    DWORD ldr_pc_pc;     /* ldr pc, [pc, #4] */
435 436
    const char *dll;
    const char *name;
437 438
    const void* entry;
};
439
#elif defined(__aarch64__) || defined(__arm64ec__)
440 441
struct stub
{
442 443 444 445 446
    DWORD ldr_x0;        /* ldr x0, $dll */
    DWORD ldr_x1;        /* ldr x1, $name */
    DWORD mov_x2_lr;     /* mov x2, lr */
    DWORD ldr_x16;       /* ldr x16, $entry */
    DWORD br_x16;        /* br x16 */
447 448 449 450
    const char *dll;
    const char *name;
    const void *entry;
};
451 452 453 454 455 456 457 458 459 460 461 462 463
#else
struct stub
{
    BYTE movq_rdi[2];      /* movq $dll,%rdi */
    const char *dll;
    BYTE movq_rsi[2];      /* movq $name,%rsi */
    const char *name;
    BYTE movq_rsp_rdx[4];  /* movq (%rsp),%rdx */
    BYTE movq_rax[2];      /* movq $entry, %rax */
    const void* entry;
    BYTE jmpq_rax[2];      /* jmp %rax */
};
#endif
464
#include "poppack.h"
465 466 467 468 469 470

/*************************************************************************
 *		allocate_stub
 *
 * Allocate a stub entry point.
 */
471
static ULONG_PTR allocate_stub( const char *dll, const char *name )
472 473 474 475 476 477
{
#define MAX_SIZE 65536
    static struct stub *stubs;
    static unsigned int nb_stubs;
    struct stub *stub;

478
    if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
479 480 481

    if (!stubs)
    {
482
        SIZE_T size = MAX_SIZE;
483
        if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
484
                                     MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
485
            return 0xdeadbeef;
486 487
    }
    stub = &stubs[nb_stubs++];
488
#ifdef __i386__
489 490 491 492
    stub->pushl1    = 0x68;  /* pushl $name */
    stub->name      = name;
    stub->pushl2    = 0x68;  /* pushl $dll */
    stub->dll       = dll;
493
    stub->call      = 0xe8;  /* call stub_entry_point */
494
    stub->entry     = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
495
#elif defined(__arm__)
496 497 498 499 500 501 502
    stub->ldr_r0    = 0xe59f0008;   /* ldr r0, [pc, #8] ($dll) */
    stub->ldr_r1    = 0xe59f1008;   /* ldr r1, [pc, #8] ($name) */
    stub->mov_r2_lr = 0xe1a0200e;   /* mov r2, lr */
    stub->ldr_pc_pc = 0xe59ff004;   /* ldr pc, [pc, #4] */
    stub->dll       = dll;
    stub->name      = name;
    stub->entry     = stub_entry_point;
503
#elif defined(__aarch64__) || defined(__arm64ec__)
504 505 506 507 508 509 510 511
    stub->ldr_x0    = 0x580000a0; /* ldr x0, #20 ($dll) */
    stub->ldr_x1    = 0x580000c1; /* ldr x1, #24 ($name) */
    stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
    stub->ldr_x16   = 0x580000d0; /* ldr x16, #24 ($entry) */
    stub->br_x16    = 0xd61f0200; /* br x16 */
    stub->dll       = dll;
    stub->name      = name;
    stub->entry     = stub_entry_point;
512
#else
513 514
    stub->movq_rdi[0]     = 0x48;  /* movq $dll,%rcx */
    stub->movq_rdi[1]     = 0xb9;
515
    stub->dll             = dll;
516 517
    stub->movq_rsi[0]     = 0x48;  /* movq $name,%rdx */
    stub->movq_rsi[1]     = 0xba;
518
    stub->name            = name;
519
    stub->movq_rsp_rdx[0] = 0x4c;  /* movq (%rsp),%r8 */
520
    stub->movq_rsp_rdx[1] = 0x8b;
521
    stub->movq_rsp_rdx[2] = 0x04;
522 523 524 525 526 527 528
    stub->movq_rsp_rdx[3] = 0x24;
    stub->movq_rax[0]     = 0x48;  /* movq $entry, %rax */
    stub->movq_rax[1]     = 0xb8;
    stub->entry           = stub_entry_point;
    stub->jmpq_rax[0]     = 0xff;  /* jmp %rax */
    stub->jmpq_rax[1]     = 0xe0;
#endif
529
    return (ULONG_PTR)stub;
530 531 532
}

#else  /* __i386__ */
533
static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
534 535
#endif  /* __i386__ */

536
/* call ldr notifications */
537
static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
538 539 540 541 542 543 544
{
    struct ldr_notification *notify, *notify_next;
    LDR_DLL_NOTIFICATION_DATA data;

    data.Loaded.Flags       = 0;
    data.Loaded.FullDllName = &module->FullDllName;
    data.Loaded.BaseDllName = &module->BaseDllName;
545
    data.Loaded.DllBase     = module->DllBase;
546 547 548 549
    data.Loaded.SizeOfImage = module->SizeOfImage;

    LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
    {
550
        TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%lu,data=%p,context=%p)\n",
551 552 553 554
                notify->callback, reason, &data, notify->context );

        notify->callback(reason, &data, notify->context);

555
        TRACE_(relay)("\1Ret  LDR notification callback (proc=%p,reason=%lu,data=%p,context=%p)\n",
556 557 558
                notify->callback, reason, &data, notify->context );
    }
}
559

560
/*************************************************************************
561 562 563 564
 *		get_modref
 *
 * Looks for the referenced HMODULE in the current process
 * The loader_section must be locked while calling this function.
565
 */
566
static WINE_MODREF *get_modref( HMODULE hmod )
567
{
568
    PLIST_ENTRY mark, entry;
569
    PLDR_DATA_TABLE_ENTRY mod;
570

571
    if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref;
572

573 574
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
575
    {
576
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
577
        if (mod->DllBase == hmod)
578
            return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
579
    }
580
    return NULL;
581 582 583
}


584
/**********************************************************************
585
 *	    find_basename_module
586
 *
587
 * Find a module from its base name.
588 589
 * The loader_section must be locked while calling this function
 */
590
static WINE_MODREF *find_basename_module( LPCWSTR name )
591 592
{
    PLIST_ENTRY mark, entry;
593
    UNICODE_STRING name_str;
594

595 596 597
    RtlInitUnicodeString( &name_str, name );

    if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
598
        return cached_modref;
599

600 601
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
602
    {
603 604
        WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks);
        if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && !mod->system)
605 606 607 608
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
609
    }
610 611 612 613 614 615 616 617 618 619
    return NULL;
}


/**********************************************************************
 *	    find_fullname_module
 *
 * Find a module from its full path name.
 * The loader_section must be locked while calling this function
 */
620
static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
621 622
{
    PLIST_ENTRY mark, entry;
623
    UNICODE_STRING name = *nt_name;
624

625 626 627 628 629
    if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
    name.Length -= 4 * sizeof(WCHAR);  /* for \??\ prefix */
    name.Buffer += 4;

    if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
630
        return cached_modref;
631 632 633 634

    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
635
        LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
636
        if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
637 638 639 640
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
641
    }
642
    return NULL;
643 644 645
}


646 647 648 649 650 651
/**********************************************************************
 *	    find_fileid_module
 *
 * Find a module from its file id.
 * The loader_section must be locked while calling this function
 */
652
static WINE_MODREF *find_fileid_module( const struct file_id *id )
653 654 655
{
    LIST_ENTRY *mark, *entry;

656
    if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref;
657 658 659 660

    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
661
        LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
662 663
        WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );

664
        if (!memcmp( &wm->id, id, sizeof(*id) ))
665 666 667 668 669 670 671 672
        {
            cached_modref = wm;
            return wm;
        }
    }
    return NULL;
}

673

674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
/******************************************************************************
 *	get_apiset_entry
 */
static NTSTATUS get_apiset_entry( const API_SET_NAMESPACE *map, const WCHAR *name, ULONG len,
                                  const API_SET_NAMESPACE_ENTRY **entry )
{
    const API_SET_HASH_ENTRY *hash_entry;
    ULONG hash, i, hash_len;
    int min, max;

    if (len <= 4) return STATUS_INVALID_PARAMETER;
    if (wcsnicmp( name, L"api-", 4 ) && wcsnicmp( name, L"ext-", 4 )) return STATUS_INVALID_PARAMETER;
    if (!map) return STATUS_APISET_NOT_PRESENT;

    for (i = hash_len = 0; i < len; i++)
    {
        if (name[i] == '.') break;
        if (name[i] == '-') hash_len = i;
    }
    for (i = hash = 0; i < hash_len; i++)
        hash = hash * map->HashFactor + ((name[i] >= 'A' && name[i] <= 'Z') ? name[i] + 32 : name[i]);

    hash_entry = (API_SET_HASH_ENTRY *)((char *)map + map->HashOffset);
    min = 0;
    max = map->Count - 1;
    while (min <= max)
    {
        int pos = (min + max) / 2;
        if (hash_entry[pos].Hash < hash) min = pos + 1;
        else if (hash_entry[pos].Hash > hash) max = pos - 1;
        else
        {
            *entry = (API_SET_NAMESPACE_ENTRY *)((char *)map + map->EntryOffset) + hash_entry[pos].Index;
            if ((*entry)->HashedLength != hash_len * sizeof(WCHAR)) break;
            if (wcsnicmp( (WCHAR *)((char *)map + (*entry)->NameOffset), name, hash_len )) break;
            return STATUS_SUCCESS;
        }
    }
    return STATUS_APISET_NOT_PRESENT;
}


/******************************************************************************
 *	get_apiset_target
 */
static NTSTATUS get_apiset_target( const API_SET_NAMESPACE *map, const API_SET_NAMESPACE_ENTRY *entry,
                                   const WCHAR *host, UNICODE_STRING *ret )
{
    const API_SET_VALUE_ENTRY *value = (API_SET_VALUE_ENTRY *)((char *)map + entry->ValueOffset);
    ULONG i, len;

    if (!entry->ValueCount) return STATUS_DLL_NOT_FOUND;
    if (host)
    {
        /* look for specific host in entries 1..n, entry 0 is the default */
        for (i = 1; i < entry->ValueCount; i++)
        {
            len = value[i].NameLength / sizeof(WCHAR);
            if (!wcsnicmp( host, (WCHAR *)((char *)map + value[i].NameOffset), len ) && !host[len])
            {
                value += i;
                break;
            }
        }
    }
    if (!value->ValueOffset) return STATUS_DLL_NOT_FOUND;
    ret->Buffer = (WCHAR *)((char *)map + value->ValueOffset);
    ret->Length = value->ValueLength;
    return STATUS_SUCCESS;
}


746 747 748 749 750
/**********************************************************************
 *	    build_import_name
 */
static NTSTATUS build_import_name( WCHAR buffer[256], const char *import, int len )
{
751 752 753 754 755
    const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
    const API_SET_NAMESPACE_ENTRY *entry;
    const WCHAR *host = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
    UNICODE_STRING str;

756 757 758 759 760
    while (len && import[len-1] == ' ') len--;  /* remove trailing spaces */
    if (len + sizeof(".dll") > 256) return STATUS_DLL_NOT_FOUND;
    ascii_to_unicode( buffer, import, len );
    buffer[len] = 0;
    if (!wcschr( buffer, '.' )) wcscpy( buffer + len, L".dll" );
761 762 763 764 765 766 767 768 769

    if (get_apiset_entry( map, buffer, wcslen(buffer), &entry )) return STATUS_SUCCESS;

    if (get_apiset_target( map, entry, host, &str )) return STATUS_DLL_NOT_FOUND;
    if (str.Length >= 256 * sizeof(WCHAR)) return STATUS_DLL_NOT_FOUND;

    TRACE( "found %s for %s\n", debugstr_us(&str), debugstr_w(buffer));
    memcpy( buffer, str.Buffer, str.Length );
    buffer[str.Length / sizeof(WCHAR)] = 0;
770 771 772 773
    return STATUS_SUCCESS;
}


774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
/**********************************************************************
 *	    append_dll_ext
 */
static WCHAR *append_dll_ext( const WCHAR *name )
{
    const WCHAR *ext = wcsrchr( name, '.' );

    if (!ext || wcschr( ext, '/' ) || wcschr( ext, '\\'))
    {
        WCHAR *ret = RtlAllocateHeap( GetProcessHeap(), 0,
                                      wcslen(name) * sizeof(WCHAR) + sizeof(L".dll") );
        if (!ret) return NULL;
        wcscpy( ret, name );
        wcscat( ret, L".dll" );
        return ret;
    }
    return NULL;
}


794 795 796 797 798 799 800
/***********************************************************************
 *           is_import_dll_system
 */
static BOOL is_import_dll_system( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_IMPORT_DESCRIPTOR *import )
{
    const char *name = get_rva( mod->DllBase, import->Name );

801
    return !_stricmp( name, "ntdll.dll" ) || !_stricmp( name, "kernel32.dll" );
802 803
}

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
/**********************************************************************
 *	    insert_single_list_tail
 */
static void insert_single_list_after( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *prev, SINGLE_LIST_ENTRY *entry )
{
    if (!list->Tail)
    {
        assert( !prev );
        entry->Next = entry;
        list->Tail = entry;
        return;
    }
    if (!prev)
    {
        /* Insert at head. */
        entry->Next = list->Tail->Next;
        list->Tail->Next = entry;
        return;
    }
    entry->Next = prev->Next;
    prev->Next = entry;
    if (prev == list->Tail) list->Tail = entry;
}
827

828 829
/**********************************************************************
 *	    remove_single_list_entry
830
 */
831
static void remove_single_list_entry( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *entry )
832
{
833
    SINGLE_LIST_ENTRY *prev;
834

835
    assert( list->Tail );
836

837
    if (entry->Next == entry)
838
    {
839 840 841
        assert( list->Tail == entry );
        list->Tail = NULL;
        return;
842
    }
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909

    prev = list->Tail->Next;
    while (prev->Next != entry && prev != list->Tail)
        prev = prev->Next;
    assert( prev->Next == entry );
    prev->Next = entry->Next;
    if (list->Tail == entry) list->Tail = prev;
    entry->Next = NULL;
}

/**********************************************************************
 *	    add_module_dependency_after
 */
static BOOL add_module_dependency_after( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to,
                                         SINGLE_LIST_ENTRY *dep_after )
{
    LDR_DEPENDENCY *dep;

    if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE;

    dep->dependency_from = from;
    insert_single_list_after( &from->Dependencies, dep_after, &dep->dependency_to_entry );
    dep->dependency_to = to;
    insert_single_list_after( &to->IncomingDependencies, NULL, &dep->dependency_from_entry );

    return TRUE;
}

/**********************************************************************
 *	    add_module_dependency
 */
static BOOL add_module_dependency( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to )
{
    return add_module_dependency_after( from, to, from->Dependencies.Tail );
}

/**********************************************************************
 *	    remove_module_dependency
 */
static void remove_module_dependency( LDR_DEPENDENCY *dep )
{
    remove_single_list_entry( &dep->dependency_to->IncomingDependencies, &dep->dependency_from_entry );
    remove_single_list_entry( &dep->dependency_from->Dependencies, &dep->dependency_to_entry );
    RtlFreeHeap( GetProcessHeap(), 0, dep );
}

/**********************************************************************
 *	    walk_node_dependencies
 */
static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
                                        NTSTATUS (*callback)( LDR_DDAG_NODE *, void * ))
{
    SINGLE_LIST_ENTRY *entry;
    LDR_DEPENDENCY *dep;
    NTSTATUS status;

    if (!(entry = node->Dependencies.Tail)) return STATUS_SUCCESS;

    do
    {
        entry = entry->Next;
        dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
        assert( dep->dependency_from == node );
        if ((status = callback( dep->dependency_to, context ))) break;
    } while (entry != node->Dependencies.Tail);

    return status;
910 911
}

912 913 914 915 916 917
/*************************************************************************
 *		find_forwarded_export
 *
 * Find the final function pointer for a forwarded function.
 * The loader_section must be locked while calling this function.
 */
918
static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
919
{
Eric Pouech's avatar
Eric Pouech committed
920
    const IMAGE_EXPORT_DIRECTORY *exports;
921 922
    DWORD exp_size;
    WINE_MODREF *wm;
923
    WCHAR mod_name[256];
924
    const char *end = strrchr(forward, '.');
925 926 927
    FARPROC proc = NULL;

    if (!end) return NULL;
928
    if (build_import_name( mod_name, forward, end - forward )) return NULL;
929

930
    if (!(wm = find_basename_module( mod_name )))
931
    {
932
        WINE_MODREF *imp = get_modref( module );
933
        TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
934
        if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS &&
935 936
            !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
        {
937 938
            if (!imports_fixup_done && current_modref)
            {
939
                add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode );
940
            }
941
            else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
942
            {
943
                LdrUnloadDll( wm->ldr.DllBase );
944 945 946 947 948 949 950
                wm = NULL;
            }
        }

        if (!wm)
        {
            ERR( "module not found for forward '%s' used by %s\n",
951
                 forward, debugstr_w(imp->ldr.FullDllName.Buffer) );
952 953
            return NULL;
        }
954
    }
955
    if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
956
                                                 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
957 958
    {
        const char *name = end + 1;
959 960 961 962 963

        if (*name == '#') { /* ordinal */
            proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
                                        atoi(name+1) - exports->Base, load_path );
        } else
964
            proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
965
    }
966 967 968

    if (!proc)
    {
969 970 971 972
        ERR("function not found for forward '%s' used by %s."
            " If you are using builtin %s, try using the native one instead.\n",
            forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
            debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
973 974 975 976 977 978 979 980 981 982 983 984
    }
    return proc;
}


/*************************************************************************
 *		find_ordinal_export
 *
 * Find an exported function by ordinal.
 * The exports base must have been subtracted from the ordinal already.
 * The loader_section must be locked while calling this function.
 */
Eric Pouech's avatar
Eric Pouech committed
985
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
986
                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
987 988
{
    FARPROC proc;
Eric Pouech's avatar
Eric Pouech committed
989
    const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
990 991 992

    if (ordinal >= exports->NumberOfFunctions)
    {
993
        TRACE("	ordinal %ld out of range!\n", ordinal + exports->Base );
994 995 996 997 998 999 1000
        return NULL;
    }
    if (!functions[ordinal]) return NULL;

    proc = get_rva( module, functions[ordinal] );

    /* if the address falls into the export dir, it's a forward */
Eric Pouech's avatar
Eric Pouech committed
1001 1002
    if (((const char *)proc >= (const char *)exports) && 
        ((const char *)proc < (const char *)exports + exp_size))
1003
        return find_forwarded_export( module, (const char *)proc, load_path );
1004

1005
    if (TRACE_ON(snoop))
1006
    {
1007 1008
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
        proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
1009
    }
1010
    if (TRACE_ON(relay))
1011
    {
1012
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
1013
        proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
1014 1015 1016 1017 1018
    }
    return proc;
}


1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
/*************************************************************************
 *		find_name_in_exports
 *
 * Helper for find_named_export.
 */
static int find_name_in_exports( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, const char *name )
{
    const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
    const DWORD *names = get_rva( module, exports->AddressOfNames );
    int min = 0, max = exports->NumberOfNames - 1;

    while (min <= max)
    {
        int res, pos = (min + max) / 2;
        char *ename = get_rva( module, names[pos] );
        if (!(res = strcmp( ename, name ))) return ordinals[pos];
        if (res > 0) max = pos - 1;
        else min = pos + 1;
    }
    return -1;
}


1042 1043 1044 1045 1046 1047
/*************************************************************************
 *		find_named_export
 *
 * Find an exported function by name.
 * The loader_section must be locked while calling this function.
 */
Eric Pouech's avatar
Eric Pouech committed
1048
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
1049
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
1050
{
Eric Pouech's avatar
Eric Pouech committed
1051 1052
    const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
    const DWORD *names = get_rva( module, exports->AddressOfNames );
1053
    int ordinal;
1054 1055

    /* first check the hint */
1056
    if (hint >= 0 && hint < exports->NumberOfNames)
1057 1058 1059
    {
        char *ename = get_rva( module, names[hint] );
        if (!strcmp( ename, name ))
1060
            return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
1061 1062 1063
    }

    /* then do a binary search */
1064 1065
    if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
    return find_ordinal_export( module, exports, exp_size, ordinal, load_path );
1066 1067 1068 1069

}


1070 1071 1072 1073 1074 1075 1076 1077 1078
/*************************************************************************
 *		RtlFindExportedRoutineByName
 */
void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
{
    const IMAGE_EXPORT_DIRECTORY *exports;
    const DWORD *functions;
    DWORD exp_size;
    int ordinal;
1079
    void *proc;
1080 1081 1082 1083 1084 1085 1086 1087

    exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
    if (!exports || exp_size < sizeof(*exports)) return NULL;

    if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
    if (ordinal >= exports->NumberOfFunctions) return NULL;
    functions = get_rva( module, exports->AddressOfFunctions );
    if (!functions[ordinal]) return NULL;
1088 1089 1090 1091 1092 1093
    proc = get_rva( module, functions[ordinal] );
    /* if the address falls into the export dir, it's a forward */
    if (((const char *)proc >= (const char *)exports) &&
        ((const char *)proc < (const char *)exports + exp_size))
        return NULL;
    return proc;
1094 1095 1096
}


1097 1098 1099 1100 1101 1102
/*************************************************************************
 *		import_dll
 *
 * Import the dll specified by the given import descriptor.
 * The loader_section must be locked while calling this function.
 */
1103
static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
1104
{
1105
    BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL);
1106 1107 1108
    NTSTATUS status;
    WINE_MODREF *wmImp;
    HMODULE imp_mod;
Eric Pouech's avatar
Eric Pouech committed
1109
    const IMAGE_EXPORT_DIRECTORY *exports;
1110
    DWORD exp_size;
Eric Pouech's avatar
Eric Pouech committed
1111 1112
    const IMAGE_THUNK_DATA *import_list;
    IMAGE_THUNK_DATA *thunk_list;
1113
    WCHAR buffer[256];
Eric Pouech's avatar
Eric Pouech committed
1114
    const char *name = get_rva( module, descr->Name );
1115
    DWORD len = strlen(name);
1116
    PVOID protect_base;
1117
    SIZE_T protect_size = 0;
1118
    DWORD protect_old;
1119

1120
    thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
1121 1122
    if (descr->OriginalFirstThunk)
        import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );
1123 1124 1125
    else
        import_list = thunk_list;

1126 1127 1128 1129 1130 1131 1132
    if (!import_list->u1.Ordinal)
    {
        WARN( "Skipping unused import %s\n", name );
        *pwm = NULL;
        return TRUE;
    }

1133
    status = build_import_name( buffer, name, len );
1134
    if (!status) status = load_dll( load_path, buffer, 0, &wmImp, system );
1135 1136 1137

    if (status)
    {
1138
        if (status == STATUS_DLL_NOT_FOUND)
1139
            ERR("Library %s (which is needed by %s) not found\n",
1140
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
1141
        else
1142
            ERR("Loading library %s (which is needed by %s) failed (error %lx).\n",
1143
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
1144
        return FALSE;
1145 1146
    }

1147 1148 1149 1150 1151
    /* unprotect the import address table since it can be located in
     * readonly section */
    while (import_list[protect_size].u1.Ordinal) protect_size++;
    protect_base = thunk_list;
    protect_size *= sizeof(*thunk_list);
1152
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
1153
                            &protect_size, PAGE_READWRITE, &protect_old );
1154

1155
    imp_mod = wmImp->ldr.DllBase;
1156 1157
    exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );

1158 1159 1160 1161 1162 1163 1164
    if (!exports)
    {
        /* set all imported function to deadbeef */
        while (import_list->u1.Ordinal)
        {
            if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
            {
1165 1166
                int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
                WARN("No implementation for %s.%d", name, ordinal );
1167
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1168 1169 1170 1171
            }
            else
            {
                IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1172
                WARN("No implementation for %s.%s", name, pe_name->Name );
Mike McCormack's avatar
Mike McCormack committed
1173
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1174
            }
1175
            WARN(" imported from %s, allocating stub %p\n",
1176 1177
                 debugstr_w(current_modref->ldr.FullDllName.Buffer),
                 (void *)thunk_list->u1.Function );
1178 1179 1180
            import_list++;
            thunk_list++;
        }
1181
        goto done;
1182
    }
1183 1184 1185 1186 1187 1188 1189

    while (import_list->u1.Ordinal)
    {
        if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
        {
            int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);

1190
            thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
1191
                                                                      ordinal - exports->Base, load_path );
1192 1193
            if (!thunk_list->u1.Function)
            {
1194
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1195
                WARN("No implementation for %s.%d imported from %s, setting to %p\n",
1196 1197
                     name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
1198
            }
1199
            TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
1200 1201 1202 1203 1204
        }
        else  /* import by name */
        {
            IMAGE_IMPORT_BY_NAME *pe_name;
            pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1205
            thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
1206 1207
                                                                    (const char*)pe_name->Name,
                                                                    pe_name->Hint, load_path );
1208 1209
            if (!thunk_list->u1.Function)
            {
Mike McCormack's avatar
Mike McCormack committed
1210
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1211
                WARN("No implementation for %s.%s imported from %s, setting to %p\n",
1212 1213
                     name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
1214
            }
1215 1216
            TRACE_(imports)("--- %s %s.%d = %p\n",
                            pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
1217 1218 1219 1220
        }
        import_list++;
        thunk_list++;
    }
1221 1222 1223

done:
    /* restore old protection of the import address table */
1224
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
1225 1226
    *pwm = wmImp;
    return TRUE;
1227 1228 1229
}


1230 1231 1232
/***********************************************************************
 *           create_module_activation_context
 */
1233
static NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
1234 1235 1236 1237 1238 1239 1240 1241
{
    NTSTATUS status;
    LDR_RESOURCE_INFO info;
    const IMAGE_RESOURCE_DATA_ENTRY *entry;

    info.Type = RT_MANIFEST;
    info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
    info.Language = 0;
1242
    if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
1243 1244 1245 1246 1247
    {
        ACTCTXW ctx;
        ctx.cbSize   = sizeof(ctx);
        ctx.lpSource = NULL;
        ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
1248
        ctx.hModule  = module->DllBase;
1249 1250 1251 1252 1253 1254 1255
        ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
        status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
    }
    return status;
}


1256 1257 1258 1259 1260 1261 1262
/*************************************************************************
 *		is_dll_native_subsystem
 *
 * Check if dll is a proper native driver.
 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
 * while being perfectly normal DLLs.  This heuristic should catch such breakages.
 */
1263
static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
1264 1265 1266 1267 1268
{
    const IMAGE_IMPORT_DESCRIPTOR *imports;
    DWORD i, size;

    if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
1269
    if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
1270
    if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
1271

1272
    if ((imports = RtlImageDirectoryEntryToData( mod->DllBase, TRUE,
1273 1274 1275
                                                 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
    {
        for (i = 0; imports[i].Name; i++)
1276
            if (is_import_dll_system( mod, &imports[i] ))
1277
            {
1278
                TRACE( "%s imports system dll, assuming not native\n", debugstr_w(filename) );
1279 1280 1281 1282 1283 1284
                return FALSE;
            }
    }
    return TRUE;
}

1285 1286 1287 1288 1289 1290
/*************************************************************************
 *		alloc_tls_slot
 *
 * Allocate a TLS slot for a newly-loaded module.
 * The loader_section must be locked while calling this function.
 */
1291
static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1292 1293 1294 1295
{
    const IMAGE_TLS_DIRECTORY *dir;
    ULONG i, size;
    void *new_ptr;
1296
    LIST_ENTRY *entry;
1297

1298
    if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1299
        return FALSE;
1300 1301

    size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1302
    if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return FALSE;
1303

1304 1305 1306 1307 1308 1309
    for (i = 0; i < tls_module_count; i++)
    {
        if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
            !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
            break;
    }
1310

1311
    TRACE( "module %p data %p-%p zerofill %lu index %p callback %p flags %lx -> slot %lu\n", mod->DllBase,
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
           (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
           (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );

    if (i == tls_module_count)
    {
        UINT new_count = max( 32, tls_module_count * 2 );

        if (!tls_dirs)
            new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
        else
            new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
                                         new_count * sizeof(*tls_dirs) );
1324
        if (!new_ptr) return FALSE;
1325 1326 1327 1328 1329 1330 1331 1332

        /* resize the pointer block in all running threads */
        for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
        {
            TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
            void **old = teb->ThreadLocalStoragePointer;
            void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));

1333
            if (!new) return FALSE;
1334 1335
            if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
            teb->ThreadLocalStoragePointer = new;
1336
#ifdef __x86_64__  /* macOS-specific hack */
1337
            if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = new;
1338
#endif
1339
            TRACE( "thread %04lx tls block %p -> %p\n", HandleToULong(teb->ClientId.UniqueThread), old, new );
1340 1341 1342
            /* FIXME: can't free old block here, should be freed at thread exit */
        }

1343 1344 1345 1346
        tls_dirs = new_ptr;
        tls_module_count = new_count;
    }

1347 1348 1349 1350 1351 1352 1353 1354 1355
    /* allocate the data block in all running threads */
    for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
    {
        TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );

        if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
        memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
        memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );

1356 1357
        TRACE( "thread %04lx slot %lu: %lu/%lu bytes at %p\n",
               HandleToULong(teb->ClientId.UniqueThread), i, size, dir->SizeOfZeroFill, new_ptr );
1358 1359

        RtlFreeHeap( GetProcessHeap(), 0,
1360
                     InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1361 1362
    }

1363
    *(DWORD *)dir->AddressOfIndex = i;
1364
    tls_dirs[i] = *dir;
1365
    return TRUE;
1366 1367 1368 1369 1370 1371 1372 1373 1374
}


/*************************************************************************
 *		free_tls_slot
 *
 * Free the module TLS slot on unload.
 * The loader_section must be locked while calling this function.
 */
1375
static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1376
{
1377 1378 1379 1380 1381 1382 1383
    const IMAGE_TLS_DIRECTORY *dir;
    ULONG i, size;

    if (mod->TlsIndex != -1)
        return;
    if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
        return;
1384

1385
    i = *(ULONG*)dir->AddressOfIndex;
1386
    assert( i < tls_module_count );
1387
    memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1388 1389
}

1390

1391 1392 1393 1394 1395 1396 1397 1398 1399
/****************************************************************
 *       fixup_imports_ilonly
 *
 * Fixup imports for an IL-only module. All we do is import mscoree.
 * The loader_section must be locked while calling this function.
 */
static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
{
    NTSTATUS status;
1400 1401
    void *proc;
    const char *name;
1402 1403 1404 1405 1406 1407 1408
    WINE_MODREF *prev, *imp;

    if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
    wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;

    prev = current_modref;
    current_modref = wm;
1409
    assert( !wm->ldr.DdagNode->Dependencies.Tail );
1410
    if (!(status = load_dll( load_path, L"mscoree.dll", 0, &imp, FALSE ))
1411 1412
          && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
        status = STATUS_NO_MEMORY;
1413
    current_modref = prev;
1414 1415 1416 1417 1418 1419
    if (status)
    {
        ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
             debugstr_w(wm->ldr.BaseDllName.Buffer) );
        return status;
    }
1420 1421 1422

    TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );

1423 1424
    name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
    if (!(proc = RtlFindExportedRoutineByName( imp->ldr.DllBase, name ))) return STATUS_PROCEDURE_NOT_FOUND;
1425 1426 1427 1428 1429
    *entry = proc;
    return STATUS_SUCCESS;
}


1430 1431 1432 1433 1434 1435 1436 1437 1438
/****************************************************************
 *       fixup_imports
 *
 * Fixup all imports of a given module.
 * The loader_section must be locked while calling this function.
 */
static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
{
    const IMAGE_IMPORT_DESCRIPTOR *imports;
1439
    SINGLE_LIST_ENTRY *dep_after;
1440
    WINE_MODREF *prev, *imp;
1441
    int i, nb_imports;
1442 1443 1444 1445 1446 1447 1448
    DWORD size;
    NTSTATUS status;
    ULONG_PTR cookie;

    if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
    wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;

1449
    if (alloc_tls_slot( &wm->ldr )) wm->ldr.TlsIndex = -1;
1450

1451
    if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470
                                                  IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
        return STATUS_SUCCESS;

    nb_imports = 0;
    while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;

    if (!nb_imports) return STATUS_SUCCESS;  /* no imports */

    if (!create_module_activation_context( &wm->ldr ))
        RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );

    /* load the imported modules. They are automatically
     * added to the modref list of the process.
     */
    prev = current_modref;
    current_modref = wm;
    status = STATUS_SUCCESS;
    for (i = 0; i < nb_imports; i++)
    {
1471
        dep_after = wm->ldr.DdagNode->Dependencies.Tail;
1472
        if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
1473
            status = STATUS_DLL_NOT_FOUND;
1474
        else if (imp && imp->ldr.DdagNode != node_ntdll && imp->ldr.DdagNode != node_kernel32)
1475
            add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after );
1476 1477 1478 1479 1480 1481 1482
    }
    current_modref = prev;
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
    return status;
}


1483
/*************************************************************************
1484
 *		alloc_module
1485 1486
 *
 * Allocate a WINE_MODREF structure and add it to the process list
1487
 * The loader_section must be locked while calling this function.
1488
 */
1489
static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1490
{
1491
    WCHAR *buffer;
1492
    WINE_MODREF *wm;
Eric Pouech's avatar
Eric Pouech committed
1493 1494
    const WCHAR *p;
    const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1495

1496
    if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1497

1498
    wm->ldr.DllBase       = hModule;
1499
    wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
1500
    wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1501
    wm->ldr.TlsIndex      = 0;
1502
    wm->ldr.LoadCount     = 1;
1503
    wm->CheckSum          = nt->OptionalHeader.CheckSum;
1504
    wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
1505

1506 1507 1508 1509 1510
    if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
    {
        RtlFreeHeap( GetProcessHeap(), 0, wm );
        return NULL;
    }
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520

    if (!(wm->ldr.DdagNode = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm->ldr.DdagNode) )))
    {
        RtlFreeHeap( GetProcessHeap(), 0, buffer );
        RtlFreeHeap( GetProcessHeap(), 0, wm );
        return NULL;
    }
    InitializeListHead(&wm->ldr.DdagNode->Modules);
    InsertTailList(&wm->ldr.DdagNode->Modules, &wm->ldr.NodeModuleLink);

1521 1522 1523 1524 1525
    memcpy( buffer, nt_name->Buffer + 4 /* \??\ prefix */, nt_name->Length - 4 * sizeof(WCHAR) );
    buffer[nt_name->Length/sizeof(WCHAR) - 4] = 0;
    if ((p = wcsrchr( buffer, '\\' ))) p++;
    else p = buffer;
    RtlInitUnicodeString( &wm->ldr.FullDllName, buffer );
1526 1527
    RtlInitUnicodeString( &wm->ldr.BaseDllName, p );

1528
    if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1529
    {
1530 1531
        if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
            wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1532 1533
        if (nt->OptionalHeader.AddressOfEntryPoint)
            wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1534 1535
    }

1536
    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1537
                   &wm->ldr.InLoadOrderLinks);
1538
    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1539
                   &wm->ldr.InMemoryOrderLinks);
1540
    /* wait until init is called for inserting into InInitializationOrderModuleList */
1541 1542 1543

    if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
    {
1544
        ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1545
        WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1546
        NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1547
    }
1548 1549 1550 1551
    return wm;
}


1552 1553 1554 1555 1556 1557 1558 1559
/*************************************************************************
 *              alloc_thread_tls
 *
 * Allocate the per-thread structure for module TLS storage.
 */
static NTSTATUS alloc_thread_tls(void)
{
    void **pointers;
1560
    UINT i, size;
1561 1562 1563

    if (!tls_module_count) return STATUS_SUCCESS;

1564 1565
    if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                      tls_module_count * sizeof(*pointers) )))
1566 1567 1568 1569
        return STATUS_NO_MEMORY;

    for (i = 0; i < tls_module_count; i++)
    {
1570
        const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1571 1572

        if (!dir) continue;
1573
        size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
        if (!size && !dir->SizeOfZeroFill) continue;

        if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
        {
            while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
            RtlFreeHeap( GetProcessHeap(), 0, pointers );
            return STATUS_NO_MEMORY;
        }
        memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
        memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1584

1585
        TRACE( "slot %u: %u/%lu bytes at %p\n", i, size, dir->SizeOfZeroFill, pointers[i] );
1586
    }
1587
    NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1588
#ifdef __x86_64__  /* macOS-specific hack */
1589 1590
    if (NtCurrentTeb()->Instrumentation[0])
        ((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = pointers;
1591
#endif
1592 1593 1594 1595
    return STATUS_SUCCESS;
}


1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
/*************************************************************************
 *              call_tls_callbacks
 */
static void call_tls_callbacks( HMODULE module, UINT reason )
{
    const IMAGE_TLS_DIRECTORY *dir;
    const PIMAGE_TLS_CALLBACK *callback;
    ULONG dirsize;

    dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
    if (!dir || !dir->AddressOfCallBacks) return;

1608
    for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1609
    {
1610 1611
        TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                      *callback, module, reason_names[reason] );
1612 1613
        __TRY
        {
1614
            call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1615
        }
1616
        __EXCEPT_ALL
1617
        {
1618
            TRACE_(relay)("\1exception %08lx in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1619
                          GetExceptionCode(), callback, module, reason_names[reason] );
1620 1621 1622
            return;
        }
        __ENDTRY
1623 1624
        TRACE_(relay)("\1Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                      *callback, module, reason_names[reason] );
1625 1626 1627
    }
}

1628 1629 1630
/*************************************************************************
 *              MODULE_InitDLL
 */
1631
static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1632
{
1633
    WCHAR mod_name[64];
1634
    NTSTATUS status = STATUS_SUCCESS;
1635
    DLLENTRYPROC entry = wm->ldr.EntryPoint;
1636
    void *module = wm->ldr.DllBase;
1637
    BOOL retv = FALSE;
1638 1639 1640

    /* Skip calls for modules loaded with special load flags */

1641
    if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1642
    if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, reason );
1643
    if (!entry) return STATUS_SUCCESS;
1644 1645

    if (TRACE_ON(relay))
1646
    {
1647
        size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1648 1649
        memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
        mod_name[len / sizeof(WCHAR)] = 0;
1650 1651
        TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
                      entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1652
    }
1653 1654
    else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
               reason_names[reason], lpReserved );
1655

1656 1657 1658 1659 1660 1661
    __TRY
    {
        retv = call_dll_entry_point( entry, module, reason, lpReserved );
        if (!retv)
            status = STATUS_DLL_INIT_FAILED;
    }
1662
    __EXCEPT_ALL
1663 1664
    {
        status = GetExceptionCode();
1665
        TRACE_(relay)("\1exception %08lx in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1666
                      status, entry, module, reason_names[reason], lpReserved );
1667 1668
    }
    __ENDTRY
1669 1670

    /* The state of the module list may have changed due to the call
1671
       to the dll. We cannot assume that this module has not been
1672
       deleted.  */
1673
    if (TRACE_ON(relay))
1674 1675 1676 1677
        TRACE_(relay)("\1Ret  PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
                      entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
    else
        TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1678

1679
    return status;
1680 1681 1682 1683
}


/*************************************************************************
1684
 *		process_attach
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
 *
 * Send the process attach notification to all DLLs the given module
 * depends on (recursively). This is somewhat complicated due to the fact that
 *
 * - we have to respect the module dependencies, i.e. modules implicitly
 *   referenced by another module have to be initialized before the module
 *   itself can be initialized
 *
 * - the initialization routine of a DLL can itself call LoadLibrary,
 *   thereby introducing a whole new set of dependencies (even involving
 *   the 'old' modules) at any time during the whole process
 *
 * (Note that this routine can be recursively entered not only directly
 *  from itself, but also via LoadLibrary from one of the called initialization
 *  routines.)
 *
 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
 * the process *detach* notifications to be sent in the correct order.
 * This must not only take into account module dependencies, but also
 * 'hidden' dependencies created by modules calling LoadLibrary in their
 * attach notification routine.
 *
 * The strategy is rather simple: we move a WINE_MODREF to the head of the
 * list after the attach notification has returned.  This implies that the
 * detach notifications are called in the reverse of the sequence the attach
 * notifications *returned*.
1711 1712
 *
 * The loader_section must be locked while calling this function.
1713
 */
1714
static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
1715
{
1716
    NTSTATUS status = STATUS_SUCCESS;
1717
    LDR_DATA_TABLE_ENTRY *mod;
1718
    ULONG_PTR cookie;
1719
    WINE_MODREF *wm;
1720

1721 1722
    if (process_detaching) return status;

1723 1724 1725
    mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
    wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );

1726
    /* prevent infinite recursion in case of cyclical dependencies */
1727 1728
    if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
         || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1729
        return status;
1730

1731
    TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1732 1733

    /* Tag current MODREF to prevent recursive loop */
1734
    wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1735
    if (lpReserved) wm->ldr.LoadCount = -1;  /* pin it if imported by the main exe */
1736
    if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1737 1738

    /* Recursively attach all DLLs this one depends on */
1739
    status = walk_node_dependencies( node, lpReserved, process_attach );
1740

1741
    if (!wm->ldr.InInitializationOrderLinks.Flink)
1742
        InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1743
                &wm->ldr.InInitializationOrderLinks);
1744

1745
    /* Call DLL entry point */
1746
    if (status == STATUS_SUCCESS)
1747
    {
1748 1749
        WINE_MODREF *prev = current_modref;
        current_modref = wm;
1750 1751

        call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1752 1753
        status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
        if (status == STATUS_SUCCESS)
1754
        {
1755
            wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1756
        }
1757
        else
1758
        {
1759
            MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1760 1761
            call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );

1762 1763 1764 1765
            /* point to the name so LdrInitializeThunk can print it */
            last_failed_modref = wm;
            WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
        }
1766
        current_modref = prev;
1767 1768
    }

1769
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1770
    /* Remove recursion flag */
1771
    wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1772

1773
    TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1774
    return status;
1775 1776
}

1777

1778
/*************************************************************************
1779
 *		process_detach
1780 1781
 *
 * Send DLL process detach notifications.  See the comment about calling
1782
 * sequence at process_attach.
1783
 */
1784
static void process_detach(void)
1785
{
1786
    PLIST_ENTRY mark, entry;
1787
    PLDR_DATA_TABLE_ENTRY mod;
1788

1789
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1790 1791
    do
    {
1792
        for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1793
        {
1794
            mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1795
                                    InInitializationOrderLinks);
1796
            /* Check whether to detach this DLL */
1797
            if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1798
                continue;
1799
            if ( mod->LoadCount && !process_detaching )
1800 1801 1802
                continue;

            /* Call detach notification */
1803 1804
            mod->Flags &= ~LDR_PROCESS_ATTACHED;
            MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
1805
                            DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1806
            call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1807 1808 1809 1810 1811

            /* Restart at head of WINE_MODREF list, as entries might have
               been added and/or removed while performing the call ... */
            break;
        }
1812
    } while (entry != mark);
1813 1814 1815
}

/*************************************************************************
1816
 *		thread_attach
1817 1818 1819
 *
 * Send DLL thread attach notifications. These are sent in the
 * reverse sequence of process detach notification.
1820
 * The loader_section must be locked while calling this function.
1821
 */
1822
static void thread_attach(void)
1823
{
1824
    PLIST_ENTRY mark, entry;
1825
    PLDR_DATA_TABLE_ENTRY mod;
1826

1827 1828
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1829
    {
1830
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1831
                                InInitializationOrderLinks);
1832
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1833
            continue;
1834
        if ( mod->Flags & LDR_NO_DLL_CALLS )
1835 1836
            continue;

1837
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1838 1839 1840
    }
}

1841 1842 1843 1844 1845
/******************************************************************
 *		LdrDisableThreadCalloutsForDll (NTDLL.@)
 *
 */
NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1846
{
1847 1848 1849 1850 1851
    WINE_MODREF *wm;
    NTSTATUS    ret = STATUS_SUCCESS;

    RtlEnterCriticalSection( &loader_section );

1852
    wm = get_modref( hModule );
1853
    if (!wm || wm->ldr.TlsIndex == -1)
1854
        ret = STATUS_DLL_NOT_FOUND;
1855
    else
1856
        wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1857 1858 1859 1860

    RtlLeaveCriticalSection( &loader_section );

    return ret;
1861
}
1862

1863 1864 1865 1866 1867
/******************************************************************
 *              LdrFindEntryForAddress (NTDLL.@)
 *
 * The loader_section must be locked while calling this function
 */
1868
NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
1869
{
1870
    PLIST_ENTRY mark, entry;
1871
    PLDR_DATA_TABLE_ENTRY mod;
1872

1873 1874
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1875
    {
1876
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
1877 1878
        if (mod->DllBase <= addr &&
            (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
1879
        {
1880
            *pmod = mod;
1881 1882 1883 1884 1885 1886
            return STATUS_SUCCESS;
        }
    }
    return STATUS_NO_MORE_ENTRIES;
}

1887 1888 1889 1890 1891 1892
/******************************************************************
 *              LdrEnumerateLoadedModules (NTDLL.@)
 */
NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
{
    LIST_ENTRY *mark, *entry;
1893
    LDR_DATA_TABLE_ENTRY *mod;
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
    BOOLEAN stop = FALSE;

    TRACE( "(%p, %p, %p)\n", unknown, callback, context );

    if (unknown || !callback)
        return STATUS_INVALID_PARAMETER;

    RtlEnterCriticalSection( &loader_section );

    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
1906
        mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
1907 1908 1909 1910 1911 1912 1913 1914
        callback( mod, context, &stop );
        if (stop) break;
    }

    RtlLeaveCriticalSection( &loader_section );
    return STATUS_SUCCESS;
}

1915 1916 1917 1918 1919 1920
/******************************************************************
 *              LdrRegisterDllNotification (NTDLL.@)
 */
NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
                                           void *context, void **cookie)
{
1921 1922
    struct ldr_notification *notify;

1923
    TRACE( "(%lx, %p, %p, %p)\n", flags, callback, context, cookie );
1924 1925 1926 1927 1928

    if (!callback || !cookie)
        return STATUS_INVALID_PARAMETER;

    if (flags)
1929
        FIXME( "ignoring flags %lx\n", flags );
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941

    notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
    if (!notify) return STATUS_NO_MEMORY;
    notify->callback = callback;
    notify->context = context;

    RtlEnterCriticalSection( &loader_section );
    list_add_tail( &ldr_notifications, &notify->entry );
    RtlLeaveCriticalSection( &loader_section );

    *cookie = notify;
    return STATUS_SUCCESS;
1942 1943 1944 1945 1946 1947 1948
}

/******************************************************************
 *              LdrUnregisterDllNotification (NTDLL.@)
 */
NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
{
1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
    struct ldr_notification *notify = cookie;

    TRACE( "(%p)\n", cookie );

    if (!notify) return STATUS_INVALID_PARAMETER;

    RtlEnterCriticalSection( &loader_section );
    list_remove( &notify->entry );
    RtlLeaveCriticalSection( &loader_section );

    RtlFreeHeap( GetProcessHeap(), 0, notify );
    return STATUS_SUCCESS;
1961 1962
}

1963 1964 1965
/******************************************************************
 *		LdrLockLoaderLock  (NTDLL.@)
 *
1966
 * Note: some flags are not implemented.
1967 1968
 * Flag 0x01 is used to raise exceptions on errors.
 */
1969
NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1970
{
1971
    if (flags & ~0x2) FIXME( "flags %lx not supported\n", flags );
1972

1973 1974 1975 1976
    if (result) *result = 0;
    if (magic) *magic = 0;
    if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
    if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1977
    if (!magic) return STATUS_INVALID_PARAMETER_3;
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992

    if (flags & 0x2)
    {
        if (!RtlTryEnterCriticalSection( &loader_section ))
        {
            *result = 2;
            return STATUS_SUCCESS;
        }
        *result = 1;
    }
    else
    {
        RtlEnterCriticalSection( &loader_section );
        if (result) *result = 1;
    }
1993 1994 1995 1996 1997 1998 1999 2000
    *magic = GetCurrentThreadId();
    return STATUS_SUCCESS;
}


/******************************************************************
 *		LdrUnlockLoaderUnlock  (NTDLL.@)
 */
2001
NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011
{
    if (magic)
    {
        if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
        RtlLeaveCriticalSection( &loader_section );
    }
    return STATUS_SUCCESS;
}


2012 2013
/******************************************************************
 *		LdrGetProcedureAddress  (NTDLL.@)
2014
 */
2015 2016
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
                                       ULONG ord, PVOID *address)
2017
{
2018
    IMAGE_EXPORT_DIRECTORY *exports;
2019
    WINE_MODREF *wm;
2020 2021
    DWORD exp_size;
    NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
2022

2023
    RtlEnterCriticalSection( &loader_section );
2024

2025
    /* check if the module itself is invalid to return the proper error */
2026
    if (!(wm = get_modref( module ))) ret = STATUS_DLL_NOT_FOUND;
2027 2028
    else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
                                                      IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
2029
    {
2030 2031
        void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
                          : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
2032 2033 2034 2035 2036
        if (proc)
        {
            *address = proc;
            ret = STATUS_SUCCESS;
        }
2037 2038 2039 2040 2041
        else
        {
            WARN( "%s (ordinal %lu) not found in %s\n", debugstr_a(name ? name->Buffer : NULL),
                  ord, debugstr_us(&wm->ldr.FullDllName) );
        }
2042
    }
2043

2044 2045
    RtlLeaveCriticalSection( &loader_section );
    return ret;
2046
}
2047 2048


2049 2050 2051 2052 2053 2054
/***********************************************************************
 *           set_security_cookie
 *
 * Create a random security cookie for buffer overflow protection. Make
 * sure it does not accidentally match the default cookie value.
 */
2055
static void set_security_cookie( ULONG_PTR *cookie )
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080
{
    static ULONG seed;

    TRACE( "initializing security cookie %p\n", cookie );

    if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
    for (;;)
    {
        if (*cookie == DEFAULT_SECURITY_COOKIE_16)
            *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
        else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
            *cookie = RtlRandom( &seed );
#ifdef DEFAULT_SECURITY_COOKIE_64
        else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
        {
            *cookie = RtlRandom( &seed );
            /* fill up, but keep the highest word clear */
            *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
        }
#endif
        else
            break;
    }
}

2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110

/***********************************************************************
 *           update_load_config
 */
static void update_load_config( void *module )
{
    IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
    IMAGE_LOAD_CONFIG_DIRECTORY *cfg;
    ULONG size;

    cfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size );
    if (!cfg) return;
    size = min( size, cfg->Size );
    if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie ) &&
        cfg->SecurityCookie > (ULONG_PTR)module &&
        cfg->SecurityCookie < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
    {
        set_security_cookie( (ULONG_PTR *)cfg->SecurityCookie );
    }
#ifdef __arm64ec__
    if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer ) &&
        cfg->CHPEMetadataPointer > (ULONG_PTR)module &&
        cfg->CHPEMetadataPointer < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
    {
        update_hybrid_metadata( module, nt, (void *)cfg->CHPEMetadataPointer );
    }
#endif
}


2111
static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
2112 2113 2114 2115 2116 2117 2118 2119 2120
{
    char *base;
    IMAGE_BASE_RELOCATION *rel, *end;
    const IMAGE_DATA_DIRECTORY *relocs;
    const IMAGE_SECTION_HEADER *sec;
    INT_PTR delta;
    ULONG protect_old[96], i;

    base = (char *)nt->OptionalHeader.ImageBase;
2121
    if (module == base) return STATUS_SUCCESS;  /* nothing to do */
2122 2123 2124 2125 2126

    /* no relocations are performed on non page-aligned binaries */
    if (nt->OptionalHeader.SectionAlignment < page_size)
        return STATUS_SUCCESS;

2127 2128
    if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
        module != NtCurrentTeb()->Peb->ImageBaseAddress)
2129 2130 2131 2132
        return STATUS_SUCCESS;

    relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

2133
    if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
2134 2135 2136 2137 2138 2139
    {
        WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
              base, module );
        return STATUS_CONFLICTING_ADDRESSES;
    }

2140 2141 2142
    if (!relocs->Size) return STATUS_SUCCESS;
    if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;

2143
    if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
2144 2145
        return STATUS_INVALID_IMAGE_FORMAT;

2146
    sec = IMAGE_FIRST_SECTION( nt );
2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184
    for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
    {
        void *addr = get_rva( module, sec[i].VirtualAddress );
        SIZE_T size = sec[i].SizeOfRawData;
        NtProtectVirtualMemory( NtCurrentProcess(), &addr,
                                &size, PAGE_READWRITE, &protect_old[i] );
    }

    TRACE( "relocating from %p-%p to %p-%p\n",
           base, base + len, module, (char *)module + len );

    rel = get_rva( module, relocs->VirtualAddress );
    end = get_rva( module, relocs->VirtualAddress + relocs->Size );
    delta = (char *)module - base;

    while (rel < end - 1 && rel->SizeOfBlock)
    {
        if (rel->VirtualAddress >= len)
        {
            WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
            return STATUS_ACCESS_VIOLATION;
        }
        rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
                                         (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
                                         (USHORT *)(rel + 1), delta );
        if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
    }

    for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
    {
        void *addr = get_rva( module, sec[i].VirtualAddress );
        SIZE_T size = sec[i].SizeOfRawData;
        NtProtectVirtualMemory( NtCurrentProcess(), &addr,
                                &size, protect_old[i], &protect_old[i] );
    }

    return STATUS_SUCCESS;
}
2185

2186 2187 2188 2189 2190 2191 2192

/*************************************************************************
 *		build_module
 *
 * Build the module data for a mapped dll.
 */
static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
2193
                              const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2194
                              DWORD flags, BOOL system, WINE_MODREF **pwm )
2195
{
2196 2197 2198
    static const char builtin_signature[] = "Wine builtin DLL";
    char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1);
    BOOL is_builtin;
2199 2200 2201
    IMAGE_NT_HEADERS *nt;
    WINE_MODREF *wm;
    NTSTATUS status;
2202
    SIZE_T map_size;
2203 2204 2205

    if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT;

2206 2207
    map_size = (nt->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
    if ((status = perform_relocations( *module, nt, map_size ))) return status;
2208

2209 2210 2211
    is_builtin = ((char *)nt - signature >= sizeof(builtin_signature) &&
                  !memcmp( signature, builtin_signature, sizeof(builtin_signature) ));

2212 2213
    /* create the MODREF */

2214
    if (!(wm = alloc_module( *module, nt_name, is_builtin ))) return STATUS_NO_MEMORY;
2215 2216

    if (id) wm->id = *id;
2217
    if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE;
2218
    if (image_info->ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
2219
    wm->system = system;
2220

2221
    update_load_config( *module );
2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250

    /* fixup imports */

    if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
        ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
         nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
    {
        if (wm->ldr.Flags & LDR_COR_ILONLY)
            status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
        else
            status = fixup_imports( wm, load_path );
        if (status != STATUS_SUCCESS)
        {
            /* the module has only be inserted in the load & memory order lists */
            RemoveEntryList(&wm->ldr.InLoadOrderLinks);
            RemoveEntryList(&wm->ldr.InMemoryOrderLinks);

            /* FIXME: there are several more dangling references
             * left. Including dlls loaded by this dll before the
             * failed one. Unrolling is rather difficult with the
             * current structure and we can leave them lying
             * around with no problems, so we don't care.
             * As these might reference our wm, we don't free it.
             */
            *module = NULL;
            return status;
        }
    }

2251
    TRACE( "loaded %s %p %p\n", debugstr_us(nt_name), wm, *module );
2252

2253
    if (is_builtin)
2254 2255 2256 2257 2258 2259 2260 2261 2262
    {
        if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
    }
    else
    {
        if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
    }

    TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module,
2263
                     is_builtin ? "builtin" : "native" );
2264 2265 2266 2267 2268 2269 2270 2271 2272

    wm->ldr.LoadCount = 1;
    *pwm = wm;
    *module = NULL;
    return STATUS_SUCCESS;
}


/*************************************************************************
2273
 *		build_ntdll_module
2274
 *
2275
 * Build the module data for the initially-loaded ntdll.
2276
 */
2277
static void build_ntdll_module(void)
2278
{
2279
    UNICODE_STRING nt_name = RTL_CONSTANT_STRING( L"\\??\\C:\\windows\\system32\\ntdll.dll" );
2280
    MEMORY_BASIC_INFORMATION meminfo;
2281
    WINE_MODREF *wm;
2282
    void *module;
2283

2284 2285 2286
    NtQueryVirtualMemory( GetCurrentProcess(), LdrInitializeThunk, MemoryBasicInformation,
                          &meminfo, sizeof(meminfo), NULL );
    module = meminfo.AllocationBase;
2287
    wm = alloc_module( module, &nt_name, TRUE );
2288 2289
    assert( wm );
    wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
2290
    node_ntdll = wm->ldr.DdagNode;
2291
    if (TRACE_ON(relay)) RELAY_SetupDLL( module );
2292 2293 2294
}


2295 2296
#ifdef _WIN64
/* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
2297
static BOOL convert_to_pe64( HMODULE module, const SECTION_IMAGE_INFORMATION *info )
2298 2299 2300 2301 2302 2303 2304 2305 2306
{
    static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
                                       IMAGE_DIRECTORY_ENTRY_SECURITY,
                                       IMAGE_DIRECTORY_ENTRY_BASERELOC,
                                       IMAGE_DIRECTORY_ENTRY_DEBUG,
                                       IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
    IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
    IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
    IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2307
    IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
2308
    SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
2309
    SIZE_T size = min( nt->OptionalHeader.SizeOfHeaders, nt->OptionalHeader.SizeOfImage );
2310 2311 2312
    void *addr = module;
    ULONG i, old_prot;

2313
    if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return TRUE;  /* already 64-bit */
2314
    if (NtCurrentTeb()->WowTebOffset) return TRUE;  /* no need to convert */
2315
    if (!info->ImageContainsCode) return TRUE;  /* no need to convert */
2316

2317 2318 2319 2320 2321
    TRACE( "%p\n", module );

    if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
        return FALSE;

2322 2323 2324 2325 2326 2327
    if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
    {
        NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
        return FALSE;
    }

2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347
    memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
    memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
    hdr64.Magic               = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    hdr64.AddressOfEntryPoint = 0;
    hdr64.ImageBase           = hdr32.ImageBase;
    hdr64.SizeOfStackReserve  = hdr32.SizeOfStackReserve;
    hdr64.SizeOfStackCommit   = hdr32.SizeOfStackCommit;
    hdr64.SizeOfHeapReserve   = hdr32.SizeOfHeapReserve;
    hdr64.SizeOfHeapCommit    = hdr32.SizeOfHeapCommit;
    hdr64.LoaderFlags         = hdr32.LoaderFlags;
    hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
    for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
        hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];

    memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
    nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
    nt->OptionalHeader = hdr64;
    NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
    return TRUE;
}
2348

2349 2350 2351
/* read data out of a PE image directory */
static ULONG read_image_directory( HANDLE file, const SECTION_IMAGE_INFORMATION *info,
                                   ULONG dir, void *buffer, ULONG maxlen, USHORT *magic )
2352 2353 2354 2355 2356 2357 2358
{
    IMAGE_DOS_HEADER mz;
    IO_STATUS_BLOCK io;
    LARGE_INTEGER offset;
    IMAGE_SECTION_HEADER sec[96];
    unsigned int i, count;
    DWORD va, size;
2359 2360 2361 2362 2363
    union
    {
        IMAGE_NT_HEADERS32 nt32;
        IMAGE_NT_HEADERS64 nt64;
    } nt;
2364 2365

    offset.QuadPart = 0;
2366 2367 2368
    if (NtReadFile( file, 0, NULL, NULL, &io, &mz, sizeof(mz), &offset, NULL )) return 0;
    if (io.Information != sizeof(mz)) return 0;
    if (mz.e_magic != IMAGE_DOS_SIGNATURE) return 0;
2369
    offset.QuadPart = mz.e_lfanew;
2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391
    if (NtReadFile( file, 0, NULL, NULL, &io, &nt, sizeof(nt), &offset, NULL )) return 0;
    if (io.Information != sizeof(nt)) return 0;
    if (nt.nt32.Signature != IMAGE_NT_SIGNATURE) return 0;
    *magic = nt.nt32.OptionalHeader.Magic;
    switch (nt.nt32.OptionalHeader.Magic)
    {
    case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
        va = nt.nt32.OptionalHeader.DataDirectory[dir].VirtualAddress;
        size = nt.nt32.OptionalHeader.DataDirectory[dir].Size;
        break;
    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
        va = nt.nt64.OptionalHeader.DataDirectory[dir].VirtualAddress;
        size = nt.nt64.OptionalHeader.DataDirectory[dir].Size;
        break;
    default:
        return 0;
    }
    if (!va) return 0;
    offset.QuadPart += offsetof( IMAGE_NT_HEADERS32, OptionalHeader ) + nt.nt32.FileHeader.SizeOfOptionalHeader;
    count = min( 96, nt.nt32.FileHeader.NumberOfSections );
    if (NtReadFile( file, 0, NULL, NULL, &io, &sec, count * sizeof(*sec), &offset, NULL )) return 0;
    if (io.Information != count * sizeof(*sec)) return 0;
2392 2393 2394 2395
    for (i = 0; i < count; i++)
    {
        if (va < sec[i].VirtualAddress) continue;
        if (sec[i].Misc.VirtualSize && va - sec[i].VirtualAddress >= sec[i].Misc.VirtualSize) continue;
2396
        offset.QuadPart = sec[i].PointerToRawData + va - sec[i].VirtualAddress;
2397 2398
        if (NtReadFile( file, 0, NULL, NULL, &io, buffer, min( maxlen, size ), &offset, NULL )) return 0;
        return io.Information;
2399
    }
2400
    return 0;
2401
}
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415

/* check COM header for ILONLY flag, ignoring runtime version */
static BOOL is_com_ilonly( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
{
    USHORT magic;
    IMAGE_COR20_HEADER cor_header;
    ULONG len = read_image_directory( file, info, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
                                      &cor_header, sizeof(cor_header), &magic );

    if (len != sizeof(cor_header)) return FALSE;
    if (magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return FALSE;
    return !!(cor_header.Flags & COMIMAGE_FLAGS_ILONLY);
}

2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429
/* check LOAD_CONFIG header for CHPE metadata */
static BOOL has_chpe_metadata( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
{
    USHORT magic;
    IMAGE_LOAD_CONFIG_DIRECTORY64 loadcfg;
    ULONG len = read_image_directory( file, info, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
                                      &loadcfg, sizeof(loadcfg), &magic );

    if (!len) return FALSE;
    if (magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return FALSE;
    len = min( len, loadcfg.Size );
    if (len <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY64, CHPEMetadataPointer )) return FALSE;
    return !!loadcfg.CHPEMetadataPointer;
}
2430 2431 2432

/* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
/* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2433
static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2434
{
2435
    if (info->Machine == current_machine) return TRUE;
2436
    if (NtCurrentTeb()->WowTebOffset) return TRUE;
2437 2438 2439
    /* support ARM64EC binaries on x86-64 */
    if (current_machine == IMAGE_FILE_MACHINE_AMD64 && has_chpe_metadata( file, info )) return TRUE;
    /* support 32-bit IL-only images on 64-bit */
2440
    if (!info->ImageContainsCode) return TRUE;
2441
    if (info->ComPlusNativeReady) return TRUE;
2442
    return is_com_ilonly( file, info );
2443 2444
}

2445 2446 2447 2448 2449 2450 2451 2452 2453
#else  /* _WIN64 */

static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
{
    return (info->Machine == current_machine);
}

#endif  /* _WIN64 */

2454

2455 2456 2457 2458 2459 2460 2461 2462 2463 2464
/******************************************************************
 *		get_module_path_end
 *
 * Returns the end of the directory component of the module path.
 */
static inline const WCHAR *get_module_path_end( const WCHAR *module )
{
    const WCHAR *p;
    const WCHAR *mod_end = module;

2465 2466
    if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
    if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479
    if (mod_end == module + 2 && module[1] == ':') mod_end++;
    if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
    return mod_end;
}


/******************************************************************
 *		append_path
 *
 * Append a counted string to the load path. Helper for get_dll_load_path.
 */
static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
{
2480
    if (len == -1) len = wcslen(str);
2481 2482 2483 2484 2485 2486 2487
    if (!len) return p;
    memcpy( p, str, len * sizeof(WCHAR) );
    p[len] = ';';
    return p + len + 1;
}


2488 2489 2490
/******************************************************************
 *           get_dll_load_path
 */
2491
static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2492 2493
{
    const WCHAR *mod_end = module;
2494
    UNICODE_STRING name = RTL_CONSTANT_STRING( L"PATH" ), value;
2495
    WCHAR *p, *ret;
2496
    int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2497 2498 2499

    if (module)
    {
2500
        mod_end = get_module_path_end( module );
2501 2502 2503 2504 2505 2506 2507 2508 2509
        len += (mod_end - module) + 1;
    }

    value.Length = 0;
    value.MaximumLength = 0;
    value.Buffer = NULL;
    if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
        path_len = value.Length;

2510
    if (dll_dir) len += wcslen( dll_dir ) + 1;
2511 2512
    else len += 2;  /* current directory */
    if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2513
        return STATUS_NO_MEMORY;
2514 2515 2516

    p = append_path( p, module, mod_end - module );
    if (dll_dir) p = append_path( p, dll_dir, -1 );
2517
    else if (!safe_mode) p = append_path( p, L".", -1 );
2518
    p = append_path( p, system_path, -1 );
2519
    if (!dll_dir && safe_mode) p = append_path( p, L".", -1 );
2520 2521

    value.Buffer = p;
2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544
    value.MaximumLength = path_len;

    while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
    {
        WCHAR *new_ptr;

        /* grow the buffer and retry */
        path_len = value.Length;
        if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
        {
            RtlFreeHeap( GetProcessHeap(), 0, ret );
            return STATUS_NO_MEMORY;
        }
        value.Buffer = new_ptr + (value.Buffer - ret);
        value.MaximumLength = path_len;
        ret = new_ptr;
    }
    value.Buffer[value.Length / sizeof(WCHAR)] = 0;
    *path = ret;
    return STATUS_SUCCESS;
}


2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562
/******************************************************************
 *		get_dll_load_path_search_flags
 */
static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
{
    const WCHAR *image = NULL, *mod_end, *image_end;
    struct dll_dir_entry *dir;
    WCHAR *p, *ret;
    int len = 1;

    if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
        flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
                  LOAD_LIBRARY_SEARCH_USER_DIRS |
                  LOAD_LIBRARY_SEARCH_SYSTEM32);

    if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
    {
        DWORD type = RtlDetermineDosPathNameType_U( module );
2563
        if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579
            return STATUS_INVALID_PARAMETER;
        mod_end = get_module_path_end( module );
        len += (mod_end - module) + 1;
    }
    else module = NULL;

    if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
    {
        image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
        image_end = get_module_path_end( image );
        len += (image_end - image) + 1;
    }

    if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
    {
        LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2580
            len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2581 2582 2583
        if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
    }

2584
    if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595

    if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
    {
        if (module) p = append_path( p, module, mod_end - module );
        if (image) p = append_path( p, image, image_end - image );
        if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
        {
            LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
                p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
            p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
        }
2596
        if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607
        else
        {
            if (p > ret) p--;
            *p = 0;
        }
    }
    *path = ret;
    return STATUS_SUCCESS;
}


2608 2609 2610 2611 2612
/***********************************************************************
 *	open_dll_file
 *
 * Open a file for a new dll. Helper for find_dll_file.
 */
2613
static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2614
                               SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2615 2616 2617 2618 2619
{
    FILE_BASIC_INFORMATION info;
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK io;
    LARGE_INTEGER size;
2620
    FILE_OBJECTID_BUFFER fid;
2621
    NTSTATUS status;
2622
    HANDLE handle;
2623

2624
    if ((*pwm = find_fullname_module( nt_name ))) return STATUS_SUCCESS;
2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.ObjectName = nt_name;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
                              FILE_SHARE_READ | FILE_SHARE_DELETE,
                              FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
    {
        if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
            status != STATUS_OBJECT_NAME_NOT_FOUND &&
            !NtQueryAttributesFile( &attr, &info ))
        {
            /* if the file exists but failed to open, report the error */
            return status;
        }
        /* otherwise continue searching */
        return STATUS_DLL_NOT_FOUND;
    }

2647
    if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
2648
    {
2649 2650
        memcpy( id, fid.ObjectId, sizeof(*id) );
        if ((*pwm = find_fileid_module( id )))
2651 2652
        {
            TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2653
                   (*pwm)->ldr.DllBase, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2654 2655 2656 2657 2658 2659
            NtClose( handle );
            return STATUS_SUCCESS;
        }
    }

    size.QuadPart = 0;
2660
    status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2661 2662 2663
                              SECTION_MAP_READ | SECTION_MAP_EXECUTE,
                              NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
    if (!status)
2664
    {
2665
        NtQuerySection( *mapping, SectionImageInformation, image_info, sizeof(*image_info), NULL );
2666 2667 2668
        if (!is_valid_binary( handle, image_info ))
        {
            TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->Machine );
2669
            status = STATUS_NOT_SUPPORTED;
2670
            NtClose( *mapping );
2671
            *mapping = NULL;
2672 2673 2674
        }
    }
    NtClose( handle );
2675 2676 2677 2678
    return status;
}


2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697
/******************************************************************************
 *	find_existing_module
 *
 * Find an existing module that is the same mapping as the new module.
 */
static WINE_MODREF *find_existing_module( HMODULE module )
{
    WINE_MODREF *wm;
    LIST_ENTRY *mark, *entry;
    LDR_DATA_TABLE_ENTRY *mod;
    IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );

    if ((wm = get_modref( module ))) return wm;

    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
        mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
        if (mod->TimeDateStamp != nt->FileHeader.TimeDateStamp) continue;
2698 2699
        wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
        if (wm->CheckSum != nt->OptionalHeader.CheckSum) continue;
2700 2701 2702 2703 2704 2705 2706
        if (NtAreMappedFilesTheSame( mod->DllBase, module ) != STATUS_SUCCESS) continue;
        return CONTAINING_RECORD( mod, WINE_MODREF, ldr );
    }
    return NULL;
}


2707 2708 2709
/******************************************************************************
 *	load_native_dll  (internal)
 */
2710
static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping,
2711
                                 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2712
                                 DWORD flags, BOOL system, WINE_MODREF** pwm )
2713
{
2714 2715 2716 2717 2718
    void *module = NULL;
    SIZE_T len = 0;
    NTSTATUS status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
                                          ViewShare, 0, PAGE_EXECUTE_READ );

2719
    if (!NT_SUCCESS(status)) return status;
2720 2721 2722 2723 2724 2725 2726 2727 2728 2729

    if ((*pwm = find_existing_module( module )))  /* already loaded */
    {
        if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
        TRACE( "found %s for %s at %p, count=%d\n",
               debugstr_us(&(*pwm)->ldr.FullDllName), debugstr_us(nt_name),
               (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
        if (module != (*pwm)->ldr.DllBase) NtUnmapViewOfSection( NtCurrentProcess(), module );
        return STATUS_SUCCESS;
    }
2730
#ifdef _WIN64
2731 2732
    if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH && !convert_to_pe64( module, image_info ))
        status = STATUS_INVALID_IMAGE_FORMAT;
2733
#endif
2734
    if (NT_SUCCESS(status)) status = build_module( load_path, nt_name, &module, image_info, id, flags, system, pwm );
2735 2736
    if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module );
    return status;
2737 2738 2739
}


2740
/***********************************************************************
2741
 *           load_so_dll
2742
 */
2743
static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2744
                             DWORD flags, WINE_MODREF **pwm )
2745
{
2746 2747 2748
    void *module;
    NTSTATUS status;
    WINE_MODREF *wm;
2749
    struct load_so_dll_params params = { *nt_name, &module };
2750

2751
    TRACE( "trying %s as so lib\n", debugstr_us(nt_name) );
2752
    if ((status = WINE_UNIX_CALL( unix_load_so_dll, &params )))
2753
    {
2754
        WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
2755 2756
        if (status == STATUS_INVALID_IMAGE_FORMAT) status = STATUS_INVALID_IMAGE_NOT_MZ;
        return status;
2757
    }
2758

2759
    if ((wm = get_modref( module )))  /* already loaded */
2760
    {
2761
        TRACE( "Found %s at %p for builtin %s\n",
2762 2763
               debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
        if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2764 2765 2766
    }
    else
    {
2767 2768
        SECTION_IMAGE_INFORMATION image_info = { 0 };

2769
        if ((status = build_module( load_path, &params.nt_name, &module, &image_info, NULL, flags, FALSE, &wm )))
2770
        {
2771
            if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2772 2773
            return status;
        }
2774
        TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
2775
    }
2776
    *pwm = wm;
2777
    return STATUS_SUCCESS;
2778 2779 2780
}


2781 2782 2783 2784 2785
/*************************************************************************
 *		build_main_module
 *
 * Build the module data for the main image.
 */
2786
static WINE_MODREF *build_main_module(void)
2787 2788 2789 2790 2791 2792 2793 2794
{
    SECTION_IMAGE_INFORMATION info;
    UNICODE_STRING nt_name;
    WINE_MODREF *wm;
    NTSTATUS status;
    RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
    void *module = NtCurrentTeb()->Peb->ImageBaseAddress;

2795 2796 2797 2798
    default_load_path = params->DllPath.Buffer;
    if (!default_load_path)
        get_dll_load_path( params->ImagePathName.Buffer, NULL, dll_safe_mode, &default_load_path );

2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
    NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info), NULL );
    if (info.ImageCharacteristics & IMAGE_FILE_DLL)
    {
        MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_us(&params->ImagePathName) );
        NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
    }
#ifdef _WIN64
    if (!convert_to_pe64( module, &info ))
    {
        status = STATUS_INVALID_IMAGE_FORMAT;
        goto failed;
    }
#endif
    status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
    if (status) goto failed;
2814
    status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, FALSE, &wm );
2815
    if (status) goto failed;
2816
    RtlFreeUnicodeString( &nt_name );
2817 2818
    wm->ldr.LoadCount = -1;
    return wm;
2819
failed:
2820
    MESSAGE( "wine: failed to create main module for %s, status %lx\n",
2821 2822
             debugstr_us(&params->ImagePathName), status );
    NtTerminateProcess( GetCurrentProcess(), status );
2823
    return NULL;  /* unreached */
2824 2825 2826
}


2827 2828 2829 2830 2831 2832 2833
/***********************************************************************
 *	build_dlldata_path
 *
 * Helper for find_actctx_dll.
 */
static NTSTATUS build_dlldata_path( LPCWSTR libname, ACTCTX_SECTION_KEYED_DATA *data, LPWSTR *fullname )
{
2834 2835
    ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *dlldata = data->lpData;
    ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT *path;
2836
    char *base = data->lpSectionBase;
2837
    SIZE_T total = dlldata->TotalPathLength + (wcslen(libname) + 1) * sizeof(WCHAR);
2838 2839 2840 2841 2842
    WCHAR *p, *buffer;
    NTSTATUS status = STATUS_SUCCESS;
    ULONG i;

    if (!(p = buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
2843 2844
    path = (ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT *)(dlldata + 1);
    for (i = 0; i < dlldata->PathSegmentCount; i++)
2845
    {
2846 2847
        memcpy( p, base + path[i].Offset, path[i].Length );
        p += path[i].Length / sizeof(WCHAR);
2848
    }
2849 2850
    if (p == buffer || p[-1] == '\\') wcscpy( p, libname );
    else *p = 0;
2851

2852
    if (dlldata->Flags & ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_EXPAND)
2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867
    {
        RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), NULL, 0, &total );
        if ((*fullname = RtlAllocateHeap( GetProcessHeap(), 0, total * sizeof(WCHAR) )))
            RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), *fullname, total, NULL );
        else
            status = STATUS_NO_MEMORY;

        RtlFreeHeap( GetProcessHeap(), 0, buffer );
    }
    else *fullname = buffer;

    return status;
}


2868 2869 2870 2871 2872 2873 2874 2875 2876
/***********************************************************************
 *	find_actctx_dll
 *
 * Find the full path (if any) of the dll from the activation context.
 */
static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
{
    static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};

2877
    ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info = NULL;
2878
    ACTCTX_SECTION_KEYED_DATA data;
2879
    ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *dlldata;
2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891
    UNICODE_STRING nameW;
    NTSTATUS status;
    SIZE_T needed, size = 1024;
    WCHAR *p;

    RtlInitUnicodeString( &nameW, libname );
    data.cbSize = sizeof(data);
    status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
                                                    ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
                                                    &nameW, &data );
    if (status != STATUS_SUCCESS) return status;

2892
    if (data.ulLength < sizeof(*dlldata))
2893 2894 2895 2896 2897
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }
    dlldata = data.lpData;
2898
    if (!(dlldata->Flags & ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_OMITS_ASSEMBLY_ROOT))
2899 2900 2901 2902 2903
    {
        status = build_dlldata_path( libname, &data, fullname );
        goto done;
    }

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920
    for (;;)
    {
        if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
        {
            status = STATUS_NO_MEMORY;
            goto done;
        }
        status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
                                                       AssemblyDetailedInformationInActivationContext,
                                                       info, size, &needed );
        if (status == STATUS_SUCCESS) break;
        if (status != STATUS_BUFFER_TOO_SMALL) goto done;
        RtlFreeHeap( GetProcessHeap(), 0, info );
        size = needed;
        /* restart with larger buffer */
    }

2921
    if (!info->lpAssemblyManifestPath)
2922 2923 2924 2925 2926
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }

2927
    if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2928
    {
2929
        DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2930
        p++;
2931
        len = wcslen( p );
2932 2933
        if (!dirlen || len <= dirlen ||
            RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2934
            wcsicmp( p + dirlen, L".manifest" ))
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946
        {
            /* manifest name does not match directory name, so it's not a global
             * windows/winsxs manifest; use the manifest directory name instead */
            dirlen = p - info->lpAssemblyManifestPath;
            needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
            if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
            {
                status = STATUS_NO_MEMORY;
                goto done;
            }
            memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
            p += dirlen;
2947
            wcscpy( p, libname );
2948 2949 2950 2951
            goto done;
        }
    }

2952 2953 2954 2955 2956 2957
    if (!info->lpAssemblyDirectoryName)
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }

2958
    needed = (wcslen(windows_dir) * sizeof(WCHAR) +
2959
              sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2960 2961 2962 2963 2964 2965

    if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
    {
        status = STATUS_NO_MEMORY;
        goto done;
    }
2966
    wcscpy( p, windows_dir );
2967
    p += wcslen(p);
2968
    memcpy( p, winsxsW, sizeof(winsxsW) );
2969
    p += ARRAY_SIZE( winsxsW );
2970 2971 2972
    memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
    p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
    *p++ = '\\';
2973
    wcscpy( p, libname );
2974 2975 2976 2977 2978 2979 2980
done:
    RtlFreeHeap( GetProcessHeap(), 0, info );
    RtlReleaseActivationContext( data.hActCtx );
    return status;
}


2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004

/******************************************************************************
 *	find_apiset_dll
 */
static NTSTATUS find_apiset_dll( const WCHAR *name, WCHAR **fullname )
{
    const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
    const API_SET_NAMESPACE_ENTRY *entry;
    UNICODE_STRING str;
    ULONG len;

    if (get_apiset_entry( map, name, wcslen(name), &entry )) return STATUS_APISET_NOT_PRESENT;
    if (get_apiset_target( map, entry, NULL, &str )) return STATUS_DLL_NOT_FOUND;

    len = wcslen( system_dir ) + str.Length / sizeof(WCHAR);
    if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
        return STATUS_NO_MEMORY;
    wcscpy( *fullname, system_dir );
    memcpy( *fullname + wcslen( system_dir ), str.Buffer, str.Length );
    (*fullname)[len] = 0;
    return STATUS_SUCCESS;
}


3005 3006 3007 3008 3009 3010 3011 3012 3013 3014
/***********************************************************************
 *	get_env_var
 */
static NTSTATUS get_env_var( const WCHAR *name, SIZE_T extra, UNICODE_STRING *ret )
{
    NTSTATUS status;
    SIZE_T len, size = 1024 + extra;

    for (;;)
    {
3015
        ret->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );
3016 3017 3018 3019 3020 3021 3022 3023 3024 3025
        status = RtlQueryEnvironmentVariable( NULL, name, wcslen(name),
                                              ret->Buffer, size - extra - 1, &len );
        if (!status)
        {
            ret->Buffer[len] = 0;
            ret->Length = len * sizeof(WCHAR);
            ret->MaximumLength = size * sizeof(WCHAR);
            return status;
        }
        RtlFreeHeap( GetProcessHeap(), 0, ret->Buffer );
3026 3027 3028 3029 3030
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            ret->Buffer = NULL;
            return status;
        }
3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051
        size = len + 1 + extra;
    }
}


/***********************************************************************
 *	find_builtin_without_file
 *
 * Find a builtin dll when the corresponding file cannot be found in the prefix.
 * This is used during prefix bootstrap.
 */
static NTSTATUS find_builtin_without_file( const WCHAR *name, UNICODE_STRING *new_name,
                                           WINE_MODREF **pwm, HANDLE *mapping,
                                           SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
{
    const WCHAR *ext;
    WCHAR dllpath[32];
    DWORD i, len;
    NTSTATUS status = STATUS_DLL_NOT_FOUND;
    BOOL found_image = FALSE;

3052 3053 3054 3055 3056 3057 3058 3059
    if (contains_path( name )) return status;

    if (!is_prefix_bootstrap)
    {
        /* 16-bit files can't be loaded from the prefix */
        if (!name[1] || wcscmp( name + wcslen(name) - 2, L"16" )) return status;
    }

3060
    if (!get_env_var( L"WINEBUILDDIR", 20 + 2 * wcslen(name) + wcslen(pe_dir), new_name ))
3061
    {
3062
        len = new_name->Length;
3063 3064 3065
        RtlAppendUnicodeToString( new_name, L"\\dlls\\" );
        RtlAppendUnicodeToString( new_name, name );
        if ((ext = wcsrchr( name, '.' )) && !wcscmp( ext, L".dll" )) new_name->Length -= 4 * sizeof(WCHAR);
3066
        RtlAppendUnicodeToString( new_name, pe_dir );
3067 3068
        RtlAppendUnicodeToString( new_name, L"\\" );
        RtlAppendUnicodeToString( new_name, name );
3069 3070 3071 3072 3073 3074
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
        if (status != STATUS_DLL_NOT_FOUND) goto done;

        new_name->Length = len;
        RtlAppendUnicodeToString( new_name, L"\\programs\\" );
        RtlAppendUnicodeToString( new_name, name );
3075
        RtlAppendUnicodeToString( new_name, pe_dir );
3076 3077
        RtlAppendUnicodeToString( new_name, L"\\" );
        RtlAppendUnicodeToString( new_name, name );
3078
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
3079
        if (status != STATUS_DLL_NOT_FOUND) goto done;
3080 3081
        RtlFreeUnicodeString( new_name );
    }
3082

3083 3084 3085
    for (i = 0; ; i++)
    {
        swprintf( dllpath, ARRAY_SIZE(dllpath), L"WINEDLLDIR%u", i );
3086
        if (get_env_var( dllpath, wcslen(pe_dir) + wcslen(name) + 1, new_name )) break;
3087
        len = new_name->Length;
3088 3089 3090 3091 3092 3093
        RtlAppendUnicodeToString( new_name, pe_dir );
        RtlAppendUnicodeToString( new_name, L"\\" );
        RtlAppendUnicodeToString( new_name, name );
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
        if (status != STATUS_DLL_NOT_FOUND) goto done;
        new_name->Length = len;
3094 3095 3096
        RtlAppendUnicodeToString( new_name, L"\\" );
        RtlAppendUnicodeToString( new_name, name );
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
3097
        if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
3098
        else if (status != STATUS_DLL_NOT_FOUND) goto done;
3099 3100
        RtlFreeUnicodeString( new_name );
    }
3101
    if (found_image) status = STATUS_NOT_SUPPORTED;
3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112

done:
    RtlFreeUnicodeString( new_name );
    if (!status)
    {
        new_name->Length = (4 + wcslen(system_dir) + wcslen(name)) * sizeof(WCHAR);
        new_name->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, new_name->Length + sizeof(WCHAR) );
        wcscpy( new_name->Buffer, L"\\??\\" );
        wcscat( new_name->Buffer, system_dir );
        wcscat( new_name->Buffer, name );
    }
3113 3114 3115 3116
    return status;
}


3117 3118 3119 3120 3121
/***********************************************************************
 *	search_dll_file
 *
 * Search for dll in the specified paths.
 */
3122
static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
3123
                                 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
3124
                                 struct file_id *id )
3125 3126
{
    WCHAR *name;
3127
    BOOL found_image = FALSE;
3128
    NTSTATUS status = STATUS_DLL_NOT_FOUND;
3129 3130 3131 3132
    ULONG len;

    if (!paths) paths = default_load_path;
    len = wcslen( paths );
3133

3134 3135
    if (len < wcslen( system_dir )) len = wcslen( system_dir );
    len += wcslen( search ) + 2;
3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148

    if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
        return STATUS_NO_MEMORY;

    while (*paths)
    {
        LPCWSTR ptr = paths;

        while (*ptr && *ptr != ';') ptr++;
        len = ptr - paths;
        if (*ptr == ';') ptr++;
        memcpy( name, paths, len * sizeof(WCHAR) );
        if (len && name[len - 1] != '\\') name[len++] = '\\';
3149
        wcscpy( name + len, search );
3150 3151 3152 3153

        nt_name->Buffer = NULL;
        if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;

3154
        status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3155
        if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
3156
        else if (status != STATUS_DLL_NOT_FOUND) goto done;
3157
        RtlFreeUnicodeString( nt_name );
3158 3159 3160
        paths = ptr;
    }

3161
    if (found_image) status = STATUS_NOT_SUPPORTED;
3162 3163 3164 3165 3166 3167

done:
    RtlFreeHeap( GetProcessHeap(), 0, name );
    return status;
}

3168 3169 3170 3171 3172
/***********************************************************************
 *	find_dll_file
 *
 * Find the file (or already loaded module) for a given dll name.
 */
3173 3174 3175
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNICODE_STRING *nt_name,
                               WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
                               struct file_id *id )
3176
{
3177
    WCHAR *fullname = NULL;
3178
    NTSTATUS status;
3179
    ULONG wow64_old_value = 0;
3180

3181
    *pwm = NULL;
3182

3183
    /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
3184
    RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
3185

3186
    nt_name->Buffer = NULL;
3187 3188 3189

    if (!contains_path( libname ))
    {
3190 3191 3192 3193 3194
        status = find_apiset_dll( libname, &fullname );
        if (status == STATUS_DLL_NOT_FOUND) goto done;

        if (status) status = find_actctx_dll( libname, &fullname );

3195 3196
        if (status == STATUS_SUCCESS)
        {
3197
            TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
3198
            libname = fullname;
3199
        }
3200 3201 3202 3203 3204 3205 3206 3207 3208
        else
        {
            if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
            if ((*pwm = find_basename_module( libname )) != NULL)
            {
                status = STATUS_SUCCESS;
                goto done;
            }
        }
3209 3210
    }

3211
    if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
3212
    {
3213
        status = search_dll_file( load_path, libname, nt_name, pwm, mapping, image_info, id );
3214 3215 3216
        if (status == STATUS_DLL_NOT_FOUND)
            status = find_builtin_without_file( libname, nt_name, pwm, mapping, image_info, id );
    }
3217
    else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
3218
        status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3219

3220
    if (status == STATUS_NOT_SUPPORTED) status = STATUS_INVALID_IMAGE_FORMAT;
3221

3222
done:
3223
    RtlFreeHeap( GetProcessHeap(), 0, fullname );
3224
    if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
3225
    return status;
3226 3227 3228
}


3229
/***********************************************************************
3230
 *	load_dll  (internal)
3231 3232
 *
 * Load a PE style module according to the load order.
3233
 * The loader_section must be locked while calling this function.
3234
 */
3235
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system )
3236
{
3237
    UNICODE_STRING nt_name;
3238
    struct file_id id;
3239
    HANDLE mapping = 0;
3240
    SECTION_IMAGE_INFORMATION image_info;
3241
    NTSTATUS nts = STATUS_DLL_NOT_FOUND;
3242
    ULONG64 prev;
3243

3244
    TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
3245

3246 3247 3248 3249 3250 3251 3252 3253
    if (system && system_dll_path.Buffer)
        nts = search_dll_file( system_dll_path.Buffer, libname, &nt_name, pwm, &mapping, &image_info, &id );

    if (nts)
    {
        nts = find_dll_file( load_path, libname, &nt_name, pwm, &mapping, &image_info, &id );
        system = FALSE;
    }
3254 3255

    if (*pwm)  /* found already loaded module */
3256
    {
3257 3258
        if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;

3259
        TRACE("Found %s for %s at %p, count=%d\n",
3260
              debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
3261
              (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
3262
        RtlFreeUnicodeString( &nt_name );
3263
        return STATUS_SUCCESS;
3264 3265
    }

3266
    if (nts && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
3267

3268 3269 3270 3271 3272 3273 3274 3275 3276 3277
    if (NtCurrentTeb64())
    {
        prev = NtCurrentTeb64()->Tib.ArbitraryUserPointer;
        NtCurrentTeb64()->Tib.ArbitraryUserPointer = (ULONG_PTR)(nt_name.Buffer + 4);
    }
    else
    {
        prev = (ULONG_PTR)NtCurrentTeb()->Tib.ArbitraryUserPointer;
        NtCurrentTeb()->Tib.ArbitraryUserPointer = nt_name.Buffer + 4;
    }
3278

3279
    switch (nts)
3280
    {
3281
    case STATUS_INVALID_IMAGE_NOT_MZ:  /* not in PE format, maybe it's a .so file */
3282
        if (__wine_unixlib_handle) nts = load_so_dll( load_path, &nt_name, flags, pwm );
3283 3284 3285
        break;

    case STATUS_SUCCESS:  /* valid PE file */
3286
        nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, system, pwm );
3287
        break;
3288
    }
3289 3290 3291 3292 3293

    if (NtCurrentTeb64())
        NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev;
    else
        NtCurrentTeb()->Tib.ArbitraryUserPointer = (void *)(ULONG_PTR)prev;
3294

3295
done:
3296
    if (nts == STATUS_SUCCESS)
3297
        TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.DllBase);
3298
    else
3299
        WARN("Failed to load module %s; status=%lx\n", debugstr_w(libname), nts);
3300

3301
    if (mapping) NtClose( mapping );
3302
    RtlFreeUnicodeString( &nt_name );
3303
    return nts;
3304 3305
}

3306

3307 3308 3309 3310 3311
/***********************************************************************
 *              __wine_ctrl_routine
 */
NTSTATUS WINAPI __wine_ctrl_routine( void *arg )
{
3312
    DWORD ret = pCtrlRoutine ? pCtrlRoutine( arg ) : 0;
3313 3314 3315
    RtlExitUserThread( ret );
}

3316 3317 3318 3319 3320 3321 3322 3323 3324 3325

/***********************************************************************
 *              __wine_unix_call
 */
NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args )
{
    return __wine_unix_call_dispatcher( handle, code, args );
}


3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336
/***********************************************************************
 *           __wine_unix_spawnvp
 */
NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait )
{
    struct wine_spawnvp_params params = { (char **)argv, wait };

    return WINE_UNIX_CALL( unix_wine_spawnvp, &params );
}


3337 3338 3339 3340 3341 3342 3343 3344 3345
/***********************************************************************
 *           wine_server_call
 */
unsigned int CDECL wine_server_call( void *req_ptr )
{
    return WINE_UNIX_CALL( unix_wine_server_call, req_ptr );
}


3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357
/***********************************************************************
 *           wine_server_fd_to_handle
 */
NTSTATUS CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes,
                                         HANDLE *handle )
{
    struct wine_server_fd_to_handle_params params = { fd, access, attributes, handle };

    return WINE_UNIX_CALL( unix_wine_server_fd_to_handle, &params );
}


3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368
/***********************************************************************
 *           wine_server_handle_to_fd (NTDLL.@)
 */
NTSTATUS CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
                                         unsigned int *options )
{
    struct wine_server_handle_to_fd_params params = { handle, access, unix_fd, options };

    return WINE_UNIX_CALL( unix_wine_server_handle_to_fd, &params );
}

3369 3370 3371
/******************************************************************
 *		LdrLoadDll (NTDLL.@)
 */
3372 3373
NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
                                             const UNICODE_STRING *libname, HMODULE* hModule)
3374 3375
{
    WINE_MODREF *wm;
3376
    NTSTATUS nts;
3377
    WCHAR *dllname = append_dll_ext( libname->Buffer );
3378 3379 3380

    RtlEnterCriticalSection( &loader_section );

3381
    nts = load_dll( path_name, dllname ? dllname : libname->Buffer, flags, &wm, FALSE );
3382 3383

    if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
3384
    {
3385
        nts = process_attach( wm->ldr.DdagNode, NULL );
3386
        if (nts != STATUS_SUCCESS)
3387
        {
3388
            LdrUnloadDll(wm->ldr.DllBase);
3389 3390 3391
            wm = NULL;
        }
    }
3392
    *hModule = (wm) ? wm->ldr.DllBase : NULL;
3393

3394
    RtlLeaveCriticalSection( &loader_section );
3395
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
3396 3397 3398
    return nts;
}

3399

3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425
/******************************************************************
 *		LdrGetDllFullName (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllFullName( HMODULE module, UNICODE_STRING *name )
{
    WINE_MODREF *wm;
    NTSTATUS status;

    TRACE( "module %p, name %p.\n", module, name );

    if (!module) module = NtCurrentTeb()->Peb->ImageBaseAddress;

    RtlEnterCriticalSection( &loader_section );
    wm = get_modref( module );
    if (wm)
    {
        RtlCopyUnicodeString( name, &wm->ldr.FullDllName );
        if (name->MaximumLength < wm->ldr.FullDllName.Length + sizeof(WCHAR)) status = STATUS_BUFFER_TOO_SMALL;
        else status = STATUS_SUCCESS;
    } else status = STATUS_DLL_NOT_FOUND;
    RtlLeaveCriticalSection( &loader_section );

    return status;
}


3426
/******************************************************************
3427
 *		LdrGetDllHandleEx (NTDLL.@)
3428
 */
3429 3430
NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics,
                                           const UNICODE_STRING *name, HMODULE *base )
3431
{
3432 3433 3434 3435 3436
    static const ULONG supported_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
                                         | LDR_GET_DLL_HANDLE_EX_FLAG_PIN;
    static const ULONG valid_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
                                     | LDR_GET_DLL_HANDLE_EX_FLAG_PIN | 4;
    SECTION_IMAGE_INFORMATION image_info;
3437
    UNICODE_STRING nt_name;
3438 3439
    struct file_id id;
    NTSTATUS status;
3440
    WINE_MODREF *wm;
3441
    WCHAR *dllname;
3442
    HANDLE mapping;
3443

3444
    TRACE( "flags %#lx, load_path %p, dll_characteristics %p, name %p, base %p.\n",
3445 3446 3447 3448 3449 3450 3451 3452
            flags, load_path, dll_characteristics, name, base );

    if (flags & ~valid_flags) return STATUS_INVALID_PARAMETER;

    if ((flags & (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
                 == (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
        return STATUS_INVALID_PARAMETER;

3453
    if (flags & ~supported_flags) FIXME( "Unsupported flags %#lx.\n", flags );
3454
    if (dll_characteristics) FIXME( "dll_characteristics unsupported.\n" );
3455

3456 3457
    dllname = append_dll_ext( name->Buffer );

3458 3459
    RtlEnterCriticalSection( &loader_section );

3460 3461
    status = find_dll_file( load_path, dllname ? dllname : name->Buffer,
                            &nt_name, &wm, &mapping, &image_info, &id );
3462

3463
    if (wm) *base = wm->ldr.DllBase;
3464
    else
3465
    {
3466
        if (status == STATUS_SUCCESS) NtClose( mapping );
3467
        status = STATUS_DLL_NOT_FOUND;
3468
    }
3469
    RtlFreeUnicodeString( &nt_name );
3470

3471 3472 3473 3474 3475 3476 3477 3478
    if (!status)
    {
        if (flags & LDR_GET_DLL_HANDLE_EX_FLAG_PIN)
            LdrAddRefDll( LDR_ADDREF_DLL_PIN, *base );
        else if (!(flags & LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
            LdrAddRefDll( 0, *base );
    }

3479
    RtlLeaveCriticalSection( &loader_section );
3480
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
3481 3482 3483 3484 3485
    TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
    return status;
}


3486 3487 3488 3489 3490 3491 3492 3493 3494
/******************************************************************
 *		LdrGetDllHandle (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
{
    return LdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, load_path, NULL, name, base );
}


3495 3496 3497 3498 3499 3500 3501 3502
/******************************************************************
 *		LdrAddRefDll (NTDLL.@)
 */
NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
{
    NTSTATUS ret = STATUS_SUCCESS;
    WINE_MODREF *wm;

3503
    if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %lx not implemented\n", module, flags );
3504 3505 3506 3507 3508

    RtlEnterCriticalSection( &loader_section );

    if ((wm = get_modref( module )))
    {
3509 3510 3511 3512
        if (flags & LDR_ADDREF_DLL_PIN)
            wm->ldr.LoadCount = -1;
        else
            if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3513 3514 3515 3516 3517 3518 3519 3520 3521
        TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
    }
    else ret = STATUS_INVALID_PARAMETER;

    RtlLeaveCriticalSection( &loader_section );
    return ret;
}


3522 3523 3524 3525 3526 3527
/***********************************************************************
 *           LdrProcessRelocationBlock  (NTDLL.@)
 *
 * Apply relocations to a given page of a mapped PE image.
 */
IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3528
                                                          USHORT *relocs, INT_PTR delta )
3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546
{
    while (count--)
    {
        USHORT offset = *relocs & 0xfff;
        int type = *relocs >> 12;
        switch(type)
        {
        case IMAGE_REL_BASED_ABSOLUTE:
            break;
        case IMAGE_REL_BASED_HIGH:
            *(short *)((char *)page + offset) += HIWORD(delta);
            break;
        case IMAGE_REL_BASED_LOW:
            *(short *)((char *)page + offset) += LOWORD(delta);
            break;
        case IMAGE_REL_BASED_HIGHLOW:
            *(int *)((char *)page + offset) += delta;
            break;
3547
#ifdef _WIN64
3548 3549 3550
        case IMAGE_REL_BASED_DIR64:
            *(INT_PTR *)((char *)page + offset) += delta;
            break;
3551 3552 3553
#elif defined(__arm__)
        case IMAGE_REL_BASED_THUMB_MOV32:
        {
3554
            UINT *inst = (UINT *)((char *)page + offset);
3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571
            WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
                      ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
            WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
                      ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
            DWORD imm = MAKELONG( lo, hi ) + delta;

            lo = LOWORD( imm );
            hi = HIWORD( imm );

            if ((inst[0] & 0x8000fbf0) != 0x0000f240 || (inst[1] & 0x8000fbf0) != 0x0000f2c0)
                ERR("wrong Thumb2 instruction @%p %08x:%08x, expected MOVW/MOVT\n",
                    inst, inst[0], inst[1] );

            inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
                                               ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
            inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
                                               ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
3572
            break;
3573
        }
3574
#endif
3575 3576 3577 3578 3579 3580 3581 3582 3583 3584
        default:
            FIXME("Unknown/unsupported fixup type %x.\n", type);
            return NULL;
        }
        relocs++;
    }
    return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
}


3585 3586 3587 3588
/******************************************************************
 *		LdrQueryProcessModuleInformation
 *
 */
3589
NTSTATUS WINAPI LdrQueryProcessModuleInformation(RTL_PROCESS_MODULES *smi,
3590 3591
                                                 ULONG buf_size, ULONG* req_size)
{
3592
    RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[0];
3593 3594 3595 3596
    ULONG               size = sizeof(ULONG);
    NTSTATUS            nts = STATUS_SUCCESS;
    ANSI_STRING         str;
    char*               ptr;
3597
    PLIST_ENTRY         mark, entry;
3598
    LDR_DATA_TABLE_ENTRY *mod;
3599
    WORD id = 0;
3600 3601 3602 3603

    smi->ModulesCount = 0;

    RtlEnterCriticalSection( &loader_section );
3604 3605
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3606
    {
3607
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3608 3609 3610
        size += sizeof(*sm);
        if (size <= buf_size)
        {
3611
            sm->Section = 0; /* FIXME */
3612 3613
            sm->MappedBaseAddress = mod->DllBase;
            sm->ImageBaseAddress = mod->DllBase;
3614 3615
            sm->ImageSize = mod->SizeOfImage;
            sm->Flags = mod->Flags;
3616 3617 3618
            sm->LoadOrderIndex = id++;
            sm->InitOrderIndex = 0; /* FIXME */
            sm->LoadCount = mod->LoadCount;
3619 3620
            str.Length = 0;
            str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
Mike McCormack's avatar
Mike McCormack committed
3621
            str.Buffer = (char*)sm->Name;
3622
            RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
Mike McCormack's avatar
Mike McCormack committed
3623 3624
            ptr = strrchr(str.Buffer, '\\');
            sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637

            smi->ModulesCount++;
            sm++;
        }
        else nts = STATUS_INFO_LENGTH_MISMATCH;
    }
    RtlLeaveCriticalSection( &loader_section );

    if (req_size) *req_size = size;

    return nts;
}

3638

3639
static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, LONG *value )
3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655
{
    NTSTATUS status;
    UNICODE_STRING str;
    ULONG size;
    WCHAR buffer[64];
    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;

    RtlInitUnicodeString( &str, name );

    size = sizeof(buffer) - sizeof(WCHAR);
    if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
        return status;

    if (info->Type != REG_DWORD)
    {
        buffer[size / sizeof(WCHAR)] = 0;
3656
        *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693
    }
    else memcpy( value, info->Data, sizeof(*value) );
    return status;
}

static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
                                     void *data, ULONG in_size, ULONG *out_size )
{
    NTSTATUS status;
    UNICODE_STRING str;
    ULONG size;
    char *buffer;
    KEY_VALUE_PARTIAL_INFORMATION *info;
    static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );

    RtlInitUnicodeString( &str, name );

    size = info_size + in_size;
    if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
    info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
    status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
    if (!status || status == STATUS_BUFFER_OVERFLOW)
    {
        if (out_size) *out_size = info->DataLength;
        if (data && !status) memcpy( data, info->Data, info->DataLength );
    }
    RtlFreeHeap( GetProcessHeap(), 0, buffer );
    return status;
}


/******************************************************************
 *		LdrQueryImageFileExecutionOptions  (NTDLL.@)
 */
NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
                                                   void *data, ULONG in_size, ULONG *out_size )
{
3694
    static const WCHAR optionsW[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\";
3695
    WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING name_str;
    HANDLE hkey;
    NTSTATUS status;
    ULONG len;
    WCHAR *p;

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.ObjectName = &name_str;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

3710 3711
    p = key->Buffer + key->Length / sizeof(WCHAR);
    while (p > key->Buffer && p[-1] != '\\') p--;
3712 3713
    len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
    name_str.Buffer = path;
3714
    name_str.Length = sizeof(optionsW) - sizeof(WCHAR) + len;
3715 3716
    name_str.MaximumLength = name_str.Length;
    memcpy( path, optionsW, sizeof(optionsW) );
3717
    memcpy( path + ARRAY_SIZE( optionsW ) - 1, p, len );
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732
    if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;

    if (type == REG_DWORD)
    {
        if (out_size) *out_size = sizeof(ULONG);
        if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
        else status = STATUS_BUFFER_OVERFLOW;
    }
    else status = query_string_option( hkey, value, type, data, in_size, out_size );

    NtClose( hkey );
    return status;
}


3733 3734 3735 3736 3737 3738 3739 3740
/******************************************************************
 *		RtlDllShutdownInProgress  (NTDLL.@)
 */
BOOLEAN WINAPI RtlDllShutdownInProgress(void)
{
    return process_detaching;
}

3741 3742 3743 3744
/****************************************************************************
 *              LdrResolveDelayLoadedAPI   (NTDLL.@)
 */
void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3745 3746
                                       PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
                                       PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757
                                       IMAGE_THUNK_DATA* addr, ULONG flags )
{
    IMAGE_THUNK_DATA *pIAT, *pINT;
    DELAYLOAD_INFO delayinfo;
    UNICODE_STRING mod;
    const CHAR* name;
    HMODULE *phmod;
    NTSTATUS nts;
    FARPROC fp;
    DWORD id;

3758
    TRACE( "(%p, %p, %p, %p, %p, 0x%08lx)\n", base, desc, dllhook, syshook, addr, flags );
3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803

    phmod = get_rva(base, desc->ModuleHandleRVA);
    pIAT = get_rva(base, desc->ImportAddressTableRVA);
    pINT = get_rva(base, desc->ImportNameTableRVA);
    name = get_rva(base, desc->DllNameRVA);
    id = addr - pIAT;

    if (!*phmod)
    {
        if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
        {
            nts = STATUS_NO_MEMORY;
            goto fail;
        }
        nts = LdrLoadDll(NULL, 0, &mod, phmod);
        RtlFreeUnicodeString(&mod);
        if (nts) goto fail;
    }

    if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
        nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
    else
    {
        const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
        ANSI_STRING fnc;

        RtlInitAnsiString(&fnc, (char*)iibn->Name);
        nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
    }
    if (!nts)
    {
        pIAT[id].u1.Function = (ULONG_PTR)fp;
        return fp;
    }

fail:
    delayinfo.Size = sizeof(delayinfo);
    delayinfo.DelayloadDescriptor = desc;
    delayinfo.ThunkAddress = addr;
    delayinfo.TargetDllName = name;
    delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
    delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
    delayinfo.TargetModuleBase = *phmod;
    delayinfo.Unused = NULL;
    delayinfo.LastError = nts;
3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817

    if (dllhook)
        return dllhook(4, &delayinfo);

    if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
    {
        DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
        return syshook(name, (const char *)ord);
    }
    else
    {
        const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
        return syshook(name, (const char *)iibn->Name);
    }
3818
}
3819

3820 3821 3822 3823
/******************************************************************
 *		LdrShutdownProcess (NTDLL.@)
 *
 */
3824
void WINAPI LdrShutdownProcess(void)
3825
{
3826 3827
    BOOL detaching = process_detaching;

3828
    TRACE("()\n");
3829

3830 3831
    process_detaching = TRUE;
    if (!detaching)
3832 3833
        RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );

3834
    process_detach();
3835 3836
}

3837 3838 3839 3840 3841 3842 3843 3844 3845 3846

/******************************************************************
 *		RtlExitUserProcess (NTDLL.@)
 */
void WINAPI RtlExitUserProcess( DWORD status )
{
    RtlEnterCriticalSection( &loader_section );
    RtlAcquirePebLock();
    NtTerminateProcess( 0, status );
    LdrShutdownProcess();
3847
    for (;;) NtTerminateProcess( GetCurrentProcess(), status );
3848 3849
}

3850 3851 3852 3853
/******************************************************************
 *		LdrShutdownThread (NTDLL.@)
 *
 */
3854
void WINAPI LdrShutdownThread(void)
3855
{
3856
    PLIST_ENTRY mark, entry;
3857
    LDR_DATA_TABLE_ENTRY *mod;
3858
    WINE_MODREF *wm;
3859 3860
    UINT i;
    void **pointers;
3861

3862 3863 3864
    TRACE("()\n");

    /* don't do any detach calls if process is exiting */
3865
    if (process_detaching) return;
3866

3867 3868
    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );

3869
    RtlEnterCriticalSection( &loader_section );
3870
    wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3871

3872 3873
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3874
    {
3875
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
3876
                                InInitializationOrderLinks);
3877
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3878
            continue;
3879
        if ( mod->Flags & LDR_NO_DLL_CALLS )
3880 3881
            continue;

3882 3883
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
                        DLL_THREAD_DETACH, NULL );
3884 3885
    }

3886
    if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
3887

3888
    RtlAcquirePebLock();
3889
    if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3890 3891 3892 3893 3894
    if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
    {
        for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
        RtlFreeHeap( GetProcessHeap(), 0, pointers );
    }
3895
    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
3896
    NtCurrentTeb()->FlsSlots = NULL;
3897
    RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3898 3899 3900
    NtCurrentTeb()->TlsExpansionSlots = NULL;
    RtlReleasePebLock();

3901
    RtlLeaveCriticalSection( &loader_section );
3902 3903
    /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */
    if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] );
3904
    RtlFreeThreadActivationContextStack();
3905 3906

    heap_thread_detach();
3907 3908
}

3909 3910 3911 3912 3913 3914 3915

/***********************************************************************
 *           free_modref
 *
 */
static void free_modref( WINE_MODREF *wm )
{
3916 3917 3918
    SINGLE_LIST_ENTRY *entry;
    LDR_DEPENDENCY *dep;

3919
    RemoveEntryList(&wm->ldr.InLoadOrderLinks);
3920
    RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
3921 3922
    if (wm->ldr.InInitializationOrderLinks.Flink)
        RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
3923

3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937
    while ((entry = wm->ldr.DdagNode->Dependencies.Tail))
    {
        dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
        assert( dep->dependency_from == wm->ldr.DdagNode );
        remove_module_dependency( dep );
    }

    while ((entry = wm->ldr.DdagNode->IncomingDependencies.Tail))
    {
        dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_from_entry );
        assert( dep->dependency_to == wm->ldr.DdagNode );
        remove_module_dependency( dep );
    }

3938 3939 3940 3941
    RemoveEntryList(&wm->ldr.NodeModuleLink);
    if (IsListEmpty(&wm->ldr.DdagNode->Modules))
        RtlFreeHeap( GetProcessHeap(), 0, wm->ldr.DdagNode );

3942 3943 3944 3945 3946 3947
    TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
    if (!TRACE_ON(module))
        TRACE_(loaddll)("Unloaded module %s : %s\n",
                        debugstr_w(wm->ldr.FullDllName.Buffer),
                        (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );

3948
    free_tls_slot( &wm->ldr );
3949
    RtlReleaseActivationContext( wm->ldr.ActivationContext );
3950
    NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
3951 3952 3953 3954 3955
    if (cached_modref == wm) cached_modref = NULL;
    RtlFreeUnicodeString( &wm->ldr.FullDllName );
    RtlFreeHeap( GetProcessHeap(), 0, wm );
}

3956 3957 3958 3959 3960
/***********************************************************************
 *           MODULE_FlushModrefs
 *
 * Remove all unused modrefs and call the internal unloading routines
 * for the library type.
3961 3962
 *
 * The loader_section must be locked while calling this function.
3963 3964 3965
 */
static void MODULE_FlushModrefs(void)
{
3966
    PLIST_ENTRY mark, entry, prev;
3967
    LDR_DATA_TABLE_ENTRY *mod;
3968
    WINE_MODREF*wm;
3969

3970 3971
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = prev)
3972
    {
3973
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
3974 3975
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
3976 3977
        if (!mod->LoadCount) free_modref( wm );
    }
3978

3979 3980 3981 3982
    /* check load order list too for modules that haven't been initialized yet */
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = prev)
    {
3983
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3984 3985 3986
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
        if (!mod->LoadCount) free_modref( wm );
3987 3988 3989 3990 3991 3992
    }
}

/***********************************************************************
 *           MODULE_DecRefCount
 *
3993
 * The loader_section must be locked while calling this function.
3994
 */
3995
static NTSTATUS MODULE_DecRefCount( LDR_DDAG_NODE *node, void *context )
3996
{
3997 3998 3999 4000 4001
    LDR_DATA_TABLE_ENTRY *mod;
    WINE_MODREF *wm;

    mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
    wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
4002

4003
    if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
4004
        return STATUS_SUCCESS;
4005

4006
    if ( wm->ldr.LoadCount <= 0 )
4007
        return STATUS_SUCCESS;
4008

4009
    --wm->ldr.LoadCount;
4010
    TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
4011

4012
    if ( wm->ldr.LoadCount == 0 )
4013
    {
4014
        wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
4015
        walk_node_dependencies( node, context, MODULE_DecRefCount );
4016
        wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
4017
        module_push_unload_trace( wm );
4018
    }
4019
    return STATUS_SUCCESS;
4020 4021 4022 4023 4024 4025 4026 4027 4028
}

/******************************************************************
 *		LdrUnloadDll (NTDLL.@)
 *
 *
 */
NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
{
4029
    WINE_MODREF *wm;
4030 4031
    NTSTATUS retv = STATUS_SUCCESS;

4032 4033
    if (process_detaching) return retv;

4034 4035 4036 4037
    TRACE("(%p)\n", hModule);

    RtlEnterCriticalSection( &loader_section );

4038 4039
    free_lib_count++;
    if ((wm = get_modref( hModule )) != NULL)
4040
    {
4041
        TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
4042

4043
        /* Recursively decrement reference counts */
4044
        MODULE_DecRefCount( wm->ldr.DdagNode, NULL );
4045

4046 4047 4048 4049 4050
        /* Call process detach notifications */
        if ( free_lib_count <= 1 )
        {
            process_detach();
            MODULE_FlushModrefs();
4051 4052
        }

4053
        TRACE("END\n");
4054
    }
4055 4056 4057 4058
    else
        retv = STATUS_DLL_NOT_FOUND;

    free_lib_count--;
4059 4060 4061 4062 4063 4064

    RtlLeaveCriticalSection( &loader_section );

    return retv;
}

4065 4066 4067 4068 4069
/***********************************************************************
 *           RtlImageNtHeader   (NTDLL.@)
 */
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
{
4070
    IMAGE_NT_HEADERS *ret;
4071

4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082
    __TRY
    {
        IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;

        ret = NULL;
        if (dos->e_magic == IMAGE_DOS_SIGNATURE)
        {
            ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
            if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
        }
    }
4083
    __EXCEPT_PAGE_FAULT
4084
    {
4085
        return NULL;
4086
    }
4087
    __ENDTRY
4088 4089 4090
    return ret;
}

4091 4092 4093 4094 4095 4096
/***********************************************************************
 *           load_global_options
 */
static void load_global_options(void)
{
    OBJECT_ATTRIBUTES attr;
4097 4098 4099 4100
    UNICODE_STRING bootstrap_mode_str = RTL_CONSTANT_STRING( L"WINEBOOTSTRAPMODE" );
    UNICODE_STRING session_manager_str =
        RTL_CONSTANT_STRING( L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
    UNICODE_STRING val_str;
4101 4102
    HANDLE hkey;

4103
    val_str.MaximumLength = 0;
4104 4105
    is_prefix_bootstrap =
        RtlQueryEnvironmentVariable_U( NULL, &bootstrap_mode_str, &val_str ) != STATUS_VARIABLE_NOT_FOUND;
4106

4107 4108
    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
4109
    attr.ObjectName = &session_manager_str;
4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

    if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
    {
        query_dword_option( hkey, L"SafeProcessSearchMode", &path_safe_mode );
        query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode );
        NtClose( hkey );
    }
}

4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135
static BOOL needs_elevation(void)
{
    ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION run_level;

    if (!RtlQueryInformationActivationContext( 0, NULL, NULL, RunlevelInformationInActivationContext,
                                               &run_level, sizeof(run_level), NULL ))
    {
        TRACE( "image requested run level %#x\n", run_level.RunLevel );
        if (run_level.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE
                || run_level.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN)
            return TRUE;
    }
    return FALSE;
}
4136

4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149
static void elevate_token(void)
{
    PROCESS_ACCESS_TOKEN token;
    TOKEN_ELEVATION_TYPE type;
    TOKEN_LINKED_TOKEN linked;

    NtQueryInformationToken( GetCurrentThreadEffectiveToken(),
                             TokenElevationType, &type, sizeof(type), NULL );

    if (type == TokenElevationTypeFull) return;

    NtQueryInformationToken( GetCurrentThreadEffectiveToken(),
                             TokenLinkedToken, &linked, sizeof(linked), NULL );
4150
    NtDuplicateToken( linked.LinkedToken, 0, NULL, FALSE, TokenPrimary, &token.Token );
4151 4152 4153

    token.Thread = NULL;
    NtSetInformationProcess( GetCurrentProcess(), ProcessAccessToken, &token, sizeof(token) );
4154
    NtClose( token.Token );
4155 4156
    NtClose( linked.LinkedToken );
}
4157 4158 4159

#ifdef _WIN64

4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173
static void build_wow64_main_module(void)
{
    UNICODE_STRING nt_name;
    WINE_MODREF *wm;
    RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
    void *module = NtCurrentTeb()->Peb->ImageBaseAddress;

    RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
    wm = alloc_module( module, &nt_name, FALSE );
    assert( wm );
    wm->ldr.LoadCount = -1;
    RtlFreeUnicodeString( &nt_name );
}

4174 4175
static void (WINAPI *pWow64LdrpInitialize)( CONTEXT *ctx );

4176 4177
void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ) = NULL;

4178 4179 4180 4181 4182 4183 4184 4185 4186
static void init_wow64( CONTEXT *context )
{
    if (!imports_fixup_done)
    {
        HMODULE wow64;
        WINE_MODREF *wm;
        NTSTATUS status;
        static const WCHAR wow64_path[] = L"C:\\windows\\system32\\wow64.dll";

4187 4188 4189
        build_wow64_main_module();
        build_ntdll_module();

4190
        if ((status = load_dll( NULL, wow64_path, 0, &wm, FALSE )))
4191
        {
4192
            ERR( "could not load %s, status %lx\n", debugstr_w(wow64_path), status );
4193 4194 4195 4196 4197 4198 4199
            NtTerminateProcess( GetCurrentProcess(), status );
        }
        wow64 = wm->ldr.DllBase;
#define GET_PTR(name) \
        if (!(p ## name = RtlFindExportedRoutineByName( wow64, #name ))) ERR( "failed to load %s\n", #name )

        GET_PTR( Wow64LdrpInitialize );
4200
        GET_PTR( Wow64PrepareForException );
4201 4202 4203 4204
#undef GET_PTR
        imports_fixup_done = TRUE;
    }

4205 4206 4207 4208
    RtlAcquirePebLock();
    InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
    RtlReleasePebLock();

4209 4210 4211 4212 4213 4214 4215
    RtlLeaveCriticalSection( &loader_section );
    pWow64LdrpInitialize( context );
}


#else

4216 4217 4218 4219 4220 4221
void *Wow64Transition = NULL;

static void map_wow64cpu(void)
{
    SIZE_T size = 0;
    OBJECT_ATTRIBUTES attr;
4222
    UNICODE_STRING string = RTL_CONSTANT_STRING( L"\\??\\C:\\windows\\sysnative\\wow64cpu.dll" );
4223 4224 4225 4226 4227 4228 4229 4230
    HANDLE file, section;
    IO_STATUS_BLOCK io;
    NTSTATUS status;

    InitializeObjectAttributes( &attr, &string, 0, NULL, NULL );
    if ((status = NtOpenFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ,
                              FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
    {
4231
        WARN("failed to open wow64cpu, status %#lx\n", status);
4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244
        return;
    }
    if (!NtCreateSection( &section, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
                          SECTION_MAP_READ | SECTION_MAP_EXECUTE,
                          NULL, NULL, PAGE_EXECUTE_READ, SEC_COMMIT, file ))
    {
        NtMapViewOfSection( section, NtCurrentProcess(), &Wow64Transition, 0,
                            0, NULL, &size, ViewShare, 0, PAGE_EXECUTE_READ );
        NtClose( section );
    }
    NtClose( file );
}

4245
static void init_wow64( CONTEXT *context )
4246 4247
{
    PEB *peb = NtCurrentTeb()->Peb;
4248 4249 4250
    PEB64 *peb64 = UlongToPtr( NtCurrentTeb64()->Peb );

    if (Wow64Transition) return;  /* already initialized */
4251 4252 4253 4254 4255 4256

    peb64->OSMajorVersion   = peb->OSMajorVersion;
    peb64->OSMinorVersion   = peb->OSMinorVersion;
    peb64->OSBuildNumber    = peb->OSBuildNumber;
    peb64->OSPlatformId     = peb->OSPlatformId;

4257 4258 4259 4260 4261 4262
#define SET_INIT_BLOCK(func) LdrSystemDllInitBlock.p ## func = PtrToUlong( &func )
    SET_INIT_BLOCK( KiUserApcDispatcher );
    SET_INIT_BLOCK( KiUserExceptionDispatcher );
    SET_INIT_BLOCK( LdrInitializeThunk );
    SET_INIT_BLOCK( LdrSystemDllInitBlock );
    SET_INIT_BLOCK( RtlUserThreadStart );
4263
    SET_INIT_BLOCK( KiUserCallbackDispatcher );
4264 4265 4266 4267 4268
    /* SET_INIT_BLOCK( RtlpQueryProcessDebugInformationRemote ); */
    /* SET_INIT_BLOCK( RtlpFreezeTimeBias ); */
    /* LdrSystemDllInitBlock.ntdll_handle */
#undef SET_INIT_BLOCK

4269 4270 4271 4272 4273
    map_wow64cpu();
}
#endif


4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284
/* release some address space once dlls are loaded*/
static void release_address_space(void)
{
#ifndef _WIN64
    void *addr = (void *)1;
    SIZE_T size = 0;

    NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
#endif
}

4285
/******************************************************************
4286
 *		loader_init
4287
 *
4288 4289
 * Attach to all the loaded dlls.
 * If this is the first time, perform the full process initialization.
4290
 */
4291
void loader_init( CONTEXT *context, void **entry )
4292
{
4293
    static int attach_done;
4294
    NTSTATUS status;
4295
    ULONG_PTR cookie, port = 0;
4296
    WINE_MODREF *wm;
4297

4298
    if (process_detaching) NtTerminateThread( GetCurrentThread(), 0 );
4299

4300
    RtlEnterCriticalSection( &loader_section );
4301 4302

    if (!imports_fixup_done)
4303
    {
4304
        ANSI_STRING ctrl_routine = RTL_CONSTANT_STRING( "CtrlRoutine" );
4305
        WINE_MODREF *kernel32;
4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317
        PEB *peb = NtCurrentTeb()->Peb;

        peb->LdrData            = &ldr;
        peb->FastPebLock        = &peb_lock;
        peb->TlsBitmap          = &tls_bitmap;
        peb->TlsExpansionBitmap = &tls_expansion_bitmap;
        peb->LoaderLock         = &loader_section;
        peb->ProcessHeap        = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );

        RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
        RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
                             sizeof(peb->TlsExpansionBitmapBits) * 8 );
4318 4319
        /* TLS index 0 is always reserved, and wow64 reserves extra TLS entries */
        RtlSetBits( peb->TlsBitmap, 0, NtCurrentTeb()->WowTebOffset ? WOW64_TLS_MAX_NUMBER : 1 );
4320
        RtlSetBits( peb->TlsBitmap, NTDLL_TLS_ERRNO, 1 );
4321

4322 4323 4324
        init_user_process_params();
        load_global_options();
        version_init();
4325

4326
        if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4327

4328
        wm = build_main_module();
4329
        build_ntdll_module();
4330

4331
        if ((status = load_dll( NULL, L"kernel32.dll", 0, &kernel32, FALSE )) != STATUS_SUCCESS)
4332
        {
4333
            MESSAGE( "wine: could not load kernel32.dll, status %lx\n", status );
4334 4335
            NtTerminateProcess( GetCurrentProcess(), status );
        }
4336
        node_kernel32 = kernel32->ldr.DdagNode;
4337
        pBaseThreadInitThunk = RtlFindExportedRoutineByName( kernel32->ldr.DllBase, "BaseThreadInitThunk" );
4338
        LdrGetProcedureAddress( kernel32->ldr.DllBase, &ctrl_routine, 0, (void **)&pCtrlRoutine );
4339

4340
        actctx_init();
4341
        locale_init();
4342 4343
        if (needs_elevation())
            elevate_token();
4344
        get_env_var( L"WINESYSTEMDLLPATH", 0, &system_dll_path );
4345
        if (wm->ldr.Flags & LDR_COR_ILONLY)
4346
            status = fixup_imports_ilonly( wm, NULL, entry );
4347
        else
4348
            status = fixup_imports( wm, NULL );
4349 4350

        if (status)
4351
        {
4352
            ERR( "Importing dlls for %s failed, status %lx\n",
4353 4354 4355
                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }
4356
        imports_fixup_done = TRUE;
4357
    }
4358
    else wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
4359

4360 4361 4362 4363
#ifdef _WIN64
    if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
#endif

4364 4365 4366 4367
    RtlAcquirePebLock();
    InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
    RtlReleasePebLock();

4368 4369
    NtCurrentTeb()->FlsSlots = fls_alloc_data();

4370
    if (!attach_done)  /* first time around */
4371
    {
4372
        attach_done = 1;
4373 4374
        if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
        {
4375
            ERR( "TLS init  failed when loading %s, status %lx\n",
4376 4377 4378
                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }
4379
        wm->ldr.Flags |= LDR_PROCESS_ATTACHED;  /* don't try to attach again */
4380 4381 4382
        if (wm->ldr.ActivationContext)
            RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );

4383 4384 4385
        if ((status = process_attach( node_ntdll, context ))
             || (status = process_attach( node_kernel32, context )))
        {
4386
            ERR( "Initializing system dll for %s failed, status %lx\n",
4387 4388 4389 4390
                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }

4391
        if ((status = walk_node_dependencies( wm->ldr.DdagNode, context, process_attach )))
4392
        {
4393 4394 4395
            if (last_failed_modref)
                ERR( "%s failed to initialize, aborting\n",
                     debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
4396
            ERR( "Initializing dlls for %s failed, status %lx\n",
4397 4398
                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
            NtTerminateProcess( GetCurrentProcess(), status );
4399
        }
4400
        release_address_space();
4401
        if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
4402
        if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
4403 4404 4405

        NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort, &port, sizeof(port), NULL );
        if (port) process_breakpoint();
4406 4407 4408
    }
    else
    {
4409 4410
        if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
            NtTerminateThread( GetCurrentThread(), status );
4411
        thread_attach();
4412
        if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
4413 4414
    }

4415 4416 4417 4418
    RtlLeaveCriticalSection( &loader_section );
}


4419 4420 4421 4422 4423 4424 4425 4426
/***********************************************************************
 *           RtlImageDirectoryEntryToData   (NTDLL.@)
 */
PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
{
    const IMAGE_NT_HEADERS *nt;
    DWORD addr;

4427 4428
    if ((ULONG_PTR)module & 1) image = FALSE;  /* mapped as data file */
    module = (HMODULE)((ULONG_PTR)module & ~3);
4429
    if (!(nt = RtlImageNtHeader( module ))) return NULL;
4430 4431
    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
    {
4432
        const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
4433 4434 4435 4436 4437 4438 4439 4440

        if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
        if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
        *size = nt64->OptionalHeader.DataDirectory[dir].Size;
        if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
    }
    else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
    {
4441
        const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
4442 4443 4444 4445 4446 4447 4448

        if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
        if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
        *size = nt32->OptionalHeader.DataDirectory[dir].Size;
        if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
    }
    else return NULL;
4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461

    /* not mapped as image, need to find the section containing the virtual address */
    return RtlImageRvaToVa( nt, module, addr, NULL );
}


/***********************************************************************
 *           RtlImageRvaToSection   (NTDLL.@)
 */
PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
                                                   HMODULE module, DWORD rva )
{
    int i;
4462
    const IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
Eric Pouech's avatar
Eric Pouech committed
4463

4464 4465 4466
    for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
    {
        if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
Eric Pouech's avatar
Eric Pouech committed
4467
            return (PIMAGE_SECTION_HEADER)sec;
4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491
    }
    return NULL;
}


/***********************************************************************
 *           RtlImageRvaToVa   (NTDLL.@)
 */
PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
                              DWORD rva, IMAGE_SECTION_HEADER **section )
{
    IMAGE_SECTION_HEADER *sec;

    if (section && *section)  /* try this section first */
    {
        sec = *section;
        if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
            goto found;
    }
    if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
 found:
    if (section) *section = sec;
    return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
}
4492 4493


4494 4495 4496 4497 4498 4499 4500 4501 4502
/***********************************************************************
 *           RtlAddressInSectionTable   (NTDLL.@)
 */
PVOID WINAPI RtlAddressInSectionTable( const IMAGE_NT_HEADERS *nt, HMODULE module,
                                       DWORD rva )
{
    return RtlImageRvaToVa( nt, module, rva, NULL );
}

4503 4504 4505 4506 4507
/***********************************************************************
 *           RtlPcToFileHeader   (NTDLL.@)
 */
PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
{
4508
    LDR_DATA_TABLE_ENTRY *module;
4509 4510 4511
    PVOID ret = NULL;

    RtlEnterCriticalSection( &loader_section );
4512
    if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase;
4513 4514 4515 4516 4517 4518
    RtlLeaveCriticalSection( &loader_section );
    *address = ret;
    return ret;
}


4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557
/****************************************************************************
 *		LdrGetDllDirectory  (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
{
    NTSTATUS status = STATUS_SUCCESS;

    RtlEnterCriticalSection( &dlldir_section );
    dir->Length = dll_directory.Length + sizeof(WCHAR);
    if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
    else
    {
        status = STATUS_BUFFER_TOO_SMALL;
        if (dir->MaximumLength) dir->Buffer[0] = 0;
    }
    RtlLeaveCriticalSection( &dlldir_section );
    return status;
}


/****************************************************************************
 *		LdrSetDllDirectory  (NTDLL.@)
 */
NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
{
    NTSTATUS status = STATUS_SUCCESS;
    UNICODE_STRING new;

    if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
    else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;

    RtlEnterCriticalSection( &dlldir_section );
    RtlFreeUnicodeString( &dll_directory );
    dll_directory = new;
    RtlLeaveCriticalSection( &dlldir_section );
    return status;
}


4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664
/****************************************************************************
 *		LdrAddDllDirectory  (NTDLL.@)
 */
NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
{
    FILE_BASIC_INFORMATION info;
    UNICODE_STRING nt_name;
    NTSTATUS status;
    OBJECT_ATTRIBUTES attr;
    DWORD len;
    struct dll_dir_entry *ptr;
    DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );

    if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
        return STATUS_INVALID_PARAMETER;

    status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
    if (status) return status;
    len = nt_name.Length / sizeof(WCHAR);
    if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
        return STATUS_NO_MEMORY;
    memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.ObjectName = &nt_name;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    status = NtQueryAttributesFile( &attr, &info );
    RtlFreeUnicodeString( &nt_name );

    if (!status)
    {
        TRACE( "%s\n", debugstr_w( ptr->dir ));
        RtlEnterCriticalSection( &dlldir_section );
        list_add_head( &dll_dir_list, &ptr->entry );
        RtlLeaveCriticalSection( &dlldir_section );
        *cookie = ptr;
    }
    else RtlFreeHeap( GetProcessHeap(), 0, ptr );
    return status;
}


/****************************************************************************
 *		LdrRemoveDllDirectory  (NTDLL.@)
 */
NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
{
    struct dll_dir_entry *ptr = cookie;

    TRACE( "%s\n", debugstr_w( ptr->dir ));

    RtlEnterCriticalSection( &dlldir_section );
    list_remove( &ptr->entry );
    RtlFreeHeap( GetProcessHeap(), 0, ptr );
    RtlLeaveCriticalSection( &dlldir_section );
    return STATUS_SUCCESS;
}


/*************************************************************************
 *		LdrSetDefaultDllDirectories  (NTDLL.@)
 */
NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
{
    /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
    const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
                                             LOAD_LIBRARY_SEARCH_USER_DIRS |
                                             LOAD_LIBRARY_SEARCH_SYSTEM32 |
                                             LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);

    if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
    default_search_flags = flags;
    return STATUS_SUCCESS;
}


/******************************************************************
 *		LdrGetDllPath  (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
{
    NTSTATUS status;
    const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
                                             LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
                                             LOAD_LIBRARY_SEARCH_USER_DIRS |
                                             LOAD_LIBRARY_SEARCH_SYSTEM32 |
                                             LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);

    if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
    {
        if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
        if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
    }
    else if (!(flags & load_library_search_flags)) flags |= default_search_flags;

    RtlEnterCriticalSection( &dlldir_section );

    if (flags & load_library_search_flags)
    {
        status = get_dll_load_path_search_flags( module, flags, path );
    }
    else
    {
        const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
4665
        if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH) || !wcschr( module, L'\\' ))
4666 4667 4668 4669 4670 4671 4672 4673 4674 4675
            module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
        status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
    }

    RtlLeaveCriticalSection( &dlldir_section );
    *unknown = NULL;
    return status;
}


4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691
/*************************************************************************
 *		RtlSetSearchPathMode (NTDLL.@)
 */
NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
{
    int val;

    switch (flags)
    {
    case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
        val = 1;
        break;
    case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
        val = 0;
        break;
    case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4692
        InterlockedExchange( &path_safe_mode, 2 );
4693 4694 4695 4696 4697 4698 4699
        return STATUS_SUCCESS;
    default:
        return STATUS_INVALID_PARAMETER;
    }

    for (;;)
    {
4700
        LONG prev = path_safe_mode;
4701
        if (prev == 2) break;  /* permanently set */
4702
        if (InterlockedCompareExchange( &path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4703 4704 4705 4706 4707
    }
    return STATUS_ACCESS_DENIED;
}


4708 4709 4710 4711 4712
/******************************************************************
 *           RtlGetExePath   (NTDLL.@)
 */
NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
{
4713
    const WCHAR *dlldir = L".";
4714 4715 4716
    const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;

    /* same check as NeedCurrentDirectoryForExePathW */
4717
    if (!wcschr( name, '\\' ))
4718
    {
4719
        UNICODE_STRING name = RTL_CONSTANT_STRING( L"NoDefaultCurrentDirectoryInExePath" ), value = { 0 };
4720 4721

        if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4722
            dlldir = L"";
4723 4724 4725 4726 4727
    }
    return get_dll_load_path( module, dlldir, FALSE, path );
}


4728 4729 4730 4731 4732
/******************************************************************
 *           RtlGetSearchPath   (NTDLL.@)
 */
NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
{
4733 4734
    const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
    return get_dll_load_path( module, NULL, path_safe_mode, path );
4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746
}


/******************************************************************
 *           RtlReleasePath   (NTDLL.@)
 */
void WINAPI RtlReleasePath( PWSTR path )
{
    RtlFreeHeap( GetProcessHeap(), 0, path );
}


4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791
/*********************************************************************
 *           ApiSetQueryApiSetPresence   (NTDLL.@)
 */
NTSTATUS WINAPI ApiSetQueryApiSetPresence( const UNICODE_STRING *name, BOOLEAN *present )
{
    const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
    const API_SET_NAMESPACE_ENTRY *entry;
    UNICODE_STRING str;

    *present = (!get_apiset_entry( map, name->Buffer, name->Length / sizeof(WCHAR), &entry ) &&
                !get_apiset_target( map, entry, NULL, &str ));
    return STATUS_SUCCESS;
}


/*********************************************************************
 *           ApiSetQueryApiSetPresenceEx   (NTDLL.@)
 */
NTSTATUS WINAPI ApiSetQueryApiSetPresenceEx( const UNICODE_STRING *name, BOOLEAN *in_schema, BOOLEAN *present )
{
    const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
    const API_SET_NAMESPACE_ENTRY *entry;
    NTSTATUS status;
    UNICODE_STRING str;
    ULONG i, len = name->Length / sizeof(WCHAR);

    /* extension not allowed */
    for (i = 0; i < len; i++) if (name->Buffer[i] == '.') return STATUS_INVALID_PARAMETER;

    status = get_apiset_entry( map, name->Buffer, len, &entry );
    if (status == STATUS_APISET_NOT_PRESENT)
    {
        *in_schema = *present = FALSE;
        return STATUS_SUCCESS;
    }
    if (status) return status;

    /* the name must match exactly */
    *in_schema = (entry->NameLength == name->Length &&
                  !wcsnicmp( (WCHAR *)((char *)map + entry->NameOffset), name->Buffer, len ));
    *present = *in_schema && !get_apiset_target( map, entry, NULL, &str );
    return STATUS_SUCCESS;
}


4792 4793 4794 4795 4796 4797 4798 4799
/******************************************************************
 *		DllMain   (NTDLL.@)
 */
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
{
    if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
    return TRUE;
}