~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to loader/pe_image.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:45:33 UTC
  • Revision ID: siretart@tauware.de-20060708084533-dbc155bde7122e78
imported mplayer_0.99+1.0pre7try2+cvs20060117

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 *  Copyright   1994    Eric Youndale & Erik Bos
 
3
 *  Copyright   1995    Martin von Lďż˝wis
 
4
 *  Copyright   1996-98 Marcus Meissner
 
5
 *
 
6
 *      based on Eric Youndale's pe-test and:
 
7
 *
 
8
 *      ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
 
9
 * make that:
 
10
 *      ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
 
11
 *
 
12
 * Modified for use with MPlayer, detailed CVS changelog at
 
13
 * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
 
14
 * $Id: pe_image.c,v 1.10 2005/05/25 08:48:31 diego Exp $
 
15
 *
 
16
 */
 
17
/* Notes:
 
18
 * Before you start changing something in this file be aware of the following:
 
19
 *
 
20
 * - There are several functions called recursively. In a very subtle and 
 
21
 *   obscure way. DLLs can reference each other recursively etc.
 
22
 * - If you want to enhance, speed up or clean up something in here, think
 
23
 *   twice WHY it is implemented in that strange way. There is usually a reason.
 
24
 *   Though sometimes it might just be lazyness ;)
 
25
 * - In PE_MapImage, right before fixup_imports() all external and internal 
 
26
 *   state MUST be correct since this function can be called with the SAME image
 
27
 *   AGAIN. (Thats recursion for you.) That means MODREF.module and
 
28
 *   NE_MODULE.module32.
 
29
 * - Sometimes, we can't use Linux mmap() to mmap() the images directly.
 
30
 *
 
31
 *   The problem is, that there is not direct 1:1 mapping from a diskimage and
 
32
 *   a memoryimage. The headers at the start are mapped linear, but the sections
 
33
 *   are not. Older x86 pe binaries are 512 byte aligned in file and 4096 byte
 
34
 *   aligned in memory. Linux likes them 4096 byte aligned in memory (due to
 
35
 *   x86 pagesize, this cannot be fixed without a rather large kernel rewrite)
 
36
 *   and 'blocksize' file-aligned (offsets). Since we have 512/1024/2048 (CDROM)
 
37
 *   and other byte blocksizes, we can't always do this.  We *can* do this for
 
38
 *   newer pe binaries produced by MSVC 5 and later, since they are also aligned
 
39
 *   to 4096 byte boundaries on disk.
 
40
 */
 
41
#include "config.h"
 
42
 
 
43
#include <errno.h>
 
44
#include <assert.h>
 
45
#include <stdio.h>
 
46
#include <stdlib.h>
 
47
#include <string.h>
 
48
#include <unistd.h>
 
49
#include <sys/types.h>
 
50
#include <sys/stat.h>
 
51
#include <fcntl.h>
 
52
#ifdef HAVE_SYS_MMAN_H
 
53
#include <sys/mman.h>
 
54
#endif
 
55
#include "wine/windef.h"
 
56
#include "wine/winbase.h"
 
57
#include "wine/winerror.h"
 
58
#include "wine/heap.h"
 
59
#include "wine/pe_image.h"
 
60
#include "wine/module.h"
 
61
#include "wine/debugtools.h"
 
62
#include "ext.h"
 
63
#include "win32.h"
 
64
 
 
65
#define RVA(x) ((void *)((char *)load_addr+(unsigned int)(x)))
 
66
 
 
67
#define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta))
 
68
 
 
69
extern void* LookupExternal(const char* library, int ordinal);
 
70
extern void* LookupExternalByName(const char* library, const char* name);
 
71
 
 
72
static void dump_exports( HMODULE hModule )
 
73
 
74
  char          *Module;
 
75
  unsigned int i, j;
 
76
  u_short       *ordinal;
 
77
  u_long        *function,*functions;
 
78
  u_char        **name;
 
79
  unsigned int load_addr = hModule;
 
80
 
 
81
  DWORD rva_start = PE_HEADER(hModule)->OptionalHeader
 
82
                   .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
 
83
  DWORD rva_end = rva_start + PE_HEADER(hModule)->OptionalHeader
 
84
                   .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
 
85
  IMAGE_EXPORT_DIRECTORY *pe_exports = (IMAGE_EXPORT_DIRECTORY*)RVA(rva_start);
 
86
 
 
87
  Module = (char*)RVA(pe_exports->Name);
 
88
  TRACE("*******EXPORT DATA*******\n");
 
89
  TRACE("Module name is %s, %ld functions, %ld names\n", 
 
90
        Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames);
 
91
 
 
92
  ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals);
 
93
  functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions);
 
94
  name=(u_char**) RVA(pe_exports->AddressOfNames);
 
95
 
 
96
  TRACE(" Ord    RVA     Addr   Name\n" );
 
97
  for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
 
98
  {
 
99
      if (!*function) continue;  
 
100
      if (TRACE_ON(win32))
 
101
      {
 
102
        DPRINTF( "%4ld %08lx %p", i + pe_exports->Base, *function, RVA(*function) );
 
103
        
 
104
        for (j = 0; j < pe_exports->NumberOfNames; j++)
 
105
          if (ordinal[j] == i)
 
106
          {
 
107
              DPRINTF( "  %s", (char*)RVA(name[j]) );
 
108
              break;
 
109
          }
 
110
        if ((*function >= rva_start) && (*function <= rva_end))
 
111
          DPRINTF(" (forwarded -> %s)", (char *)RVA(*function));
 
112
        DPRINTF("\n");
 
113
      }
 
114
  }
 
115
}
 
