Renamed all LPIMAGE_* types to PIMAGE_*.
[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  *
8  *      ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
9  * make that:
10  *      ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
11  */
12 /* Notes:
13  * Before you start changing something in this file be aware of the following:
14  *
15  * - There are several functions called recursively. In a very subtle and 
16  *   obscure way. DLLs can reference each other recursively etc.
17  * - If you want to enhance, speed up or clean up something in here, think
18  *   twice WHY it is implemented in that strange way. There is usually a reason.
19  *   Though sometimes it might just be lazyness ;)
20  * - In PE_MapImage, right before fixup_imports() all external and internal 
21  *   state MUST be correct since this function can be called with the SAME image
22  *   AGAIN. (Thats recursion for you.) That means MODREF.module and
23  *   NE_MODULE.module32.
24  * - No, you (usually) cannot use Linux mmap() to mmap() the images directly.
25  *
26  *   The problem is, that there is not direct 1:1 mapping from a diskimage and
27  *   a memoryimage. The headers at the start are mapped linear, but the sections
28  *   are not. For x86 the sections are 512 byte aligned in file and 4096 byte
29  *   aligned in memory. Linux likes them 4096 byte aligned in memory (due to
30  *   x86 pagesize, this cannot be fixed without a rather large kernel rewrite)
31  *   and 'blocksize' file-aligned (offsets). Since we have 512/1024/2048 (CDROM)
32  *   and other byte blocksizes, we can't do this. However, this could be less
33  *   difficult to support... (See mm/filemap.c).
34  * - All those function map things into a new addresspace. From the wrong
35  *   process and the wrong thread. So calling other API functions will mess 
36  *   things up badly sometimes.
37  */
38
39 #include <errno.h>
40 #include <assert.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/mman.h>
47 #include "windows.h"
48 #include "winbase.h"
49 #include "callback.h"
50 #include "file.h"
51 #include "heap.h"
52 #include "neexe.h"
53 #include "peexe.h"
54 #include "process.h"
55 #include "thread.h"
56 #include "pe_image.h"
57 #include "module.h"
58 #include "global.h"
59 #include "task.h"
60 #include "snoop.h"
61 #include "debug.h"
62
63
64 /* convert PE image VirtualAddress to Real Address */
65 #define RVA(x) ((unsigned int)load_addr+(unsigned int)(x))
66
67 #define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta))
68
69 void dump_exports( HMODULE32 hModule )
70
71   char          *Module;
72   int           i, j;
73   u_short       *ordinal;
74   u_long        *function,*functions;
75   u_char        **name;
76   unsigned int load_addr = hModule;
77
78   DWORD rva_start = PE_HEADER(hModule)->OptionalHeader
79                    .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
80   DWORD rva_end = rva_start + PE_HEADER(hModule)->OptionalHeader
81                    .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
82   IMAGE_EXPORT_DIRECTORY *pe_exports = (IMAGE_EXPORT_DIRECTORY*)RVA(rva_start);
83
84   Module = (char*)RVA(pe_exports->Name);
85   TRACE(win32,"*******EXPORT DATA*******\n");
86   TRACE(win32,"Module name is %s, %ld functions, %ld names\n", 
87                Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames);
88
89   ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals);
90   functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions);
91   name=(u_char**) RVA(pe_exports->AddressOfNames);
92
93   TRACE(win32," Ord    RVA     Addr   Name\n" );
94   for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
95   {
96       if (!*function) continue;  /* No such function */
97       if (TRACE_ON(win32)){
98         dbg_decl_str(win32, 1024);
99
100         dsprintf(win32,"%4ld %08lx %08x",
101                  i + pe_exports->Base, *function, RVA(*function) );
102         /* Check if we have a name for it */
103         for (j = 0; j < pe_exports->NumberOfNames; j++)
104           if (ordinal[j] == i)
105             dsprintf(win32, "  %s", (char*)RVA(name[j]) );
106         if ((*function >= rva_start) && (*function <= rva_end))
107           dsprintf(win32, " (forwarded -> %s)", (char *)RVA(*function));
108         TRACE(win32,"%s\n", dbg_str(win32));
109       }
110   }
111 }
112
113 /* Look up the specified function or ordinal in the exportlist:
114  * If it is a string:
115  *      - look up the name in the Name list. 
116  *      - look up the ordinal with that index.
117  *      - use the ordinal as offset into the functionlist
118  * If it is a ordinal:
119  *      - use ordinal-pe_export->Base as offset into the functionlist
120  */
121 FARPROC32 PE_FindExportedFunction( 
122         PDB32 *process,         /* [in] process context */
123         WINE_MODREF *wm,        /* [in] WINE modreference */
124         LPCSTR funcName,        /* [in] function name */
125         BOOL32 snoop )
126 {
127         u_short                         * ordinal;
128         u_long                          * function;
129         u_char                          ** name, *ename;
130         int                             i;
131         PE_MODREF                       *pem = &(wm->binfmt.pe);
132         IMAGE_EXPORT_DIRECTORY          *exports = pem->pe_export;
133         unsigned int                    load_addr = wm->module;
134         u_long                          rva_start, rva_end, addr;
135         char                            * forward;
136
137         if (HIWORD(funcName))
138                 TRACE(win32,"(%s)\n",funcName);
139         else
140                 TRACE(win32,"(%d)\n",(int)funcName);
141         if (!exports) {
142                 /* Not a fatal problem, some apps do
143                  * GetProcAddress(0,"RegisterPenApp") which triggers this
144                  * case.
145                  */
146                 WARN(win32,"Module %08x(%s)/MODREF %p doesn't have a exports table.\n",wm->module,wm->modname,pem);
147                 return NULL;
148         }
149         ordinal = (u_short*)  RVA(exports->AddressOfNameOrdinals);
150         function= (u_long*)   RVA(exports->AddressOfFunctions);
151         name    = (u_char **) RVA(exports->AddressOfNames);
152         forward = NULL;
153         rva_start = PE_HEADER(wm->module)->OptionalHeader
154                 .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
155         rva_end = rva_start + PE_HEADER(wm->module)->OptionalHeader
156                 .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
157
158         if (HIWORD(funcName)) {
159                 for(i=0; i<exports->NumberOfNames; i++) {
160                         ename=(char*)RVA(*name);
161                         if(!strcmp(ename,funcName))
162                         {
163                             addr = function[*ordinal];
164                             if (!addr) return NULL;
165                             if ((addr < rva_start) || (addr >= rva_end))
166                                 return snoop? SNOOP_GetProcAddress32(wm->module,ename,*ordinal,(FARPROC32)RVA(addr))
167                                             : (FARPROC32)RVA(addr);
168                             forward = (char *)RVA(addr);
169                             break;
170                         }
171                         ordinal++;
172                         name++;
173                 }
174         } else  {
175                 int i;
176                 if (LOWORD(funcName)-exports->Base > exports->NumberOfFunctions) {
177                         TRACE(win32,"   ordinal %d out of range!\n",
178                                       LOWORD(funcName));
179                         return NULL;
180                 }
181                 addr = function[(int)funcName-exports->Base];
182                 if (!addr) return NULL;
183                 ename = "";
184                 if (name) {
185                     for (i=0;i<exports->NumberOfNames;i++) {
186                             ename = (char*)RVA(*name);
187                             if (*ordinal == LOWORD(funcName)-exports->Base)
188                                 break;
189                             ordinal++;
190                             name++;
191                     }
192                     if (i==exports->NumberOfNames)
193                         ename = "";
194                 }
195                 if ((addr < rva_start) || (addr >= rva_end))
196                         return snoop? SNOOP_GetProcAddress32(wm->module,ename,(DWORD)funcName-exports->Base,(FARPROC32)RVA(addr))
197                                     : (FARPROC32)RVA(addr);
198                 forward = (char *)RVA(addr);
199         }
200         if (forward)
201         {
202                 HMODULE32 hMod;
203                 char module[256];
204                 char *end = strchr(forward, '.');
205
206                 if (!end) return NULL;
207                 assert(end-forward<256);
208                 strncpy(module, forward, (end - forward));
209                 module[end-forward] = 0;
210                 hMod = MODULE_FindModule32(process,module);
211                 assert(hMod);
212                 return MODULE_GetProcAddress32( process, hMod, end + 1, snoop );
213         }
214         return NULL;
215 }
216
217 DWORD fixup_imports (PDB32 *process,WINE_MODREF *wm)
218 {
219     IMAGE_IMPORT_DESCRIPTOR     *pe_imp;
220     WINE_MODREF                 *xwm;
221     PE_MODREF                   *pem;
222     unsigned int load_addr      = wm->module;
223     int                         i;
224     char                        *modname;
225     
226     assert(wm->type==MODULE32_PE);
227     pem = &(wm->binfmt.pe);
228     if (pem->pe_export)
229         modname = (char*) RVA(pem->pe_export->Name);
230     else
231         modname = "<unknown>";
232
233     /* OK, now dump the import list */
234     TRACE(win32, "Dumping imports list\n");
235
236     /* first, count the number of imported non-internal modules */
237     pe_imp = pem->pe_import;
238     if (!pe_imp) 
239         ERR(win32, "no import directory????\n");
240
241     /* FIXME: should terminate on 0 Characteristics */
242     for (i = 0; pe_imp->Name; pe_imp++)
243         i++;
244
245     /* Allocate module dependency list */
246     wm->nDeps = i;
247     wm->deps  = HeapAlloc(process->heap, 0, i*sizeof(WINE_MODREF *));
248
249     /* load the imported modules. They are automatically 
250      * added to the modref list of the process.
251      */
252  
253     /* FIXME: should terminate on 0 Characteristics */
254     for (i = 0, pe_imp = pem->pe_import; pe_imp->Name; pe_imp++) {
255         HMODULE32               hImpModule;
256         IMAGE_IMPORT_BY_NAME    *pe_name;
257         PIMAGE_THUNK_DATA       import_list,thunk_list;
258         char                    *name = (char *) RVA(pe_imp->Name);
259
260         /* don't use MODULE_Load, Win32 creates new task differently */
261         hImpModule = MODULE_LoadLibraryEx32A( name, process, 0, 0 );
262         if (!hImpModule) {
263             char *p,buffer[2000];
264             
265             /* GetModuleFileName would use the wrong process, so don't use it */
266             strcpy(buffer,wm->shortname);
267             if (!(p = strrchr (buffer, '\\')))
268                 p = buffer;
269             strcpy (p + 1, name);
270             hImpModule = MODULE_LoadLibraryEx32A( buffer, process, 0, 0 );
271         }
272         if (!hImpModule) {
273             ERR (module, "Module %s not found\n", name);
274             return 1;
275         }
276         xwm = MODULE32_LookupHMODULE(process, hImpModule);
277         assert( xwm );
278         wm->deps[i++] = xwm;
279
280         /* FIXME: forwarder entries ... */
281
282         if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
283             TRACE(win32, "Microsoft style imports used\n");
284             import_list =(PIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk);
285             thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
286
287             while (import_list->u1.Ordinal) {
288                 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
289                     int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
290
291                     TRACE(win32, "--- Ordinal %s,%d\n", name, ordinal);
292                     thunk_list->u1.Function=MODULE_GetProcAddress32(
293                         process, hImpModule, (LPCSTR)ordinal, TRUE
294                     );
295                     if (!thunk_list->u1.Function) {
296                         ERR(win32,"No implementation for %s.%d, setting to 0xdeadbeef\n",
297                                 name, ordinal);
298                         thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
299                     }
300                 } else {                /* import by name */
301                     pe_name = (PIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
302                     TRACE(win32, "--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
303                     thunk_list->u1.Function=MODULE_GetProcAddress32(
304                         process, hImpModule, pe_name->Name, TRUE
305                     );
306                     if (!thunk_list->u1.Function) {
307                         ERR(win32,"No implementation for %s.%d(%s), setting to 0xdeadbeef\n",
308                                 name,pe_name->Hint,pe_name->Name);
309                         thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
310                     }
311                 }
312                 import_list++;
313                 thunk_list++;
314             }
315         } else {        /* Borland style */
316             TRACE(win32, "Borland style imports used\n");
317             thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
318             while (thunk_list->u1.Ordinal) {
319                 if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
320                     /* not sure about this branch, but it seems to work */
321                     int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
322
323                     TRACE(win32,"--- Ordinal %s.%d\n",name,ordinal);
324                     thunk_list->u1.Function=MODULE_GetProcAddress32(
325                         process, hImpModule, (LPCSTR) ordinal, TRUE
326                     );
327                     if (!thunk_list->u1.Function) {
328                         ERR(win32, "No implementation for %s.%d, setting to 0xdeadbeef\n",
329                                 name,ordinal);
330                         thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
331                     }
332                 } else {
333                     pe_name=(PIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData);
334                     TRACE(win32,"--- %s %s.%d\n",
335                                   pe_name->Name,name,pe_name->Hint);
336                     thunk_list->u1.Function=MODULE_GetProcAddress32(
337                         process, hImpModule, pe_name->Name, TRUE
338                     );
339                     if (!thunk_list->u1.Function) {
340                         ERR(win32, "No implementation for %s.%d, setting to 0xdeadbeef\n",
341                                 name, pe_name->Hint);
342                         thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
343                     }
344                 }
345                 thunk_list++;
346             }
347         }
348     }
349     return 0;
350 }
351
352 static int calc_vma_size( HMODULE32 hModule )
353 {
354     int i,vma_size = 0;
355     IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(hModule);
356
357     TRACE(win32, "Dump of segment table\n");
358     TRACE(win32, "   Name    VSz  Vaddr     SzRaw   Fileadr  *Reloc *Lineum #Reloc #Linum Char\n");
359     for (i = 0; i< PE_HEADER(hModule)->FileHeader.NumberOfSections; i++)
360     {
361         TRACE(win32, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n", 
362                       pe_seg->Name, 
363                       pe_seg->Misc.VirtualSize,
364                       pe_seg->VirtualAddress,
365                       pe_seg->SizeOfRawData,
366                       pe_seg->PointerToRawData,
367                       pe_seg->PointerToRelocations,
368                       pe_seg->PointerToLinenumbers,
369                       pe_seg->NumberOfRelocations,
370                       pe_seg->NumberOfLinenumbers,
371                       pe_seg->Characteristics);
372         vma_size = MAX(vma_size, pe_seg->VirtualAddress+pe_seg->SizeOfRawData);
373         pe_seg++;
374     }
375     return vma_size;
376 }
377
378 static void do_relocations(WINE_MODREF *wm)
379 {
380     PE_MODREF   *pem = &(wm->binfmt.pe);
381     int delta = wm->module - PE_HEADER(wm->module)->OptionalHeader.ImageBase;
382     unsigned int load_addr= wm->module;
383
384         IMAGE_BASE_RELOCATION           *r = pem->pe_reloc;
385         int                             hdelta = (delta >> 16) & 0xFFFF;
386         int                             ldelta = delta & 0xFFFF;
387
388         /* int reloc_size = */
389
390         if(delta == 0)
391                 /* Nothing to do */
392                 return;
393         while(r->VirtualAddress)
394         {
395                 char *page = (char*) RVA(r->VirtualAddress);
396                 int count = (r->SizeOfBlock - 8)/2;
397                 int i;
398                 TRACE(fixup, "%x relocations for page %lx\n",
399                         count, r->VirtualAddress);
400                 /* patching in reverse order */
401                 for(i=0;i<count;i++)
402                 {
403                         int offset = r->TypeOffset[i] & 0xFFF;
404                         int type = r->TypeOffset[i] >> 12;
405                         TRACE(fixup,"patching %x type %x\n", offset, type);
406                         switch(type)
407                         {
408                         case IMAGE_REL_BASED_ABSOLUTE: break;
409                         case IMAGE_REL_BASED_HIGH:
410                                 *(short*)(page+offset) += hdelta;
411                                 break;
412                         case IMAGE_REL_BASED_LOW:
413                                 *(short*)(page+offset) += ldelta;
414                                 break;
415                         case IMAGE_REL_BASED_HIGHLOW:
416 #if 1
417                                 *(int*)(page+offset) += delta;
418 #else
419                                 { int h=*(unsigned short*)(page+offset);
420                                   int l=r->TypeOffset[++i];
421                                   *(unsigned int*)(page + offset) = (h<<16) + l + delta;
422                                 }
423 #endif
424                                 break;
425                         case IMAGE_REL_BASED_HIGHADJ:
426                                 WARN(win32, "Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
427                                 break;
428                         case IMAGE_REL_BASED_MIPS_JMPADDR:
429                                 WARN(win32, "Is this a MIPS machine ???\n");
430                                 break;
431                         default:
432                                 WARN(win32, "Unknown fixup type\n");
433                                 break;
434                         }
435                 }
436                 r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
437         }
438 }
439                 
440
441         
442         
443
444 /**********************************************************************
445  *                      PE_LoadImage
446  * Load one PE format DLL/EXE into memory
447  * 
448  * Unluckily we can't just mmap the sections where we want them, for 
449  * (at least) Linux does only support offsets which are page-aligned.
450  *
451  * BUT we have to map the whole image anyway, for Win32 programs sometimes
452  * want to access them. (HMODULE32 point to the start of it)
453  */
454 static HMODULE32 PE_LoadImage( HFILE32 hFile )
455 {
456     HMODULE32   hModule;
457     HANDLE32    mapping;
458     int         i,rawsize = 0;
459     IMAGE_SECTION_HEADER        *pe_sec;
460     BY_HANDLE_FILE_INFORMATION  bhfi;
461
462
463     /* map the PE file somewhere */
464     mapping = CreateFileMapping32A( hFile, NULL, PAGE_READONLY | SEC_COMMIT,
465                                     0, 0, NULL );
466     if (!mapping)
467     {
468         WARN( win32, "CreateFileMapping error %ld\n",
469                  GetLastError() );
470         return 0;
471     }
472     hModule = (HMODULE32)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
473     CloseHandle( mapping );
474     if (!hModule)
475     {
476         WARN( win32, "PE_LoadImage: MapViewOfFile error %ld\n",
477                  GetLastError() );
478         return 0;
479     }
480
481     if (PE_HEADER(hModule)->Signature != IMAGE_NT_SIGNATURE)
482     {
483         WARN(win32,"image doesn't have PE signature, but 0x%08lx\n",
484                 PE_HEADER(hModule)->Signature );
485         goto error;
486     }
487
488     if (PE_HEADER(hModule)->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
489     {
490         MSG("Trying to load PE image for unsupported architecture (");
491         switch (PE_HEADER(hModule)->FileHeader.Machine)
492         {
493         case IMAGE_FILE_MACHINE_UNKNOWN: MSG("Unknown\n"); break;
494         case IMAGE_FILE_MACHINE_I860:    MSG("I860\n"); break;
495         case IMAGE_FILE_MACHINE_R3000:   MSG("R3000\n"); break;
496         case IMAGE_FILE_MACHINE_R4000:   MSG("R4000\n"); break;
497         case IMAGE_FILE_MACHINE_R10000:  MSG("R10000\n"); break;
498         case IMAGE_FILE_MACHINE_ALPHA:   MSG("Alpha\n"); break;
499         case IMAGE_FILE_MACHINE_POWERPC: MSG("PowerPC\n"); break;
500         default: MSG("Unknown-%04x\n",
501                          PE_HEADER(hModule)->FileHeader.Machine); break;
502         }
503         goto error;
504     }
505     /* find out how large this executeable should be */
506     pe_sec = PE_SECTIONS(hModule);
507     for (i=0;i<PE_HEADER(hModule)->FileHeader.NumberOfSections;i++) {
508         if (pe_sec[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
509             continue;
510         if (pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData > rawsize)
511             rawsize = pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData;
512     }
513     if (GetFileInformationByHandle(hFile,&bhfi)) {
514         /* FIXME: 64 bit */
515         if (bhfi.nFileSizeLow < rawsize) {
516             ERR(win32,"PE module is too small (header: %d, filesize: %d), probably truncated download?\n",rawsize,bhfi.nFileSizeLow);
517             goto error;
518         }
519     }
520     /* Else ... Hmm, we have opened it, so we should be able to get info?
521      * Anyway, don't care in this case
522      */
523     return hModule;
524
525 error:
526     UnmapViewOfFile( (LPVOID)hModule );
527     return 0;
528 }
529
530 /**********************************************************************
531  * This maps a loaded PE dll into the address space of the specified process.
532  */
533 static BOOL32 PE_MapImage( PDB32 *process,WINE_MODREF *wm, OFSTRUCT *ofs, DWORD flags )
534 {
535         PE_MODREF               *pem;
536         int                     i, result;
537         DWORD                   load_addr;
538         IMAGE_DATA_DIRECTORY    dir;
539         char                    *modname;
540         int                     vma_size;
541         HMODULE32               hModule = wm->module;
542
543         IMAGE_SECTION_HEADER *pe_seg;
544         IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER *)hModule;
545         IMAGE_NT_HEADERS *nt_header = PE_HEADER(hModule);
546         
547         pem     = &(wm->binfmt.pe);
548
549         result = GetLongPathName32A(ofs->szPathName,NULL,0);
550         wm->longname = (char*)HeapAlloc(process->heap,0,result+1);
551         GetLongPathName32A(ofs->szPathName,wm->longname,result+1);
552
553         wm->shortname = HEAP_strdupA(process->heap,0,ofs->szPathName);
554
555         if (!(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
556         {
557                 if (process->exe_modref)
558                         FIXME(win32,"overwriting old exe_modref... arrgh\n");
559                 process->exe_modref = wm;
560         }
561
562         load_addr = nt_header->OptionalHeader.ImageBase;
563         vma_size = calc_vma_size( hModule );
564         TRACE(win32, "Load addr is %lx\n",load_addr);
565         load_addr = (DWORD)VirtualAlloc( (void*)load_addr, vma_size,
566                                          MEM_RESERVE | MEM_COMMIT,
567                                          PAGE_EXECUTE_READWRITE );
568         if (load_addr == 0) {
569                 load_addr = (DWORD)VirtualAlloc( NULL, vma_size,
570                                                  MEM_RESERVE | MEM_COMMIT,
571                                                  PAGE_EXECUTE_READWRITE );
572         }
573         /* NOTE: this changes a value in the process modref chain, which can
574          * be accessed independently from this function
575          */
576         wm->module = (HMODULE32)load_addr;
577
578         TRACE(win32, "Load addr is really %lx, range %x\n",
579                       load_addr, vma_size);
580
581         TRACE(segment, "Loading %s at %lx, range %x\n",
582               ofs->szPathName, load_addr, vma_size );
583         
584         /* Store the NT header at the load addr
585          * (FIXME: should really use mmap)
586          */
587         *(IMAGE_DOS_HEADER *)load_addr = *dos_header;
588         *(IMAGE_NT_HEADERS *)(load_addr + dos_header->e_lfanew) = *nt_header;
589         memcpy(PE_SECTIONS(load_addr),PE_SECTIONS(hModule),sizeof(IMAGE_SECTION_HEADER)*nt_header->FileHeader.NumberOfSections);
590
591         pe_seg = PE_SECTIONS(hModule);
592         for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++, pe_seg++)
593         {
594                 /* memcpy only non-BSS segments */
595                 /* FIXME: this should be done by mmap(..MAP_PRIVATE|MAP_FIXED..)
596                  * but it is not possible for (at least) Linux needs
597                  * a page-aligned offset.
598                  */
599                 if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
600                     memcpy((char*)RVA(pe_seg->VirtualAddress),
601                         (char*)(hModule + pe_seg->PointerToRawData),
602                         pe_seg->SizeOfRawData
603                     );
604
605                 result = RVA (pe_seg->VirtualAddress);
606 #if 1
607                 /* not needed, memory is zero */
608                 if(strcmp(pe_seg->Name, ".bss") == 0)
609                     memset((void *)result, 0, 
610                            pe_seg->Misc.VirtualSize ?
611                            pe_seg->Misc.VirtualSize :
612                            pe_seg->SizeOfRawData);
613 #endif
614
615                 if(strcmp(pe_seg->Name, ".idata") == 0)
616                         pem->pe_import = (PIMAGE_IMPORT_DESCRIPTOR) result;
617
618                 if(strcmp(pe_seg->Name, ".edata") == 0)
619                         pem->pe_export = (PIMAGE_EXPORT_DIRECTORY) result;
620
621                 if(strcmp(pe_seg->Name, ".rsrc") == 0)
622                         pem->pe_resource = (PIMAGE_RESOURCE_DIRECTORY) result;
623
624                 if(strcmp(pe_seg->Name, ".reloc") == 0)
625                         pem->pe_reloc = (PIMAGE_BASE_RELOCATION) result;
626         }
627
628         /* There is word that the actual loader does not care about the
629            section names, and only goes for the DataDirectory */
630         dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
631         if(dir.Size)
632         {
633                 if(pem->pe_export && (int)pem->pe_export!=RVA(dir.VirtualAddress))
634                         WARN(win32,"wrong export directory??\n");
635                 /* always trust the directory */
636                 pem->pe_export = (PIMAGE_EXPORT_DIRECTORY) RVA(dir.VirtualAddress);
637         }
638
639         dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
640         if(dir.Size)
641         {
642                 /* 
643                 if(pem->pe_import && (int)pem->pe_import!=RVA(dir.VirtualAddress))
644                         WARN(win32,"wrong import directory??\n");
645                  */
646                 pem->pe_import = (PIMAGE_IMPORT_DESCRIPTOR) RVA(dir.VirtualAddress);
647         }
648
649         dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
650         if(dir.Size)
651         {
652                 if(pem->pe_resource && (int)pem->pe_resource!=RVA(dir.VirtualAddress))
653                         WARN(win32,"wrong resource directory??\n");
654                 pem->pe_resource = (PIMAGE_RESOURCE_DIRECTORY) RVA(dir.VirtualAddress);
655         }
656
657         if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size)
658                 FIXME(win32,"Exception directory ignored\n");
659
660         if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
661                 FIXME(win32,"Security directory ignored\n");
662
663
664
665         dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
666         if(dir.Size)
667         {
668                 if(pem->pe_reloc && (int)pem->pe_reloc!= RVA(dir.VirtualAddress))
669                         WARN(win32,"wrong relocation list??\n");
670                 pem->pe_reloc = (void *) RVA(dir.VirtualAddress);
671         }
672
673         if(nt_header->OptionalHeader.DataDirectory
674                 [IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size)
675                 FIXME(win32,"Copyright string ignored\n");
676
677         if(nt_header->OptionalHeader.DataDirectory
678                 [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size)
679                 FIXME(win32,"Global Pointer (MIPS) ignored\n");
680
681         if(nt_header->OptionalHeader.DataDirectory
682                 [IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size)
683                 FIXME(win32,"Load Configuration directory ignored\n");
684
685         if(nt_header->OptionalHeader.DataDirectory
686                 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size)
687                 TRACE(win32,"Bound Import directory ignored\n");
688
689         if(nt_header->OptionalHeader.DataDirectory
690                 [IMAGE_DIRECTORY_ENTRY_IAT].Size)
691                 TRACE(win32,"Import Address Table directory ignored\n");
692         if(nt_header->OptionalHeader.DataDirectory[13].Size)
693                 FIXME(win32,"Unknown directory 13 ignored\n");
694         if(nt_header->OptionalHeader.DataDirectory[14].Size)
695                 FIXME(win32,"Unknown directory 14 ignored\n");
696         if(nt_header->OptionalHeader.DataDirectory[15].Size)
697                 FIXME(win32,"Unknown directory 15 ignored\n");
698
699         if(pem->pe_reloc)       do_relocations(wm);
700         if(pem->pe_export) {
701                 dump_exports(wm->module);
702
703                 wm->modname = HEAP_strdupA(process->heap,0,(char*)RVA(pem->pe_export->Name));
704         } else {
705                 /* try to find out the name from the OFSTRUCT */
706                 char *s;
707                 modname = s = ofs->szPathName;
708                 while ((s=strchr(modname,'\\')))
709                         modname = s+1;
710                 wm->modname = HEAP_strdupA(process->heap,0,modname);
711         }
712         if(pem->pe_import)      {
713                 if (fixup_imports(process,wm)) {
714                         WINE_MODREF     **xwm;
715
716                         /* remove entry from modref chain */
717                         xwm = &(process->modref_list);
718                         while (*xwm) {
719                                 if (*xwm==wm) {
720                                         *xwm = wm->next;
721                                         break;
722                                 }
723                                 xwm = &((*xwm)->next);
724                         }
725                         /* FIXME: there are several more dangling references
726                          * left. Including dlls loaded by this dll before the
727                          * failed one. Unrolling is rather difficult with the
728                          * current structure and we can leave it them lying
729                          * around with no problems, so we don't care
730                          */
731                         return 0;
732                 }
733         }
734                 
735         /* Now that we got everything at the right address,
736          * we can unmap the previous module */
737         UnmapViewOfFile( (LPVOID)hModule );
738         return 1;
739 }
740
741 /******************************************************************************
742  * The PE Library Loader frontend. 
743  * FIXME: handle the flags.
744  *        internal module handling should be made better here (and in builtin.c)
745  */
746 HMODULE32 PE_LoadLibraryEx32A (LPCSTR name, PDB32 *process,
747                                HFILE32 hFile, DWORD flags)
748 {
749         OFSTRUCT        ofs;
750         HMODULE32       hModule;
751         NE_MODULE       *pModule;
752         WINE_MODREF     *wm;
753
754         if ((hModule = MODULE_FindModule32( process, name ))) {
755                 for (wm= process->modref_list;wm;wm=wm->next)
756                         if (wm->module == hModule)
757                                 return hModule;
758                 /* Since MODULE_FindModule32 uses the modref chain too, the
759                  * module MUST have been found above. If not, something has gone
760                  * terribly wrong.
761                  */
762                 assert(0);
763         }
764         /* try to load builtin, enabled modules first */
765         if ((hModule = BUILTIN32_LoadModule( name, FALSE, process )))
766             return hModule;
767
768         /* try to load the specified dll/exe */
769         if (HFILE_ERROR32==(hFile=OpenFile32(name,&ofs,OF_READ))) {
770                 /* Now try the built-in even if disabled */
771                 if ((hModule = BUILTIN32_LoadModule( name, TRUE, process ))) {
772                     WARN( module, "Could not load external DLL '%s', using built-in module.\n", name );
773                     return hModule;
774                 }
775                 return 0;
776         }
777         /* will go away ... */
778         if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) {
779                 _lclose32(hFile);
780                 return hModule;
781         }
782         pModule         = (NE_MODULE *)GlobalLock16( hModule );
783         pModule->flags  = NE_FFLAGS_WIN32;
784         /* .. */
785
786         wm=(WINE_MODREF*)HeapAlloc(process->heap,HEAP_ZERO_MEMORY,sizeof(*wm));
787         wm->type = MODULE32_PE;
788         /* NOTE: fixup_imports takes care of the correct order */
789         wm->next = process->modref_list;
790         process->modref_list = wm;
791
792         wm->module = pModule->module32 = PE_LoadImage( hFile );
793
794         CloseHandle( hFile );
795         if (wm->module < 32) 
796         {
797             process->modref_list = wm->next;
798             FreeLibrary16( hModule);
799             HeapFree(process->heap,0,wm);
800             ERR(win32,"can't load %s\n",ofs.szPathName);
801             return 0;
802         }
803
804         /* (possible) recursion */
805         if (!PE_MapImage(process,wm,&ofs,flags)) {
806             /* ERROR cleanup ... */
807             WINE_MODREF **xwm;
808
809             ERR(win32,"couldn't load %s\n",ofs.szPathName);
810             /* unlink from process modref chain */
811             for (    xwm=&(process->modref_list);
812                      *xwm && (*xwm!=wm);
813                      xwm=&((*xwm)->next)
814             ) /* EMPTY */;
815             if (*xwm)
816                 *xwm=(*xwm)->next;
817                 
818             return 0;
819         }
820         pModule->module32 = wm->module;
821         if (wm->binfmt.pe.pe_export)
822                 SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
823         return wm->module;
824 }
825
826 /*****************************************************************************
827  * Load the PE main .EXE. All other loading is done by PE_LoadLibraryEx32A
828  * FIXME: this function should use PE_LoadLibraryEx32A, but currently can't
829  * due to the PROCESS_Create stuff.
830  */
831 HINSTANCE16 PE_CreateProcess( LPCSTR name, LPCSTR cmd_line,
832                               LPCSTR env, LPSTARTUPINFO32A startup,
833                               LPPROCESS_INFORMATION info )
834 {
835     HMODULE16 hModule16;
836     HMODULE32 hModule32;
837     HINSTANCE16 hInstance;
838     NE_MODULE *pModule;
839     HFILE32 hFile;
840     OFSTRUCT ofs;
841     PDB32 *process;
842     TDB *pTask;
843     WINE_MODREF *wm;
844
845     if ((hFile = OpenFile32( name, &ofs, OF_READ )) == HFILE_ERROR32)
846         return 2;  /* File not found */
847
848     if ((hModule16 = MODULE_CreateDummyModule( &ofs )) < 32) return hModule16;
849     pModule = (NE_MODULE *)GlobalLock16( hModule16 );
850     pModule->flags = NE_FFLAGS_WIN32;
851
852     pModule->module32 = hModule32 = PE_LoadImage( hFile );
853     if (hModule32 < 32) return 21;
854
855     if (PE_HEADER(hModule32)->FileHeader.Characteristics & IMAGE_FILE_DLL)
856         return 11;
857
858     hInstance = NE_CreateInstance( pModule, NULL, FALSE );
859     process = PROCESS_Create( pModule, cmd_line, env,
860                               hInstance, 0, startup, info );
861     pTask = (TDB *)GlobalLock16( process->task );
862
863     wm=(WINE_MODREF*)HeapAlloc(process->heap,HEAP_ZERO_MEMORY,sizeof(*wm));
864     wm->type = MODULE32_PE;
865     /* NOTE: fixup_imports takes care of the correct order */
866     wm->next = process->modref_list;
867     wm->module = hModule32;
868     process->modref_list = wm;
869     if (!PE_MapImage( process, wm, &ofs, 0 ))
870     {
871         /* FIXME: should destroy the task created and free referenced stuff */
872         return 0;
873     }
874     pModule->module32 = wm->module;
875
876     /* FIXME: Yuck. Is there no other good place to do that? */
877     PE_InitTls( pTask->thdb );
878
879     return hInstance;
880 }
881
882 /*********************************************************************
883  * PE_UnloadImage [internal]
884  */
885 int PE_UnloadImage( HMODULE32 hModule )
886 {
887         FIXME(win32,"stub.\n");
888         /* free resources, image, unmap */
889         return 1;
890 }
891
892 /* Called if the library is loaded or freed.
893  * NOTE: if a thread attaches a DLL, the current thread will only do
894  * DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH
895  * (SDK)
896  */
897 void PE_InitDLL(WINE_MODREF *wm, DWORD type, LPVOID lpReserved)
898 {
899     if (wm->type!=MODULE32_PE)
900         return;
901     if (wm->binfmt.pe.flags & PE_MODREF_NO_DLL_CALLS)
902         return;
903     if (type==DLL_PROCESS_ATTACH)
904     {
905         if (wm->binfmt.pe.flags & PE_MODREF_PROCESS_ATTACHED)
906             return;
907
908         wm->binfmt.pe.flags |= PE_MODREF_PROCESS_ATTACHED;
909     }
910
911     /*  DLL_ATTACH_PROCESS:
912      *          lpreserved is NULL for dynamic loads, not-NULL for static loads
913      *  DLL_DETACH_PROCESS:
914      *          lpreserved is NULL if called by FreeLibrary, not-NULL otherwise
915      *  the SDK doesn't mention anything for DLL_THREAD_*
916      */
917         
918     /* Is this a library? And has it got an entrypoint? */
919     if ((PE_HEADER(wm->module)->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
920         (PE_HEADER(wm->module)->OptionalHeader.AddressOfEntryPoint)
921     ) {
922         DLLENTRYPROC32 entry = (void*)RVA_PTR( wm->module,OptionalHeader.AddressOfEntryPoint );
923         TRACE(relay, "CallTo32(entryproc=%p,module=%08x,type=%ld,res=%p)\n",
924                        entry, wm->module, type, lpReserved );
925
926         entry( wm->module, type, lpReserved );
927     }
928 }
929
930 void PE_InitTls(THDB *thdb)
931 {
932         WINE_MODREF             *wm;
933         PE_MODREF               *pem;
934         IMAGE_NT_HEADERS        *peh;
935         DWORD                   size,datasize;
936         LPVOID                  mem;
937         PIMAGE_TLS_DIRECTORY    pdir;
938         PDB32                   *pdb = thdb->process;
939         int delta;
940         
941         for (wm = pdb->modref_list;wm;wm=wm->next) {
942                 if (wm->type!=MODULE32_PE)
943                         continue;
944                 pem = &(wm->binfmt.pe);
945                 peh = PE_HEADER(wm->module);
946                 delta = wm->module - peh->OptionalHeader.ImageBase;
947                 if (!peh->OptionalHeader.DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress)
948                         continue;
949                 pdir = (LPVOID)(wm->module + peh->OptionalHeader.
950                         DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress);
951                 
952                 
953                 if (!(pem->flags & PE_MODREF_TLS_ALLOCED)) {
954                         pem->tlsindex = THREAD_TlsAlloc(thdb);
955                         *(LPDWORD)AdjustPtr(pdir->AddressOfIndex,delta)
956                           =pem->tlsindex;   
957                 }
958                 pem->flags |= PE_MODREF_TLS_ALLOCED;
959                 datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
960                 size    = datasize + pdir->SizeOfZeroFill;
961                 mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
962                 memcpy(mem,
963                        AdjustPtr(pdir->StartAddressOfRawData,delta), 
964                        datasize);
965
966                 /* don't use TlsSetValue, we are in the wrong thread */
967                 if (pdir->AddressOfCallBacks) {
968                      PIMAGE_TLS_CALLBACK *cbs = 
969                        (PIMAGE_TLS_CALLBACK *)
970                        AdjustPtr(pdir->AddressOfCallBacks, delta);
971
972                      if (*cbs) {
973                        FIXME(win32, "TLS Callbacks aren't going to be called\n");
974                      }
975                 }
976                 thdb->tls_array[pem->tlsindex] = mem;
977         }
978 }
979
980 /****************************************************************************
981  *              DisableThreadLibraryCalls (KERNEL32.74)
982  * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
983  */
984 BOOL32 WINAPI DisableThreadLibraryCalls(HMODULE32 hModule)
985 {
986         WINE_MODREF     *wm;
987
988         for (wm=PROCESS_Current()->modref_list;wm;wm=wm->next)
989                 if ((wm->module == hModule) && (wm->type==MODULE32_PE))
990                         wm->binfmt.pe.flags|=PE_MODREF_NO_DLL_CALLS;
991         return TRUE;
992 }