loader.c 144 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
#define NONAMELESSUNION
29
#define NONAMELESSSTRUCT
30
#include "windef.h"
31
#include "winnt.h"
32
#include "winioctl.h"
33
#include "winternl.h"
34
#include "delayloadhandler.h"
35

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

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

48 49 50 51 52 53
#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)

54 55 56 57 58 59 60 61 62 63 64 65
#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

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

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

73
void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
74

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

77 78
const struct unix_funcs *unix_funcs = NULL;

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

84
HMODULE kernel32_handle = 0;
85

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

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

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 */
106

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

static struct list ldr_notifications = LIST_INIT( ldr_notifications );

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

124 125 126 127 128 129
struct file_id
{
    BYTE ObjectId[16];
};

/* internal representation of loaded modules */
130
typedef struct _wine_modref
131
{
132
    LDR_DATA_TABLE_ENTRY  ldr;
133
    struct file_id        id;
134
    int                   alloc_deps;
135 136
    int                   nDeps;
    struct _wine_modref **deps;
137
} WINE_MODREF;
138

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

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

152 153 154 155 156 157 158 159 160
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 };

161 162 163 164 165 166 167 168 169
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 };

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

178 179 180
static RTL_BITMAP tls_bitmap;
static RTL_BITMAP tls_expansion_bitmap;

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

185 186
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
                          DWORD flags, WINE_MODREF** pwm );
187
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
188 189
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
190
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
191
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
192 193

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

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

205 206 207 208 209 210 211 212 213 214 215 216 217
#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];
218
static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
219 220
static unsigned int unload_trace_seq;

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

226
    ptr->BaseAddress = ldr->DllBase;
227 228 229 230 231 232 233 234
    ptr->SizeOfImage = ldr->SizeOfImage;
    ptr->Sequence = unload_trace_seq;
    ptr->TimeDateStamp = ldr->TimeDateStamp;
    ptr->CheckSum = ldr->CheckSum;
    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);
235
    unload_trace_ptr = unload_traces;
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
}

/*********************************************************************
 *           RtlGetUnloadEventTrace [NTDLL.@]
 */
RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
{
    return unload_traces;
}

/*********************************************************************
 *           RtlGetUnloadEventTraceEx [NTDLL.@]
 */
void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
{
    static unsigned int element_size = sizeof(*unload_traces);
    static unsigned int element_count = ARRAY_SIZE(unload_traces);

    *size = &element_size;
    *count = &element_count;
256
    *trace = &unload_trace_ptr;
257
}
258 259 260 261 262

/*************************************************************************
 *		call_dll_entry_point
 *
 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
263 264 265
 * 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.
266 267 268 269 270
 */
#ifdef __i386__
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"
271 272
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
                  __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
273
                  "movl %esp,%ebp\n\t"
274
                  __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
275
                  "pushl %ebx\n\t"
276
                  __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
277 278 279 280 281 282
                  "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")
283 284 285 286 287
                  "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"
288 289 290 291 292 293 294
                  "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")
295
                  "popl %ebx\n\t"
296
                  __ASM_CFI(".cfi_same_value %ebx\n\t")
297
                  "popl %ebp\n\t"
298 299
                  __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
                  __ASM_CFI(".cfi_same_value %ebp\n\t")
300
                  "ret" )
301 302 303 304 305 306 307 308 309
#else /* __i386__ */
static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
                                         UINT reason, void *reserved )
{
    return proc( module, reason, reserved );
}
#endif /* __i386__ */


310
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
311 312 313 314 315
/*************************************************************************
 *		stub_entry_point
 *
 * Entry point for stub functions.
 */
316
static void WINAPI stub_entry_point( const char *dll, const char *name, void *ret_addr )
317 318 319 320 321 322
{
    EXCEPTION_RECORD rec;

    rec.ExceptionCode           = EXCEPTION_WINE_STUB;
    rec.ExceptionFlags          = EH_NONCONTINUABLE;
    rec.ExceptionRecord         = NULL;
323
    rec.ExceptionAddress        = ret_addr;
324
    rec.NumberParameters        = 2;
325 326
    rec.ExceptionInformation[0] = (ULONG_PTR)dll;
    rec.ExceptionInformation[1] = (ULONG_PTR)name;
327 328 329 330
    for (;;) RtlRaiseException( &rec );
}


331
#include "pshpack1.h"
332
#ifdef __i386__
333 334 335 336 337 338
struct stub
{
    BYTE        pushl1;     /* pushl $name */
    const char *name;
    BYTE        pushl2;     /* pushl $dll */
    const char *dll;
339
    BYTE        call;       /* call stub_entry_point */
340 341
    DWORD       entry;
};
342 343 344
#elif defined(__arm__)
struct stub
{
345 346 347 348
    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] */
349 350
    const char *dll;
    const char *name;
351 352
    const void* entry;
};
353 354 355
#elif defined(__aarch64__)
struct stub
{
356 357 358 359 360
    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 */
361 362 363 364
    const char *dll;
    const char *name;
    const void *entry;
};
365 366 367 368 369 370 371 372 373 374 375 376 377
#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
378
#include "poppack.h"
379 380 381 382 383 384

/*************************************************************************
 *		allocate_stub
 *
 * Allocate a stub entry point.
 */
385
static ULONG_PTR allocate_stub( const char *dll, const char *name )
386 387 388 389 390 391
{
#define MAX_SIZE 65536
    static struct stub *stubs;
    static unsigned int nb_stubs;
    struct stub *stub;

392
    if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
393 394 395

    if (!stubs)
    {
396
        SIZE_T size = MAX_SIZE;
397
        if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
398
                                     MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
399
            return 0xdeadbeef;
400 401
    }
    stub = &stubs[nb_stubs++];
402
#ifdef __i386__
403 404 405 406
    stub->pushl1    = 0x68;  /* pushl $name */
    stub->name      = name;
    stub->pushl2    = 0x68;  /* pushl $dll */
    stub->dll       = dll;
407
    stub->call      = 0xe8;  /* call stub_entry_point */
408
    stub->entry     = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
409
#elif defined(__arm__)
410 411 412 413 414 415 416
    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;
417
#elif defined(__aarch64__)
418 419 420 421 422 423 424 425
    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;
426
#else
427 428
    stub->movq_rdi[0]     = 0x48;  /* movq $dll,%rcx */
    stub->movq_rdi[1]     = 0xb9;
429
    stub->dll             = dll;
430 431
    stub->movq_rsi[0]     = 0x48;  /* movq $name,%rdx */
    stub->movq_rsi[1]     = 0xba;
432
    stub->name            = name;
433
    stub->movq_rsp_rdx[0] = 0x4c;  /* movq (%rsp),%r8 */
434
    stub->movq_rsp_rdx[1] = 0x8b;
435
    stub->movq_rsp_rdx[2] = 0x04;
436 437 438 439 440 441 442
    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
443
    return (ULONG_PTR)stub;
444 445 446
}

#else  /* __i386__ */
447
static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
448 449
#endif  /* __i386__ */

450
/* call ldr notifications */
451
static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
452 453 454 455 456 457 458
{
    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;
459
    data.Loaded.DllBase     = module->DllBase;
460 461 462 463 464 465 466 467 468 469 470 471 472
    data.Loaded.SizeOfImage = module->SizeOfImage;

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

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

        TRACE_(relay)("\1Ret  LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
                notify->callback, reason, &data, notify->context );
    }
}
473

474
/*************************************************************************
475 476 477 478
 *		get_modref
 *
 * Looks for the referenced HMODULE in the current process
 * The loader_section must be locked while calling this function.
479
 */
480
static WINE_MODREF *get_modref( HMODULE hmod )
481
{
482
    PLIST_ENTRY mark, entry;
483
    PLDR_DATA_TABLE_ENTRY mod;
484

485
    if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref;
486

487 488
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
489
    {
490
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
491
        if (mod->DllBase == hmod)
492
            return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
493
    }
494
    return NULL;
495 496 497
}


498
/**********************************************************************
499
 *	    find_basename_module
500
 *
501
 * Find a module from its base name.
502 503
 * The loader_section must be locked while calling this function
 */
504
static WINE_MODREF *find_basename_module( LPCWSTR name )
505 506
{
    PLIST_ENTRY mark, entry;
507
    UNICODE_STRING name_str;
508

509 510 511
    RtlInitUnicodeString( &name_str, name );

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

514 515
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
516
    {
517
        LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
518
        if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE ))
519 520 521 522
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
523
    }
524 525 526 527 528 529 530 531 532 533
    return NULL;
}


/**********************************************************************
 *	    find_fullname_module
 *
 * Find a module from its full path name.
 * The loader_section must be locked while calling this function
 */
534
static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
535 536
{
    PLIST_ENTRY mark, entry;
537
    UNICODE_STRING name = *nt_name;
538

539 540 541 542 543
    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 ))
544
        return cached_modref;
545 546 547 548

    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
549
        LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
550
        if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
551 552 553 554
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
555
    }
556
    return NULL;
557 558 559
}


560 561 562 563 564 565
/**********************************************************************
 *	    find_fileid_module
 *
 * Find a module from its file id.
 * The loader_section must be locked while calling this function
 */
566
static WINE_MODREF *find_fileid_module( const struct file_id *id )
567 568 569
{
    LIST_ENTRY *mark, *entry;

570
    if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref;
571 572 573 574

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

578
        if (!memcmp( &wm->id, id, sizeof(*id) ))
579 580 581 582 583 584 585 586 587
        {
            cached_modref = wm;
            return wm;
        }
    }
    return NULL;
}


588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
/*************************************************************************
 *		grow_module_deps
 */
static WINE_MODREF **grow_module_deps( WINE_MODREF *wm, int count )
{
    WINE_MODREF **deps;

    if (wm->alloc_deps)
        deps = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, wm->deps,
                                  (wm->alloc_deps + count) * sizeof(*deps) );
    else
        deps = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(*deps) );

    if (deps)
    {
        wm->deps = deps;
        wm->alloc_deps += count;
    }
    return deps;
}

609 610 611 612 613 614
/*************************************************************************
 *		find_forwarded_export
 *
 * Find the final function pointer for a forwarded function.
 * The loader_section must be locked while calling this function.
 */