116
 
 
117
/* Look up the specified function or ordinal in the exportlist:
 
118
 * If it is a string:
 
119
 *      - look up the name in the Name list. 
 
120
 *      - look up the ordinal with that index.
 
121
 *      - use the ordinal as offset into the functionlist
 
122
 * If it is a ordinal:
 
123
 *      - use ordinal-pe_export->Base as offset into the functionlist
 
124
 */
 
125
FARPROC PE_FindExportedFunction( 
 
126
        WINE_MODREF *wm,        
 
127
        LPCSTR funcName,        
 
128
        WIN_BOOL snoop )
 
129
{
 
130
        u_short                         * ordinals;
 
131
        u_long                          * function;
 
132
        u_char                          ** name;
 
133
        const char *ename = NULL;
 
134
        int                             i, ordinal;
 
135
        PE_MODREF                       *pem = &(wm->binfmt.pe);
 
136
        IMAGE_EXPORT_DIRECTORY          *exports = pem->pe_export;
 
137
        unsigned int                    load_addr = wm->module;
 
138
        u_long                          rva_start, rva_end, addr;
 
139
        char                            * forward;
 
140
 
 
141
        if (HIWORD(funcName))
 
142
                TRACE("(%s)\n",funcName);
 
143
        else
 
144
                TRACE("(%d)\n",(int)funcName);
 
145
        if (!exports) {
 
146
                /* Not a fatal problem, some apps do
 
147
                 * GetProcAddress(0,"RegisterPenApp") which triggers this
 
148
                 * case.
 
149
                 */
 
150
                WARN("Module %08x(%s)/MODREF %p doesn't have a exports table.\n",wm->module,wm->modname,pem);
 
151
                return NULL;
 
152
        }
 
153
        ordinals= (u_short*)  RVA(exports->AddressOfNameOrdinals);
 
154
        function= (u_long*)   RVA(exports->AddressOfFunctions);
 
155
        name    = (u_char **) RVA(exports->AddressOfNames);
 
156
        forward = NULL;
 
157
        rva_start = PE_HEADER(wm->module)->OptionalHeader
 
158
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
 
159
        rva_end = rva_start + PE_HEADER(wm->module)->OptionalHeader
 
160
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
 
161
 
 
162
        if (HIWORD(funcName))
 
163
        {
 
164
            
 
165
            int min = 0, max = exports->NumberOfNames - 1;
 
166
            while (min <= max)
 
167
            {
 
168
                int res, pos = (min + max) / 2;
 
169
                ename = (const char*) RVA(name[pos]);
 
170
                if (!(res = strcmp( ename, funcName )))
 
171
                {
 
172
                    ordinal = ordinals[pos];
 
173
                    goto found;
 
174
                }
 
175
                if (res > 0) max = pos - 1;
 
176
                else min = pos + 1;
 
177
            }
 
178
            
 
179
            for (i = 0; i < exports->NumberOfNames; i++)
 
180
            {
 
181
                ename = (const char*) RVA(name[i]);
 
182
                if (!strcmp( ename, funcName ))
 
183
                {
 
184
                    ERR( "%s.%s required a linear search\n", wm->modname, funcName );
 
185
                    ordinal = ordinals[i];
 
186
                    goto found;
 
187
                }
 
188
            }
 
189
            return NULL;
 
190
        }
 
191
        else  
 
192
        {
 
193
            ordinal = LOWORD(funcName) - exports->Base;
 
194
            if (snoop && name)  
 
195
            {
 
196
                for (i = 0; i < exports->NumberOfNames; i++)
 
197
                    if (ordinals[i] == ordinal)
 
198
                    {
 
199
                        ename = RVA(name[i]);
 
200
                        break;
 
201
                    }
 
202
            }
 
203
        }
 
204
 
 
205
 found:
 
206
        if (ordinal >= exports->NumberOfFunctions)
 
207
        {
 
208
            TRACE("     ordinal %ld out of range!\n", ordinal + exports->Base );
 
209
            return NULL;
 
210
        }
 
211
        addr = function[ordinal];
 
212
        if (!addr) return NULL;
 
213
        if ((addr < rva_start) || (addr >= rva_end))
 
214
        {
 
215
            FARPROC proc = RVA(addr);
 
216
            if (snoop)
 
217
            {
 
218
                if (!ename) ename = "@";
 
219
//                proc = SNOOP_GetProcAddress(wm->module,ename,ordinal,proc);
 
220
                TRACE("SNOOP_GetProcAddress n/a\n");
 
221
                
 
222
            }
 
223
            return proc;
 
224
        }
 
225
        else  
 
226
        {
 
227
                WINE_MODREF *wm;
 
228
                char *forward = RVA(addr);
 
229
                char module[256];
 
230
                char *end = strchr(forward, '.');
 
231
 
 
232
                if (!end) return NULL;
 
233
                if (end - forward >= sizeof(module)) return NULL;
 
234
                memcpy( module, forward, end - forward );
 
235
                module[end-forward] = 0;
 
236
                if (!(wm = MODULE_FindModule( module )))
 
237
                {
 
238
                    ERR("module not found for forward '%s'\n", forward );
 
239
                    return NULL;
 
240
                }
 
241
                return MODULE_GetProcAddress( wm->module, end + 1, snoop );
 
242
        }
 
243
}
 
244
 
 
245
static DWORD fixup_imports( WINE_MODREF *wm )
 
