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