615
static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
616
{
Eric Pouech's avatar
Eric Pouech committed
617
    const IMAGE_EXPORT_DIRECTORY *exports;
618 619
    DWORD exp_size;
    WINE_MODREF *wm;
620
    WCHAR buffer[32], *mod_name = buffer;
621
    const char *end = strrchr(forward, '.');
622 623 624
    FARPROC proc = NULL;

    if (!end) return NULL;
625
    if ((end - forward) * sizeof(WCHAR) > sizeof(buffer) - sizeof(L".dll"))
626
    {
627 628
        if (!(mod_name = RtlAllocateHeap( GetProcessHeap(), 0,
                                          (end - forward + sizeof(L".dll")) * sizeof(WCHAR) )))
629 630
            return NULL;
    }
631
    ascii_to_unicode( mod_name, forward, end - forward );
632
    mod_name[end - forward] = 0;
633
    if (!wcschr( mod_name, '.' ))
634
        memcpy( mod_name + (end - forward), L".dll", sizeof(L".dll") );
635

636
    if (!(wm = find_basename_module( mod_name )))
637
    {
638
        TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
639
        if (load_dll( load_path, mod_name, L".dll", 0, &wm ) == STATUS_SUCCESS &&
640 641
            !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
        {
642 643
            if (!imports_fixup_done && current_modref)
            {
644 645
                WINE_MODREF **deps = grow_module_deps( current_modref, 1 );
                if (deps) deps[current_modref->nDeps++] = wm;
646 647
            }
            else if (process_attach( wm, NULL ) != STATUS_SUCCESS)
648
            {
649
                LdrUnloadDll( wm->ldr.DllBase );
650 651 652 653 654 655
                wm = NULL;
            }
        }

        if (!wm)
        {
656
            if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name );
657 658 659 660
            ERR( "module not found for forward '%s' used by %s\n",
                 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
            return NULL;
        }
661
    }
662
    if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
663
                                                 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
664 665
    {
        const char *name = end + 1;
666 667 668 669 670

        if (*name == '#') { /* ordinal */
            proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
                                        atoi(name+1) - exports->Base, load_path );
        } else
671
            proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
672
    }
673 674 675

    if (!proc)
    {
676 677 678 679
        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) );
680
    }
681
    if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name );
682 683 684 685 686 687 688 689 690 691 692
    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
693
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
694
                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
695 696
{
    FARPROC proc;
Eric Pouech's avatar
Eric Pouech committed
697
    const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
698 699 700

    if (ordinal >= exports->NumberOfFunctions)
    {
701
        TRACE("	ordinal %d out of range!\n", ordinal + exports->Base );
702 703 704 705 706 707 708
        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
709 710
    if (((const char *)proc >= (const char *)exports) && 
        ((const char *)proc < (const char *)exports + exp_size))
711
        return find_forwarded_export( module, (const char *)proc, load_path );
712

713
    if (TRACE_ON(snoop))
714
    {
715 716
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
        proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
717
    }
718
    if (TRACE_ON(relay))
719
    {
720
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
721
        proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
722 723 724 725 726
    }
    return proc;
}


727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
/*************************************************************************
 *		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;
}


750 751 752 753 754 755
/*************************************************************************
 *		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
756
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
757
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
758
{
Eric Pouech's avatar
Eric Pouech committed
759 760
    const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
    const DWORD *names = get_rva( module, exports->AddressOfNames );
761
    int ordinal;
762 763

    /* first check the hint */
764
    if (hint >= 0 && hint < exports->NumberOfNames)
765 766 767
    {
        char *ename = get_rva( module, names[hint] );
        if (!strcmp( ename, name ))
768
            return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
769 770 771
    }

    /* then do a binary search */
772 773
    if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
    return find_ordinal_export( module, exports, exp_size, ordinal, load_path );
774 775 776 777

}


778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
/*************************************************************************
 *		RtlFindExportedRoutineByName
 */
void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
{
    const IMAGE_EXPORT_DIRECTORY *exports;
    const DWORD *functions;
    DWORD exp_size;
    int ordinal;

    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;
    return get_rva( module, functions[ordinal] );
}


799 800 801 802 803 804
/*************************************************************************
 *		import_dll
 *
 * Import the dll specified by the given import descriptor.
 * The loader_section must be locked while calling this function.
 */
805
static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
806 807 808 809
{
    NTSTATUS status;
    WINE_MODREF *wmImp;
    HMODULE imp_mod;
Eric Pouech's avatar
Eric Pouech committed
810
    const IMAGE_EXPORT_DIRECTORY *exports;
811
    DWORD exp_size;
Eric Pouech's avatar
Eric Pouech committed
812 813
    const IMAGE_THUNK_DATA *import_list;
    IMAGE_THUNK_DATA *thunk_list;
814
    WCHAR buffer[32];
Eric Pouech's avatar
Eric Pouech committed
815
    const char *name = get_rva( module, descr->Name );
816
    DWORD len = strlen(name);
817
    PVOID protect_base;
818
    SIZE_T protect_size = 0;
819
    DWORD protect_old;
820

821 822 823 824 825 826
    thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
    if (descr->u.OriginalFirstThunk)
        import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
    else
        import_list = thunk_list;

827 828 829 830 831 832 833
    if (!import_list->u1.Ordinal)
    {
        WARN( "Skipping unused import %s\n", name );
        *pwm = NULL;
        return TRUE;
    }

834 835 836
    while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */

    if (len * sizeof(WCHAR) < sizeof(buffer))
837 838
    {
        ascii_to_unicode( buffer, name, len );
839
        buffer[len] = 0;
840
        status = load_dll( load_path, buffer, L".dll", 0, &wmImp );
841 842 843
    }
    else  /* need to allocate a larger buffer */
    {
844
        WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
845
        if (!ptr) return FALSE;
846
        ascii_to_unicode( ptr, name, len );
847
        ptr[len] = 0;
848
        status = load_dll( load_path, ptr, L".dll", 0, &wmImp );
849 850
        RtlFreeHeap( GetProcessHeap(), 0, ptr );
    }
851 852 853

    if (status)
    {
854
        if (status == STATUS_DLL_NOT_FOUND)
855
            ERR("Library %s (which is needed by %s) not found\n",
856
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
857
        else
858
            ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
859
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
860
        return FALSE;
861 862
    }

863 864 865 866 867
    /* 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);
868
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
869
                            &protect_size, PAGE_READWRITE, &protect_old );
870

871
    imp_mod = wmImp->ldr.DllBase;
872 873
    exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );

874 875 876 877 878 879 880
    if (!exports)
    {
        /* set all imported function to deadbeef */
        while (import_list->u1.Ordinal)
        {
            if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
            {
881 882
                int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
                WARN("No implementation for %s.%d", name, ordinal );
883
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
884 885 886 887
            }
            else
            {
                IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
888
                WARN("No implementation for %s.%s", name, pe_name->Name );
Mike McCormack's avatar
Mike McCormack committed
889
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
890
            }
891
            WARN(" imported from %s, allocating stub %p\n",
892 893
                 debugstr_w(current_modref->ldr.FullDllName.Buffer),
                 (void *)thunk_list->u1.Function );
894 895 896
            import_list++;
            thunk_list++;
        }
897
        goto done;
898
    }
899 900 901 902 903 904 905

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

906
            thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
907
                                                                      ordinal - exports->Base, load_path );
908 909
            if (!thunk_list->u1.Function)
            {
910
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
911
                WARN("No implementation for %s.%d imported from %s, setting to %p\n",
912 913
                     name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
914
            }
915
            TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
916 917 918 919 920
        }
        else  /* import by name */
        {
            IMAGE_IMPORT_BY_NAME *pe_name;
            pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
921
            thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
922 923
                                                                    (const char*)pe_name->Name,
                                                                    pe_name->Hint, load_path );
924 925
            if (!thunk_list->u1.Function)
            {
Mike McCormack's avatar
Mike McCormack committed
926
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
927
                WARN("No implementation for %s.%s imported from %s, setting to %p\n",
928 929
                     name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
930
            }
931 932
            TRACE_(imports)("--- %s %s.%d = %p\n",
                            pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
933 934 935 936
        }
        import_list++;
        thunk_list++;
    }
937 938 939

done:
    /* restore old protection of the import address table */
940
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
941 942
    *pwm = wmImp;
    return TRUE;
943 944 945
}


946 947 948
/***********************************************************************
 *           create_module_activation_context
 */
949
static NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
950 951 952 953 954 955 956 957
{
    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;
958
    if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
959 960 961 962 963
    {
        ACTCTXW ctx;
        ctx.cbSize   = sizeof(ctx);
        ctx.lpSource = NULL;
        ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
964
        ctx.hModule  = module->DllBase;
965 966 967 968 969 970 971
        ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
        status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
    }
    return status;
}


972 973 974 975 976 977 978
/*************************************************************************
 *		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.
 */
979
static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
980 981 982 983 984 985
{
    const IMAGE_IMPORT_DESCRIPTOR *imports;
    DWORD i, size;
    WCHAR buffer[16];

    if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
986
    if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
987
    if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
988

989
    if ((imports = RtlImageDirectoryEntryToData( mod->DllBase, TRUE,
990 991 992 993
                                                 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
    {
        for (i = 0; imports[i].Name; i++)
        {
994
            const char *name = get_rva( mod->DllBase, imports[i].Name );
995 996 997
            DWORD len = strlen(name);
            if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
            ascii_to_unicode( buffer, name, len + 1 );
998
            if (!wcsicmp( buffer, L"ntdll.dll" ) || !wcsicmp( buffer, L"kernel32.dll" ))
999 1000 1001 1002 1003 1004 1005 1006 1007
            {
                TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
                return FALSE;
            }
        }
    }
    return TRUE;
}

1008 1009 1010 1011 1012 1013
/*************************************************************************
 *		alloc_tls_slot
 *
 * Allocate a TLS slot for a newly-loaded module.
 * The loader_section must be locked while calling this function.
 */
1014
static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1015 1016 1017 1018
{
    const IMAGE_TLS_DIRECTORY *dir;
    ULONG i, size;
    void *new_ptr;
1019
    LIST_ENTRY *entry;
1020

1021
    if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1022 1023 1024 1025 1026
        return -1;

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

1027 1028 1029 1030 1031 1032
    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;
    }
1033

1034
    TRACE( "module %p data %p-%p zerofill %u index %p callback %p flags %x -> slot %u\n", mod->DllBase,
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
           (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) );
        if (!new_ptr) return -1;
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

        /* 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));

            if (!new) return -1;
            if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
            teb->ThreadLocalStoragePointer = new;
1059 1060
#ifdef __x86_64__  /* macOS-specific hack */
            if (teb->Reserved5[0]) ((TEB *)teb->Reserved5[0])->ThreadLocalStoragePointer = new;
1061
#endif
1062 1063 1064 1065
            TRACE( "thread %04lx tls block %p -> %p\n", (ULONG_PTR)teb->ClientId.UniqueThread, old, new );
            /* FIXME: can't free old block here, should be freed at thread exit */
        }

1066 1067 1068 1069
        tls_dirs = new_ptr;
        tls_module_count = new_count;
    }

1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
    /* 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 );

        TRACE( "thread %04lx slot %u: %u/%u bytes at %p\n",
               (ULONG_PTR)teb->ClientId.UniqueThread, i, size, dir->SizeOfZeroFill, new_ptr );

        RtlFreeHeap( GetProcessHeap(), 0,
1083
                     InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1084 1085
    }

1086
    *(DWORD *)dir->AddressOfIndex = i;
1087
    tls_dirs[i] = *dir;
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
    return i;
}


/*************************************************************************
 *		free_tls_slot
 *
 * Free the module TLS slot on unload.
 * The loader_section must be locked while calling this function.
 */
1098
static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1099 1100 1101 1102 1103
{
    ULONG i = (USHORT)mod->TlsIndex;

    if (mod->TlsIndex == -1) return;
    assert( i < tls_module_count );
1104
    memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1105 1106
}

1107

1108 1109 1110 1111 1112 1113 1114 1115 1116
/****************************************************************
 *       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;
1117 1118
    void *proc;
    const char *name;
1119 1120 1121 1122 1123
    WINE_MODREF *prev, *imp;

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

1124
    if (!grow_module_deps( wm, 1 )) return STATUS_NO_MEMORY;
1125 1126 1127 1128
    wm->nDeps = 1;

    prev = current_modref;
    current_modref = wm;
1129
    if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp ))) wm->deps[0] = imp;
1130
    current_modref = prev;
1131 1132 1133 1134 1135 1136
    if (status)
    {
        ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
             debugstr_w(wm->ldr.BaseDllName.Buffer) );
        return status;
    }
1137 1138 1139

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

1140 1141
    name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
    if (!(proc = RtlFindExportedRoutineByName( imp->ldr.DllBase, name ))) return STATUS_PROCEDURE_NOT_FOUND;
1142 1143 1144 1145 1146
    *entry = proc;
    return STATUS_SUCCESS;
}


1147 1148 1149 1150 1151 1152 1153 1154
/****************************************************************
 *       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 )
{
1155
    int i, dep, nb_imports;
1156
    const IMAGE_IMPORT_DESCRIPTOR *imports;
1157
    WINE_MODREF *prev, *imp;
1158 1159 1160 1161 1162 1163 1164
    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;

1165 1166
    wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr );

1167
    if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
1168 1169 1170 1171 1172 1173 1174
                                                  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 */
1175
    if (!grow_module_deps( wm, nb_imports )) return STATUS_NO_MEMORY;
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187

    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++)
    {
1188 1189
        dep = wm->nDeps++;

1190
        if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
1191
        {
1192
            imp = NULL;
1193
            status = STATUS_DLL_NOT_FOUND;
1194
        }
1195
        wm->deps[dep] = imp;
1196 1197 1198 1199 1200 1201 1202
    }
    current_modref = prev;
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
    return status;
}


