loader.c 101 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
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
22 23 24
#include "config.h"
#include "wine/port.h"

25
#include <assert.h>
26
#include <stdarg.h>
27 28 29
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
30

31 32 33
#define NONAMELESSUNION
#define NONAMELESSSTRUCT

34 35
#include "ntstatus.h"
#define WIN32_NO_STATUS
36
#include "windef.h"
37
#include "winnt.h"
38
#include "winternl.h"
39

40
#include "wine/exception.h"
41
#include "wine/library.h"
42
#include "wine/unicode.h"
43
#include "wine/debug.h"
44 45
#include "wine/server.h"
#include "ntdll_misc.h"
46
#include "ddk/wdm.h"
47

48 49
WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay);
50
WINE_DECLARE_DEBUG_CHANNEL(snoop);
51
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
52
WINE_DECLARE_DEBUG_CHANNEL(imports);
53

54 55 56 57
/* we don't want to include winuser.h */
#define RT_MANIFEST                         ((ULONG_PTR)24)
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)

58 59
typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);

60
static int process_detaching = 0;  /* set on process detach to avoid deadlocks with thread detach */
61
static int free_lib_count;   /* recursion depth of LdrUnloadDll calls */
62

63 64 65 66 67
static const char * const reason_names[] =
{
    "PROCESS_DETACH",
    "PROCESS_ATTACH",
    "THREAD_ATTACH",
68 69 70
    "THREAD_DETACH",
    NULL, NULL, NULL, NULL,
    "WINE_PREATTACH"
71 72
};

73 74 75
static const WCHAR dllW[] = {'.','d','l','l',0};

/* internal representation of 32bit modules. per process. */
76
typedef struct _wine_modref
77 78 79 80
{
    LDR_MODULE            ldr;
    int                   nDeps;
    struct _wine_modref **deps;
81
} WINE_MODREF;
82

83 84 85 86 87
/* info about the current builtin dll load */
/* used to keep track of things across the register_dll constructor call */
struct builtin_load_info
{
    const WCHAR *load_path;
88
    const WCHAR *filename;
89 90 91 92
    NTSTATUS     status;
    WINE_MODREF *wm;
};

93 94
static struct builtin_load_info default_load_info;
static struct builtin_load_info *builtin_load_info = &default_load_info;
95

96
static HANDLE main_exe_file;
97 98 99
static UINT tls_module_count;      /* number of modules with TLS directory */
static UINT tls_total_size;        /* total size of TLS storage */
static const IMAGE_TLS_DIRECTORY **tls_dirs;  /* array of TLS directories */
100 101
#define TLS_ALIGNMENT (2 * sizeof(void *))
#define TLS_ALIGN(size) (((size) + TLS_ALIGNMENT - 1) & ~(TLS_ALIGNMENT - 1))
102

103 104
static RTL_CRITICAL_SECTION loader_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
105 106 107
{
    0, 0, &loader_section,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
108
      0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
109
};
110
static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
111

112
static WINE_MODREF *cached_modref;
113
static WINE_MODREF *current_modref;
114
static WINE_MODREF *last_failed_modref;
115

116
static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm );
117
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
118 119
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
120
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
121
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
122 123

/* convert PE image VirtualAddress to Real Address */
124
static inline void *get_rva( HMODULE module, DWORD va )
125 126 127
{
    return (void *)((char *)module + va);
}
128

129
/* check whether the file name contains a path */
130
static inline int contains_path( LPCWSTR name )
131 132 133 134 135
{
    return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
}

/* convert from straight ASCII to Unicode without depending on the current codepage */
136
static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
137 138 139 140
{
    while (len--) *dst++ = (unsigned char)*src++;
}

141 142 143 144 145 146 147 148 149 150 151

/*************************************************************************
 *		call_dll_entry_point
 *
 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
 * their entry point, so we need a small asm wrapper.
 */
#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"
152 153
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
                  __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
154
                  "movl %esp,%ebp\n\t"
155
                  __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
156
                  "pushl %ebx\n\t"
157
                  __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
158
                  "subl $8,%esp\n\t"
159 160 161 162 163 164 165
                  "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"
                  "leal -4(%ebp),%esp\n\t"
                  "popl %ebx\n\t"
166
                  __ASM_CFI(".cfi_same_value %ebx\n\t")
167
                  "popl %ebp\n\t"
168 169
                  __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
                  __ASM_CFI(".cfi_same_value %ebp\n\t")
170
                  "ret" )
171 172 173 174 175 176 177 178 179
#else /* __i386__ */
static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
                                         UINT reason, void *reserved )
{
    return proc( module, reason, reserved );
}
#endif /* __i386__ */


180
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
181 182 183 184 185
/*************************************************************************
 *		stub_entry_point
 *
 * Entry point for stub functions.
 */
186
static void stub_entry_point( const char *dll, const char *name, void *ret_addr )
187 188 189 190 191 192
{
    EXCEPTION_RECORD rec;

    rec.ExceptionCode           = EXCEPTION_WINE_STUB;
    rec.ExceptionFlags          = EH_NONCONTINUABLE;
    rec.ExceptionRecord         = NULL;
193
    rec.ExceptionAddress        = ret_addr;
194
    rec.NumberParameters        = 2;
195 196
    rec.ExceptionInformation[0] = (ULONG_PTR)dll;
    rec.ExceptionInformation[1] = (ULONG_PTR)name;
197 198 199 200
    for (;;) RtlRaiseException( &rec );
}


201
#include "pshpack1.h"
202
#ifdef __i386__
203 204 205 206 207 208
struct stub
{
    BYTE        pushl1;     /* pushl $name */
    const char *name;
    BYTE        pushl2;     /* pushl $dll */
    const char *dll;
209
    BYTE        call;       /* call stub_entry_point */
210 211
    DWORD       entry;
};
212 213 214 215 216 217 218 219 220 221 222 223 224
#elif defined(__arm__)
struct stub
{
    BYTE ldr_r0[4];        /* ldr r0, $dll */
    BYTE mov_pc_pc1[4];    /* mov pc,pc */
    const char *dll;
    BYTE ldr_r1[4];        /* ldr r1, $name */
    BYTE mov_pc_pc2[4];    /* mov pc,pc */
    const char *name;
    BYTE mov_r2_lr[4];     /* mov r2, lr */
    BYTE ldr_pc_pc[4];     /* ldr pc, [pc, #-4] */
    const void* entry;
};
225 226 227 228 229 230 231 232 233 234 235 236 237
#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
238
#include "poppack.h"
239 240 241 242 243 244

/*************************************************************************
 *		allocate_stub
 *
 * Allocate a stub entry point.
 */
245
static ULONG_PTR allocate_stub( const char *dll, const char *name )
246 247 248 249 250 251
{
#define MAX_SIZE 65536
    static struct stub *stubs;
    static unsigned int nb_stubs;
    struct stub *stub;

252
    if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
253 254 255

    if (!stubs)
    {
256
        SIZE_T size = MAX_SIZE;
257
        if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
258
                                     MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
259
            return 0xdeadbeef;
260 261
    }
    stub = &stubs[nb_stubs++];
262
#ifdef __i386__
263 264 265 266
    stub->pushl1    = 0x68;  /* pushl $name */
    stub->name      = name;
    stub->pushl2    = 0x68;  /* pushl $dll */
    stub->dll       = dll;
267
    stub->call      = 0xe8;  /* call stub_entry_point */
268
    stub->entry     = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
#elif defined(__arm__)
    stub->ldr_r0[0]     = 0x00;   /* ldr r0, $dll */
    stub->ldr_r0[1]     = 0x00;
    stub->ldr_r0[2]     = 0x9f;
    stub->ldr_r0[3]     = 0xe5;
    stub->mov_pc_pc1[0] = 0x0f;   /* mov pc,pc */
    stub->mov_pc_pc1[1] = 0xf0;
    stub->mov_pc_pc1[2] = 0xa0;
    stub->mov_pc_pc1[3] = 0xe1;
    stub->dll           = dll;
    stub->ldr_r1[0]     = 0x00;   /* ldr r1, $name */
    stub->ldr_r1[1]     = 0x10;
    stub->ldr_r1[2]     = 0x9f;
    stub->ldr_r1[3]     = 0xe5;
    stub->mov_pc_pc2[0] = 0x0f;   /* mov pc,pc */
    stub->mov_pc_pc2[1] = 0xf0;
    stub->mov_pc_pc2[2] = 0xa0;
    stub->mov_pc_pc2[3] = 0xe1;
    stub->name          = name;
    stub->mov_r2_lr[0]  = 0x0e;   /* mov r2, lr */
    stub->mov_r2_lr[1]  = 0x20;
    stub->mov_r2_lr[2]  = 0xa0;
    stub->mov_r2_lr[3]  = 0xe1;
    stub->ldr_pc_pc[0]  = 0x04;   /* ldr pc, [pc, #-4] */
    stub->ldr_pc_pc[1]  = 0xf0;
    stub->ldr_pc_pc[2]  = 0x1f;
    stub->ldr_pc_pc[3]  = 0xe5;
    stub->entry         = stub_entry_point;
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
#else
    stub->movq_rdi[0]     = 0x48;  /* movq $dll,%rdi */
    stub->movq_rdi[1]     = 0xbf;
    stub->dll             = dll;
    stub->movq_rsi[0]     = 0x48;  /* movq $name,%rsi */
    stub->movq_rsi[1]     = 0xbe;
    stub->name            = name;
    stub->movq_rsp_rdx[0] = 0x48;  /* movq (%rsp),%rdx */
    stub->movq_rsp_rdx[1] = 0x8b;
    stub->movq_rsp_rdx[2] = 0x14;
    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
314
    return (ULONG_PTR)stub;
315 316 317
}

#else  /* __i386__ */
318
static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
319 320 321
#endif  /* __i386__ */


322
/*************************************************************************
323 324 325 326
 *		get_modref
 *
 * Looks for the referenced HMODULE in the current process
 * The loader_section must be locked while calling this function.
327
 */