246
{
 
247
    IMAGE_IMPORT_DESCRIPTOR     *pe_imp;
 
248
    PE_MODREF                   *pem;
 
249
    unsigned int load_addr      = wm->module;
 
250
    int                         i,characteristics_detection=1;
 
251
    char                        *modname;
 
252
    
 
253
    assert(wm->type==MODULE32_PE);
 
254
    pem = &(wm->binfmt.pe);
 
255
    if (pem->pe_export)
 
256
        modname = (char*) RVA(pem->pe_export->Name);
 
257
    else
 
258
        modname = "<unknown>";
 
259
 
 
260
    
 
261
    TRACE("Dumping imports list\n");
 
262
 
 
263
    
 
264
    pe_imp = pem->pe_import;
 
265
    if (!pe_imp) return 0;
 
266
 
 
267
    /* We assume that we have at least one import with !0 characteristics and
 
268
     * detect broken imports with all characteristsics 0 (notably Borland) and
 
269
     * switch the detection off for them.
 
270
     */
 
271
    for (i = 0; pe_imp->Name ; pe_imp++) {
 
272
        if (!i && !pe_imp->u.Characteristics)
 
273
                characteristics_detection = 0;
 
274
        if (characteristics_detection && !pe_imp->u.Characteristics)
 
275
                break;
 
276
        i++;
 
277
    }
 
278
    if (!i) return 0;  
 
279
 
 
280
    
 
281
    wm->nDeps = i;
 
282
    wm->deps  = HeapAlloc( GetProcessHeap(), 0, i*sizeof(WINE_MODREF *) );
 
283
 
 
284
    /* load the imported modules. They are automatically 
 
285
     * added to the modref list of the process.
 
286
     */
 
287
 
 
288
    for (i = 0, pe_imp = pem->pe_import; pe_imp->Name ; pe_imp++) {
 
289
        WINE_MODREF             *wmImp;
 
290
        IMAGE_IMPORT_BY_NAME    *pe_name;
 
291
        PIMAGE_THUNK_DATA       import_list,thunk_list;
 
292
        char                    *name = (char *) RVA(pe_imp->Name);
 
293
 
 
294
        if (characteristics_detection && !pe_imp->u.Characteristics)
 
295
                break;
 
296
 
 
297
//#warning FIXME: here we should fill imports
 
298
        TRACE("Loading imports for %s.dll\n", name);
 
299
    
 
300
        if (pe_imp->u.OriginalFirstThunk != 0) { 
 
301
            TRACE("Microsoft style imports used\n");
 
302
            import_list =(PIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk);
 
303
            thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
 
304
 
 
305
            while (import_list->u1.Ordinal) {
 
306
                if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
 
307
                    int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
 
308
 
 
309
//                  TRACE("--- Ordinal %s,%d\n", name, ordinal);
 
310
                    
 
311
                    thunk_list->u1.Function=LookupExternal(name, ordinal);
 
312
                } else {                
 
313
                    pe_name = (PIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
 
314
//                  TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
 
315
                    thunk_list->u1.Function=LookupExternalByName(name, pe_name->Name);
 
316
                }
 
317
                import_list++;
 
318
                thunk_list++;
 
319
            }
 
320
        } else {        
 
321
            TRACE("Borland style imports used\n");
 
322
            thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
 
323
            while (thunk_list->u1.Ordinal) {
 
324
                if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
 
325
                    
 
326
                    int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
 
327
 
 
328
                    TRACE("--- Ordinal %s.%d\n",name,ordinal);
 
329
                    thunk_list->u1.Function=LookupExternal(
 
330
                      name, ordinal);
 
331
                } else {
 
332
                    pe_name=(PIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData);
 
333
                    TRACE("--- %s %s.%d\n",
 
334
                                  pe_name->Name,name,pe_name->Hint);
 
335
                    thunk_list->u1.Function=LookupExternalByName(
 
336
                      name, pe_name->Name);
 
337
                }
 
338
                thunk_list++;
 
339
            }
 
340
        }
 
341
    }
 
342
    return 0;
 
343
}
 
344
 
 
345
static int calc_vma_size( HMODULE hModule )
 
346
{
 
347
    int i,vma_size = 0;
 
348
    IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(hModule);
 
349
 
 
350
    TRACE("Dump of segment table\n");
 
351
    TRACE("   Name    VSz  Vaddr     SzRaw   Fileadr  *Reloc *Lineum #Reloc #Linum Char\n");
 
352
    for (i = 0; i< PE_HEADER(hModule)->FileHeader.NumberOfSections; i++)
 
353
    {
 
354
        TRACE("%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n", 
 
355
                      pe_seg->Name, 
 
356
                      pe_seg->Misc.VirtualSize,
 
357
                      pe_seg->VirtualAddress,
 
358
                      pe_seg->SizeOfRawData,
 
359
                      pe_seg->PointerToRawData,
 
360
                      pe_seg->PointerToRelocations,
 
361
                      pe_seg->PointerToLinenumbers,
 
362
                      pe_seg->NumberOfRelocations,
 
363
                      pe_seg->NumberOfLinenumbers,
 
364
                      pe_seg->Characteristics);
 
365
        vma_size=max(vma_size, pe_seg->VirtualAddress+pe_seg->SizeOfRawData);
 
366
        vma_size=max(vma_size, pe_seg->VirtualAddress+pe_seg->Misc.VirtualSize);
 
367
        pe_seg++;
 
368
    }
 
369
    return vma_size;
 
370
}
 
371
 
 
372
static void do_relocations( unsigned int load_addr, IMAGE_BASE_RELOCATION *r )
 