1203
/*************************************************************************
1204
 *		alloc_module
1205 1206
 *
 * Allocate a WINE_MODREF structure and add it to the process list
1207
 * The loader_section must be locked while calling this function.
1208
 */
1209
static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1210
{
1211
    WCHAR *buffer;
1212
    WINE_MODREF *wm;
Eric Pouech's avatar
Eric Pouech committed
1213 1214
    const WCHAR *p;
    const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1215

1216
    if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1217

1218
    wm->ldr.DllBase       = hModule;
1219
    wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
1220
    wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1221
    wm->ldr.TlsIndex      = -1;
1222
    wm->ldr.LoadCount     = 1;
1223 1224
    wm->ldr.CheckSum      = nt->OptionalHeader.CheckSum;
    wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
1225

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
    if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
    {
        RtlFreeHeap( GetProcessHeap(), 0, wm );
        return NULL;
    }
    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 );
1236 1237
    RtlInitUnicodeString( &wm->ldr.BaseDllName, p );

1238
    if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1239
    {
1240 1241
        if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
            wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1242 1243
        if (nt->OptionalHeader.AddressOfEntryPoint)
            wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1244 1245
    }

1246
    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1247
                   &wm->ldr.InLoadOrderLinks);
1248
    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1249
                   &wm->ldr.InMemoryOrderLinks);
1250
    /* wait until init is called for inserting into InInitializationOrderModuleList */
1251 1252 1253

    if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
    {
1254
        ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1255
        WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1256
        NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1257
    }
1258 1259 1260 1261
    return wm;
}


1262 1263 1264 1265 1266 1267 1268 1269
/*************************************************************************
 *              alloc_thread_tls
 *
 * Allocate the per-thread structure for module TLS storage.
 */
static NTSTATUS alloc_thread_tls(void)
{
    void **pointers;
1270
    UINT i, size;
1271 1272 1273

    if (!tls_module_count) return STATUS_SUCCESS;

1274 1275
    if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                      tls_module_count * sizeof(*pointers) )))
1276 1277 1278 1279
        return STATUS_NO_MEMORY;

    for (i = 0; i < tls_module_count; i++)
    {
1280
        const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1281 1282

        if (!dir) continue;
1283
        size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
        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 );
1294

1295 1296
        TRACE( "thread %04x slot %u: %u/%u bytes at %p\n",
               GetCurrentThreadId(), i, size, dir->SizeOfZeroFill, pointers[i] );
1297
    }
1298
    NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1299 1300 1301
#ifdef __x86_64__  /* macOS-specific hack */
    if (NtCurrentTeb()->Reserved5[0])
        ((TEB *)NtCurrentTeb()->Reserved5[0])->ThreadLocalStoragePointer = pointers;
1302
#endif
1303 1304 1305 1306
    return STATUS_SUCCESS;
}


1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
/*************************************************************************
 *              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;

1319
    for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1320
    {
1321 1322
        TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                      *callback, module, reason_names[reason] );
1323 1324
        __TRY
        {
1325
            call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1326
        }
1327
        __EXCEPT_ALL
1328
        {
1329 1330
            TRACE_(relay)("\1exception %08x in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                          GetExceptionCode(), callback, module, reason_names[reason] );
1331 1332 1333
            return;
        }
        __ENDTRY
1334 1335
        TRACE_(relay)("\1Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                      *callback, module, reason_names[reason] );
1336 1337 1338
    }
}

1339 1340 1341
/*************************************************************************
 *              MODULE_InitDLL
 */
1342
static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1343
{
1344
    WCHAR mod_name[32];
1345
    NTSTATUS status = STATUS_SUCCESS;
1346
    DLLENTRYPROC entry = wm->ldr.EntryPoint;
1347
    void *module = wm->ldr.DllBase;
1348
    BOOL retv = FALSE;
1349 1350 1351

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

1352
    if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1353
    if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, reason );
1354 1355
    if (wm->ldr.Flags & LDR_WINE_INTERNAL && reason == DLL_PROCESS_ATTACH)
        unix_funcs->init_builtin_dll( wm->ldr.DllBase );
1356
    if (!entry) return STATUS_SUCCESS;
1357 1358

    if (TRACE_ON(relay))
1359
    {
1360
        size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1361 1362
        memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
        mod_name[len / sizeof(WCHAR)] = 0;
1363 1364
        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 );
1365
    }
1366 1367
    else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
               reason_names[reason], lpReserved );
1368

1369 1370 1371 1372 1373 1374
    __TRY
    {
        retv = call_dll_entry_point( entry, module, reason, lpReserved );
        if (!retv)
            status = STATUS_DLL_INIT_FAILED;
    }
1375
    __EXCEPT_ALL
1376 1377
    {
        status = GetExceptionCode();
1378 1379
        TRACE_(relay)("\1exception %08x in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
                      status, entry, module, reason_names[reason], lpReserved );
1380 1381
    }
    __ENDTRY
1382 1383

    /* The state of the module list may have changed due to the call
1384
       to the dll. We cannot assume that this module has not been
1385
       deleted.  */
1386
    if (TRACE_ON(relay))
1387 1388 1389 1390
        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 );
1391

1392
    return status;
1393 1394 1395 1396
}


/*************************************************************************
1397
 *		process_attach
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
 *
 * 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*.
1424 1425
 *
 * The loader_section must be locked while calling this function.
1426
 */
1427
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1428
{
1429
    NTSTATUS status = STATUS_SUCCESS;
1430
    ULONG_PTR cookie;
1431 1432
    int i;

1433 1434
    if (process_detaching) return status;

1435
    /* prevent infinite recursion in case of cyclical dependencies */
1436 1437
    if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
         || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1438
        return status;
1439

1440
    TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1441 1442

    /* Tag current MODREF to prevent recursive loop */
1443
    wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1444
    if (lpReserved) wm->ldr.LoadCount = -1;  /* pin it if imported by the main exe */
1445
    if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1446 1447

    /* Recursively attach all DLLs this one depends on */
1448 1449 1450
    for ( i = 0; i < wm->nDeps; i++ )
    {
        if (!wm->deps[i]) continue;
1451
        if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1452
    }
1453

1454
    if (!wm->ldr.InInitializationOrderLinks.Flink)
1455
        InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1456
                &wm->ldr.InInitializationOrderLinks);
1457

1458
    /* Call DLL entry point */
1459
    if (status == STATUS_SUCCESS)
1460
    {
1461 1462
        WINE_MODREF *prev = current_modref;
        current_modref = wm;
1463 1464

        call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1465 1466
        status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
        if (status == STATUS_SUCCESS)
1467
        {
1468
            wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1469
        }
1470
        else
1471
        {
1472
            MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1473 1474
            call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );

1475 1476 1477 1478
            /* 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));
        }
1479
        current_modref = prev;
1480 1481
    }

1482
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1483
    /* Remove recursion flag */
1484
    wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1485

1486
    TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1487
    return status;
1488 1489
}

1490

1491
/*************************************************************************
1492
 *		process_detach
1493 1494
 *
 * Send DLL process detach notifications.  See the comment about calling
1495
 * sequence at process_attach.
1496
 */