328
static WINE_MODREF *get_modref( HMODULE hmod )
329
{
330 331
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
332

333
    if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
334

335 336
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
337
    {
338 339 340 341
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
        if (mod->BaseAddress == hmod)
            return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        if (mod->BaseAddress > (void*)hmod) break;
342
    }
343
    return NULL;
344 345 346
}


347
/**********************************************************************
348
 *	    find_basename_module
349
 *
350
 * Find a module from its base name.
351 352
 * The loader_section must be locked while calling this function
 */
353
static WINE_MODREF *find_basename_module( LPCWSTR name )
354 355 356
{
    PLIST_ENTRY mark, entry;

357 358
    if (cached_modref && !strcmpiW( name, cached_modref->ldr.BaseDllName.Buffer ))
        return cached_modref;
359

360 361
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
362
    {
363 364 365 366 367 368
        LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
        if (!strcmpiW( name, mod->BaseDllName.Buffer ))
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
369
    }
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
    return NULL;
}


/**********************************************************************
 *	    find_fullname_module
 *
 * Find a module from its full path name.
 * The loader_section must be locked while calling this function
 */
static WINE_MODREF *find_fullname_module( LPCWSTR name )
{
    PLIST_ENTRY mark, entry;

    if (cached_modref && !strcmpiW( name, cached_modref->ldr.FullDllName.Buffer ))
        return cached_modref;
386 387 388 389

    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
390 391 392 393 394 395
        LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
        if (!strcmpiW( name, mod->FullDllName.Buffer ))
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
396
    }
397
    return NULL;
398 399 400
}


401 402 403 404 405 406
/*************************************************************************
 *		find_forwarded_export
 *
 * Find the final function pointer for a forwarded function.
 * The loader_section must be locked while calling this function.
 */
407
static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
408
{
Eric Pouech's avatar
Eric Pouech committed
409
    const IMAGE_EXPORT_DIRECTORY *exports;
410 411
    DWORD exp_size;
    WINE_MODREF *wm;
412
    WCHAR mod_name[32];
413
    const char *end = strrchr(forward, '.');
414 415 416
    FARPROC proc = NULL;

    if (!end) return NULL;
417
    if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL;
418
    ascii_to_unicode( mod_name, forward, end - forward );
419 420 421 422 423 424
    mod_name[end - forward] = 0;
    if (!strchrW( mod_name, '.' ))
    {
        if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name) - sizeof(dllW)) return NULL;
        memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
    }
425

426
    if (!(wm = find_basename_module( mod_name )))
427
    {
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
        TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
        if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS &&
            !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
        {
            if (process_attach( wm, NULL ) != STATUS_SUCCESS)
            {
                LdrUnloadDll( wm->ldr.BaseAddress );
                wm = NULL;
            }
        }

        if (!wm)
        {
            ERR( "module not found for forward '%s' used by %s\n",
                 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
            return NULL;
        }
445 446 447
    }
    if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
                                                 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
448 449 450 451 452 453 454
    {
        const char *name = end + 1;
        if (*name == '#')  /* ordinal */
            proc = find_ordinal_export( wm->ldr.BaseAddress, exports, exp_size, atoi(name+1), load_path );
        else
            proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, name, -1, load_path );
    }
455 456 457

    if (!proc)
    {
458 459 460 461
        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) );
462 463 464 465 466 467 468 469 470 471 472 473
    }
    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
474
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
475
                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
476 477
{
    FARPROC proc;
Eric Pouech's avatar
Eric Pouech committed
478
    const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
479 480 481

    if (ordinal >= exports->NumberOfFunctions)
    {
482
        TRACE("	ordinal %d out of range!\n", ordinal + exports->Base );
483 484 485 486 487 488 489
        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
490 491
    if (((const char *)proc >= (const char *)exports) && 
        ((const char *)proc < (const char *)exports + exp_size))
492
        return find_forwarded_export( module, (const char *)proc, load_path );
493

494
    if (TRACE_ON(snoop))
495
    {
496 497
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
        proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
498
    }
499
    if (TRACE_ON(relay))
500
    {
501
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
502
        proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
503 504 505 506 507 508 509 510 511 512 513
    }
    return proc;
}


/*************************************************************************
 *		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
514
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
515
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
516
{
Eric Pouech's avatar
Eric Pouech committed
517 518
    const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
    const DWORD *names = get_rva( module, exports->AddressOfNames );
519 520 521 522 523 524 525
    int min = 0, max = exports->NumberOfNames - 1;

    /* first check the hint */
    if (hint >= 0 && hint <= max)
    {
        char *ename = get_rva( module, names[hint] );
        if (!strcmp( ename, name ))
526
            return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
527 528 529 530 531 532 533 534
    }

    /* then do a binary search */
    while (min <= max)
    {
        int res, pos = (min + max) / 2;
        char *ename = get_rva( module, names[pos] );
        if (!(res = strcmp( ename, name )))
535
            return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
536 537 538
        if (res > 0) max = pos - 1;
        else min = pos + 1;
    }
539
    return NULL;
540 541 542 543 544 545 546 547 548 549

}


/*************************************************************************
 *		import_dll
 *
 * Import the dll specified by the given import descriptor.
 * The loader_section must be locked while calling this function.
 */
Eric Pouech's avatar
Eric Pouech committed
550
static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
551 552 553 554
{
    NTSTATUS status;
    WINE_MODREF *wmImp;
    HMODULE imp_mod;
Eric Pouech's avatar
Eric Pouech committed
555
    const IMAGE_EXPORT_DIRECTORY *exports;
556
    DWORD exp_size;
Eric Pouech's avatar
Eric Pouech committed
557 558
    const IMAGE_THUNK_DATA *import_list;
    IMAGE_THUNK_DATA *thunk_list;
559
    WCHAR buffer[32];
Eric Pouech's avatar
Eric Pouech committed
560
    const char *name = get_rva( module, descr->Name );
561
    DWORD len = strlen(name);
562
    PVOID protect_base;
563
    SIZE_T protect_size = 0;
564
    DWORD protect_old;
565

566 567 568 569 570 571
    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;

572 573 574
    while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */

    if (len * sizeof(WCHAR) < sizeof(buffer))
575 576
    {
        ascii_to_unicode( buffer, name, len );
577
        buffer[len] = 0;
578
        status = load_dll( load_path, buffer, 0, &wmImp );
579 580 581
    }
    else  /* need to allocate a larger buffer */
    {
582
        WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
583 584
        if (!ptr) return NULL;
        ascii_to_unicode( ptr, name, len );
585
        ptr[len] = 0;
586
        status = load_dll( load_path, ptr, 0, &wmImp );
587 588
        RtlFreeHeap( GetProcessHeap(), 0, ptr );
    }
589 590 591

    if (status)
    {
592
        if (status == STATUS_DLL_NOT_FOUND)
593
            ERR("Library %s (which is needed by %s) not found\n",
594
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
595
        else
596
            ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
597
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
598
        return NULL;
599 600
    }

601 602 603 604 605
    /* 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);
606
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
607
                            &protect_size, PAGE_READWRITE, &protect_old );
608

609 610 611
    imp_mod = wmImp->ldr.BaseAddress;
    exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );

612 613 614 615 616 617 618
    if (!exports)
    {
        /* set all imported function to deadbeef */
        while (import_list->u1.Ordinal)
        {
            if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
            {
619 620
                int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
                WARN("No implementation for %s.%d", name, ordinal );
621
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
622 623 624 625
            }
            else
            {
                IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
626
                WARN("No implementation for %s.%s", name, pe_name->Name );
Mike McCormack's avatar
Mike McCormack committed
627
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
628
            }
629
            WARN(" imported from %s, allocating stub %p\n",
630 631
                 debugstr_w(current_modref->ldr.FullDllName.Buffer),
                 (void *)thunk_list->u1.Function );
632 633 634
            import_list++;
            thunk_list++;
        }
635
        goto done;
636
    }
637 638 639 640 641 642 643

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

644
            thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
645
                                                                      ordinal - exports->Base, load_path );
646 647
            if (!thunk_list->u1.Function)
            {
648
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
649
                WARN("No implementation for %s.%d imported from %s, setting to %p\n",
650 651
                     name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
652
            }
653
            TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
654 655 656 657 658
        }
        else  /* import by name */
        {
            IMAGE_IMPORT_BY_NAME *pe_name;
            pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
659
            thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
660 661
                                                                    (const char*)pe_name->Name,
                                                                    pe_name->Hint, load_path );
662 663
            if (!thunk_list->u1.Function)
            {
Mike McCormack's avatar
Mike McCormack committed
664
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
665
                WARN("No implementation for %s.%s imported from %s, setting to %p\n",
666 667
                     name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
668
            }
669 670
            TRACE_(imports)("--- %s %s.%d = %p\n",
                            pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
671 672 673 674
        }
        import_list++;
        thunk_list++;
    }
675 676 677

done:
    /* restore old protection of the import address table */
678
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
679 680 681 682
    return wmImp;
}


683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
/***********************************************************************
 *           create_module_activation_context
 */
static NTSTATUS create_module_activation_context( LDR_MODULE *module )
{
    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;
    if (!(status = LdrFindResource_U( module->BaseAddress, &info, 3, &entry )))
    {
        ACTCTXW ctx;
        ctx.cbSize   = sizeof(ctx);
        ctx.lpSource = NULL;
        ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
        ctx.hModule  = module->BaseAddress;
        ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
        status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
    }
    return status;
}


709
/****************************************************************
710
 *       fixup_imports
711 712 713 714
 *
 * Fixup all imports of a given module.
 * The loader_section must be locked while calling this function.
 */
715
static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
716 717
{
    int i, nb_imports;
Eric Pouech's avatar
Eric Pouech committed
718
    const IMAGE_IMPORT_DESCRIPTOR *imports;
719
    WINE_MODREF *prev;
720
    DWORD size;
721
    NTSTATUS status;
722
    ULONG_PTR cookie;
723

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

727 728
    if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
                                                  IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
729
        return STATUS_SUCCESS;
730

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

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

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

739 740
    /* Allocate module dependency list */
    wm->nDeps = nb_imports;
741
    wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
742 743 744 745

    /* load the imported modules. They are automatically
     * added to the modref list of the process.
     */
746 747
    prev = current_modref;
    current_modref = wm;
748
    status = STATUS_SUCCESS;
749 750
    for (i = 0; i < nb_imports; i++)
    {
751 752
        if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
            status = STATUS_DLL_NOT_FOUND;
753
    }
754
    current_modref = prev;
755
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
756
    return status;
757
}
758

