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