1497
static void process_detach(void)
1498
{
1499
    PLIST_ENTRY mark, entry;
1500
    PLDR_DATA_TABLE_ENTRY mod;
1501

1502
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1503 1504
    do
    {
1505
        for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1506
        {
1507
            mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1508
                                    InInitializationOrderLinks);
1509
            /* Check whether to detach this DLL */
1510
            if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1511
                continue;
1512
            if ( mod->LoadCount && !process_detaching )
1513 1514 1515
                continue;

            /* Call detach notification */
1516 1517
            mod->Flags &= ~LDR_PROCESS_ATTACHED;
            MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
1518
                            DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1519
            call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1520 1521 1522 1523 1524

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

/*************************************************************************
1529
 *		thread_attach
1530 1531 1532
 *
 * Send DLL thread attach notifications. These are sent in the
 * reverse sequence of process detach notification.
1533
 * The loader_section must be locked while calling this function.
1534
 */
1535
static void thread_attach(void)
1536
{
1537
    PLIST_ENTRY mark, entry;
1538
    PLDR_DATA_TABLE_ENTRY mod;
1539

1540 1541
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1542
    {
1543
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1544
                                InInitializationOrderLinks);
1545
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1546
            continue;
1547
        if ( mod->Flags & LDR_NO_DLL_CALLS )
1548 1549
            continue;

1550
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1551 1552 1553
    }
}

1554 1555 1556 1557 1558
/******************************************************************
 *		LdrDisableThreadCalloutsForDll (NTDLL.@)
 *
 */
NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1559
{
1560 1561 1562 1563 1564
    WINE_MODREF *wm;
    NTSTATUS    ret = STATUS_SUCCESS;

    RtlEnterCriticalSection( &loader_section );

1565
    wm = get_modref( hModule );
1566
    if (!wm || wm->ldr.TlsIndex != -1)
1567
        ret = STATUS_DLL_NOT_FOUND;
1568
    else
1569
        wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1570 1571 1572 1573

    RtlLeaveCriticalSection( &loader_section );

    return ret;
1574
}
1575

1576 1577 1578 1579 1580
/******************************************************************
 *              LdrFindEntryForAddress (NTDLL.@)
 *
 * The loader_section must be locked while calling this function
 */
1581
NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
1582
{
1583
    PLIST_ENTRY mark, entry;
1584
    PLDR_DATA_TABLE_ENTRY mod;
1585

1586 1587
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1588
    {
1589
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
1590 1591
        if (mod->DllBase <= addr &&
            (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
1592
        {
1593
            *pmod = mod;
1594 1595 1596 1597 1598 1599
            return STATUS_SUCCESS;
        }
    }
    return STATUS_NO_MORE_ENTRIES;
}

1600 1601 1602 1603 1604 1605
/******************************************************************
 *              LdrEnumerateLoadedModules (NTDLL.@)
 */
NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
{
    LIST_ENTRY *mark, *entry;
1606
    LDR_DATA_TABLE_ENTRY *mod;
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
    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)
    {
1619
        mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
1620 1621 1622 1623 1624 1625 1626 1627
        callback( mod, context, &stop );
        if (stop) break;
    }

    RtlLeaveCriticalSection( &loader_section );
    return STATUS_SUCCESS;
}

1628 1629 1630 1631 1632 1633
/******************************************************************
 *              LdrRegisterDllNotification (NTDLL.@)
 */
NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
                                           void *context, void **cookie)
{
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
    struct ldr_notification *notify;

    TRACE( "(%x, %p, %p, %p)\n", flags, callback, context, cookie );

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

    if (flags)
        FIXME( "ignoring flags %x\n", flags );

    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;
1655 1656 1657 1658 1659 1660 1661
}

/******************************************************************
 *              LdrUnregisterDllNotification (NTDLL.@)
 */
NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
{
1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
    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;
1674 1675
}

1676 1677 1678
/******************************************************************
 *		LdrLockLoaderLock  (NTDLL.@)
 *
1679
 * Note: some flags are not implemented.
1680 1681
 * Flag 0x01 is used to raise exceptions on errors.
 */
1682
NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1683
{
1684
    if (flags & ~0x2) FIXME( "flags %x not supported\n", flags );
1685

1686 1687 1688 1689
    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;
1690
    if (!magic) return STATUS_INVALID_PARAMETER_3;
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705

    if (flags & 0x2)
    {
        if (!RtlTryEnterCriticalSection( &loader_section ))
        {
            *result = 2;
            return STATUS_SUCCESS;
        }
        *result = 1;
    }
    else
    {
        RtlEnterCriticalSection( &loader_section );
        if (result) *result = 1;
    }
1706 1707 1708 1709 1710 1711 1712 1713
    *magic = GetCurrentThreadId();
    return STATUS_SUCCESS;
}


/******************************************************************
 *		LdrUnlockLoaderUnlock  (NTDLL.@)
 */
1714
NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
{
    if (magic)
    {
        if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
        RtlLeaveCriticalSection( &loader_section );
    }
    return STATUS_SUCCESS;
}


1725 1726
/******************************************************************
 *		LdrGetProcedureAddress  (NTDLL.@)
1727
 */
1728 1729
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
                                       ULONG ord, PVOID *address)
1730
{
1731 1732 1733
    IMAGE_EXPORT_DIRECTORY *exports;
    DWORD exp_size;
    NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1734

1735
    RtlEnterCriticalSection( &loader_section );
1736

1737 1738 1739 1740
    /* check if the module itself is invalid to return the proper error */
    if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
    else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
                                                      IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1741
    {
1742 1743
        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 );
1744 1745 1746 1747 1748 1749
        if (proc)
        {
            *address = proc;
            ret = STATUS_SUCCESS;
        }
    }
1750

1751 1752
    RtlLeaveCriticalSection( &loader_section );
    return ret;
1753
}
1754 1755


1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
/***********************************************************************
 *           set_security_cookie
 *
 * Create a random security cookie for buffer overflow protection. Make
 * sure it does not accidentally match the default cookie value.
 */
static void set_security_cookie( void *module, SIZE_T len )
{
    static ULONG seed;
    IMAGE_LOAD_CONFIG_DIRECTORY *loadcfg;
    ULONG loadcfg_size;
    ULONG_PTR *cookie;

    loadcfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &loadcfg_size );
    if (!loadcfg) return;
    if (loadcfg_size < offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie) + sizeof(loadcfg->SecurityCookie)) return;
    if (!loadcfg->SecurityCookie) return;
    if (loadcfg->SecurityCookie < (ULONG_PTR)module ||
        loadcfg->SecurityCookie > (ULONG_PTR)module + len - sizeof(ULONG_PTR))
    {
        WARN( "security cookie %p outside of image %p-%p\n",
              (void *)loadcfg->SecurityCookie, module, (char *)module + len );
        return;
    }

    cookie = (ULONG_PTR *)loadcfg->SecurityCookie;
    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;
    }
}

1804
static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
1805 1806 1807 1808 1809 1810 1811 1812 1813
{
    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;
1814
    if (module == base) return STATUS_SUCCESS;  /* nothing to do */
1815 1816 1817 1818 1819 1820 1821 1822 1823 1824

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

    if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
        return STATUS_SUCCESS;

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

1825
    if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1826 1827 1828 1829 1830 1831
    {
        WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
              base, module );
        return STATUS_CONFLICTING_ADDRESSES;
    }

1832 1833 1834
    if (!relocs->Size) return STATUS_SUCCESS;
    if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;

1835
    if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877
        return STATUS_INVALID_IMAGE_FORMAT;

    sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
                                         nt->FileHeader.SizeOfOptionalHeader);
    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;
}
1878

1879 1880 1881 1882 1883 1884 1885

/*************************************************************************
 *		build_module
 *
 * Build the module data for a mapped dll.
 */
static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
1886
                              const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
1887 1888
                              DWORD flags, WINE_MODREF **pwm )
{
1889 1890 1891
    static const char builtin_signature[] = "Wine builtin DLL";
    char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1);
    BOOL is_builtin;
1892 1893 1894
    IMAGE_NT_HEADERS *nt;
    WINE_MODREF *wm;
    NTSTATUS status;
1895
    SIZE_T map_size;
1896 1897 1898

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

1899 1900
    map_size = (nt->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
    if ((status = perform_relocations( *module, nt, map_size ))) return status;
1901

1902 1903 1904
    is_builtin = ((char *)nt - signature >= sizeof(builtin_signature) &&
                  !memcmp( signature, builtin_signature, sizeof(builtin_signature) ));

1905 1906
    /* create the MODREF */

1907
    if (!(wm = alloc_module( *module, nt_name, is_builtin ))) return STATUS_NO_MEMORY;
1908 1909

    if (id) wm->id = *id;
1910
    if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE;
1911
    if (image_info->u.s.ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
1912

1913
    set_security_cookie( *module, map_size );
1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942

    /* 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;
        }
    }

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

1945
    if (is_builtin)
1946 1947 1948 1949 1950 1951 1952 1953 1954
    {
        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,
1955
                     is_builtin ? "builtin" : "native" );
1956 1957 1958 1959 1960 1961 1962 1963 1964

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


/*************************************************************************
1965
 *		build_ntdll_module
1966
 *
1967
 * Build the module data for the initially-loaded ntdll.
1968
 */
1969
static void build_ntdll_module(void)
1970
{
1971 1972 1973
    MEMORY_BASIC_INFORMATION meminfo;
    UNICODE_STRING nt_name;
    WINE_MODREF *wm;
1974

1975 1976 1977 1978 1979 1980 1981
    RtlInitUnicodeString( &nt_name, L"\\??\\C:\\windows\\system32\\ntdll.dll" );
    NtQueryVirtualMemory( GetCurrentProcess(), build_ntdll_module, MemoryBasicInformation,
                          &meminfo, sizeof(meminfo), NULL );
    wm = alloc_module( meminfo.AllocationBase, &nt_name, TRUE );
    assert( wm );
    wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
    if (TRACE_ON(relay)) RELAY_SetupDLL( meminfo.AllocationBase );
1982 1983 1984
}


1985 1986
#ifdef _WIN64
/* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
1987
static BOOL convert_to_pe64( HMODULE module, const SECTION_IMAGE_INFORMATION *info )
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
{
    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 );
    SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
    IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + hdr_size);
1999
    SIZE_T size = min( nt->OptionalHeader.SizeOfHeaders, nt->OptionalHeader.SizeOfImage );
2000 2001 2002
    void *addr = module;
    ULONG i, old_prot;

2003
    if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return TRUE;  /* already 64-bit */
2004
    if (!info->ImageContainsCode) return TRUE;  /* no need to convert */
2005

2006 2007 2008 2009 2010
    TRACE( "%p\n", module );

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

2011 2012 2013 2014 2015 2016
    if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
    {
        NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
        return FALSE;
    }

2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036
    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;
}
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060

/* check COM header for ILONLY flag, ignoring runtime version */
static BOOL get_cor_header( HANDLE file, const SECTION_IMAGE_INFORMATION *info, IMAGE_COR20_HEADER *cor )
{
    IMAGE_DOS_HEADER mz;
    IMAGE_NT_HEADERS32 nt;
    IO_STATUS_BLOCK io;
    LARGE_INTEGER offset;
    IMAGE_SECTION_HEADER sec[96];
    unsigned int i, count;
    DWORD va, size;

    offset.QuadPart = 0;
    if (NtReadFile( file, 0, NULL, NULL, &io, &mz, sizeof(mz), &offset, NULL )) return FALSE;
    if (io.Information != sizeof(mz)) return FALSE;
    if (mz.e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
    offset.QuadPart = mz.e_lfanew;
    if (NtReadFile( file, 0, NULL, NULL, &io, &nt, sizeof(nt), &offset, NULL )) return FALSE;
    if (io.Information != sizeof(nt)) return FALSE;
    if (nt.Signature != IMAGE_NT_SIGNATURE) return FALSE;
    if (nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return FALSE;
    va = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
    size = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
    if (!va || size < sizeof(*cor)) return FALSE;
2061
    offset.QuadPart += offsetof( IMAGE_NT_HEADERS32, OptionalHeader ) + nt.FileHeader.SizeOfOptionalHeader;
2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
    count = min( 96, nt.FileHeader.NumberOfSections );
    if (NtReadFile( file, 0, NULL, NULL, &io, &sec, count * sizeof(*sec), &offset, NULL )) return FALSE;
    if (io.Information != count * sizeof(*sec)) return FALSE;
    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;
        offset.QuadPart = sec->PointerToRawData + va - sec[i].VirtualAddress;
        if (NtReadFile( file, 0, NULL, NULL, &io, cor, sizeof(*cor), &offset, NULL )) return FALSE;
        return (io.Information == sizeof(*cor));
    }
    return FALSE;
}
2075
#endif
2076 2077 2078

/* 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 */
2079
static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2080 2081
{
#ifdef __i386__
2082
    return info->Machine == IMAGE_FILE_MACHINE_I386;
2083
#elif defined(__arm__)
2084 2085 2086
    return info->Machine == IMAGE_FILE_MACHINE_ARM ||
           info->Machine == IMAGE_FILE_MACHINE_THUMB ||
           info->Machine == IMAGE_FILE_MACHINE_ARMNT;
2087
#elif defined(_WIN64)  /* support 32-bit IL-only images on 64-bit */
2088
#ifdef __x86_64__
2089
    if (info->Machine == IMAGE_FILE_MACHINE_AMD64) return TRUE;
2090
#else
2091
    if (info->Machine == IMAGE_FILE_MACHINE_ARM64) return TRUE;
2092
#endif
2093
    if (!info->ImageContainsCode) return TRUE;
2094
    if (!(info->u.s.ComPlusNativeReady))
2095
    {
2096 2097 2098
        IMAGE_COR20_HEADER cor_header;
        if (!get_cor_header( file, info, &cor_header )) return FALSE;
        if (!(cor_header.Flags & COMIMAGE_FLAGS_ILONLY)) return FALSE;
2099
    }
2100
    return TRUE;
2101 2102 2103 2104 2105 2106
#else
    return FALSE;  /* no wow64 support on other platforms */
#endif
}


2107 2108 2109 2110 2111 2112 2113 2114 2115 2116
/******************************************************************
 *		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;

2117 2118
    if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
    if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131
    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 )
{
2132
    if (len == -1) len = wcslen(str);
2133 2134 2135 2136 2137 2138 2139
    if (!len) return p;
    memcpy( p, str, len * sizeof(WCHAR) );
    p[len] = ';';
    return p + len + 1;
}


2140 2141 2142
/******************************************************************
 *           get_dll_load_path
 */
2143
static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2144 2145 2146 2147
{
    const WCHAR *mod_end = module;
    UNICODE_STRING name, value;
    WCHAR *p, *ret;
2148
    int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2149 2150 2151

    if (module)
    {
2152
        mod_end = get_module_path_end( module );
2153 2154 2155
        len += (mod_end - module) + 1;
    }

2156
    RtlInitUnicodeString( &name, L"PATH" );
2157 2158 2159 2160 2161 2162
    value.Length = 0;
    value.MaximumLength = 0;
    value.Buffer = NULL;
    if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
        path_len = value.Length;

2163
    if (dll_dir) len += wcslen( dll_dir ) + 1;
2164 2165
    else len += 2;  /* current directory */
    if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2166
        return STATUS_NO_MEMORY;
2167 2168 2169

    p = append_path( p, module, mod_end - module );
    if (dll_dir) p = append_path( p, dll_dir, -1 );
2170
    else if (!safe_mode) p = append_path( p, L".", -1 );
2171
    p = append_path( p, system_path, -1 );
2172
    if (!dll_dir && safe_mode) p = append_path( p, L".", -1 );
2173 2174

    value.Buffer = p;
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
    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;
}


2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
/******************************************************************
 *		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 );
2216
        if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
            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 )
2233
            len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2234 2235 2236
        if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
    }

2237
    if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248

    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) );
        }
2249
        if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260
        else
        {
            if (p > ret) p--;
            *p = 0;
        }
    }
    *path = ret;
    return STATUS_SUCCESS;
}


2261 2262 2263 2264 2265
/***********************************************************************
 *	open_dll_file
 *
 * Open a file for a new dll. Helper for find_dll_file.
 */
2266
static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2267
                               SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2268 2269 2270 2271 2272
{
    FILE_BASIC_INFORMATION info;
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK io;
    LARGE_INTEGER size;
2273
    FILE_OBJECTID_BUFFER fid;
2274
    NTSTATUS status;
2275
    HANDLE handle;
2276

2277
    if ((*pwm = find_fullname_module( nt_name ))) return STATUS_SUCCESS;
2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299

    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;
    }

2300
    if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
2301
    {
2302 2303
        memcpy( id, fid.ObjectId, sizeof(*id) );
        if ((*pwm = find_fileid_module( id )))
2304 2305
        {
            TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2306
                   (*pwm)->ldr.DllBase, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2307 2308 2309 2310 2311 2312
            NtClose( handle );
            return STATUS_SUCCESS;
        }
    }

    size.QuadPart = 0;
2313
    status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2314 2315 2316
                              SECTION_MAP_READ | SECTION_MAP_EXECUTE,
                              NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
    if (!status)
2317
    {
2318
        NtQuerySection( *mapping, SectionImageInformation, image_info, sizeof(*image_info), NULL );
2319 2320 2321 2322
        if (!is_valid_binary( handle, image_info ))
        {
            TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->Machine );
            status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2323
            NtClose( *mapping );
2324
            *mapping = NULL;
2325 2326 2327
        }
    }
    NtClose( handle );
2328 2329 2330 2331
    return status;
}