759

760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
/*************************************************************************
 *		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.
 */
static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
{
    static const WCHAR ntdllW[]    = {'n','t','d','l','l','.','d','l','l',0};
    static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
    const IMAGE_IMPORT_DESCRIPTOR *imports;
    DWORD i, size;
    WCHAR buffer[16];

    if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
776
    if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

    if ((imports = RtlImageDirectoryEntryToData( module, TRUE,
                                                 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
    {
        for (i = 0; imports[i].Name; i++)
        {
            const char *name = get_rva( module, imports[i].Name );
            DWORD len = strlen(name);
            if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
            ascii_to_unicode( buffer, name, len + 1 );
            if (!strcmpiW( buffer, ntdllW ) || !strcmpiW( buffer, kernel32W ))
            {
                TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
                return FALSE;
            }
        }
    }
    return TRUE;
}


798
/*************************************************************************
799
 *		alloc_module
800 801
 *
 * Allocate a WINE_MODREF structure and add it to the process list
802
 * The loader_section must be locked while calling this function.
803
 */
804
static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
805 806
{
    WINE_MODREF *wm;
Eric Pouech's avatar
Eric Pouech committed
807 808
    const WCHAR *p;
    const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
809 810
    PLIST_ENTRY entry, mark;

811
    if (!(wm = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wm) ))) return NULL;
812

813 814 815 816
    wm->nDeps    = 0;
    wm->deps     = NULL;

    wm->ldr.BaseAddress   = hModule;
817
    wm->ldr.EntryPoint    = NULL;
818
    wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
819
    wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;
820
    wm->ldr.LoadCount     = 1;
821 822 823 824
    wm->ldr.TlsIndex      = -1;
    wm->ldr.SectionHandle = NULL;
    wm->ldr.CheckSum      = 0;
    wm->ldr.TimeDateStamp = 0;
825
    wm->ldr.ActivationContext = 0;
826 827 828 829 830 831

    RtlCreateUnicodeString( &wm->ldr.FullDllName, filename );
    if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
    else p = wm->ldr.FullDllName.Buffer;
    RtlInitUnicodeString( &wm->ldr.BaseDllName, p );

832
    if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))
833
    {
834 835 836
        wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
        if (nt->OptionalHeader.AddressOfEntryPoint)
            wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
837 838
    }

839 840
    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
                   &wm->ldr.InLoadOrderModuleList);
841

842 843 844 845 846 847
    /* insert module in MemoryList, sorted in increasing base addresses */
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
        if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
            break;
848
    }
849 850 851 852 853 854 855 856
    entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
    wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
    wm->ldr.InMemoryOrderModuleList.Flink = entry;
    entry->Blink = &wm->ldr.InMemoryOrderModuleList;

    /* wait until init is called for inserting into this list */
    wm->ldr.InInitializationOrderModuleList.Flink = NULL;
    wm->ldr.InInitializationOrderModuleList.Blink = NULL;
857 858 859

    if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
    {
860
        ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
861
        WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
862
        NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
863
    }
864 865 866 867
    return wm;
}


868 869 870 871 872 873 874
/*************************************************************************
 *              alloc_process_tls
 *
 * Allocate the process-wide structure for module TLS storage.
 */
static NTSTATUS alloc_process_tls(void)
{
875 876
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
Eric Pouech's avatar
Eric Pouech committed
877
    const IMAGE_TLS_DIRECTORY *dir;
878 879
    ULONG size, i;

880 881
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
882
    {
883 884
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
        if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
885 886 887
                                                  IMAGE_DIRECTORY_ENTRY_TLS, &size )))
            continue;
        size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
888
        if (!size && !dir->AddressOfCallBacks) continue;
889
        tls_total_size += TLS_ALIGN(size);
890 891 892 893 894 895
        tls_module_count++;
    }
    if (!tls_module_count) return STATUS_SUCCESS;

    TRACE( "count %u size %u\n", tls_module_count, tls_total_size );

896
    tls_dirs = RtlAllocateHeap( GetProcessHeap(), 0, tls_module_count * sizeof(*tls_dirs) );
897 898
    if (!tls_dirs) return STATUS_NO_MEMORY;

899
    for (i = 0, entry = mark->Flink; entry != mark; entry = entry->Flink)
900
    {
901 902
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
        if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
903 904 905
                                                  IMAGE_DIRECTORY_ENTRY_TLS, &size )))
            continue;
        tls_dirs[i] = dir;
906
        *(DWORD *)dir->AddressOfIndex = i;
907 908
        mod->TlsIndex = i;
        mod->LoadCount = -1;  /* can't unload it */
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
        i++;
    }
    return STATUS_SUCCESS;
}


/*************************************************************************
 *              alloc_thread_tls
 *
 * Allocate the per-thread structure for module TLS storage.
 */
static NTSTATUS alloc_thread_tls(void)
{
    void **pointers;
    char *data;
924
    UINT i, size;
925 926 927

    if (!tls_module_count) return STATUS_SUCCESS;

928 929
    size = TLS_ALIGN( tls_module_count * sizeof(*pointers) );
    if (!(pointers = RtlAllocateHeap( GetProcessHeap(), 0, size + tls_total_size )))
930
        return STATUS_NO_MEMORY;
931
    data = (char *)pointers + size;
932 933 934 935

    for (i = 0; i < tls_module_count; i++)
    {
        const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
936
        size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
937

938
        TRACE( "thread %04x idx %d: %d/%d bytes from %p to %p\n",
939 940 941 942 943
               GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
               (void *)dir->StartAddressOfRawData, data );

        pointers[i] = data;
        memcpy( data, (void *)dir->StartAddressOfRawData, size );
944 945
        memset( data + size, 0, dir->SizeOfZeroFill );
        data += TLS_ALIGN( size + dir->SizeOfZeroFill );
946
    }
947
    NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
948 949 950 951
    return STATUS_SUCCESS;
}


952 953 954 955 956 957 958 959 960 961 962 963
/*************************************************************************
 *              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;

964
    for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
965 966
    {
        if (TRACE_ON(relay))
967
            DPRINTF("%04x:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
968
                    GetCurrentThreadId(), *callback, module, reason_names[reason] );
969 970 971 972
        __TRY
        {
            (*callback)( module, reason, NULL );
        }
973
        __EXCEPT_ALL
974 975 976 977 978 979 980
        {
            if (TRACE_ON(relay))
                DPRINTF("%04x:exception in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                        GetCurrentThreadId(), callback, module, reason_names[reason] );
            return;
        }
        __ENDTRY
981
        if (TRACE_ON(relay))
982
            DPRINTF("%04x:Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
983 984 985 986 987
                    GetCurrentThreadId(), *callback, module, reason_names[reason] );
    }
}


988 989 990
/*************************************************************************
 *              MODULE_InitDLL
 */
991
static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
992
{
993
    WCHAR mod_name[32];
994
    NTSTATUS status = STATUS_SUCCESS;
995 996
    DLLENTRYPROC entry = wm->ldr.EntryPoint;
    void *module = wm->ldr.BaseAddress;
997
    BOOL retv = FALSE;
998 999 1000

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

1001
    if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1002
    if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
1003
    if (!entry) return STATUS_SUCCESS;
1004 1005

    if (TRACE_ON(relay))
1006
    {
1007
        size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1008 1009
        memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
        mod_name[len / sizeof(WCHAR)] = 0;
1010
        DPRINTF("%04x:Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1011 1012
                GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
                reason_names[reason], lpReserved );
1013
    }
1014 1015
    else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
               reason_names[reason], lpReserved );
1016

1017 1018 1019 1020 1021 1022
    __TRY
    {
        retv = call_dll_entry_point( entry, module, reason, lpReserved );
        if (!retv)
            status = STATUS_DLL_INIT_FAILED;
    }
1023
    __EXCEPT_ALL
1024 1025 1026 1027 1028 1029 1030
    {
        if (TRACE_ON(relay))
            DPRINTF("%04x:exception in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
                    GetCurrentThreadId(), entry, module, reason_names[reason], lpReserved );
        status = GetExceptionCode();
    }
    __ENDTRY
1031 1032

    /* The state of the module list may have changed due to the call
1033
       to the dll. We cannot assume that this module has not been
1034
       deleted.  */
1035
    if (TRACE_ON(relay))
1036
        DPRINTF("%04x:Ret  PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1037 1038
                GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
                reason_names[reason], lpReserved, retv );
1039
    else TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1040

1041
    return status;
1042 1043 1044 1045
}


/*************************************************************************
1046
 *		process_attach
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
 *
 * 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*.
1073 1074
 *
 * The loader_section must be locked while calling this function.
1075
 */