373
{
 
374
    int delta = load_addr - PE_HEADER(load_addr)->OptionalHeader.ImageBase;
 
375
    int hdelta = (delta >> 16) & 0xFFFF;
 
376
    int ldelta = delta & 0xFFFF;
 
377
 
 
378
        if(delta == 0)
 
379
                
 
380
                return;
 
381
        while(r->VirtualAddress)
 
382
        {
 
383
                char *page = (char*) RVA(r->VirtualAddress);
 
384
                int count = (r->SizeOfBlock - 8)/2;
 
385
                int i;
 
386
                TRACE_(fixup)("%x relocations for page %lx\n",
 
387
                        count, r->VirtualAddress);
 
388
                
 
389
                for(i=0;i<count;i++)
 
390
                {
 
391
                        int offset = r->TypeOffset[i] & 0xFFF;
 
392
                        int type = r->TypeOffset[i] >> 12;
 
393
//                      TRACE_(fixup)("patching %x type %x\n", offset, type);
 
394
                        switch(type)
 
395
                        {
 
396
                        case IMAGE_REL_BASED_ABSOLUTE: break;
 
397
                        case IMAGE_REL_BASED_HIGH:
 
398
                                *(short*)(page+offset) += hdelta;
 
399
                                break;
 
400
                        case IMAGE_REL_BASED_LOW:
 
401
                                *(short*)(page+offset) += ldelta;
 
402
                                break;
 
403
                        case IMAGE_REL_BASED_HIGHLOW:
 
404
                                *(int*)(page+offset) += delta;
 
405
                                
 
406
                                break;
 
407
                        case IMAGE_REL_BASED_HIGHADJ:
 
408
                                FIXME("Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
 
409
                                break;
 
410
                        case IMAGE_REL_BASED_MIPS_JMPADDR:
 
411
                                FIXME("Is this a MIPS machine ???\n");
 
412
                                break;
 
413
                        default:
 
414
                                FIXME("Unknown fixup type\n");
 
415
                                break;
 
416
                        }
 
417
                }
 
418
                r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
 
419
        }
 
420
}
 
421
                
 
422
 
 
423
        
 
424
        
 
425
 
 
426
/**********************************************************************
 
427
 *                      PE_LoadImage
 
428
 * Load one PE format DLL/EXE into memory
 
429
 * 
 
430
 * Unluckily we can't just mmap the sections where we want them, for 
 
431
 * (at least) Linux does only support offsets which are page-aligned.
 
432
 *
 
433
 * BUT we have to map the whole image anyway, for Win32 programs sometimes
 
434
 * want to access them. (HMODULE32 point to the start of it)
 
435
 */
 
436
HMODULE PE_LoadImage( int handle, LPCSTR filename, WORD *version )
 
437
{
 
438
    HMODULE     hModule;
 
439
    HANDLE      mapping;
 
440
 
 
441
    IMAGE_NT_HEADERS *nt;
 
442
    IMAGE_SECTION_HEADER *pe_sec;
 
443
    IMAGE_DATA_DIRECTORY *dir;
 
444
    BY_HANDLE_FILE_INFORMATION bhfi;
 
445
    int i, rawsize, lowest_va, vma_size, file_size = 0;
 
446
    DWORD load_addr = 0, aoep, reloc = 0;
 
447
//    struct get_read_fd_request *req = get_req_buffer();
 
448
    int unix_handle = handle;
 
449
    int page_size = getpagesize();
 
450
 
 
451
    
 
452
//    if ( GetFileInformationByHandle( hFile, &bhfi ) ) 
 
453
//      file_size = bhfi.nFileSizeLow; 
 
454
    file_size=lseek(handle, 0, SEEK_END);
 
455
    lseek(handle, 0, SEEK_SET);
 
456
 
 
457
//#warning fix CreateFileMappingA
 
458
    mapping = CreateFileMappingA( handle, NULL, PAGE_READONLY | SEC_COMMIT,
 
459
                                    0, 0, NULL );
 
460
    if (!mapping)
 
461
    {
 
462
        WARN("CreateFileMapping error %ld\n", GetLastError() );
 
463
        return 0;
 
464
    }
 
465
//    hModule = (HMODULE)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
 
466
    hModule=(HMODULE)mapping;
 
467
//    CloseHandle( mapping );
 
468
    if (!hModule)
 
469
    {
 
470
        WARN("MapViewOfFile error %ld\n", GetLastError() );
 
471
        return 0;
 
472
    }
 
473
    if ( *(WORD*)hModule !=IMAGE_DOS_SIGNATURE)
 
474
    {
 
475
        WARN("%s image doesn't have DOS signature, but 0x%04x\n", filename,*(WORD*)hModule);
 
476
        goto error;
 
477
    }
 
478
 
 
479
    nt = PE_HEADER( hModule );
 
480
 
 
481
    
 
482
    if ( nt->Signature != IMAGE_NT_SIGNATURE )
 
483
    {
 
484
        WARN("%s image doesn't have PE signature, but 0x%08lx\n", filename, nt->Signature );
 
485
        goto error;
 
486
    }
 
487
 
 
488
    
 
489
    if ( nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 )
 
490
    {
 
491
        MESSAGE("Trying to load PE image for unsupported architecture (");
 
492
        switch (nt->FileHeader.Machine)
 
493
        {
 
494
        case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
 
495
        case IMAGE_FILE_MACHINE_I860:    MESSAGE("I860"); break;
 
496
        case IMAGE_FILE_MACHINE_R3000:   MESSAGE("R3000"); break;
 
497
        case IMAGE_FILE_MACHINE_R4000:   MESSAGE("R4000"); break;
 
498
        case IMAGE_FILE_MACHINE_R10000:  MESSAGE("R10000"); break;
 
499
        case IMAGE_FILE_MACHINE_ALPHA:   MESSAGE("Alpha"); break;
 
500
        case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
 
501
        default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
 
502
        }
 
503
        MESSAGE(")\n");
 
504
        goto error;
 
505
    }
 
506
 
 
507
    
 
508
    pe_sec = PE_SECTIONS( hModule );
 
509
    rawsize = 0; lowest_va = 0x10000;
 
510
    for (i = 0; i < nt->FileHeader.NumberOfSections; i++) 
 
511
    {
 
512
        if (lowest_va > pe_sec[i].VirtualAddress)
 
513
           lowest_va = pe_sec[i].VirtualAddress;
 
514
        if (pe_sec[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
 
515
            continue;
 
516
        if (pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData > rawsize)
 
517
            rawsize = pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData;
 
518
    }
 
519
 
 
520
    
 
521
    if ( file_size && file_size < rawsize )
 
522
    {
 
523
        ERR("PE module is too small (header: %d, filesize: %d), "
 
524
                    "probably truncated download?\n", 
 
525
                    rawsize, file_size );
 
526
        goto error;
 
527
    }
 
528
 
 
529
    
 
530
    aoep = nt->OptionalHeader.AddressOfEntryPoint;
 
531
    if (aoep && (aoep < lowest_va))
 
532
        FIXME("VIRUS WARNING: '%s' has an invalid entrypoint (0x%08lx) "
 
533
                      "below the first virtual address (0x%08x) "
 
534
                      "(possibly infected by Tchernobyl/SpaceFiller virus)!\n",
 
535
                       filename, aoep, lowest_va );
 
536
 
 
537
 
 
538
    /* FIXME:  Hack!  While we don't really support shared sections yet,
 
539
     *         this checks for those special cases where the whole DLL
 
540
     *         consists only of shared sections and is mapped into the
 
541
     *         shared address space > 2GB.  In this case, we assume that
 
542
     *         the module got mapped at its base address. Thus we simply
 
543
     *         check whether the module has actually been mapped there
 
544
     *         and use it, if so.  This is needed to get Win95 USER32.DLL
 
545
     *         to work (until we support shared sections properly).
 
546
     */
 
547
 
 
548
    if ( nt->OptionalHeader.ImageBase & 0x80000000 )
 
549
    {
 
550
        HMODULE sharedMod = (HMODULE)nt->OptionalHeader.ImageBase; 
 
551
        IMAGE_NT_HEADERS *sharedNt = (PIMAGE_NT_HEADERS)
 
552
               ( (LPBYTE)sharedMod + ((LPBYTE)nt - (LPBYTE)hModule) );
 
553
 
 
554
        /* Well, this check is not really comprehensive, 
 
555
           but should be good enough for now ... */
 
556
        if (    !IsBadReadPtr( (LPBYTE)sharedMod, sizeof(IMAGE_DOS_HEADER) )
 
557
             && memcmp( (LPBYTE)sharedMod, (LPBYTE)hModule, sizeof(IMAGE_DOS_HEADER) ) == 0
 
558
             && !IsBadReadPtr( sharedNt, sizeof(IMAGE_NT_HEADERS) )
 
559
             && memcmp( sharedNt, nt, sizeof(IMAGE_NT_HEADERS) ) == 0 )
 
560
        {
 
561
            UnmapViewOfFile( (LPVOID)hModule );
 
562
            return sharedMod;
 
563
        }
 
564
    }
 
565
 
 
566
 
 
567
    
 
568
    load_addr = nt->OptionalHeader.ImageBase;
 
569
    vma_size = calc_vma_size( hModule );
 
570
 
 
571
    load_addr = (DWORD)VirtualAlloc( (void*)load_addr, vma_size,
 
572
                                     MEM_RESERVE | MEM_COMMIT,
 
573
                                     PAGE_EXECUTE_READWRITE );
 
574
    if (load_addr == 0) 
 
575
    {
 
576
        
 
577
        FIXME("We need to perform base relocations for %s\n", filename);
 
578
        dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BASERELOC;
 
579
        if (dir->Size)
 
580
            reloc = dir->VirtualAddress;
 
581
        else 
 
582
        {
 
583
            FIXME( "FATAL: Need to relocate %s, but no relocation records present (%s). Try to run that file directly !\n",
 
584
                   filename,
 
585
                   (nt->FileHeader.Characteristics&IMAGE_FILE_RELOCS_STRIPPED)?
 
586
                   "stripped during link" : "unknown reason" );
 
587
            goto error;
 
588
        }
 
589
 
 
590
        /* FIXME: If we need to relocate a system DLL (base > 2GB) we should
 
591
         *        really make sure that the *new* base address is also > 2GB.
 
592
         *        Some DLLs really check the MSB of the module handle :-/
 
593
         */
 
594
        if ( nt->OptionalHeader.ImageBase & 0x80000000 )
 
595
            ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
 
596
 
 
597
        load_addr = (DWORD)VirtualAlloc( NULL, vma_size,
 
598
                                         MEM_RESERVE | MEM_COMMIT,
 
599
                                         PAGE_EXECUTE_READWRITE );
 
600
        if (!load_addr) {
 
601
            FIXME_(win32)(
 
602
                   "FATAL: Couldn't load module %s (out of memory, %d needed)!\n", filename, vma_size);
 
603
            goto error;
 
604
        }
 
605
    }
 
606
 
 
607
    TRACE("Load addr is %lx (base %lx), range %x\n",
 
608
          load_addr, nt->OptionalHeader.ImageBase, vma_size );
 
609
    TRACE_(segment)("Loading %s at %lx, range %x\n",
 
610
                    filename, load_addr, vma_size );
 
611
 
 
612
#if 0
 
613
    
 
614
    *(PIMAGE_DOS_HEADER)load_addr = *(PIMAGE_DOS_HEADER)hModule;
 
615
    *PE_HEADER( load_addr ) = *nt;
 
616
    memcpy( PE_SECTIONS(load_addr), PE_SECTIONS(hModule),
 
617
            sizeof(IMAGE_SECTION_HEADER) * nt->FileHeader.NumberOfSections );
 
618
 
 
619
    
 
620
    memcpy( load_addr, hModule, lowest_fa );
 
621
#endif
 
622
 
 
623
    if ((void*)FILE_dommap( handle, (void *)load_addr, 0, nt->OptionalHeader.SizeOfHeaders,
 
624
                     0, 0, PROT_EXEC | PROT_WRITE | PROT_READ,
 
625
                     MAP_PRIVATE | MAP_FIXED ) != (void*)load_addr)
 
626
    {
 
627
        ERR_(win32)( "Critical Error: failed to map PE header to necessary address.\n");        
 
628
        goto error;
 
629
    }
 
630
 
 
631
    
 
632
    pe_sec = PE_SECTIONS( hModule );
 
633
    for (i = 0; i < nt->FileHeader.NumberOfSections; i++, pe_sec++)
 
634
    {
 
635
        if (!pe_sec->SizeOfRawData || !pe_sec->PointerToRawData) continue;
 
636
        TRACE("%s: mmaping section %s at %p off %lx size %lx/%lx\n",
 
637
              filename, pe_sec->Name, (void*)RVA(pe_sec->VirtualAddress),
 
638
              pe_sec->PointerToRawData, pe_sec->SizeOfRawData, pe_sec->Misc.VirtualSize );
 
639
        if ((void*)FILE_dommap( unix_handle, (void*)RVA(pe_sec->VirtualAddress),
 
640
                         0, pe_sec->SizeOfRawData, 0, pe_sec->PointerToRawData,
 
641
                         PROT_EXEC | PROT_WRITE | PROT_READ,
 
642
                         MAP_PRIVATE | MAP_FIXED ) != (void*)RVA(pe_sec->VirtualAddress))
 
643
        {
 
644
            
 
645
            ERR_(win32)( "Critical Error: failed to map PE section to necessary address.\n");
 
646
            goto error;
 
647
        }
 
648
        if ((pe_sec->SizeOfRawData < pe_sec->Misc.VirtualSize) &&
 
649
            (pe_sec->SizeOfRawData & (page_size-1)))
 
650
        {
 
651
            DWORD end = (pe_sec->SizeOfRawData & ~(page_size-1)) + page_size;
 
652
            if (end > pe_sec->Misc.VirtualSize) end = pe_sec->Misc.VirtualSize;
 
653
            TRACE("clearing %p - %p\n",
 
654
                  RVA(pe_sec->VirtualAddress) + pe_sec->SizeOfRawData,
 
655
                  RVA(pe_sec->VirtualAddress) + end );
 
656
            memset( (char*)RVA(pe_sec->VirtualAddress) + pe_sec->SizeOfRawData, 0,
 
657
                    end - pe_sec->SizeOfRawData );
 
658
        }
 
659
    }
 
660
 
 
661
    
 
662
    if ( reloc )
 
663
        do_relocations( load_addr, (IMAGE_BASE_RELOCATION *)RVA(reloc) );
 
664
 
 
665
    
 
666
    *version =   ( (nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 )
 
667
               |   (nt->OptionalHeader.MinorSubsystemVersion & 0xff);
 
668
 
 
669
    
 
670
    UnmapViewOfFile( (LPVOID)hModule );
 
671
    return (HMODULE)load_addr;
 
672
 
 
673
error:
 
674
    if (unix_handle != -1) close( unix_handle );
 
675
    if (load_addr) 
 
676
    VirtualFree( (LPVOID)load_addr, 0, MEM_RELEASE );
 
677
    UnmapViewOfFile( (LPVOID)hModule );
 
678
    return 0;
 
679
}
 
680
 
 
681
/**********************************************************************
 
682
 *                 PE_CreateModule
 
683
 *
 
684
 * Create WINE_MODREF structure for loaded HMODULE32, link it into
 
685
 * process modref_list, and fixup all imports.
 
686
 *
 
687
 * Note: hModule must point to a correctly allocated PE image,
 
688
 *       with base relocations applied; the 16-bit dummy module
 
689
 *       associated to hModule must already exist.
 
690
 *
 
691
 * Note: This routine must always be called in the context of the
 
692
 *       process that is to own the module to be created.
 
693
 */
 
694
WINE_MODREF *PE_CreateModule( HMODULE hModule, 
 
695
                              LPCSTR filename, DWORD flags, WIN_BOOL builtin )
 
696
{
 
697
    DWORD load_addr = (DWORD)hModule;  
 
698
    IMAGE_NT_HEADERS *nt = PE_HEADER(hModule);
 
699
    IMAGE_DATA_DIRECTORY *dir;
 
700
    IMAGE_IMPORT_DESCRIPTOR *pe_import = NULL;
 
701
    IMAGE_EXPORT_DIRECTORY *pe_export = NULL;
 
702
    IMAGE_RESOURCE_DIRECTORY *pe_resource = NULL;
 
703
    WINE_MODREF *wm;
 
704
    int result;
 
705
 
 
706
 
 
707
    
 
708
 
 
709
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT;
 
710
    if (dir->Size)
 
711
        pe_export = (PIMAGE_EXPORT_DIRECTORY)RVA(dir->VirtualAddress);
 
712
 
 
713
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IMPORT;
 
714
    if (dir->Size)
 
715
        pe_import = (PIMAGE_IMPORT_DESCRIPTOR)RVA(dir->VirtualAddress);
 
716
 
 
717
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_RESOURCE;
 
718
    if (dir->Size)
 
719
        pe_resource = (PIMAGE_RESOURCE_DIRECTORY)RVA(dir->VirtualAddress);
 
720
 
 
721
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXCEPTION;
 
722
    if (dir->Size) FIXME("Exception directory ignored\n" );
 
723
 
 
724
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_SECURITY;
 
725
    if (dir->Size) FIXME("Security directory ignored\n" );
 
726
 
 
727
    
 
728
    
 
729
 
 
730
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DEBUG;
 
731
    if (dir->Size) TRACE("Debug directory ignored\n" );
 
732
 
 
733
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COPYRIGHT;
 
734
    if (dir->Size) FIXME("Copyright string ignored\n" );
 
735
 
 
736
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_GLOBALPTR;
 
737
    if (dir->Size) FIXME("Global Pointer (MIPS) ignored\n" );
 
738
 
 
739
    
 
740
 
 
741
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG;
 
742
    if (dir->Size) FIXME("Load Configuration directory ignored\n" );
 
743
 
 
744
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT;
 
745
    if (dir->Size) TRACE("Bound Import directory ignored\n" );
 
746
 
 
747
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IAT;
 
748
    if (dir->Size) TRACE("Import Address Table directory ignored\n" );
 
749
 
 
750
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT;
 
751
    if (dir->Size)
 
752
    {
 
753
                TRACE("Delayed import, stub calls LoadLibrary\n" );
 
754
                /*
 
755
                 * Nothing to do here.
 
756
                 */
 
757
 
 
758
#ifdef ImgDelayDescr
 
759
                /*
 
760
                 * This code is useful to observe what the heck is going on.
 
761
                 */
 
762
                {
 
763
                ImgDelayDescr *pe_delay = NULL;
 
764
        pe_delay = (PImgDelayDescr)RVA(dir->VirtualAddress);
 
765
        TRACE_(delayhlp)("pe_delay->grAttrs = %08x\n", pe_delay->grAttrs);
 
766
        TRACE_(delayhlp)("pe_delay->szName = %s\n", pe_delay->szName);
 
767
        TRACE_(delayhlp)("pe_delay->phmod = %08x\n", pe_delay->phmod);
 
768
        TRACE_(delayhlp)("pe_delay->pIAT = %08x\n", pe_delay->pIAT);
 
769
        TRACE_(delayhlp)("pe_delay->pINT = %08x\n", pe_delay->pINT);
 
770
        TRACE_(delayhlp)("pe_delay->pBoundIAT = %08x\n", pe_delay->pBoundIAT);
 
771
        TRACE_(delayhlp)("pe_delay->pUnloadIAT = %08x\n", pe_delay->pUnloadIAT);
 
772
        TRACE_(delayhlp)("pe_delay->dwTimeStamp = %08x\n", pe_delay->dwTimeStamp);
 
773
        }
 
774
#endif 
 
775
        }
 
776
 
 
777
    dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR;
 
778
    if (dir->Size) FIXME("Unknown directory 14 ignored\n" );
 
779
 
 
780
    dir = nt->OptionalHeader.DataDirectory+15;
 
781
    if (dir->Size) FIXME("Unknown directory 15 ignored\n" );
 
782
 
 
783
 
 
784
    
 
785
 
 
786
    wm = (WINE_MODREF *)HeapAlloc( GetProcessHeap(), 
 
787
                                   HEAP_ZERO_MEMORY, sizeof(*wm) );
 
788
    wm->module = hModule;
 
789
 
 
790
    if ( builtin ) 
 
791
        wm->flags |= WINE_MODREF_INTERNAL;
 
792
    if ( flags & DONT_RESOLVE_DLL_REFERENCES )
 
793
        wm->flags |= WINE_MODREF_DONT_RESOLVE_REFS;
 
794
    if ( flags & LOAD_LIBRARY_AS_DATAFILE )
 
795
        wm->flags |= WINE_MODREF_LOAD_AS_DATAFILE;
 
796
 
 
797
    wm->type = MODULE32_PE;
 
798
    wm->binfmt.pe.pe_export = pe_export;
 
799
    wm->binfmt.pe.pe_import = pe_import;
 
800
    wm->binfmt.pe.pe_resource = pe_resource;
 
801
    wm->binfmt.pe.tlsindex = -1;
 
802
 
 
803
    wm->filename = malloc(strlen(filename)+1);
 
804
    strcpy(wm->filename, filename );
 
805
    wm->modname = strrchr( wm->filename, '\\' );
 
806
    if (!wm->modname) wm->modname = wm->filename;
 
807
    else wm->modname++;
 
808
 
 
809
    if ( pe_export )
 
810
        dump_exports( hModule );
 
811
 
 
812
    /* Fixup Imports */
 
813
 
 
814
    if (    pe_import
 
815
         && !( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE )
 
816
         && !( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) 
 
817
         && fixup_imports( wm ) ) 
 
818
    {
 
819
        /* remove entry from modref chain */
 
820
         return NULL;
 
821
    }
 
822
 
 
823
    return wm;
 
824
 
 
825
    return wm;
 
826
}
 
827
 
 
828
/******************************************************************************
 
829
 * The PE Library Loader frontend. 
 
830
 * FIXME: handle the flags.
 
831
 */
 
832
WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags)
 
833
{
 
834
        HMODULE         hModule32;
 
835
        WINE_MODREF     *wm;
 
836
        char            filename[256];
 
837
        int hFile;
 
838
        WORD            version = 0;
 
839
 
 
840
        
 
841
        strncpy(filename, name, sizeof(filename));      
 
842
        hFile=open(filename, O_RDONLY);
 
843
        if(hFile==-1)
 
844
            return NULL;
 
845
        
 
846
        
 
847
        hModule32 = PE_LoadImage( hFile, filename, &version );
 
848
        if (!hModule32)
 
849
        {
 
850
                SetLastError( ERROR_OUTOFMEMORY );      
 
851
                return NULL;
 
852
        }
 
853
 
 
854
        if ( !(wm = PE_CreateModule( hModule32, filename, flags, FALSE )) )
 
855
        {
 
856
                ERR( "can't load %s\n", filename );
 
857
                SetLastError( ERROR_OUTOFMEMORY );
 
858
                return NULL;
 
859
        }
 
860
        close(hFile);
 
861
        //printf("^^^^^^^^^^^^^^^^Alloc VM1  %p\n", wm);
 
862
        return wm;
 
863
}
 
864
 
 
865
 
 
866
/*****************************************************************************
 
867
 *      PE_UnloadLibrary
 
868
 *
 
869
 * Unload the library unmapping the image and freeing the modref structure.
 
870
 */
 
871
void PE_UnloadLibrary(WINE_MODREF *wm)
 
872
{
 
873
    TRACE(" unloading %s\n", wm->filename);
 
874
 
 
875
    if (wm->filename)
 
876
        free(wm->filename);
 
877
    if (wm->short_filename)
 
878
        free(wm->short_filename);
 
879
    HeapFree( GetProcessHeap(), 0, wm->deps );
 
880
    VirtualFree( (LPVOID)wm->module, 0, MEM_RELEASE );
 
881
    HeapFree( GetProcessHeap(), 0, wm );
 
882
    //printf("^^^^^^^^^^^^^^^^Free VM1  %p\n", wm);
 
883
}
 
884
 
 
885
/*****************************************************************************
 
886
 * Load the PE main .EXE. All other loading is done by PE_LoadLibraryExA
 
887
 * FIXME: this function should use PE_LoadLibraryExA, but currently can't
 
888
 * due to the PROCESS_Create stuff.
 
889
 */
 
890
 
 
891
 
 
892
/*
 
893
 * This is a dirty hack.
 
894
 * The win32 DLLs contain an alloca routine, that first probes the soon
 
895
 * to be allocated new memory *below* the current stack pointer in 4KByte
 
896
 * increments.  After the mem probing below the current %esp,  the stack
 
897
 * pointer is finally decremented to make room for the "alloca"ed memory.
 
898
 * Maybe the probing code is intended to extend the stack on a windows box.
 
899
 * Anyway, the linux kernel does *not* extend the stack by simply accessing
 
900
 * memory below %esp;  it segfaults.
 
901
 * The extend_stack_for_dll_alloca() routine just preallocates a big chunk
 
902
 * of memory on the stack, for use by the DLLs alloca routine.
 
903
 * Added the noinline attribute as e.g. gcc 3.2.2 inlines this function
 
904
 * in a way that breaks it.
 
905
 */
 
906
static void __attribute__((noinline)) extend_stack_for_dll_alloca(void)
 
907
{
 
908
#if !defined(__FreeBSD__) && !defined(__DragonFly__)
 
909
    volatile int* mem=alloca(0x20000);
 
910
    *mem=0x1234;
 
911
#endif
 
912
}
 
913
 
 
914
/* Called if the library is loaded or freed.
 
915
 * NOTE: if a thread attaches a DLL, the current thread will only do
 
916
 * DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH
 
917
 * (SDK)
 
918
 */
 
919
WIN_BOOL PE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
 
920
{
 
921
    WIN_BOOL retv = TRUE;
 
922
    assert( wm->type == MODULE32_PE );
 
923
 
 
924
    
 
925
    if ((PE_HEADER(wm->module)->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
 
926
        (PE_HEADER(wm->module)->OptionalHeader.AddressOfEntryPoint)
 
927
    ) {
 
928
        DLLENTRYPROC entry ;
 
929
        entry = (void*)PE_FindExportedFunction(wm, "DllMain", 0);
 
930
        if(entry==NULL)
 
931
            entry = (void*)RVA_PTR( wm->module,OptionalHeader.AddressOfEntryPoint );
 
932
        
 
933
        TRACE_(relay)("CallTo32(entryproc=%p,module=%08x,type=%ld,res=%p)\n",
 
934
                       entry, wm->module, type, lpReserved );
 
935
        
 
936
        
 
937
        TRACE("Entering DllMain(");
 
938
        switch(type)
 
939
        {
 
940
            case DLL_PROCESS_DETACH:
 
941
                TRACE("DLL_PROCESS_DETACH) ");
 
942
                break;
 
943
            case DLL_PROCESS_ATTACH:
 
944
                TRACE("DLL_PROCESS_ATTACH) ");
 
945
                break;
 
946
            case DLL_THREAD_DETACH:
 
947
                TRACE("DLL_THREAD_DETACH) ");
 
948
                break;
 
949
            case DLL_THREAD_ATTACH:
 
950
                TRACE("DLL_THREAD_ATTACH) ");
 
951
                break;
 
952
        }       
 
953
        TRACE("for %s\n", wm->filename);
 
954
        extend_stack_for_dll_alloca();
 
955
        retv = entry( wm->module, type, lpReserved );
 
956
    }
 
957
 
 
958
    return retv;
 
959
}
 
960
 
 
961
static LPVOID
 
962
_fixup_address(PIMAGE_OPTIONAL_HEADER opt,int delta,LPVOID addr) {
 
963
        if (    ((DWORD)addr>opt->ImageBase) &&
 
964
                ((DWORD)addr<opt->ImageBase+opt->SizeOfImage)
 
965
        )
 
966
                
 
967
                return (LPVOID)(((DWORD)addr)+delta);
 
968
        else
 
969
                
 
970
                return addr;
 
971
}