2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358
/******************************************************************************
 *	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;
        if (mod->CheckSum != nt->OptionalHeader.CheckSum) continue;
        if (NtAreMappedFilesTheSame( mod->DllBase, module ) != STATUS_SUCCESS) continue;
        return CONTAINING_RECORD( mod, WINE_MODREF, ldr );
    }
    return NULL;
}


2359 2360 2361
/******************************************************************************
 *	load_native_dll  (internal)
 */
2362
static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping,
2363
                                 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2364
                                 DWORD flags, WINE_MODREF** pwm )
2365
{
2366 2367 2368 2369 2370 2371
    void *module = NULL;
    SIZE_T len = 0;
    NTSTATUS status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
                                          ViewShare, 0, PAGE_EXECUTE_READ );

    if (status == STATUS_IMAGE_NOT_AT_BASE) status = STATUS_SUCCESS;
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
    if (status) return status;

    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;
    }
2383
#ifdef _WIN64
2384
    if (!convert_to_pe64( module, image_info )) status = STATUS_INVALID_IMAGE_FORMAT;
2385 2386 2387 2388
#endif
    if (!status) status = build_module( load_path, nt_name, &module, image_info, id, flags, pwm );
    if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module );
    return status;
2389 2390 2391
}


2392
/***********************************************************************
2393
 *           load_so_dll
2394
 */
2395
static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2396
                             DWORD flags, WINE_MODREF **pwm )
2397
{
2398 2399 2400
    void *module;
    NTSTATUS status;
    WINE_MODREF *wm;
2401
    UNICODE_STRING win_name = *nt_name;
2402

2403
    TRACE( "trying %s as so lib\n", debugstr_us(&win_name) );
2404
    if ((status = unix_funcs->load_so_dll( &win_name, &module )))
2405
    {
2406
        WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
2407 2408
        if (status == STATUS_INVALID_IMAGE_FORMAT) status = STATUS_INVALID_IMAGE_NOT_MZ;
        return status;
2409
    }
2410

2411
    if ((wm = get_modref( module )))  /* already loaded */
2412
    {
2413
        TRACE( "Found %s at %p for builtin %s\n",
2414 2415
               debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
        if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2416 2417 2418
    }
    else
    {
2419 2420
        SECTION_IMAGE_INFORMATION image_info = { 0 };

2421
        if ((status = build_module( load_path, &win_name, &module, &image_info, NULL, flags, &wm )))
2422
        {
2423
            if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2424 2425
            return status;
        }
2426
        TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
2427
    }
2428
    *pwm = wm;
2429
    return STATUS_SUCCESS;
2430 2431 2432
}


2433 2434 2435 2436 2437
/*************************************************************************
 *		build_main_module
 *
 * Build the module data for the main image.
 */
2438
static WINE_MODREF *build_main_module(void)
2439 2440 2441 2442 2443 2444 2445 2446
{
    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;

2447 2448 2449 2450
    default_load_path = params->DllPath.Buffer;
    if (!default_load_path)
        get_dll_load_path( params->ImagePathName.Buffer, NULL, dll_safe_mode, &default_load_path );

2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465
    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;
2466
    status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, &wm );
2467
    RtlFreeUnicodeString( &nt_name );
2468
    if (!status) return wm;
2469 2470 2471 2472
failed:
    MESSAGE( "wine: failed to create main module for %s, status %x\n",
             debugstr_us(&params->ImagePathName), status );
    NtTerminateProcess( GetCurrentProcess(), status );
2473
    return NULL;  /* unreached */
2474 2475 2476
}


2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
/***********************************************************************
 *	build_dlldata_path
 *
 * Helper for find_actctx_dll.
 */