1076
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1077
{
1078
    NTSTATUS status = STATUS_SUCCESS;
1079
    ULONG_PTR cookie;
1080 1081
    int i;

1082 1083
    if (process_detaching) return status;

1084
    /* prevent infinite recursion in case of cyclical dependencies */
1085 1086
    if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
         || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1087
        return status;
1088

1089
    TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1090 1091

    /* Tag current MODREF to prevent recursive loop */
1092
    wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1093
    if (lpReserved) wm->ldr.LoadCount = -1;  /* pin it if imported by the main exe */
1094
    if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1095 1096

    /* Recursively attach all DLLs this one depends on */
1097 1098 1099
    for ( i = 0; i < wm->nDeps; i++ )
    {
        if (!wm->deps[i]) continue;
1100
        if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1101
    }
1102 1103

    /* Call DLL entry point */
1104
    if (status == STATUS_SUCCESS)
1105
    {
1106 1107
        WINE_MODREF *prev = current_modref;
        current_modref = wm;
1108 1109
        status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
        if (status == STATUS_SUCCESS)
1110 1111
            wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
        else
1112
        {
1113
            MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1114 1115 1116 1117
            /* 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));
        }
1118
        current_modref = prev;
1119 1120
    }

1121 1122 1123
    if (!wm->ldr.InInitializationOrderModuleList.Flink)
        InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
                       &wm->ldr.InInitializationOrderModuleList);
1124

1125
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1126
    /* Remove recursion flag */
1127
    wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1128

1129
    TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1130
    return status;
1131 1132
}

1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

/**********************************************************************
 *	    attach_implicitly_loaded_dlls
 *
 * Attach to the (builtin) dlls that have been implicitly loaded because
 * of a dependency at the Unix level, but not imported at the Win32 level.
 */
static void attach_implicitly_loaded_dlls( LPVOID reserved )
{
    for (;;)
    {
        PLIST_ENTRY mark, entry;

        mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
        for (entry = mark->Flink; entry != mark; entry = entry->Flink)
        {
            LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);

            if (mod->Flags & (LDR_LOAD_IN_PROGRESS | LDR_PROCESS_ATTACHED)) continue;
            TRACE( "found implicitly loaded %s, attaching to it\n",
                   debugstr_w(mod->BaseDllName.Buffer));
            process_attach( CONTAINING_RECORD(mod, WINE_MODREF, ldr), reserved );
            break;  /* restart the search from the start */
        }
        if (entry == mark) break;  /* nothing found */
    }
}


1162
/*************************************************************************
1163
 *		process_detach
1164 1165
 *
 * Send DLL process detach notifications.  See the comment about calling
1166
 * sequence at process_attach.
1167
 */
1168
static void process_detach(void)
1169
{
1170 1171
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
1172

1173
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1174 1175
    do
    {
1176
        for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1177
        {
1178 1179
            mod = CONTAINING_RECORD(entry, LDR_MODULE, 
                                    InInitializationOrderModuleList);
1180
            /* Check whether to detach this DLL */
1181
            if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1182
                continue;
1183
            if ( mod->LoadCount && !process_detaching )
1184 1185 1186
                continue;

            /* Call detach notification */
1187 1188
            mod->Flags &= ~LDR_PROCESS_ATTACHED;
            MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
1189
                            DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1190 1191 1192 1193 1194

            /* Restart at head of WINE_MODREF list, as entries might have
               been added and/or removed while performing the call ... */
            break;
        }
1195
    } while (entry != mark);
1196 1197 1198 1199 1200 1201 1202 1203 1204
}

/*************************************************************************
 *		MODULE_DllThreadAttach
 *
 * Send DLL thread attach notifications. These are sent in the
 * reverse sequence of process detach notification.
 *
 */
1205
NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved )
1206
{
1207 1208 1209
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
    NTSTATUS    status;
1210 1211

    /* don't do any attach calls if process is exiting */
1212
    if (process_detaching) return STATUS_SUCCESS;
1213 1214 1215

    RtlEnterCriticalSection( &loader_section );

1216
    if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
1217

1218 1219
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1220
    {
1221 1222 1223
        mod = CONTAINING_RECORD(entry, LDR_MODULE, 
                                InInitializationOrderModuleList);
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1224
            continue;
1225
        if ( mod->Flags & LDR_NO_DLL_CALLS )
1226 1227
            continue;

1228 1229
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
                        DLL_THREAD_ATTACH, lpReserved );
1230 1231
    }

1232
done:
1233
    RtlLeaveCriticalSection( &loader_section );
1234
    return status;
1235 1236
}

1237 1238 1239 1240 1241
/******************************************************************
 *		LdrDisableThreadCalloutsForDll (NTDLL.@)
 *
 */
NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1242
{
1243 1244 1245 1246 1247
    WINE_MODREF *wm;
    NTSTATUS    ret = STATUS_SUCCESS;

    RtlEnterCriticalSection( &loader_section );

1248
    wm = get_modref( hModule );
1249
    if (!wm || wm->ldr.TlsIndex != -1)
1250
        ret = STATUS_DLL_NOT_FOUND;
1251
    else
1252
        wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1253 1254 1255 1256

    RtlLeaveCriticalSection( &loader_section );

    return ret;
1257
}
1258

1259 1260 1261 1262 1263
/******************************************************************
 *              LdrFindEntryForAddress (NTDLL.@)
 *
 * The loader_section must be locked while calling this function
 */
1264
NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
1265
{
1266 1267
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
1268

1269 1270
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1271
    {
1272
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
1273
        if (mod->BaseAddress <= addr &&
Eric Pouech's avatar
Eric Pouech committed
1274
            (const char *)addr < (char*)mod->BaseAddress + mod->SizeOfImage)
1275
        {
1276
            *pmod = mod;
1277 1278
            return STATUS_SUCCESS;
        }
1279
        if (mod->BaseAddress > addr) break;
1280 1281 1282 1283
    }
    return STATUS_NO_MORE_ENTRIES;
}

1284 1285 1286 1287 1288 1289 1290 1291 1292
/******************************************************************
 *		LdrLockLoaderLock  (NTDLL.@)
 *
 * Note: flags are not implemented.
 * Flag 0x01 is used to raise exceptions on errors.
 * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
 */
NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
{
1293
    if (flags) FIXME( "flags %x not supported\n", flags );
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316

    if (result) *result = 1;
    if (!magic) return STATUS_INVALID_PARAMETER_3;
    RtlEnterCriticalSection( &loader_section );
    *magic = GetCurrentThreadId();
    return STATUS_SUCCESS;
}


/******************************************************************
 *		LdrUnlockLoaderUnlock  (NTDLL.@)
 */
NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
{
    if (magic)
    {
        if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
        RtlLeaveCriticalSection( &loader_section );
    }
    return STATUS_SUCCESS;
}


1317 1318
/******************************************************************
 *		LdrGetProcedureAddress  (NTDLL.@)
1319
 */
1320 1321
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
                                       ULONG ord, PVOID *address)
1322
{
1323 1324 1325
    IMAGE_EXPORT_DIRECTORY *exports;
    DWORD exp_size;
    NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1326

1327
    RtlEnterCriticalSection( &loader_section );
1328

1329 1330 1331 1332
    /* 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 )))
1333
    {
1334 1335 1336
        LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
        void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path )
                          : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path );
1337 1338 1339 1340 1341 1342
        if (proc)
        {
            *address = proc;
            ret = STATUS_SUCCESS;
        }
    }
1343

1344 1345
    RtlLeaveCriticalSection( &loader_section );
    return ret;
1346
}
1347 1348


1349 1350 1351 1352 1353
/***********************************************************************
 *           is_fake_dll
 *
 * Check if a loaded native dll is a Wine fake dll.
 */
1354
static BOOL is_fake_dll( HANDLE handle )
1355 1356
{
    static const char fakedll_signature[] = "Wine placeholder DLL";
1357 1358 1359 1360
    char buffer[sizeof(IMAGE_DOS_HEADER) + sizeof(fakedll_signature)];
    const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)buffer;
    IO_STATUS_BLOCK io;
    LARGE_INTEGER offset;
1361

1362 1363 1364 1365
    offset.QuadPart = 0;
    if (NtReadFile( handle, 0, NULL, 0, &io, buffer, sizeof(buffer), &offset, NULL )) return FALSE;
    if (io.Information < sizeof(buffer)) return FALSE;
    if (dos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
1366 1367 1368 1369 1370 1371
    if (dos->e_lfanew >= sizeof(*dos) + sizeof(fakedll_signature) &&
        !memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) )) return TRUE;
    return FALSE;
}


1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413
/***********************************************************************
 *           get_builtin_fullname
 *
 * Build the full pathname for a builtin dll.
 */
static WCHAR *get_builtin_fullname( const WCHAR *path, const char *filename )
{
    static const WCHAR soW[] = {'.','s','o',0};
    WCHAR *p, *fullname;
    size_t i, len = strlen(filename);

    /* check if path can correspond to the dll we have */
    if (path && (p = strrchrW( path, '\\' )))
    {
        p++;
        for (i = 0; i < len; i++)
            if (tolowerW(p[i]) != tolowerW( (WCHAR)filename[i]) ) break;
        if (i == len && (!p[len] || !strcmpiW( p + len, soW )))
        {
            /* the filename matches, use path as the full path */
            len += p - path;
            if ((fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
            {
                memcpy( fullname, path, len * sizeof(WCHAR) );
                fullname[len] = 0;
            }
            return fullname;
        }
    }

    if ((fullname = RtlAllocateHeap( GetProcessHeap(), 0,
                                     system_dir.MaximumLength + (len + 1) * sizeof(WCHAR) )))
    {
        memcpy( fullname, system_dir.Buffer, system_dir.Length );
        p = fullname + system_dir.Length / sizeof(WCHAR);
        if (p > fullname && p[-1] != '\\') *p++ = '\\';
        ascii_to_unicode( p, filename, len + 1 );
    }
    return fullname;
}


1414 1415 1416 1417 1418 1419 1420
/***********************************************************************
 *           load_builtin_callback
 *
 * Load a library in memory; callback function for wine_dll_register
 */
static void load_builtin_callback( void *module, const char *filename )
{
1421
    static const WCHAR emptyW[1];
1422 1423
    IMAGE_NT_HEADERS *nt;
    WINE_MODREF *wm;
1424
    WCHAR *fullname;
1425
    const WCHAR *load_path;
1426 1427 1428 1429 1430 1431 1432 1433 1434

    if (!module)
    {
        ERR("could not map image for %s\n", filename ? filename : "main exe" );
        return;
    }
    if (!(nt = RtlImageNtHeader( module )))
    {
        ERR( "bad module for %s\n", filename ? filename : "main exe" );
1435
        builtin_load_info->status = STATUS_INVALID_IMAGE_FORMAT;
1436 1437
        return;
    }
1438 1439

    virtual_create_builtin_view( module );
1440

1441 1442
    /* create the MODREF */

1443
    if (!(fullname = get_builtin_fullname( builtin_load_info->filename, filename )))
1444 1445
    {
        ERR( "can't load %s\n", filename );
1446
        builtin_load_info->status = STATUS_NO_MEMORY;
1447 1448 1449
        return;
    }

1450 1451
    wm = alloc_module( module, fullname );
    RtlFreeHeap( GetProcessHeap(), 0, fullname );
1452 1453 1454
    if (!wm)
    {
        ERR( "can't load %s\n", filename );
1455
        builtin_load_info->status = STATUS_NO_MEMORY;
1456 1457 1458 1459
        return;
    }
    wm->ldr.Flags |= LDR_WINE_INTERNAL;

1460 1461
    if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
        !NtCurrentTeb()->Peb->ImageBaseAddress)  /* if we already have an executable, ignore this one */
1462
    {
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
        NtCurrentTeb()->Peb->ImageBaseAddress = module;
    }
    else
    {
        /* fixup imports */

        load_path = builtin_load_info->load_path;
        if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
        if (!load_path) load_path = emptyW;
        if (fixup_imports( wm, load_path ) != STATUS_SUCCESS)
        {
            /* the module has only be inserted in the load & memory order lists */
            RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
            RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
            /* FIXME: free the modref */
            builtin_load_info->status = STATUS_DLL_NOT_FOUND;
            return;
        }
1481
    }
1482

1483
    builtin_load_info->wm = wm;
1484 1485 1486 1487 1488 1489
    TRACE( "loaded %s %p %p\n", filename, wm, module );

    /* send the DLL load event */

    SERVER_START_REQ( load_dll )
    {
1490
        req->mapping    = 0;
1491
        req->base       = wine_server_client_ptr( module );
1492 1493 1494
        req->size       = nt->OptionalHeader.SizeOfImage;
        req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
        req->dbg_size   = nt->FileHeader.NumberOfSymbols;
1495
        req->name       = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1496
        wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
        wine_server_call( req );
    }
    SERVER_END_REQ;

    /* setup relay debugging entry points */
    if (TRACE_ON(relay)) RELAY_SetupDLL( module );
}


/******************************************************************************
 *	load_native_dll  (internal)
 */
1509 1510
static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
                                 DWORD flags, WINE_MODREF** pwm )
