Build ntdll with -DSTRICT.
[wine] / loader / pe_image.c
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  *      ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 /* Notes:
24  * Before you start changing something in this file be aware of the following:
25  *
26  * - There are several functions called recursively. In a very subtle and
27  *   obscure way. DLLs can reference each other recursively etc.
28  * - If you want to enhance, speed up or clean up something in here, think
29  *   twice WHY it is implemented in that strange way. There is usually a reason.
30  *   Though sometimes it might just be lazyness ;)
31  * - In PE_MapImage, right before PE_fixup_imports() all external and internal
32  *   state MUST be correct since this function can be called with the SAME image
33  *   AGAIN. (Thats recursion for you.) That means MODREF.module and
34  *   NE_MODULE.module32.
35  */
36
37 #include "config.h"
38
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_MMAN_H
41 #include <sys/mman.h>
42 #endif
43 #include <string.h>
44 #include "wine/winbase16.h"
45 #include "winerror.h"
46 #include "snoop.h"
47 #include "wine/server.h"
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(win32);
51 WINE_DECLARE_DEBUG_CHANNEL(delayhlp);
52 WINE_DECLARE_DEBUG_CHANNEL(fixup);
53 WINE_DECLARE_DEBUG_CHANNEL(module);
54 WINE_DECLARE_DEBUG_CHANNEL(relay);
55 WINE_DECLARE_DEBUG_CHANNEL(segment);
56
57
58 /* convert PE image VirtualAddress to Real Address */
59 inline static void *get_rva( HMODULE module, DWORD va )
60 {
61     return (void *)((char *)module + va);
62 }
63
64 #define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta))
65
66 void dump_exports( HMODULE hModule )
67 {
68   char          *Module;
69   int           i, j;
70   WORD          *ordinal;
71   DWORD         *function,*functions;
72   DWORD *name;
73   IMAGE_EXPORT_DIRECTORY *pe_exports;
74   DWORD rva_start, size;
75
76   pe_exports = RtlImageDirectoryEntryToData( hModule, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
77   rva_start = (char *)pe_exports - (char *)hModule;
78
79   Module = get_rva(hModule, pe_exports->Name);
80   DPRINTF("*******EXPORT DATA*******\n");
81   DPRINTF("Module name is %s, %ld functions, %ld names\n",
82           Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames);
83
84   ordinal = get_rva(hModule, pe_exports->AddressOfNameOrdinals);
85   functions = function = get_rva(hModule, pe_exports->AddressOfFunctions);
86   name = get_rva(hModule, pe_exports->AddressOfNames);
87
88   DPRINTF(" Ord    RVA     Addr   Name\n" );
89   for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
90   {
91       if (!*function) continue;  /* No such function */
92       DPRINTF( "%4ld %08lx %p", i + pe_exports->Base, *function, get_rva(hModule, *function) );
93       /* Check if we have a name for it */
94       for (j = 0; j < pe_exports->NumberOfNames; j++)
95           if (ordinal[j] == i)
96           {
97               DPRINTF( "  %s", (char*)get_rva(hModule, name[j]) );
98               break;
99           }
100       if ((*function >= rva_start) && (*function <= rva_start + size))
101           DPRINTF(" (forwarded -> %s)", (char *)get_rva(hModule, *function));
102       DPRINTF("\n");
103   }
104 }
105
106 /* Look up the specified function or ordinal in the export list:
107  * If it is a string:
108  *      - look up the name in the name list.
109  *      - look up the ordinal with that index.
110  *      - use the ordinal as offset into the functionlist
111  * If it is an ordinal:
112  *      - use ordinal-pe_export->Base as offset into the function list
113  */
114 static FARPROC PE_FindExportedFunction(
115         WINE_MODREF *wm,        /* [in] WINE modreference */
116         LPCSTR funcName,        /* [in] function name */
117         int hint,
118         BOOL snoop )
119 {
120         WORD                            * ordinals;
121         DWORD                           * function;
122         int                             i, ordinal;
123         DWORD                           rva_start, addr;
124         char                            * forward;
125         DWORD *name;
126         char *ename = NULL;
127         FARPROC proc;
128         IMAGE_EXPORT_DIRECTORY *exports;
129         DWORD exp_size;
130
131         if (!(exports = RtlImageDirectoryEntryToData( wm->module, TRUE,
132                                                       IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
133             return NULL;
134
135         if (HIWORD(funcName)) TRACE("(%s)\n",funcName);
136         else TRACE("(%d)\n",LOWORD(funcName));
137
138         ordinals= get_rva(wm->module, exports->AddressOfNameOrdinals);
139         function= get_rva(wm->module, exports->AddressOfFunctions);
140         name    = get_rva(wm->module, exports->AddressOfNames);
141         forward = NULL;
142         rva_start = (char *)exports - (char *)wm->module;
143
144         if (HIWORD(funcName))
145         {
146             int min = 0, max = exports->NumberOfNames - 1;
147
148             /* first check the hint */
149             if (hint >= 0 && hint <= max)
150             {
151                 ename = get_rva(wm->module, name[hint]);
152                 if (!strcmp( ename, funcName ))
153                 {
154                     ordinal = ordinals[hint];
155                     goto found;
156                 }
157             }
158
159             /* then do a binary search */
160             while (min <= max)
161             {
162                 int res, pos = (min + max) / 2;
163                 ename = get_rva(wm->module, name[pos]);
164                 if (!(res = strcmp( ename, funcName )))
165                 {
166                     ordinal = ordinals[pos];
167                     goto found;
168                 }
169                 if (res > 0) max = pos - 1;
170                 else min = pos + 1;
171             }
172             return NULL;
173         }
174         else  /* find by ordinal */
175         {
176             ordinal = LOWORD(funcName) - exports->Base;
177             if (snoop && name)  /* need to find a name for it */
178             {
179                 for (i = 0; i < exports->NumberOfNames; i++)
180                     if (ordinals[i] == ordinal)
181                     {
182                         ename = get_rva(wm->module, name[i]);
183                         break;
184                     }
185             }
186         }
187
188  found:
189         if (ordinal >= exports->NumberOfFunctions)
190         {
191             TRACE("     ordinal %ld out of range!\n", ordinal + exports->Base );
192             return NULL;
193         }
194         addr = function[ordinal];
195         if (!addr) return NULL;
196
197         proc = get_rva(wm->module, addr);
198         if (((char *)proc < (char *)exports) || ((char *)proc >= (char *)exports + exp_size))
199         {
200             if (snoop)
201             {
202                 if (!ename) ename = "@";
203                 proc = SNOOP_GetProcAddress(wm->module,ename,ordinal,proc);
204             }
205             return proc;
206         }
207         else  /* forward entry point */
208         {
209                 WINE_MODREF *wm_fw;
210                 char *forward = (char *)proc;
211                 char module[256];
212                 char *end = strchr(forward, '.');
213
214                 if (!end) return NULL;
215                 if (end - forward >= sizeof(module)) return NULL;
216                 memcpy( module, forward, end - forward );
217                 module[end-forward] = 0;
218                 if (!(wm_fw = MODULE_FindModule( module )))
219                 {
220                     ERR("module not found for forward '%s' used by '%s'\n", forward, wm->modname );
221                     return NULL;
222                 }
223                 if (!(proc = MODULE_GetProcAddress( wm_fw->module, end + 1, -1, snoop )))
224                     ERR("function not found for forward '%s' used by '%s'. If you are using builtin '%s', try using the native one instead.\n", forward, wm->modname, wm->modname );
225                 return proc;
226         }
227 }
228
229 /****************************************************************
230  *      PE_fixup_imports
231  */
232 DWORD PE_fixup_imports( WINE_MODREF *wm )
233 {
234     int i,characteristics_detection=1;
235     IMAGE_IMPORT_DESCRIPTOR *imports, *pe_imp;
236     DWORD size;
237
238     imports = RtlImageDirectoryEntryToData( wm->module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size );
239
240     /* first, count the number of imported non-internal modules */
241     pe_imp = imports;
242     if (!pe_imp) return 0;
243
244     /* OK, now dump the import list */
245     TRACE("Dumping imports list\n");
246
247     /* We assume that we have at least one import with !0 characteristics and
248      * detect broken imports with all characteristics 0 (notably Borland) and
249      * switch the detection off for them.
250      */
251     for (i = 0; pe_imp->Name ; pe_imp++) {
252         if (!i && !pe_imp->u.Characteristics)
253                 characteristics_detection = 0;
254         if (characteristics_detection && !pe_imp->u.Characteristics)
255                 break;
256         i++;
257     }
258     if (!i) return 0;  /* no imports */
259
260     /* Allocate module dependency list */
261     wm->nDeps = i;
262     wm->deps  = HeapAlloc( GetProcessHeap(), 0, i*sizeof(WINE_MODREF *) );
263
264     /* load the imported modules. They are automatically
265      * added to the modref list of the process.
266      */
267
268     for (i = 0, pe_imp = imports; pe_imp->Name ; pe_imp++) {
269         WINE_MODREF             *wmImp;
270         IMAGE_IMPORT_BY_NAME    *pe_name;
271         PIMAGE_THUNK_DATA       import_list,thunk_list;
272         char                    *name = get_rva(wm->module, pe_imp->Name);
273
274         if (characteristics_detection && !pe_imp->u.Characteristics)
275                 break;
276
277         wmImp = MODULE_LoadLibraryExA( name, 0, 0 );
278         if (!wmImp) {
279             ERR_(module)("Module (file) %s (which is needed by %s) not found\n", name, wm->filename);
280             return 1;
281         }
282         wm->deps[i++] = wmImp;
283
284         /* FIXME: forwarder entries ... */
285
286         if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
287             TRACE("Microsoft style imports used\n");
288             import_list = get_rva(wm->module, (DWORD)pe_imp->u.OriginalFirstThunk);
289             thunk_list = get_rva(wm->module, (DWORD)pe_imp->FirstThunk);
290
291             while (import_list->u1.Ordinal) {
292                 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
293                     int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
294
295                     TRACE("--- Ordinal %s,%d\n", name, ordinal);
296                     thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
297                         wmImp->module, (LPCSTR)ordinal, -1, TRUE
298                     );
299                     if (!thunk_list->u1.Function) {
300                         ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
301                                 name, ordinal, wm->filename );
302                         thunk_list->u1.Function = (PDWORD)0xdeadbeef;
303                     }
304                 } else {                /* import by name */
305                     pe_name = get_rva(wm->module, (DWORD)import_list->u1.AddressOfData);
306                     TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
307                     thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
308                         wmImp->module, pe_name->Name, pe_name->Hint, TRUE
309                     );
310                     if (!thunk_list->u1.Function) {
311                         ERR("No implementation for %s.%d(%s) imported from %s, setting to 0xdeadbeef\n",
312                                 name,pe_name->Hint,pe_name->Name,wm->filename);
313                         thunk_list->u1.Function = (PDWORD)0xdeadbeef;
314                     }
315                 }
316                 import_list++;
317                 thunk_list++;
318             }
319         } else {        /* Borland style */
320             TRACE("Borland style imports used\n");
321             thunk_list = get_rva(wm->module, (DWORD)pe_imp->FirstThunk);
322             while (thunk_list->u1.Ordinal) {
323                 if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
324                     /* not sure about this branch, but it seems to work */
325                     int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
326
327                     TRACE("--- Ordinal %s.%d\n",name,ordinal);
328                     thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
329                         wmImp->module, (LPCSTR) ordinal, -1, TRUE
330                     );
331                     if (!thunk_list->u1.Function) {
332                         ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
333                                 name,ordinal, wm->filename);
334                         thunk_list->u1.Function = (PDWORD)0xdeadbeef;
335                     }
336                 } else {
337                     pe_name=get_rva(wm->module, (DWORD)thunk_list->u1.AddressOfData);
338                     TRACE("--- %s %s.%d\n",
339                                   pe_name->Name,name,pe_name->Hint);
340                     thunk_list->u1.Function=(PDWORD)MODULE_GetProcAddress(
341                         wmImp->module, pe_name->Name, pe_name->Hint, TRUE
342                     );
343                     if (!thunk_list->u1.Function) {
344                         ERR("No implementation for %s.%d(%s) imported from %s, setting to 0xdeadbeef\n",
345                                 name, pe_name->Hint, pe_name->Name, wm->filename);
346                         thunk_list->u1.Function = (PDWORD)0xdeadbeef;
347                     }
348                 }
349                 thunk_list++;
350             }
351         }
352     }
353     return 0;
354 }
355
356 /**********************************************************************
357  *                      PE_LoadImage
358  * Load one PE format DLL/EXE into memory
359  *
360  * Unluckily we can't just mmap the sections where we want them, for
361  * (at least) Linux does only support offsets which are page-aligned.
362  *
363  * BUT we have to map the whole image anyway, for Win32 programs sometimes
364  * want to access them. (HMODULE points to the start of it)
365  */
366 HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags )
367 {
368     IMAGE_NT_HEADERS *nt;
369     HMODULE hModule;
370     HANDLE mapping;
371     void *base;
372
373     TRACE_(module)( "loading %s\n", filename );
374
375     mapping = CreateFileMappingA( hFile, NULL, SEC_IMAGE, 0, 0, NULL );
376     if (!mapping) return 0;
377     base = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
378     CloseHandle( mapping );
379     if (!base) return 0;
380
381     /* virus check */
382
383     hModule = (HMODULE)base;
384     nt = RtlImageNtHeader( hModule );
385
386     if (nt->OptionalHeader.AddressOfEntryPoint)
387     {
388         if (!RtlImageRvaToSection( nt, hModule, nt->OptionalHeader.AddressOfEntryPoint ))
389             MESSAGE("VIRUS WARNING: PE module has an invalid entrypoint (0x%08lx) "
390                     "outside all sections (possibly infected by Tchernobyl/SpaceFiller virus)!\n",
391                     nt->OptionalHeader.AddressOfEntryPoint );
392     }
393
394     return hModule;
395 }
396
397 /**********************************************************************
398  *                 PE_CreateModule
399  *
400  * Create WINE_MODREF structure for loaded HMODULE, link it into
401  * process modref_list, and fixup all imports.
402  *
403  * Note: hModule must point to a correctly allocated PE image,
404  *       with base relocations applied; the 16-bit dummy module
405  *       associated to hModule must already exist.
406  *
407  * Note: This routine must always be called in the context of the
408  *       process that is to own the module to be created.
409  *
410  * Note: Assumes that the process critical section is held
411  */
412 WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags,
413                               HANDLE hFile, BOOL builtin )
414 {
415     IMAGE_NT_HEADERS *nt;
416     IMAGE_DATA_DIRECTORY *dir;
417     IMAGE_EXPORT_DIRECTORY *pe_export = NULL;
418     WINE_MODREF *wm;
419     HMODULE16 hModule16;
420
421     /* Retrieve DataDirectory entries */
422
423     nt = RtlImageNtHeader(hModule);
424     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT;
425     if (dir->Size) pe_export = get_rva(hModule, dir->VirtualAddress);
426
427     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXCEPTION;
428     if (dir->Size) FIXME("Exception directory ignored\n" );
429
430     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_SECURITY;
431     if (dir->Size) FIXME("Security directory ignored\n" );
432
433     /* IMAGE_DIRECTORY_ENTRY_BASERELOC handled in PE_LoadImage */
434     /* IMAGE_DIRECTORY_ENTRY_DEBUG handled by debugger */
435
436     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_GLOBALPTR;
437     if (dir->Size) FIXME("Global Pointer (MIPS) ignored\n" );
438
439     /* IMAGE_DIRECTORY_ENTRY_TLS handled in PE_TlsInit */
440
441     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG;
442     if (dir->Size) FIXME("Load Configuration directory ignored\n" );
443
444     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT;
445     if (dir->Size) TRACE("Bound Import directory ignored\n" );
446
447     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IAT;
448     if (dir->Size) TRACE("Import Address Table directory ignored\n" );
449
450     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT;
451     if (dir->Size)
452     {
453         TRACE("Delayed import, stub calls LoadLibrary\n" );
454         /*
455          * Nothing to do here.
456          */
457
458 #ifdef ImgDelayDescr
459         /*
460          * This code is useful to observe what the heck is going on.
461          */
462         {
463             ImgDelayDescr *pe_delay = NULL;
464             pe_delay = get_rva(hModule, dir->VirtualAddress);
465             TRACE_(delayhlp)("pe_delay->grAttrs = %08x\n", pe_delay->grAttrs);
466             TRACE_(delayhlp)("pe_delay->szName = %s\n", pe_delay->szName);
467             TRACE_(delayhlp)("pe_delay->phmod = %08x\n", pe_delay->phmod);
468             TRACE_(delayhlp)("pe_delay->pIAT = %08x\n", pe_delay->pIAT);
469             TRACE_(delayhlp)("pe_delay->pINT = %08x\n", pe_delay->pINT);
470             TRACE_(delayhlp)("pe_delay->pBoundIAT = %08x\n", pe_delay->pBoundIAT);
471             TRACE_(delayhlp)("pe_delay->pUnloadIAT = %08x\n", pe_delay->pUnloadIAT);
472             TRACE_(delayhlp)("pe_delay->dwTimeStamp = %08x\n", pe_delay->dwTimeStamp);
473         }
474 #endif /* ImgDelayDescr */
475     }
476
477     dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR;
478     if (dir->Size) FIXME("Unknown directory 14 ignored\n" );
479
480     dir = nt->OptionalHeader.DataDirectory+15;
481     if (dir->Size) FIXME("Unknown directory 15 ignored\n" );
482
483     /* Create 16-bit dummy module */
484
485     if ((hModule16 = MODULE_CreateDummyModule( filename, hModule )) < 32)
486     {
487         SetLastError( (DWORD)hModule16 );       /* This should give the correct error */
488         return NULL;
489     }
490
491     /* Allocate and fill WINE_MODREF */
492
493     if (!(wm = MODULE_AllocModRef( hModule, filename )))
494     {
495         FreeLibrary16( hModule16 );
496         return NULL;
497     }
498     wm->hDummyMod = hModule16;
499
500     if ( builtin )
501     {
502         NE_MODULE *pModule = (NE_MODULE *)GlobalLock16( hModule16 );
503         pModule->flags |= NE_FFLAGS_BUILTIN;
504         wm->flags |= WINE_MODREF_INTERNAL;
505     }
506     else if ( flags & DONT_RESOLVE_DLL_REFERENCES )
507         wm->flags |= WINE_MODREF_DONT_RESOLVE_REFS;
508
509     wm->find_export = PE_FindExportedFunction;
510
511     /* Dump Exports */
512
513     if (pe_export && TRACE_ON(win32))
514         dump_exports( hModule );
515
516     /* Fixup Imports */
517
518     if (!(wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
519         PE_fixup_imports( wm ))
520     {
521         /* remove entry from modref chain */
522
523         if ( !wm->prev )
524             MODULE_modref_list = wm->next;
525         else
526             wm->prev->next = wm->next;
527
528         if ( wm->next ) wm->next->prev = wm->prev;
529         wm->next = wm->prev = NULL;
530
531         /* FIXME: there are several more dangling references
532          * left. Including dlls loaded by this dll before the
533          * failed one. Unrolling is rather difficult with the
534          * current structure and we can leave them lying
535          * around with no problems, so we don't care.
536          * As these might reference our wm, we don't free it.
537          */
538          return NULL;
539     }
540
541     if (!builtin && pe_export)
542         SNOOP_RegisterDLL( hModule, wm->modname, pe_export->Base, pe_export->NumberOfFunctions );
543
544     /* Send DLL load event */
545     /* we don't need to send a dll event for the main exe */
546
547     if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
548     {
549         if (hFile)
550         {
551             UINT drive_type = GetDriveTypeA( wm->short_filename );
552             /* don't keep the file handle open on removable media */
553             if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM) hFile = 0;
554         }
555         SERVER_START_REQ( load_dll )
556         {
557             req->handle     = hFile;
558             req->base       = (void *)hModule;
559             req->size       = nt->OptionalHeader.SizeOfImage;
560             req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
561             req->dbg_size   = nt->FileHeader.NumberOfSymbols;
562             req->name       = &wm->filename;
563             wine_server_add_data( req, wm->filename, strlen(wm->filename) );
564             wine_server_call( req );
565         }
566         SERVER_END_REQ;
567     }
568
569     return wm;
570 }
571
572 /******************************************************************************
573  * The PE Library Loader frontend.
574  * FIXME: handle the flags.
575  */
576 WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags)
577 {
578         HMODULE         hModule32;
579         WINE_MODREF     *wm;
580         HANDLE          hFile;
581
582         hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
583                              NULL, OPEN_EXISTING, 0, 0 );
584         if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
585
586         /* Load PE module */
587         hModule32 = PE_LoadImage( hFile, name, flags );
588         if (!hModule32)
589         {
590                 CloseHandle( hFile );
591                 return NULL;
592         }
593
594         /* Create 32-bit MODREF */
595         if ( !(wm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) )
596         {
597                 ERR( "can't load %s\n", name );
598                 CloseHandle( hFile );
599                 SetLastError( ERROR_OUTOFMEMORY );
600                 return NULL;
601         }
602
603         CloseHandle( hFile );
604         return wm;
605 }
606
607
608 /* Called if the library is loaded or freed.
609  * NOTE: if a thread attaches a DLL, the current thread will only do
610  * DLL_PROCESS_ATTACH. Only newly created threads do DLL_THREAD_ATTACH
611  * (SDK)
612  */
613 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
614
615 BOOL PE_InitDLL( HMODULE module, DWORD type, LPVOID lpReserved )
616 {
617     BOOL retv = TRUE;
618     IMAGE_NT_HEADERS *nt = RtlImageNtHeader(module);
619
620     /* Is this a library? And has it got an entrypoint? */
621     if (nt && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
622         (nt->OptionalHeader.AddressOfEntryPoint))
623     {
624         DLLENTRYPROC entry = (void*)((char*)module + nt->OptionalHeader.AddressOfEntryPoint);
625         if (TRACE_ON(relay))
626             DPRINTF("%08lx:Call PE DLL (proc=%p,module=%p,type=%ld,res=%p)\n",
627                     GetCurrentThreadId(), entry, module, type, lpReserved );
628         retv = entry( module, type, lpReserved );
629         if (TRACE_ON(relay))
630             DPRINTF("%08lx:Ret  PE DLL (proc=%p,module=%p,type=%ld,res=%p) retval=%x\n",
631                     GetCurrentThreadId(), entry, module, type, lpReserved, retv );
632     }
633
634     return retv;
635 }
636
637 /************************************************************************
638  *      PE_InitTls                      (internal)
639  *
640  * If included, initialises the thread local storages of modules.
641  * Pointers in those structs are not RVAs but real pointers which have been
642  * relocated by do_relocations() already.
643  */
644 static LPVOID
645 _fixup_address(PIMAGE_OPTIONAL_HEADER opt,int delta,LPVOID addr) {
646         if (    ((DWORD)addr>opt->ImageBase) &&
647                 ((DWORD)addr<opt->ImageBase+opt->SizeOfImage)
648         )
649                 /* the address has not been relocated! */
650                 return (LPVOID)(((DWORD)addr)+delta);
651         else
652                 /* the address has been relocated already */
653                 return addr;
654 }
655 void PE_InitTls( void )
656 {
657         WINE_MODREF             *wm;
658         IMAGE_NT_HEADERS        *peh;
659         DWORD                   size,datasize,dirsize;
660         LPVOID                  mem;
661         PIMAGE_TLS_DIRECTORY    pdir;
662         int delta;
663
664         for (wm = MODULE_modref_list;wm;wm=wm->next) {
665                 peh = RtlImageNtHeader(wm->module);
666                 pdir = RtlImageDirectoryEntryToData( wm->module, TRUE,
667                                                      IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
668                 if (!pdir) continue;
669                 delta = (char *)wm->module - (char *)peh->OptionalHeader.ImageBase;
670
671                 if ( wm->tlsindex == -1 ) {
672                         LPDWORD xaddr;
673                         wm->tlsindex = TlsAlloc();
674                         xaddr = _fixup_address(&(peh->OptionalHeader),delta,
675                                         pdir->AddressOfIndex
676                         );
677                         *xaddr=wm->tlsindex;
678                 }
679                 datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
680                 size    = datasize + pdir->SizeOfZeroFill;
681                 mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
682                 memcpy(mem,_fixup_address(&(peh->OptionalHeader),delta,(LPVOID)pdir->StartAddressOfRawData),datasize);
683                 if (pdir->AddressOfCallBacks) {
684                      PIMAGE_TLS_CALLBACK *cbs;
685
686                      cbs = _fixup_address(&(peh->OptionalHeader),delta,pdir->AddressOfCallBacks);
687                      if (*cbs)
688                        FIXME("TLS Callbacks aren't going to be called\n");
689                 }
690
691                 TlsSetValue( wm->tlsindex, mem );
692         }
693 }