static NTSTATUS build_dlldata_path( LPCWSTR libname, ACTCTX_SECTION_KEYED_DATA *data, LPWSTR *fullname )
{
    struct dllredirect_data *dlldata = data->lpData;
    char *base = data->lpSectionBase;
    SIZE_T total = dlldata->total_len + (wcslen(libname) + 1) * sizeof(WCHAR);
    WCHAR *p, *buffer;
    NTSTATUS status = STATUS_SUCCESS;
    ULONG i;

    if (!(p = buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
    for (i = 0; i < dlldata->paths_count; i++)
    {
        memcpy( p, base + dlldata->paths[i].offset, dlldata->paths[i].len );
        p += dlldata->paths[i].len / sizeof(WCHAR);
    }
2497 2498
    if (p == buffer || p[-1] == '\\') wcscpy( p, libname );
    else *p = 0;
2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515

    if (dlldata->flags & DLL_REDIRECT_PATH_EXPAND)
    {
        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;
}


2516 2517 2518 2519 2520 2521 2522 2523 2524
/***********************************************************************
 *	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','\\'};

2525
    ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info = NULL;
2526
    ACTCTX_SECTION_KEYED_DATA data;
2527
    struct dllredirect_data *dlldata;
2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
    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;

2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551
    if (data.ulLength < offsetof( struct dllredirect_data, paths[0] ))
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }
    dlldata = data.lpData;
    if (!(dlldata->flags & DLL_REDIRECT_PATH_OMITS_ASSEMBLY_ROOT))
    {
        status = build_dlldata_path( libname, &data, fullname );
        goto done;
    }

2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568
    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 */
    }

2569
    if (!info->lpAssemblyManifestPath)
2570 2571 2572 2573 2574
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }

2575
    if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2576
    {
2577
        DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2578
        p++;
2579
        len = wcslen( p );
2580 2581
        if (!dirlen || len <= dirlen ||
            RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2582
            wcsicmp( p + dirlen, L".manifest" ))
2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
        {
            /* 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;
2595
            wcscpy( p, libname );
2596 2597 2598 2599
            goto done;
        }
    }

2600 2601 2602 2603 2604 2605
    if (!info->lpAssemblyDirectoryName)
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }

2606
    needed = (wcslen(windows_dir) * sizeof(WCHAR) +
2607
              sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2608 2609 2610 2611 2612 2613

    if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
    {
        status = STATUS_NO_MEMORY;
        goto done;
    }
2614
    wcscpy( p, windows_dir );
2615
    p += wcslen(p);
2616
    memcpy( p, winsxsW, sizeof(winsxsW) );
2617
    p += ARRAY_SIZE( winsxsW );
2618 2619 2620
    memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
    p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
    *p++ = '\\';
2621
    wcscpy( p, libname );
2622 2623 2624 2625 2626 2627 2628
done:
    RtlFreeHeap( GetProcessHeap(), 0, info );
    RtlReleaseActivationContext( data.hActCtx );
    return status;
}


2629 2630 2631 2632 2633 2634 2635 2636 2637 2638
/***********************************************************************
 *	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 (;;)
    {
2639
        ret->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
        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 );
2650 2651 2652 2653 2654
        if (status != STATUS_BUFFER_TOO_SMALL)
        {
            ret->Buffer = NULL;
            return status;
        }
2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683
        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;

    if (!get_env_var( L"WINEBUILDDIR", 20 + 2 * wcslen(name), new_name ))
    {
        RtlAppendUnicodeToString( new_name, L"\\dlls\\" );
        RtlAppendUnicodeToString( new_name, name );
        if ((ext = wcsrchr( name, '.' )) && !wcscmp( ext, L".dll" )) new_name->Length -= 4 * sizeof(WCHAR);
        RtlAppendUnicodeToString( new_name, L"\\" );
        RtlAppendUnicodeToString( new_name, name );
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
2684
        if (status != STATUS_DLL_NOT_FOUND) goto done;
2685 2686
        RtlAppendUnicodeToString( new_name, L".fake" );
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
2687
        if (status != STATUS_DLL_NOT_FOUND) goto done;
2688 2689
        RtlFreeUnicodeString( new_name );
    }
2690

2691 2692 2693
    for (i = 0; ; i++)
    {
        swprintf( dllpath, ARRAY_SIZE(dllpath), L"WINEDLLDIR%u", i );
2694
        if (get_env_var( dllpath, wcslen(pe_dir) + wcslen(name) + 1, new_name )) break;
2695
        len = new_name->Length;
2696 2697 2698 2699 2700 2701
        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;
2702 2703 2704 2705
        RtlAppendUnicodeToString( new_name, L"\\" );
        RtlAppendUnicodeToString( new_name, name );
        status = open_dll_file( new_name, pwm, mapping, image_info, id );
        if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2706
        else if (status != STATUS_DLL_NOT_FOUND) goto done;
2707 2708 2709
        RtlFreeUnicodeString( new_name );
    }
    if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720

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 );
    }
2721 2722 2723 2724
    return status;
}


2725 2726 2727 2728 2729
/***********************************************************************
 *	search_dll_file
 *
 * Search for dll in the specified paths.
 */
2730
static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
2731
                                 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
2732
                                 struct file_id *id )
2733 2734
{
    WCHAR *name;
2735
    BOOL found_image = FALSE;
2736
    NTSTATUS status = STATUS_DLL_NOT_FOUND;
2737 2738 2739 2740
    ULONG len;

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

2742 2743
    if (len < wcslen( system_dir )) len = wcslen( system_dir );
    len += wcslen( search ) + 2;
2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756

    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++] = '\\';
2757
        wcscpy( name + len, search );
2758 2759 2760 2761

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

2762
        status = open_dll_file( nt_name, pwm, mapping, image_info, id );
2763 2764
        if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
        else if (status != STATUS_DLL_NOT_FOUND) goto done;
2765
        RtlFreeUnicodeString( nt_name );
2766 2767 2768
        paths = ptr;
    }

2769 2770
    if (found_image)
        status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2771
    else if (is_prefix_bootstrap && !contains_path( search ))
2772
        status = find_builtin_without_file( search, nt_name, pwm, mapping, image_info, id );
2773 2774 2775 2776 2777 2778 2779

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


2780 2781 2782 2783 2784
/***********************************************************************
 *	find_dll_file
 *
 * Find the file (or already loaded module) for a given dll name.
 */
2785
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
2786
                               UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2787
                               SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2788
{
2789
    WCHAR *ext, *dllname;
2790
    NTSTATUS status;
2791
    ULONG wow64_old_value = 0;
2792

2793
    *pwm = NULL;
2794
    dllname = NULL;
2795 2796

    if (default_ext)  /* first append default extension */
2797
    {
2798
        if (!(ext = wcsrchr( libname, '.')) || wcschr( ext, '/' ) || wcschr( ext, '\\'))
2799 2800
        {
            if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
2801
                                             (wcslen(libname)+wcslen(default_ext)+1) * sizeof(WCHAR))))
2802
                return STATUS_NO_MEMORY;
2803
            wcscpy( dllname, libname );
2804
            wcscat( dllname, default_ext );
2805 2806
            libname = dllname;
        }
2807 2808
    }

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

2812
    nt_name->Buffer = NULL;
2813 2814 2815

    if (!contains_path( libname ))
    {
2816
        WCHAR *fullname = NULL;
2817 2818 2819 2820

        status = find_actctx_dll( libname, &fullname );
        if (status == STATUS_SUCCESS)
        {
2821
            TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
2822 2823 2824
            RtlFreeHeap( GetProcessHeap(), 0, dllname );
            libname = dllname = fullname;
        }
2825 2826 2827 2828 2829 2830 2831 2832 2833
        else
        {
            if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
            if ((*pwm = find_basename_module( libname )) != NULL)
            {
                status = STATUS_SUCCESS;
                goto done;
            }
        }
2834 2835
    }

2836
    if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
2837
        status = search_dll_file( load_path, libname, nt_name, pwm, mapping, image_info, id );
2838
    else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
2839
        status = open_dll_file( nt_name, pwm, mapping, image_info, id );
2840

2841 2842 2843 2844
    /* 16-bit files can't be loaded from the prefix */
    if (status && libname[0] && libname[1] && !wcscmp( libname + wcslen(libname) - 2, L"16" ) && !contains_path( libname ))
        status = find_builtin_without_file( libname, nt_name, pwm, mapping, image_info, id );

2845 2846
    if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT;

2847
done:
2848
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
2849
    if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
2850
    return status;
2851 2852 2853
}


2854
/***********************************************************************
2855
 *	load_dll  (internal)
2856 2857
 *
 * Load a PE style module according to the load order.
2858
 * The loader_section must be locked while calling this function.
2859
 */
2860 2861
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
                          DWORD flags, WINE_MODREF** pwm )
2862
{
2863
    UNICODE_STRING nt_name;
2864
    struct file_id id;
2865
    HANDLE mapping = 0;
2866
    SECTION_IMAGE_INFORMATION image_info;
2867
    NTSTATUS nts;
2868
    ULONG64 prev;
2869

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

2872
    nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
2873 2874

    if (*pwm)  /* found already loaded module */
2875
    {
2876 2877
        if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;

2878
        TRACE("Found %s for %s at %p, count=%d\n",
2879
              debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
2880
              (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
2881
        RtlFreeUnicodeString( &nt_name );
2882
        return STATUS_SUCCESS;
2883 2884
    }

2885
    if (nts && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
2886

2887 2888 2889 2890 2891 2892 2893 2894 2895 2896
    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;
    }
2897

2898
    switch (nts)
2899
    {
2900
    case STATUS_INVALID_IMAGE_NOT_MZ:  /* not in PE format, maybe it's a .so file */
2901
        nts = load_so_dll( load_path, &nt_name, flags, pwm );
2902 2903 2904
        break;

    case STATUS_SUCCESS:  /* valid PE file */
2905 2906
        nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, pwm );
        break;
2907
    }
2908 2909 2910 2911 2912

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

2914
done:
2915
    if (nts == STATUS_SUCCESS)
2916
        TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.DllBase);
2917 2918
    else
        WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
2919

2920
    if (mapping) NtClose( mapping );
2921
    RtlFreeUnicodeString( &nt_name );
2922
    return nts;
2923 2924
}

2925 2926 2927 2928 2929 2930 2931

/***********************************************************************
 *              __wine_init_unix_lib
 */
NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
{
    WINE_MODREF *wm;
2932
    NTSTATUS ret;
2933 2934 2935

    RtlEnterCriticalSection( &loader_section );

2936
    if ((wm = get_modref( module ))) ret = unix_funcs->init_unix_lib( module, reason, ptr_in, ptr_out );
2937 2938 2939 2940 2941 2942 2943
    else ret = STATUS_INVALID_HANDLE;

    RtlLeaveCriticalSection( &loader_section );
    return ret;
}


2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954
/***********************************************************************
 *              __wine_ctrl_routine
 */
NTSTATUS WINAPI __wine_ctrl_routine( void *arg )
{
    DWORD ret = 0;

    if (pCtrlRoutine && NtCurrentTeb()->Peb->ProcessParameters->ConsoleHandle) ret = pCtrlRoutine( arg );
    RtlExitUserThread( ret );
}

2955 2956 2957
/******************************************************************
 *		LdrLoadDll (NTDLL.@)
 */
2958 2959
NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
                                             const UNICODE_STRING *libname, HMODULE* hModule)
2960 2961
{
    WINE_MODREF *wm;
2962
    NTSTATUS nts;
2963 2964 2965

    RtlEnterCriticalSection( &loader_section );

2966
    nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm );
2967 2968

    if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
2969
    {
2970
        nts = process_attach( wm, NULL );
2971
        if (nts != STATUS_SUCCESS)
2972
        {
2973
            LdrUnloadDll(wm->ldr.DllBase);
2974 2975 2976
            wm = NULL;
        }
    }
2977
    *hModule = (wm) ? wm->ldr.DllBase : NULL;
2978

2979
    RtlLeaveCriticalSection( &loader_section );
2980 2981 2982
    return nts;
}

2983 2984 2985 2986 2987 2988 2989

/******************************************************************
 *		LdrGetDllHandle (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
{
    NTSTATUS status;
2990
    UNICODE_STRING nt_name;
2991
    WINE_MODREF *wm;
2992
    HANDLE mapping;
2993
    SECTION_IMAGE_INFORMATION image_info;
2994
    struct file_id id;
2995 2996 2997

    RtlEnterCriticalSection( &loader_section );

2998
    status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id );
2999

3000
    if (wm) *base = wm->ldr.DllBase;
3001
    else
3002
    {
3003
        if (status == STATUS_SUCCESS) NtClose( mapping );
3004
        status = STATUS_DLL_NOT_FOUND;
3005
    }
3006
    RtlFreeUnicodeString( &nt_name );
3007 3008 3009 3010 3011 3012 3013

    RtlLeaveCriticalSection( &loader_section );
    TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
    return status;
}


3014 3015 3016 3017 3018 3019 3020 3021
/******************************************************************
 *		LdrAddRefDll (NTDLL.@)
 */
NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
{
    NTSTATUS ret = STATUS_SUCCESS;
    WINE_MODREF *wm;

3022
    if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %x not implemented\n", module, flags );
3023 3024 3025 3026 3027

    RtlEnterCriticalSection( &loader_section );

    if ((wm = get_modref( module )))
    {
3028 3029 3030 3031
        if (flags & LDR_ADDREF_DLL_PIN)
            wm->ldr.LoadCount = -1;
        else
            if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3032 3033 3034 3035 3036 3037 3038 3039 3040
        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;
}


3041 3042 3043 3044 3045 3046
/***********************************************************************
 *           LdrProcessRelocationBlock  (NTDLL.@)
 *
 * Apply relocations to a given page of a mapped PE image.
 */
IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3047
                                                          USHORT *relocs, INT_PTR delta )