1511 1512
{
    void *module;
1513
    HANDLE mapping;
1514 1515
    LARGE_INTEGER size;
    IMAGE_NT_HEADERS *nt;
1516
    SIZE_T len = 0;
1517 1518 1519
    WINE_MODREF *wm;
    NTSTATUS status;

1520
    TRACE("Trying native dll %s\n", debugstr_w(name));
1521 1522 1523

    size.QuadPart = 0;
    status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
1524
                              NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, file );
1525
    if (status != STATUS_SUCCESS) return status;
1526 1527

    module = NULL;
1528
    status = NtMapViewOfSection( mapping, NtCurrentProcess(),
1529
                                 &module, 0, 0, &size, &len, ViewShare, 0, PAGE_EXECUTE_READ );
1530
    if (status < 0) goto done;
1531 1532 1533

    /* create the MODREF */

1534 1535 1536 1537 1538
    if (!(wm = alloc_module( module, name )))
    {
        status = STATUS_NO_MEMORY;
        goto done;
    }
1539 1540 1541 1542 1543

    /* fixup imports */

    if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
    {
1544
        if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556
        {
            /* the module has only be inserted in the load & memory order lists */
            RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
            RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);

            /* 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.
             */
1557
            goto done;
1558 1559 1560 1561 1562 1563 1564 1565 1566
        }
    }

    /* send DLL load event */

    nt = RtlImageNtHeader( module );

    SERVER_START_REQ( load_dll )
    {
1567
        req->mapping    = wine_server_obj_handle( mapping );
1568
        req->base       = wine_server_client_ptr( module );
1569 1570 1571
        req->size       = nt->OptionalHeader.SizeOfImage;
        req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
        req->dbg_size   = nt->FileHeader.NumberOfSymbols;
1572
        req->name       = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1573
        wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1574 1575 1576 1577
        wine_server_call( req );
    }
    SERVER_END_REQ;

1578
    if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( module );
1579

1580
    TRACE_(loaddll)( "Loaded %s at %p: native\n", debugstr_w(wm->ldr.FullDllName.Buffer), module );
1581

1582
    wm->ldr.LoadCount = 1;
1583
    *pwm = wm;
1584 1585 1586 1587
    status = STATUS_SUCCESS;
done:
    NtClose( mapping );
    return status;
1588 1589 1590
}


1591 1592 1593
/***********************************************************************
 *           load_builtin_dll
 */
1594 1595
static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file,
                                  DWORD flags, WINE_MODREF** pwm )
1596
{
1597 1598 1599
    char error[256], dllname[MAX_PATH];
    const WCHAR *name, *p;
    DWORD len, i;
1600
    void *handle = NULL;
1601
    struct builtin_load_info info, *prev_info;
1602 1603 1604

    /* Fix the name in case we have a full path and extension */
    name = path;
1605 1606
    if ((p = strrchrW( name, '\\' ))) name = p + 1;
    if ((p = strrchrW( name, '/' ))) name = p + 1;
1607

1608
    /* load_library will modify info.status. Note also that load_library can be
1609
     * called several times, if the .so file we're loading has dependencies.
1610
     * info.status will gather all the errors we may get while loading all these
1611 1612
     * libraries
     */
1613
    info.load_path = load_path;
1614
    info.filename  = NULL;
1615 1616
    info.status    = STATUS_SUCCESS;
    info.wm        = NULL;
1617 1618 1619 1620 1621 1622

    if (file)  /* we have a real file, try to load it */
    {
        UNICODE_STRING nt_name;
        ANSI_STRING unix_name;

1623 1624
        TRACE("Trying built-in %s\n", debugstr_w(path));

1625 1626 1627
        if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL ))
            return STATUS_DLL_NOT_FOUND;

1628
        if (wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, FALSE ))
1629
        {
1630 1631
            RtlFreeUnicodeString( &nt_name );
            return STATUS_DLL_NOT_FOUND;
1632
        }
1633 1634 1635 1636 1637
        prev_info = builtin_load_info;
        info.filename = nt_name.Buffer + 4;  /* skip \??\ */
        builtin_load_info = &info;
        handle = wine_dlopen( unix_name.Buffer, RTLD_NOW, error, sizeof(error) );
        builtin_load_info = prev_info;
1638
        RtlFreeUnicodeString( &nt_name );
1639 1640 1641 1642 1643 1644
        RtlFreeHeap( GetProcessHeap(), 0, unix_name.Buffer );
        if (!handle)
        {
            WARN( "failed to load .so lib for builtin %s: %s\n", debugstr_w(path), error );
            return STATUS_INVALID_IMAGE_FORMAT;
        }
1645 1646 1647
    }
    else
    {
1648 1649
        int file_exists;

1650 1651
        TRACE("Trying built-in %s\n", debugstr_w(name));

1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
        /* we don't want to depend on the current codepage here */
        len = strlenW( name ) + 1;
        if (len >= sizeof(dllname)) return STATUS_NAME_TOO_LONG;
        for (i = 0; i < len; i++)
        {
            if (name[i] > 127) return STATUS_DLL_NOT_FOUND;
            dllname[i] = (char)name[i];
            if (dllname[i] >= 'A' && dllname[i] <= 'Z') dllname[i] += 'a' - 'A';
        }

        prev_info = builtin_load_info;
        builtin_load_info = &info;
        handle = wine_dll_load( dllname, error, sizeof(error), &file_exists );
        builtin_load_info = prev_info;
1666
        if (!handle)
1667
        {
1668 1669 1670 1671 1672 1673 1674 1675 1676
            if (!file_exists)
            {
                /* The file does not exist -> WARN() */
                WARN("cannot open .so lib for builtin %s: %s\n", debugstr_w(name), error);
                return STATUS_DLL_NOT_FOUND;
            }
            /* ERR() for all other errors (missing functions, ...) */
            ERR("failed to load .so lib for builtin %s: %s\n", debugstr_w(name), error );
            return STATUS_PROCEDURE_NOT_FOUND;
1677 1678
        }
    }
1679

1680 1681 1682 1683 1684
    if (info.status != STATUS_SUCCESS)
    {
        wine_dll_unload( handle );
        return info.status;
    }
1685

1686 1687
    if (!info.wm)
    {
1688
        PLIST_ENTRY mark, entry;
1689

1690 1691
        /* The constructor wasn't called, this means the .so is already
         * loaded under a different name. Try to find the wm for it. */
1692

1693 1694
        mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
        for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1695
        {
1696 1697 1698 1699
            LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
            if (mod->Flags & LDR_WINE_INTERNAL && mod->SectionHandle == handle)
            {
                info.wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
1700 1701
                TRACE( "Found %s at %p for builtin %s\n",
                       debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress, debugstr_w(path) );
1702 1703
                break;
            }
1704
        }
1705
        wine_dll_unload( handle );  /* release the libdl refcount */
1706
        if (!info.wm) return STATUS_INVALID_IMAGE_FORMAT;
1707
        if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
1708 1709 1710
    }
    else
    {
1711
        TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress );
1712
        info.wm->ldr.LoadCount = 1;
1713
        info.wm->ldr.SectionHandle = handle;
1714
    }
1715

1716
    *pwm = info.wm;
1717 1718 1719 1720
    return STATUS_SUCCESS;
}


1721 1722 1723 1724 1725 1726 1727 1728
/***********************************************************************
 *	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','\\'};
1729
    static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761

    ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
    ACTCTX_SECTION_KEYED_DATA data;
    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;

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

1762 1763 1764 1765 1766 1767
    if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName)
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }

1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790
    if ((p = strrchrW( info->lpAssemblyManifestPath, '\\' )))
    {
        DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);

        p++;
        if (strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW ))
        {
            /* 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;
            strcpyW( p, libname );
            goto done;
        }
    }

1791 1792
    needed = (strlenW(user_shared_data->NtSystemRoot) * sizeof(WCHAR) +
              sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
1793 1794 1795 1796 1797 1798

    if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
    {
        status = STATUS_NO_MEMORY;
        goto done;
    }
1799 1800
    strcpyW( p, user_shared_data->NtSystemRoot );
    p += strlenW(p);
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813
    memcpy( p, winsxsW, sizeof(winsxsW) );
    p += sizeof(winsxsW) / sizeof(WCHAR);
    memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
    p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
    *p++ = '\\';
    strcpyW( p, libname );
done:
    RtlFreeHeap( GetProcessHeap(), 0, info );
    RtlReleaseActivationContext( data.hActCtx );
    return status;
}


1814 1815 1816 1817 1818 1819 1820 1821
/***********************************************************************
 *	find_dll_file
 *
 * Find the file (or already loaded module) for a given dll name.
 */
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
                               WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
{
1822 1823 1824
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK io;
    UNICODE_STRING nt_name;
1825
    WCHAR *file_part, *ext, *dllname;
1826 1827
    ULONG len;

1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
    /* first append .dll if needed */

    dllname = NULL;
    if (!(ext = strrchrW( libname, '.')) || strchrW( ext, '/' ) || strchrW( ext, '\\'))
    {
        if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
                                         (strlenW(libname) * sizeof(WCHAR)) + sizeof(dllW) )))
            return STATUS_NO_MEMORY;
        strcpyW( dllname, libname );
        strcatW( dllname, dllW );
        libname = dllname;
    }

1841
    nt_name.Buffer = NULL;
1842 1843 1844

    if (!contains_path( libname ))
    {
1845
        NTSTATUS status;
1846
        WCHAR *fullname = NULL;
1847

1848
        if ((*pwm = find_basename_module( libname )) != NULL) goto found;
1849 1850 1851 1852

        status = find_actctx_dll( libname, &fullname );
        if (status == STATUS_SUCCESS)
        {
1853
            TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
1854 1855 1856 1857 1858 1859 1860 1861
            RtlFreeHeap( GetProcessHeap(), 0, dllname );
            libname = dllname = fullname;
        }
        else if (status != STATUS_SXS_KEY_NOT_FOUND)
        {
            RtlFreeHeap( GetProcessHeap(), 0, dllname );
            return status;
        }
1862 1863
    }

1864 1865 1866
    if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
    {
        /* we need to search for it */
1867
        len = RtlDosSearchPath_U( load_path, libname, NULL, *size, filename, &file_part );
1868 1869
        if (len)
        {
1870
            if (len >= *size) goto overflow;
1871
            if ((*pwm = find_fullname_module( filename )) || !handle) goto found;
1872

1873
            if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, NULL, NULL ))
1874 1875
            {
                RtlFreeHeap( GetProcessHeap(), 0, dllname );
1876
                return STATUS_NO_MEMORY;
1877
            }
1878 1879 1880 1881 1882 1883
            attr.Length = sizeof(attr);
            attr.RootDirectory = 0;
            attr.Attributes = OBJ_CASE_INSENSITIVE;
            attr.ObjectName = &nt_name;
            attr.SecurityDescriptor = NULL;
            attr.SecurityQualityOfService = NULL;
1884
            if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE )) *handle = 0;
1885
            goto found;
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
        }

        /* not found */

        if (!contains_path( libname ))
        {
            /* if libname doesn't contain a path at all, we simply return the name as is,
             * to be loaded as builtin */
            len = strlenW(libname) * sizeof(WCHAR);
            if (len >= *size) goto overflow;
            strcpyW( filename, libname );
1897
            goto found;
1898 1899 1900 1901 1902
        }
    }

    /* absolute path name, or relative path name but not found above */

1903
    if (!RtlDosPathNameToNtPathName_U( libname, &nt_name, &file_part, NULL ))
1904 1905
    {
        RtlFreeHeap( GetProcessHeap(), 0, dllname );
1906
        return STATUS_NO_MEMORY;
1907
    }
1908
    len = nt_name.Length - 4*sizeof(WCHAR);  /* for \??\ prefix */
1909
    if (len >= *size) goto overflow;
1910
    memcpy( filename, nt_name.Buffer + 4, len + sizeof(WCHAR) );
1911
    if (!(*pwm = find_fullname_module( filename )) && handle)
1912 1913 1914 1915 1916 1917 1918
    {
        attr.Length = sizeof(attr);
        attr.RootDirectory = 0;
        attr.Attributes = OBJ_CASE_INSENSITIVE;
        attr.ObjectName = &nt_name;
        attr.SecurityDescriptor = NULL;
        attr.SecurityQualityOfService = NULL;
1919
        if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE )) *handle = 0;
1920
    }
1921
found:
1922
    RtlFreeUnicodeString( &nt_name );
1923
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
1924 1925 1926
    return STATUS_SUCCESS;

overflow:
1927
    RtlFreeUnicodeString( &nt_name );
1928
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
1929 1930 1931 1932 1933
    *size = len + sizeof(WCHAR);
    return STATUS_BUFFER_TOO_SMALL;
}


1934
/***********************************************************************
1935
 *	load_dll  (internal)
1936 1937
 *
 * Load a PE style module according to the load order.
1938
 * The loader_section must be locked while calling this function.
1939
 */
1940
static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
1941
{
1942
    enum loadorder loadorder;
1943 1944 1945
    WCHAR buffer[32];
    WCHAR *filename;
    ULONG size;
1946
    WINE_MODREF *main_exe;
1947
    HANDLE handle = 0;
1948
    NTSTATUS nts;
1949

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

1952
    *pwm = NULL;
1953 1954 1955
    filename = buffer;
    size = sizeof(buffer);
    for (;;)
1956
    {
1957 1958 1959 1960 1961 1962
        nts = find_dll_file( load_path, libname, filename, &size, pwm, &handle );
        if (nts == STATUS_SUCCESS) break;
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        if (nts != STATUS_BUFFER_TOO_SMALL) return nts;
        /* grow the buffer and retry */
        if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
1963
    }
1964 1965

    if (*pwm)  /* found already loaded module */
1966
    {
1967 1968
        if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;

1969 1970
        if (!(flags & DONT_RESOLVE_DLL_REFERENCES)) fixup_imports( *pwm, load_path );

1971
        TRACE("Found %s for %s at %p, count=%d\n",
1972 1973 1974 1975
              debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
              (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        return STATUS_SUCCESS;
1976 1977
    }

1978
    main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
1979
    loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, filename );
1980

1981 1982 1983 1984 1985 1986 1987
    if (handle && is_fake_dll( handle ))
    {
        TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) );
        NtClose( handle );
        handle = 0;
    }

1988
    switch(loadorder)
1989
    {
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
    case LO_INVALID:
        nts = STATUS_NO_MEMORY;
        break;
    case LO_DISABLED:
        nts = STATUS_DLL_NOT_FOUND;
        break;
    case LO_NATIVE:
    case LO_NATIVE_BUILTIN:
        if (!handle) nts = STATUS_DLL_NOT_FOUND;
        else
2000
        {
2001
            nts = load_native_dll( load_path, filename, handle, flags, pwm );
2002 2003 2004
            if (nts == STATUS_INVALID_FILE_FOR_SECTION)
                /* not in PE format, maybe it's a builtin */
                nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
2005
        }
2006
        if (nts == STATUS_DLL_NOT_FOUND && loadorder == LO_NATIVE_BUILTIN)
2007 2008
            nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
        break;
2009 2010 2011
    case LO_BUILTIN:
    case LO_BUILTIN_NATIVE:
    case LO_DEFAULT:  /* default is builtin,native */
2012 2013 2014
        nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
        if (!handle) break;  /* nothing else we can try */
        /* file is not a builtin library, try without using the specified file */
2015 2016 2017
        if (nts != STATUS_SUCCESS)
            nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
        if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT &&
2018
            (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS))
2019 2020 2021 2022 2023 2024
        {
            /* stub-only dll, try native */
            TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_w(filename) );
            LdrUnloadDll( (*pwm)->ldr.BaseAddress );
            nts = STATUS_DLL_NOT_FOUND;
        }
2025
        if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN)
2026 2027 2028
            nts = load_native_dll( load_path, filename, handle, flags, pwm );
        break;
    }
2029

2030 2031 2032 2033 2034 2035 2036 2037 2038
    if (nts == STATUS_SUCCESS)
    {
        /* Initialize DLL just loaded */
        TRACE("Loaded module %s (%s) at %p\n", debugstr_w(filename),
              ((*pwm)->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native",
              (*pwm)->ldr.BaseAddress);
        if (handle) NtClose( handle );
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        return nts;
2039 2040
    }

2041
    WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
2042
    if (handle) NtClose( handle );
2043
    if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
2044
    return nts;
2045 2046 2047 2048 2049
}

/******************************************************************
 *		LdrLoadDll (NTDLL.@)
 */
2050 2051
NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
                                             const UNICODE_STRING *libname, HMODULE* hModule)
2052 2053
{
    WINE_MODREF *wm;
2054
    NTSTATUS nts;
2055 2056 2057

    RtlEnterCriticalSection( &loader_section );

2058 2059
    if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
    nts = load_dll( path_name, libname->Buffer, flags, &wm );
2060 2061

    if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
2062
    {
2063
        nts = process_attach( wm, NULL );
2064
        if (nts != STATUS_SUCCESS)
2065
        {
2066
            LdrUnloadDll(wm->ldr.BaseAddress);
2067 2068 2069
            wm = NULL;
        }
    }
2070
    *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
2071

2072
    RtlLeaveCriticalSection( &loader_section );
2073 2074 2075
    return nts;
}

2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099

/******************************************************************
 *		LdrGetDllHandle (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
{
    NTSTATUS status;
    WCHAR buffer[128];
    WCHAR *filename;
    ULONG size;
    WINE_MODREF *wm;

    RtlEnterCriticalSection( &loader_section );

    if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;

    filename = buffer;
    size = sizeof(buffer);
    for (;;)
    {
        status = find_dll_file( load_path, name->Buffer, filename, &size, &wm, NULL );
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        if (status != STATUS_BUFFER_TOO_SMALL) break;
        /* grow the buffer and retry */
2100 2101 2102 2103 2104
        if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size )))
        {
            status = STATUS_NO_MEMORY;
            break;
        }
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
    }

    if (status == STATUS_SUCCESS)
    {
        if (wm) *base = wm->ldr.BaseAddress;
        else status = STATUS_DLL_NOT_FOUND;
    }

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