3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065
{
    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;
3066
#ifdef _WIN64
3067 3068 3069
        case IMAGE_REL_BASED_DIR64:
            *(INT_PTR *)((char *)page + offset) += delta;
            break;
3070 3071 3072
#elif defined(__arm__)
        case IMAGE_REL_BASED_THUMB_MOV32:
        {
3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090
            DWORD *inst = (DWORD *)((char *)page + offset);
            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);
3091
            break;
3092
        }
3093
#endif
3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
        default:
            FIXME("Unknown/unsupported fixup type %x.\n", type);
            return NULL;
        }
        relocs++;
    }
    return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
}


3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115
/******************************************************************
 *		LdrQueryProcessModuleInformation
 *
 */
NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi, 
                                                 ULONG buf_size, ULONG* req_size)
{
    SYSTEM_MODULE*      sm = &smi->Modules[0];
    ULONG               size = sizeof(ULONG);
    NTSTATUS            nts = STATUS_SUCCESS;
    ANSI_STRING         str;
    char*               ptr;
3116
    PLIST_ENTRY         mark, entry;
3117
    LDR_DATA_TABLE_ENTRY *mod;
3118
    WORD id = 0;
3119 3120 3121 3122

    smi->ModulesCount = 0;

    RtlEnterCriticalSection( &loader_section );
3123 3124
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3125
    {
3126
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3127 3128 3129
        size += sizeof(*sm);
        if (size <= buf_size)
        {
3130
            sm->Section = 0; /* FIXME */
3131 3132
            sm->MappedBaseAddress = mod->DllBase;
            sm->ImageBaseAddress = mod->DllBase;
3133 3134
            sm->ImageSize = mod->SizeOfImage;
            sm->Flags = mod->Flags;
3135 3136 3137
            sm->LoadOrderIndex = id++;
            sm->InitOrderIndex = 0; /* FIXME */
            sm->LoadCount = mod->LoadCount;
3138 3139
            str.Length = 0;
            str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
Mike McCormack's avatar
Mike McCormack committed
3140
            str.Buffer = (char*)sm->Name;
3141
            RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
Mike McCormack's avatar
Mike McCormack committed
3142 3143
            ptr = strrchr(str.Buffer, '\\');
            sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156

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

    if (req_size) *req_size = size;

    return nts;
}

3157

3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174
static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, ULONG *value )
{
    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;
3175
        *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219
    }
    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 )
{
    static const WCHAR optionsW[] = {'M','a','c','h','i','n','e','\\',
                                     'S','o','f','t','w','a','r','e','\\',
                                     'M','i','c','r','o','s','o','f','t','\\',
                                     'W','i','n','d','o','w','s',' ','N','T','\\',
                                     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                     'I','m','a','g','e',' ','F','i','l','e',' ',
                                     'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
3220
    WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234
    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;

3235 3236
    p = key->Buffer + key->Length / sizeof(WCHAR);
    while (p > key->Buffer && p[-1] != '\\') p--;
3237 3238 3239 3240 3241
    len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
    name_str.Buffer = path;
    name_str.Length = sizeof(optionsW) + len;
    name_str.MaximumLength = name_str.Length;
    memcpy( path, optionsW, sizeof(optionsW) );
3242
    memcpy( path + ARRAY_SIZE( optionsW ), p, len );
3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257
    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;
}


3258 3259 3260 3261 3262 3263 3264 3265
/******************************************************************
 *		RtlDllShutdownInProgress  (NTDLL.@)
 */
BOOLEAN WINAPI RtlDllShutdownInProgress(void)
{
    return process_detaching;
}

3266 3267 3268 3269
/****************************************************************************
 *              LdrResolveDelayLoadedAPI   (NTDLL.@)
 */
void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3270 3271
                                       PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
                                       PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282
                                       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;

3283
    TRACE( "(%p, %p, %p, %p, %p, 0x%08x)\n", base, desc, dllhook, syshook, addr, flags );
3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328

    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;
3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342

    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);
    }
3343
}
3344

3345 3346 3347 3348
/******************************************************************
 *		LdrShutdownProcess (NTDLL.@)
 *
 */
3349
void WINAPI LdrShutdownProcess(void)
3350
{
3351 3352
    BOOL detaching = process_detaching;

3353
    TRACE("()\n");
3354

3355 3356
    process_detaching = TRUE;
    if (!detaching)
3357 3358
        RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );

3359
    process_detach();
3360 3361
}

3362 3363 3364 3365 3366 3367 3368 3369 3370 3371

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

3375 3376 3377 3378
/******************************************************************
 *		LdrShutdownThread (NTDLL.@)
 *
 */
3379
void WINAPI LdrShutdownThread(void)
3380
{
3381
    PLIST_ENTRY mark, entry;
3382
    LDR_DATA_TABLE_ENTRY *mod;
3383
    WINE_MODREF *wm;
3384 3385
    UINT i;
    void **pointers;
3386

3387 3388 3389
    TRACE("()\n");

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

3392 3393
    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );

3394
    RtlEnterCriticalSection( &loader_section );
3395
    wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3396

3397 3398
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3399
    {
3400
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
3401
                                InInitializationOrderLinks);
3402
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3403
            continue;
3404
        if ( mod->Flags & LDR_NO_DLL_CALLS )
3405 3406
            continue;

3407 3408
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
                        DLL_THREAD_DETACH, NULL );
3409 3410
    }

3411 3412
    if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );

3413 3414
    RtlAcquirePebLock();
    RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3415 3416 3417 3418 3419
    if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
    {
        for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
        RtlFreeHeap( GetProcessHeap(), 0, pointers );
    }
3420
    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
3421
    NtCurrentTeb()->FlsSlots = NULL;
3422
    RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3423 3424 3425
    NtCurrentTeb()->TlsExpansionSlots = NULL;
    RtlReleasePebLock();

3426
    RtlLeaveCriticalSection( &loader_section );
3427 3428
    /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */
    if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] );
3429
    RtlFreeThreadActivationContextStack();
3430 3431
}

3432 3433 3434 3435 3436 3437 3438

/***********************************************************************
 *           free_modref
 *
 */
static void free_modref( WINE_MODREF *wm )
{
3439
    RemoveEntryList(&wm->ldr.InLoadOrderLinks);
3440
    RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
3441 3442
    if (wm->ldr.InInitializationOrderLinks.Flink)
        RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
3443 3444 3445 3446 3447 3448 3449

    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" );

3450
    free_tls_slot( &wm->ldr );
3451
    RtlReleaseActivationContext( wm->ldr.ActivationContext );
3452
    NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
3453 3454 3455 3456 3457 3458
    if (cached_modref == wm) cached_modref = NULL;
    RtlFreeUnicodeString( &wm->ldr.FullDllName );
    RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
    RtlFreeHeap( GetProcessHeap(), 0, wm );
}

3459 3460 3461 3462 3463
/***********************************************************************
 *           MODULE_FlushModrefs
 *
 * Remove all unused modrefs and call the internal unloading routines
 * for the library type.
3464 3465
 *
 * The loader_section must be locked while calling this function.
3466 3467 3468
 */
static void MODULE_FlushModrefs(void)
{
3469
    PLIST_ENTRY mark, entry, prev;
3470
    LDR_DATA_TABLE_ENTRY *mod;
3471
    WINE_MODREF*wm;
3472

3473 3474
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = prev)
3475
    {
3476
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
3477 3478
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
3479 3480
        if (!mod->LoadCount) free_modref( wm );
    }
3481

3482 3483 3484 3485
    /* 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)
    {
3486
        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3487 3488 3489
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
        if (!mod->LoadCount) free_modref( wm );
3490 3491 3492 3493 3494 3495
    }
}

/***********************************************************************
 *           MODULE_DecRefCount
 *
3496
 * The loader_section must be locked while calling this function.
3497 3498 3499 3500 3501
 */
static void MODULE_DecRefCount( WINE_MODREF *wm )
{
    int i;

3502
    if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3503 3504
        return;

3505
    if ( wm->ldr.LoadCount <= 0 )
3506 3507
        return;

3508
    --wm->ldr.LoadCount;
3509
    TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3510

3511
    if ( wm->ldr.LoadCount == 0 )
3512
    {
3513
        wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
3514 3515 3516 3517 3518

        for ( i = 0; i < wm->nDeps; i++ )
            if ( wm->deps[i] )
                MODULE_DecRefCount( wm->deps[i] );

3519
        wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
3520 3521

        module_push_unload_trace( &wm->ldr );
3522 3523 3524 3525 3526 3527 3528 3529 3530 3531
    }
}

/******************************************************************
 *		LdrUnloadDll (NTDLL.@)
 *
 *
 */
NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
{
3532
    WINE_MODREF *wm;
3533 3534
    NTSTATUS retv = STATUS_SUCCESS;

3535 3536
    if (process_detaching) return retv;

3537 3538 3539 3540
    TRACE("(%p)\n", hModule);

    RtlEnterCriticalSection( &loader_section );

3541 3542
    free_lib_count++;
    if ((wm = get_modref( hModule )) != NULL)
3543
    {
3544
        TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
3545

3546 3547
        /* Recursively decrement reference counts */
        MODULE_DecRefCount( wm );
3548

3549 3550 3551 3552 3553
        /* Call process detach notifications */
        if ( free_lib_count <= 1 )
        {
            process_detach();
            MODULE_FlushModrefs();
3554 3555
        }

3556
        TRACE("END\n");
3557
    }
3558 3559 3560 3561
    else
        retv = STATUS_DLL_NOT_FOUND;

    free_lib_count--;
3562 3563 3564 3565 3566 3567

    RtlLeaveCriticalSection( &loader_section );

    return retv;
}

3568 3569 3570 3571 3572
/***********************************************************************
 *           RtlImageNtHeader   (NTDLL.@)
 */
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
{
3573
    IMAGE_NT_HEADERS *ret;
3574

3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585
    __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;
        }
    }
3586
    __EXCEPT_PAGE_FAULT
3587
    {
3588
        return NULL;
3589
    }
3590
    __ENDTRY
3591 3592 3593
    return ret;
}

3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616
/***********************************************************************
 *           process_breakpoint
 *
 * Trigger a debug breakpoint if the process is being debugged.
 */
static void process_breakpoint(void)
{
    DWORD_PTR port = 0;

    NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort, &port, sizeof(port), NULL );
    if (!port) return;

    __TRY
    {
        DbgBreakPoint();
    }
    __EXCEPT_ALL
    {
        /* do nothing */
    }
    __ENDTRY
}

3617

3618 3619 3620 3621 3622 3623
/***********************************************************************
 *           load_global_options
 */