2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
/******************************************************************
 *		LdrAddRefDll (NTDLL.@)
 */
NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
{
    NTSTATUS ret = STATUS_SUCCESS;
    WINE_MODREF *wm;

    if (flags) FIXME( "%p flags %x not implemented\n", module, flags );

    RtlEnterCriticalSection( &loader_section );

    if ((wm = get_modref( module )))
    {
        if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
        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;
}


2143 2144 2145 2146 2147 2148
/***********************************************************************
 *           LdrProcessRelocationBlock  (NTDLL.@)
 *
 * Apply relocations to a given page of a mapped PE image.
 */
IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
2149
                                                          USHORT *relocs, INT_PTR delta )
2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
{
    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;
2168
#ifdef __x86_64__
2169 2170 2171
        case IMAGE_REL_BASED_DIR64:
            *(INT_PTR *)((char *)page + offset) += delta;
            break;
2172 2173 2174 2175 2176
#elif defined(__arm__)
        case IMAGE_REL_BASED_THUMB_MOV32:
        {
            DWORD inst = *(INT_PTR *)((char *)page + offset);
            DWORD imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
2177
                          ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
2178 2179 2180 2181 2182 2183 2184 2185 2186 2187

            if ((inst & 0x8000fbf0) != 0x0000f240)
                ERR("wrong Thumb2 instruction %08x, expected MOVW\n", inst);

            imm16 += LOWORD(delta);
            if (imm16 > 0xffff)
                ERR("resulting immediate value won't fit: %08x\n", imm16);
            *(INT_PTR *)((char *)page + offset) = (inst & 0x8f00fbf0) + ((imm16 >> 1) & 0x0400) +
                                                  ((imm16 >> 12) & 0x000f) +
                                                  ((imm16 << 20) & 0x70000000) +
2188
                                                  ((imm16 << 16) & 0xff0000);
2189 2190 2191 2192 2193

            if (delta > 0xffff)
            {
                inst = *(INT_PTR *)((char *)page + offset + 4);
                imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
2194
                        ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205

                if ((inst & 0x8000fbf0) != 0x0000f2c0)
                    ERR("wrong Thumb2 instruction %08x, expected MOVT\n", inst);

                imm16 += HIWORD(delta);
                if (imm16 > 0xffff)
                    ERR("resulting immediate value won't fit: %08x\n", imm16);
                *(INT_PTR *)((char *)page + offset + 4) = (inst & 0x8f00fbf0) +
                                                          ((imm16 >> 1) & 0x0400) +
                                                          ((imm16 >> 12) & 0x000f) +
                                                          ((imm16 << 20) & 0x70000000) +
2206
                                                          ((imm16 << 16) & 0xff0000);
2207 2208 2209
            }
        }
            break;
2210
#endif
2211 2212 2213 2214 2215 2216 2217 2218 2219 2220
        default:
            FIXME("Unknown/unsupported fixup type %x.\n", type);
            return NULL;
        }
        relocs++;
    }
    return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
}


2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
/******************************************************************
 *		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;
2233 2234
    PLIST_ENTRY         mark, entry;
    PLDR_MODULE         mod;
2235
    WORD id = 0;
2236 2237 2238 2239

    smi->ModulesCount = 0;

    RtlEnterCriticalSection( &loader_section );
2240 2241
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2242
    {
2243
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
2244 2245 2246 2247 2248
        size += sizeof(*sm);
        if (size <= buf_size)
        {
            sm->Reserved1 = 0; /* FIXME */
            sm->Reserved2 = 0; /* FIXME */
2249 2250 2251
            sm->ImageBaseAddress = mod->BaseAddress;
            sm->ImageSize = mod->SizeOfImage;
            sm->Flags = mod->Flags;
2252
            sm->Id = id++;
2253 2254 2255 2256
            sm->Rank = 0; /* FIXME */
            sm->Unknown = 0; /* FIXME */
            str.Length = 0;
            str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
Mike McCormack's avatar
Mike McCormack committed
2257
            str.Buffer = (char*)sm->Name;
2258
            RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
Mike McCormack's avatar
Mike McCormack committed
2259 2260
            ptr = strrchr(str.Buffer, '\\');
            sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273

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

    if (req_size) *req_size = size;

    return nts;
}

2274

2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 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 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374
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;
        *value = strtoulW( (WCHAR *)info->Data, 0, 16 );
    }
    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','\\'};
    WCHAR path[MAX_PATH + sizeof(optionsW)/sizeof(WCHAR)];
    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;

    if ((p = memrchrW( key->Buffer, '\\', key->Length / sizeof(WCHAR) ))) p++;
    else p = key->Buffer;
    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) );
    memcpy( path + sizeof(optionsW)/sizeof(WCHAR), p, len );
    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;
}


2375 2376 2377 2378 2379 2380 2381 2382 2383
/******************************************************************
 *		RtlDllShutdownInProgress  (NTDLL.@)
 */
BOOLEAN WINAPI RtlDllShutdownInProgress(void)
{
    return process_detaching;
}


2384 2385 2386 2387
/******************************************************************
 *		LdrShutdownProcess (NTDLL.@)
 *
 */
2388
void WINAPI LdrShutdownProcess(void)
2389 2390
{
    TRACE("()\n");
2391 2392
    process_detaching = 1;
    process_detach();
2393 2394
}

2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408

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

2409 2410 2411 2412
/******************************************************************
 *		LdrShutdownThread (NTDLL.@)
 *
 */
2413
void WINAPI LdrShutdownThread(void)
2414
{
2415 2416 2417
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;

2418 2419 2420
    TRACE("()\n");

    /* don't do any detach calls if process is exiting */
2421
    if (process_detaching) return;
2422 2423 2424

    RtlEnterCriticalSection( &loader_section );

2425 2426
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = entry->Blink)
2427
    {
2428 2429 2430
        mod = CONTAINING_RECORD(entry, LDR_MODULE, 
                                InInitializationOrderModuleList);
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
2431
            continue;
2432
        if ( mod->Flags & LDR_NO_DLL_CALLS )
2433 2434
            continue;

2435 2436
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
                        DLL_THREAD_DETACH, NULL );
2437 2438 2439
    }

    RtlLeaveCriticalSection( &loader_section );
2440
    RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer );
2441 2442
}

2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462

/***********************************************************************
 *           free_modref
 *
 */
static void free_modref( WINE_MODREF *wm )
{
    RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
    RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
    if (wm->ldr.InInitializationOrderModuleList.Flink)
        RemoveEntryList(&wm->ldr.InInitializationOrderModuleList);

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

    SERVER_START_REQ( unload_dll )
    {
2463
        req->base = wine_server_client_ptr( wm->ldr.BaseAddress );
2464 2465 2466 2467
        wine_server_call( req );
    }
    SERVER_END_REQ;

2468
    RtlReleaseActivationContext( wm->ldr.ActivationContext );
2469 2470 2471 2472 2473 2474 2475 2476
    NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
    if (wm->ldr.Flags & LDR_WINE_INTERNAL) wine_dll_unload( wm->ldr.SectionHandle );
    if (cached_modref == wm) cached_modref = NULL;
    RtlFreeUnicodeString( &wm->ldr.FullDllName );
    RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
    RtlFreeHeap( GetProcessHeap(), 0, wm );
}

2477 2478 2479 2480 2481
/***********************************************************************
 *           MODULE_FlushModrefs
 *
 * Remove all unused modrefs and call the internal unloading routines
 * for the library type.
2482 2483
 *
 * The loader_section must be locked while calling this function.
2484 2485 2486
 */
static void MODULE_FlushModrefs(void)
{
2487 2488 2489
    PLIST_ENTRY mark, entry, prev;
    PLDR_MODULE mod;
    WINE_MODREF*wm;
2490

2491 2492
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = prev)
2493
    {
2494
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InInitializationOrderModuleList);
2495 2496
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
2497 2498
        if (!mod->LoadCount) free_modref( wm );
    }
2499

2500 2501 2502 2503 2504 2505 2506 2507
    /* 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)
    {
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
        if (!mod->LoadCount) free_modref( wm );
2508 2509 2510 2511 2512 2513
    }
}

/***********************************************************************
 *           MODULE_DecRefCount
 *
2514
 * The loader_section must be locked while calling this function.
2515 2516 2517 2518 2519
 */
static void MODULE_DecRefCount( WINE_MODREF *wm )
{
    int i;

2520
    if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
2521 2522
        return;

2523
    if ( wm->ldr.LoadCount <= 0 )
2524 2525
        return;

2526
    --wm->ldr.LoadCount;
2527
    TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
2528

2529
    if ( wm->ldr.LoadCount == 0 )
2530
    {
2531
        wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
2532 2533 2534 2535 2536

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

2537
        wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
    }
}

/******************************************************************
 *		LdrUnloadDll (NTDLL.@)
 *
 *
 */
NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
{
2548
    WINE_MODREF *wm;
2549 2550
    NTSTATUS retv = STATUS_SUCCESS;

2551 2552
    if (process_detaching) return retv;

2553 2554 2555 2556
    TRACE("(%p)\n", hModule);

    RtlEnterCriticalSection( &loader_section );

2557 2558
    free_lib_count++;
    if ((wm = get_modref( hModule )) != NULL)
2559
    {
2560
        TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
2561

2562 2563
        /* Recursively decrement reference counts */
        MODULE_DecRefCount( wm );
2564

2565 2566 2567 2568 2569
        /* Call process detach notifications */
        if ( free_lib_count <= 1 )
        {
            process_detach();
            MODULE_FlushModrefs();
2570 2571
        }

2572
        TRACE("END\n");
2573
    }
2574 2575 2576 2577
    else
        retv = STATUS_DLL_NOT_FOUND;

    free_lib_count--;
2578 2579 2580 2581 2582 2583

    RtlLeaveCriticalSection( &loader_section );

    return retv;
}

2584 2585 2586 2587 2588
/***********************************************************************
 *           RtlImageNtHeader   (NTDLL.@)
 */
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
{
2589
    IMAGE_NT_HEADERS *ret;
2590

2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601
    __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;
        }
    }