static void load_global_options(void)
{
    OBJECT_ATTRIBUTES attr;
3624
    UNICODE_STRING name_str, val_str;
3625 3626 3627
    HANDLE hkey;
    ULONG value;

3628 3629 3630 3631
    RtlInitUnicodeString( &name_str, L"WINEBOOTSTRAPMODE" );
    val_str.MaximumLength = 0;
    is_prefix_bootstrap = RtlQueryEnvironmentVariable_U( NULL, &name_str, &val_str ) != STATUS_VARIABLE_NOT_FOUND;

3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669
    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.ObjectName = &name_str;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitUnicodeString( &name_str, L"Machine\\System\\CurrentControlSet\\Control\\Session Manager" );

    if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
    {
        query_dword_option( hkey, L"GlobalFlag", &NtCurrentTeb()->Peb->NtGlobalFlag );
        query_dword_option( hkey, L"SafeProcessSearchMode", &path_safe_mode );
        query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode );

        if (!query_dword_option( hkey, L"CriticalSectionTimeout", &value ))
            NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart = (ULONGLONG)value * -10000000;

        if (!query_dword_option( hkey, L"HeapSegmentReserve", &value ))
            NtCurrentTeb()->Peb->HeapSegmentReserve = value;

        if (!query_dword_option( hkey, L"HeapSegmentCommit", &value ))
            NtCurrentTeb()->Peb->HeapSegmentCommit = value;

        if (!query_dword_option( hkey, L"HeapDeCommitTotalFreeThreshold", &value ))
            NtCurrentTeb()->Peb->HeapDeCommitTotalFreeThreshold = value;

        if (!query_dword_option( hkey, L"HeapDeCommitFreeBlockThreshold", &value ))
            NtCurrentTeb()->Peb->HeapDeCommitFreeBlockThreshold = value;

        NtClose( hkey );
    }
    LdrQueryImageFileExecutionOptions( &NtCurrentTeb()->Peb->ProcessParameters->ImagePathName,
                                       L"GlobalFlag", REG_DWORD, &NtCurrentTeb()->Peb->NtGlobalFlag,
                                       sizeof(DWORD), NULL );
    heap_set_debug_flags( GetProcessHeap() );
}


3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717
#ifndef _WIN64
void *Wow64Transition = NULL;

static void map_wow64cpu(void)
{
    SIZE_T size = 0;
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING string;
    HANDLE file, section;
    IO_STATUS_BLOCK io;
    NTSTATUS status;

    RtlInitUnicodeString( &string, L"\\??\\C:\\windows\\sysnative\\wow64cpu.dll" );
    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 )))
    {
        WARN("failed to open wow64cpu, status %#x\n", status);
        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 );
}

static void init_wow64(void)
{
    PEB *peb = NtCurrentTeb()->Peb;
    PEB64 *peb64;

    if (!NtCurrentTeb64()) return;
    peb64 = UlongToPtr( NtCurrentTeb64()->Peb );
    peb64->OSMajorVersion   = peb->OSMajorVersion;
    peb64->OSMinorVersion   = peb->OSMinorVersion;
    peb64->OSBuildNumber    = peb->OSBuildNumber;
    peb64->OSPlatformId     = peb->OSPlatformId;

    map_wow64cpu();
}
#endif


3718 3719
/******************************************************************
 *		LdrInitializeThunk (NTDLL.@)
3720
 *
3721 3722
 * Attach to all the loaded dlls.
 * If this is the first time, perform the full process initialization.
3723
 */
3724
void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR unknown3, ULONG_PTR unknown4 )
3725
{
3726 3727
    static int attach_done;
    int i;
3728
    NTSTATUS status;
3729
    ULONG_PTR cookie;
3730
    WINE_MODREF *wm;
3731
    void **entry;
3732

3733 3734 3735 3736 3737 3738 3739
#ifdef __i386__
    entry = (void **)&context->Eax;
#elif defined(__x86_64__)
    entry = (void **)&context->Rcx;
#elif defined(__arm__)
    entry = (void **)&context->R0;
#elif defined(__aarch64__)
3740
    entry = (void **)&context->u.s.X0;
3741 3742
#endif

3743
    if (process_detaching) NtTerminateThread( GetCurrentThread(), 0 );
3744

3745
    RtlEnterCriticalSection( &loader_section );
3746 3747

    if (!imports_fixup_done)
3748
    {
3749 3750
        ANSI_STRING func_name;
        WINE_MODREF *kernel32;
3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763
        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 );
        RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
3764

3765 3766 3767
        init_user_process_params();
        load_global_options();
        version_init();
3768 3769 3770
#ifndef _WIN64
        init_wow64();
#endif
3771 3772 3773 3774 3775
        wm = build_main_module();
        wm->ldr.LoadCount = -1;

        build_ntdll_module();

3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788
        if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32 )) != STATUS_SUCCESS)
        {
            MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }
        kernel32_handle = kernel32->ldr.DllBase;
        RtlInitAnsiString( &func_name, "BaseThreadInitThunk" );
        if ((status = LdrGetProcedureAddress( kernel32_handle, &func_name,
                                              0, (void **)&pBaseThreadInitThunk )) != STATUS_SUCCESS)
        {
            MESSAGE( "wine: could not find BaseThreadInitThunk in kernel32.dll, status %x\n", status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }
3789 3790
        RtlInitAnsiString( &func_name, "CtrlRoutine" );
        LdrGetProcedureAddress( kernel32_handle, &func_name, 0, (void **)&pCtrlRoutine );
3791

3792
        actctx_init();
3793
        if (wm->ldr.Flags & LDR_COR_ILONLY)
3794
            status = fixup_imports_ilonly( wm, NULL, entry );
3795
        else
3796
            status = fixup_imports( wm, NULL );
3797 3798

        if (status)
3799 3800 3801 3802 3803
        {
            ERR( "Importing dlls for %s failed, status %x\n",
                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }
3804
        imports_fixup_done = TRUE;
3805
    }
3806
    else wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3807 3808 3809 3810 3811

    RtlAcquirePebLock();
    InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
    RtlReleasePebLock();

3812 3813
    NtCurrentTeb()->FlsSlots = fls_alloc_data();

3814
    if (!attach_done)  /* first time around */
3815
    {
3816
        attach_done = 1;
3817 3818 3819 3820 3821 3822
        if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
        {
            ERR( "TLS init  failed when loading %s, status %x\n",
                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
            NtTerminateProcess( GetCurrentProcess(), status );
        }
3823
        wm->ldr.Flags |= LDR_PROCESS_ATTACHED;  /* don't try to attach again */
3824 3825 3826 3827
        if (wm->ldr.ActivationContext)
            RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );

        for (i = 0; i < wm->nDeps; i++)
3828
        {
3829 3830 3831 3832 3833 3834 3835 3836 3837 3838
            if (!wm->deps[i]) continue;
            if ((status = process_attach( wm->deps[i], context )) != STATUS_SUCCESS)
            {
                if (last_failed_modref)
                    ERR( "%s failed to initialize, aborting\n",
                         debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
                ERR( "Initializing dlls for %s failed, status %x\n",
                     debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
                NtTerminateProcess( GetCurrentProcess(), status );
            }
3839
        }
3840
        unix_funcs->virtual_release_address_space();
3841
        if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
3842
        if (wm->ldr.Flags & LDR_WINE_INTERNAL) unix_funcs->init_builtin_dll( wm->ldr.DllBase );
3843
        if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
3844
        process_breakpoint();
3845 3846 3847
    }
    else
    {
3848 3849
        if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
            NtTerminateThread( GetCurrentThread(), status );
3850
        thread_attach();
3851
        if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
3852 3853
    }

3854
    RtlLeaveCriticalSection( &loader_section );
3855
    signal_start_thread( context );
3856 3857 3858
}


3859 3860 3861 3862 3863 3864 3865 3866
/***********************************************************************
 *           RtlImageDirectoryEntryToData   (NTDLL.@)
 */
PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
{
    const IMAGE_NT_HEADERS *nt;
    DWORD addr;

3867 3868
    if ((ULONG_PTR)module & 1) image = FALSE;  /* mapped as data file */
    module = (HMODULE)((ULONG_PTR)module & ~3);
3869
    if (!(nt = RtlImageNtHeader( module ))) return NULL;
3870 3871
    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
    {
3872
        const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
3873 3874 3875 3876 3877 3878 3879 3880

        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)
    {
3881
        const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
3882 3883 3884 3885 3886 3887 3888

        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;
3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901

    /* 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;
Eric Pouech's avatar
Eric Pouech committed
3902 3903 3904 3905
    const IMAGE_SECTION_HEADER *sec;

    sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
                                        nt->FileHeader.SizeOfOptionalHeader);
3906 3907 3908
    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
3909
            return (PIMAGE_SECTION_HEADER)sec;
3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933
    }
    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);
}
3934 3935


3936 3937 3938 3939 3940
/***********************************************************************
 *           RtlPcToFileHeader   (NTDLL.@)
 */
PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
{
3941
    LDR_DATA_TABLE_ENTRY *module;
3942 3943 3944
    PVOID ret = NULL;

    RtlEnterCriticalSection( &loader_section );
3945
    if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase;
3946 3947 3948 3949 3950 3951
    RtlLeaveCriticalSection( &loader_section );
    *address = ret;
    return ret;
}


3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990
/****************************************************************************
 *		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;
}


3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108
/****************************************************************************
 *		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;
        if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH))
            module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
        status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
    }

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


4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124
/*************************************************************************
 *		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:
4125
        InterlockedExchange( (int *)&path_safe_mode, 2 );
4126 4127 4128 4129 4130 4131 4132 4133 4134
        return STATUS_SUCCESS;
    default:
        return STATUS_INVALID_PARAMETER;
    }

    for (;;)
    {
        int prev = path_safe_mode;
        if (prev == 2) break;  /* permanently set */
4135
        if (InterlockedCompareExchange( (int *)&path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4136 4137 4138 4139 4140
    }
    return STATUS_ACCESS_DENIED;
}


4141 4142 4143 4144 4145
/******************************************************************
 *           RtlGetExePath   (NTDLL.@)
 */
NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
{
4146
    const WCHAR *dlldir = L".";
4147 4148 4149
    const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;

    /* same check as NeedCurrentDirectoryForExePathW */
4150
    if (!wcschr( name, '\\' ))
4151 4152 4153
    {
        UNICODE_STRING name, value = { 0 };

4154
        RtlInitUnicodeString( &name, L"NoDefaultCurrentDirectoryInExePath" );
4155
        if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4156
            dlldir = L"";
4157 4158 4159 4160 4161
    }
    return get_dll_load_path( module, dlldir, FALSE, path );
}


4162 4163 4164 4165 4166
/******************************************************************
 *           RtlGetSearchPath   (NTDLL.@)
 */
NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
{
4167 4168
    const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
    return get_dll_load_path( module, NULL, path_safe_mode, path );
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180
}


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


4181 4182 4183 4184 4185 4186 4187 4188 4189 4190
/******************************************************************
 *		DllMain   (NTDLL.@)
 */
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
{
    if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
    return TRUE;
}


4191 4192 4193
/***********************************************************************
 *           __wine_set_unix_funcs
 */
4194
NTSTATUS CDECL __wine_set_unix_funcs( int version, const struct unix_funcs *funcs )
4195
{
4196
    if (version != NTDLL_UNIXLIB_VERSION) return STATUS_REVISION_MISMATCH;
4197
    unix_funcs = funcs;
4198
    return STATUS_SUCCESS;
4199
}