2602
    __EXCEPT_PAGE_FAULT
2603
    {
2604
        return NULL;
2605
    }
2606
    __ENDTRY
2607 2608 2609 2610
    return ret;
}


2611 2612 2613 2614 2615 2616 2617 2618 2619
/***********************************************************************
 *           attach_process_dlls
 *
 * Initial attach to all the dlls loaded by the process.
 */
static NTSTATUS attach_process_dlls( void *wm )
{
    NTSTATUS status;

2620
    pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
2621

2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635
    RtlEnterCriticalSection( &loader_section );
    if ((status = process_attach( wm, (LPVOID)1 )) != STATUS_SUCCESS)
    {
        if (last_failed_modref)
            ERR( "%s failed to initialize, aborting\n",
                 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
        return status;
    }
    attach_implicitly_loaded_dlls( (LPVOID)1 );
    RtlLeaveCriticalSection( &loader_section );
    return status;
}


2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 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 2684 2685 2686 2687 2688
/***********************************************************************
 *           load_global_options
 */
static void load_global_options(void)
{
    static const WCHAR sessionW[] = {'M','a','c','h','i','n','e','\\',
                                     'S','y','s','t','e','m','\\',
                                     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
                                     'C','o','n','t','r','o','l','\\',
                                     'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
    static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
    static const WCHAR critsectW[] = {'C','r','i','t','i','c','a','l','S','e','c','t','i','o','n','T','i','m','e','o','u','t',0};
    static const WCHAR heapresW[] = {'H','e','a','p','S','e','g','m','e','n','t','R','e','s','e','r','v','e',0};
    static const WCHAR heapcommitW[] = {'H','e','a','p','S','e','g','m','e','n','t','C','o','m','m','i','t',0};
    static const WCHAR decommittotalW[] = {'H','e','a','p','D','e','C','o','m','m','i','t','T','o','t','a','l','F','r','e','e','T','h','r','e','s','h','o','l','d',0};
    static const WCHAR decommitfreeW[] = {'H','e','a','p','D','e','C','o','m','m','i','t','F','r','e','e','B','l','o','c','k','T','h','r','e','s','h','o','l','d',0};

    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING name_str;
    HANDLE hkey;
    ULONG value;

    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, sessionW );

    if (NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr )) return;

    query_dword_option( hkey, globalflagW, &NtCurrentTeb()->Peb->NtGlobalFlag );

    query_dword_option( hkey, critsectW, &value );
    NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart = (ULONGLONG)value * -10000000;

    query_dword_option( hkey, heapresW, &value );
    NtCurrentTeb()->Peb->HeapSegmentReserve = value;

    query_dword_option( hkey, heapcommitW, &value );
    NtCurrentTeb()->Peb->HeapSegmentCommit = value;

    query_dword_option( hkey, decommittotalW, &value );
    NtCurrentTeb()->Peb->HeapDeCommitTotalFreeThreshold = value;

    query_dword_option( hkey, decommitfreeW, &value );
    NtCurrentTeb()->Peb->HeapDeCommitFreeBlockThreshold = value;

    NtClose( hkey );
}


2689 2690 2691 2692 2693 2694 2695 2696
/***********************************************************************
 *           start_process
 */
static void start_process( void *kernel_start )
{
    call_thread_entry_point( kernel_start, NtCurrentTeb()->Peb );
}

2697 2698 2699 2700
/******************************************************************
 *		LdrInitializeThunk (NTDLL.@)
 *
 */
2701 2702
void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
                                ULONG_PTR unknown3, ULONG_PTR unknown4 )
2703
{
2704
    static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
2705 2706
    NTSTATUS status;
    WINE_MODREF *wm;
2707
    LPCWSTR load_path;
2708 2709
    PEB *peb = NtCurrentTeb()->Peb;

2710 2711
    if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */

2712
    /* allocate the modref for the main exe (if not already done) */
2713 2714 2715
    wm = get_modref( peb->ImageBaseAddress );
    assert( wm );
    if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
2716
    {
2717 2718
        ERR("%s is a dll, not an executable\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
        exit(1);
2719
    }
2720

2721
    peb->LoaderLock = &loader_section;
2722
    peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
2723 2724
    if (!peb->ProcessParameters->WindowTitle.Buffer)
        peb->ProcessParameters->WindowTitle = wm->ldr.FullDllName;
2725
    version_init( wm->ldr.FullDllName.Buffer );
2726
    virtual_set_large_address_space();
2727

2728 2729 2730
    LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,
                                       REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );

2731 2732 2733 2734
    /* the main exe needs to be the first in the load order list */
    RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
    InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );

2735
    if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;
2736
    if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;
2737

2738
    actctx_init();
2739 2740
    load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
    if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
2741 2742
    if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
    if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
2743
    heap_set_debug_flags( GetProcessHeap() );
2744

2745 2746
    status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );
    if (status != STATUS_SUCCESS) goto error;
2747

2748
    virtual_release_address_space();
2749
    virtual_clear_thread_stack();
2750
    wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
2751 2752

error:
2753
    ERR( "Main exe initialization for %s failed, status %x\n",
2754
         debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), status );
2755
    NtTerminateProcess( GetCurrentProcess(), status );
2756 2757 2758
}


2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772
/***********************************************************************
 *           RtlImageDirectoryEntryToData   (NTDLL.@)
 */
PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
{
    const IMAGE_NT_HEADERS *nt;
    DWORD addr;

    if ((ULONG_PTR)module & 1)  /* mapped as data file */
    {
        module = (HMODULE)((ULONG_PTR)module & ~1);
        image = FALSE;
    }
    if (!(nt = RtlImageNtHeader( module ))) return NULL;
2773 2774
    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
    {
2775
        const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
2776 2777 2778 2779 2780 2781 2782 2783

        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)
    {
2784
        const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
2785 2786 2787 2788 2789 2790 2791

        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;
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804

    /* 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
2805 2806 2807 2808
    const IMAGE_SECTION_HEADER *sec;

    sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
                                        nt->FileHeader.SizeOfOptionalHeader);
2809 2810 2811
    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
2812
            return (PIMAGE_SECTION_HEADER)sec;
2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836
    }
    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);
}
2837 2838


2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854
/***********************************************************************
 *           RtlPcToFileHeader   (NTDLL.@)
 */
PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
{
    LDR_MODULE *module;
    PVOID ret = NULL;

    RtlEnterCriticalSection( &loader_section );
    if (!LdrFindEntryForAddress( pc, &module )) ret = module->BaseAddress;
    RtlLeaveCriticalSection( &loader_section );
    *address = ret;
    return ret;
}


2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876
/***********************************************************************
 *           NtLoadDriver   (NTDLL.@)
 *           ZwLoadDriver   (NTDLL.@)
 */
NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *DriverServiceName )
{
    FIXME("(%p), stub!\n",DriverServiceName);
    return STATUS_NOT_IMPLEMENTED;
}


/***********************************************************************
 *           NtUnloadDriver   (NTDLL.@)
 *           ZwUnloadDriver   (NTDLL.@)
 */
NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *DriverServiceName )
{
    FIXME("(%p), stub!\n",DriverServiceName);
    return STATUS_NOT_IMPLEMENTED;
}


2877 2878 2879 2880 2881 2882 2883 2884 2885 2886
/******************************************************************
 *		DllMain   (NTDLL.@)
 */
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
{
    if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
    return TRUE;
}


2887 2888 2889 2890 2891
/******************************************************************
 *		__wine_init_windows_dir   (NTDLL.@)
 *
 * Windows and system dir initialization once kernel32 has been loaded.
 */
2892
void CDECL __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir )
2893 2894 2895 2896
{
    PLIST_ENTRY mark, entry;
    LPWSTR buffer, p;

2897
    strcpyW( user_shared_data->NtSystemRoot, windir );
2898
    DIR_init_windows_dir( windir, sysdir );
2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920

    /* prepend the system dir to the name of the already created modules */
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
        LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );

        assert( mod->Flags & LDR_WINE_INTERNAL );

        buffer = RtlAllocateHeap( GetProcessHeap(), 0,
                                  system_dir.Length + mod->FullDllName.Length + 2*sizeof(WCHAR) );
        if (!buffer) continue;
        strcpyW( buffer, system_dir.Buffer );
        p = buffer + strlenW( buffer );
        if (p > buffer && p[-1] != '\\') *p++ = '\\';
        strcpyW( p, mod->FullDllName.Buffer );
        RtlInitUnicodeString( &mod->FullDllName, buffer );
        RtlInitUnicodeString( &mod->BaseDllName, p );
    }
}


2921
/***********************************************************************
2922
 *           __wine_process_init
2923
 */
2924
void __wine_process_init(void)
2925
{
2926
    static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
2927

2928 2929 2930
    WINE_MODREF *wm;
    NTSTATUS status;
    ANSI_STRING func_name;
2931
    void (* DECLSPEC_NORETURN CDECL init_func)(void);
2932

2933
    main_exe_file = thread_init();
2934

2935 2936 2937 2938
    /* retrieve current umask */
    FILE_umask = umask(0777);
    umask( FILE_umask );

2939 2940
    load_global_options();

2941
    /* setup the load callback and create ntdll modref */
2942
    wine_dll_set_callback( load_builtin_callback );
2943

2944
    if ((status = load_builtin_dll( NULL, kernel32W, 0, 0, &wm )) != STATUS_SUCCESS)
2945
    {
2946
        MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
2947 2948
        exit(1);
    }
2949 2950 2951
    RtlInitAnsiString( &func_name, "UnhandledExceptionFilter" );
    LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name, 0, (void **)&unhandled_exception_filter );

2952 2953 2954 2955
    RtlInitAnsiString( &func_name, "__wine_kernel_init" );
    if ((status = LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name,
                                          0, (void **)&init_func )) != STATUS_SUCCESS)
    {
2956
        MESSAGE( "wine: could not find __wine_kernel_init in kernel32.dll, status %x\n", status );
2957 2958 2959
        exit(1);
    }
    init_func();
2960
}