Release 970305
[wine] / loader / pe_image.c
1 #ifndef WINELIB
2 /* 
3  *  Copyright   1994    Eric Youndale & Erik Bos
4  *  Copyright   1995    Martin von Löwis
5  *  Copyright   1996    Marcus Meissner
6  *
7  *      based on Eric Youndale's pe-test and:
8  *
9  *      ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
10  * make that:
11  *      ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
12  */
13
14 #include <ctype.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include "windows.h"
21 #include "winbase.h"
22 #include "callback.h"
23 #include "neexe.h"
24 #include "peexe.h"
25 #include "pe_image.h"
26 #include "module.h"
27 #include "global.h"
28 #include "task.h"
29 #include "ldt.h"
30 #include "stddebug.h"
31 #include "debug.h"
32 #include "debugger.h"
33 #include "xmalloc.h"
34
35 /* convert PE image VirtualAddress to Real Address */
36 #define RVA(x) ((unsigned int)load_addr+(unsigned int)(x))
37
38 void dump_exports(IMAGE_EXPORT_DIRECTORY * pe_exports, unsigned int load_addr)
39
40   char          *Module,*s;
41   int           i;
42   u_short       *ordinal;
43   u_long        *function,*functions;
44   u_char        **name,*ename;
45   char          buffer[1000];
46   DBG_ADDR      daddr;
47
48   daddr.seg = 0;
49   daddr.type = NULL;
50   Module = (char*)RVA(pe_exports->Name);
51   dprintf_win32(stddeb,"\n*******EXPORT DATA*******\nModule name is %s, %ld functions, %ld names\n", 
52          Module,
53          pe_exports->NumberOfFunctions,
54          pe_exports->NumberOfNames);
55
56   ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals);
57   functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions);
58   name=(u_char**) RVA(pe_exports->AddressOfNames);
59
60   dprintf_win32(stddeb,"%-32s Ordinal Virt Addr\n", "Function Name");
61   for (i=0;i<pe_exports->NumberOfFunctions;i++) {
62       if (i<pe_exports->NumberOfNames) {
63           ename=(char*)RVA(*name++);
64           dprintf_win32(stddeb,"%-32s %4d    %8.8lx (%8.8lx)\n",ename,*ordinal,functions[*ordinal],*function);
65           sprintf(buffer,"%s_%s",Module,ename);
66           daddr.off=RVA(functions[*ordinal]);
67           ordinal++;
68           function++;
69       } else {
70           /* ordinals/names no longer valid, but we still got functions */
71           dprintf_win32(stddeb,"%-32s %4s    %8s %8.8lx\n","","","",*function);
72           sprintf(buffer,"%s_%d",Module,i);
73           daddr.off=RVA(*functions);
74           function++;
75       }
76       while ((s=strchr(buffer,'.'))) *s='_';
77       DEBUG_AddSymbol(buffer,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
78   }
79 }
80
81 /* Look up the specified function or ordinal in the exportlist:
82  * If it is a string:
83  *      - look up the name in the Name list. 
84  *      - look up the ordinal with that index.
85  *      - use the ordinal as offset into the functionlist
86  * If it is a ordinal:
87  *      - use ordinal-pe_export->Base as offset into the functionlist
88  */
89 FARPROC32 PE_FindExportedFunction(struct pe_data *pe, LPCSTR funcName)
90 {
91         IMAGE_EXPORT_DIRECTORY * exports = pe->pe_export;
92         unsigned load_addr = pe->load_addr;
93         u_short * ordinal;
94         u_long * function;
95         u_char ** name, *ename;
96         int i;
97
98         if (HIWORD(funcName))
99                 dprintf_win32(stddeb,"PE_FindExportedFunction(%s)\n",funcName);
100         else
101                 dprintf_win32(stddeb,"PE_FindExportedFunction(%d)\n",(int)funcName);
102         if (!exports)
103                 return NULL;
104         ordinal=(u_short*) RVA(exports->AddressOfNameOrdinals);
105         function=(u_long*) RVA(exports->AddressOfFunctions);
106         name=(u_char **) RVA(exports->AddressOfNames);
107         if (HIWORD(funcName)) {
108                 for(i=0; i<exports->NumberOfNames; i++) {
109                         ename=(char*) RVA(*name);
110                         if(!strcmp(ename,funcName))
111                                 return (FARPROC32) RVA(function[*ordinal]);
112                         ordinal++;
113                         name++;
114                 }
115         } else {
116                 if (LOWORD(funcName)-exports->Base > exports->NumberOfFunctions) {
117                         dprintf_win32(stddeb,"  ordinal %d out of range!\n",
118                                       LOWORD(funcName));
119                         return NULL;
120                 }
121                 return (FARPROC32) RVA(function[(int)funcName-exports->Base]);
122         }
123         return NULL;
124 }
125
126 void 
127 fixup_imports (struct pe_data *pe, HMODULE16 hModule)
128 {
129     IMAGE_IMPORT_DESCRIPTOR *pe_imp;
130     int fixup_failed = 0;
131     unsigned int load_addr = pe->load_addr;
132     int i;
133     NE_MODULE *ne_mod;
134     HMODULE16 *mod_ptr;
135     char *modname;
136     
137     if (pe->pe_export)
138         modname = (char*) RVA(pe->pe_export->Name);
139     else
140         modname = "<unknown>";
141
142     /* OK, now dump the import list */
143     dprintf_win32 (stddeb, "\nDumping imports list\n");
144
145     /* first, count the number of imported non-internal modules */
146     pe_imp = pe->pe_import;
147
148     /* FIXME: should terminate on 0 Characteristics */
149     for (i = 0; pe_imp->Name; pe_imp++)
150         i++;
151
152     /* Now, allocate memory for dlls_to_init */
153     ne_mod = GlobalLock16 (hModule);
154     ne_mod->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT, (i+1)*sizeof(HMODULE16),
155                                         hModule, FALSE, FALSE, FALSE);
156     mod_ptr = GlobalLock16 (ne_mod->dlls_to_init);
157     /* load the modules and put their handles into the list */
158  
159      /* FIXME: should terminate on 0 Characteristics */
160      for (i = 0, pe_imp = pe->pe_import; pe_imp->Name; pe_imp++) {
161         char *name = (char *) RVA(pe_imp->Name);
162         mod_ptr[i] = MODULE_Load( name, (LPVOID)-1, FALSE );
163         if (mod_ptr[i] <= (HMODULE16) 32) {
164             char *p, buffer[256];
165
166             /* Try with prepending the path of the current module */
167             GetModuleFileName16 (hModule, buffer, sizeof (buffer));
168             if (!(p = strrchr (buffer, '\\')))
169                 p = buffer;
170             strcpy (p + 1, name);
171             mod_ptr[i] = MODULE_Load( buffer, (LPVOID)-1, FALSE );
172         }
173         if (mod_ptr[i] <= (HMODULE16) 32) {
174             fprintf (stderr, "Module %s not found\n", name);
175             exit (0);
176         }
177         i++;
178     }
179     pe_imp = pe->pe_import;
180     while (pe_imp->Name) {
181         char                    *Module;
182         IMAGE_IMPORT_BY_NAME    *pe_name;
183         LPIMAGE_THUNK_DATA      import_list,thunk_list;
184         int                     ordimportwarned;
185
186         ordimportwarned = 0;
187         Module = (char *) RVA(pe_imp->Name);
188         dprintf_win32 (stddeb, "%s\n", Module);
189
190         if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
191             dprintf_win32 (stddeb, "Microsoft style imports used\n");
192             import_list =(LPIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk);
193             thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
194
195             while (import_list->u1.Ordinal) {
196                 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
197                     int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
198
199                     if(!lstrncmpi32A(Module,"kernel32",8) && !ordimportwarned){
200                        fprintf(stderr,"%s imports kernel32.dll by ordinal. May crash.\n",modname);
201                        ordimportwarned = 1;
202                     }
203                     dprintf_win32 (stddeb, "--- Ordinal %s,%d\n", Module, ordinal);
204                     thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),(LPCSTR)ordinal);
205                     if (!thunk_list->u1.Function) {
206                         fprintf(stderr,"No implementation for %s.%d, setting to NULL\n",
207                                 Module, ordinal);
208                         /* fixup_failed=1; */
209                     }
210                 } else {                /* import by name */
211                     pe_name = (LPIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
212                     dprintf_win32 (stddeb, "--- %s %s.%d\n", pe_name->Name, Module, pe_name->Hint);
213                     thunk_list->u1.Function=(LPDWORD)GetProcAddress32(
214                                                 MODULE_FindModule (Module),
215                                                 pe_name->Name);
216                     if (!thunk_list->u1.Function) {
217                         fprintf(stderr,"No implementation for %s.%d(%s), setting to NULL\n",
218                                 Module,pe_name->Hint,pe_name->Name);
219                         /* fixup_failed=1; */
220                     }
221                 }
222                 import_list++;
223                 thunk_list++;
224             }
225         } else {        /* Borland style */
226             dprintf_win32 (stddeb, "Borland style imports used\n");
227             thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
228             while (thunk_list->u1.Ordinal) {
229                 if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
230                     /* not sure about this branch, but it seems to work */
231                     int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
232
233
234                     if (!lstrncmpi32A(Module,"kernel32",8) && 
235                         !ordimportwarned
236                     ) {
237                        fprintf(stderr,"%s imports kernel32.dll by ordinal. May crash.\n",modname);
238                        ordimportwarned = 1;
239                     }
240                     dprintf_win32(stddeb,"--- Ordinal %s.%d\n",Module,ordinal);
241                     thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),
242                                                      (LPCSTR) ordinal);
243                     if (!thunk_list->u1.Function) {
244                         fprintf(stderr, "No implementation for %s.%d, setting to NULL\n",
245                                 Module,ordinal);
246                         /* fixup_failed=1; */
247                     }
248                 } else {
249                     pe_name=(LPIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData);
250                     dprintf_win32(stddeb,"--- %s %s.%d\n",
251                                   pe_name->Name,Module,pe_name->Hint);
252                     thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),pe_name->Name);
253                     if (!thunk_list->u1.Function) {
254                         fprintf(stderr, "No implementation for %s.%d, setting to NULL\n",
255                                 Module, pe_name->Hint);
256                         /* fixup_failed=1; */
257                     }
258                 }
259                 thunk_list++;
260             }
261         }
262         pe_imp++;
263     }
264     if (fixup_failed) exit(1);
265 }
266
267 static void calc_vma_size(struct pe_data *pe)
268 {
269   int i;
270
271   dprintf_win32(stddeb, "Dump of segment table\n");
272   dprintf_win32(stddeb, "   Name    VSz  Vaddr     SzRaw   Fileadr  *Reloc *Lineum #Reloc #Linum Char\n");
273   for(i=0; i< pe->pe_header->FileHeader.NumberOfSections; i++)
274     {
275       dprintf_win32(stddeb, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n", 
276              pe->pe_seg[i].Name, 
277              pe->pe_seg[i].Misc.VirtualSize,
278              pe->pe_seg[i].VirtualAddress,
279              pe->pe_seg[i].SizeOfRawData,
280              pe->pe_seg[i].PointerToRawData,
281              pe->pe_seg[i].PointerToRelocations,
282              pe->pe_seg[i].PointerToLinenumbers,
283              pe->pe_seg[i].NumberOfRelocations,
284              pe->pe_seg[i].NumberOfLinenumbers,
285              pe->pe_seg[i].Characteristics);
286           pe->vma_size = MAX(pe->vma_size,
287                         pe->pe_seg[i].VirtualAddress + 
288                         pe->pe_seg[i].SizeOfRawData);
289     }
290 }
291
292 static void do_relocations(struct pe_data *pe)
293 {
294         int delta = pe->load_addr - pe->base_addr;
295         unsigned int load_addr = pe->load_addr;
296         IMAGE_BASE_RELOCATION   *r = pe->pe_reloc;
297         int hdelta = (delta >> 16) & 0xFFFF;
298         int ldelta = delta & 0xFFFF;
299
300         /* int reloc_size = */
301
302         if(delta == 0)
303                 /* Nothing to do */
304                 return;
305         while(r->VirtualAddress)
306         {
307                 char *page = (char*) RVA(r->VirtualAddress);
308                 int count = (r->SizeOfBlock - 8)/2;
309                 int i;
310                 dprintf_fixup(stddeb, "%x relocations for page %lx\n",
311                         count, r->VirtualAddress);
312                 /* patching in reverse order */
313                 for(i=0;i<count;i++)
314                 {
315                         int offset = r->TypeOffset[i] & 0xFFF;
316                         int type = r->TypeOffset[i] >> 12;
317                         dprintf_fixup(stddeb,"patching %x type %x\n", offset, type);
318                         switch(type)
319                         {
320                         case IMAGE_REL_BASED_ABSOLUTE: break;
321                         case IMAGE_REL_BASED_HIGH:
322                                 *(short*)(page+offset) += hdelta;
323                                 break;
324                         case IMAGE_REL_BASED_LOW:
325                                 *(short*)(page+offset) += ldelta;
326                                 break;
327                         case IMAGE_REL_BASED_HIGHLOW:
328 #if 1
329                                 *(int*)(page+offset) += delta;
330 #else
331                                 { int h=*(unsigned short*)(page+offset);
332                                   int l=r->TypeOffset[++i];
333                                   *(unsigned int*)(page + offset) = (h<<16) + l + delta;
334                                 }
335 #endif
336                                 break;
337                         case IMAGE_REL_BASED_HIGHADJ:
338                                 fprintf(stderr, "Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
339                                 break;
340                         case IMAGE_REL_BASED_MIPS_JMPADDR:
341                                 fprintf(stderr, "Is this a MIPS machine ???\n");
342                                 break;
343                         default:
344                                 fprintf(stderr, "Unknown fixup type\n");
345                                 break;
346                         }
347                 }
348                 r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
349         }
350 }
351                 
352
353         
354         
355
356 /**********************************************************************
357  *                      PE_LoadImage
358  * Load one PE format executable into memory
359  */
360 static struct pe_data *PE_LoadImage( int fd, HMODULE16 hModule, WORD offset )
361 {
362         struct pe_data          *pe;
363         int                     i, result;
364         int                     load_addr;
365         IMAGE_DATA_DIRECTORY    dir;
366         char                    buffer[200];
367         DBG_ADDR                daddr;
368
369         daddr.seg=0;
370         daddr.type = NULL;
371         pe = xmalloc(sizeof(struct pe_data));
372         memset(pe,0,sizeof(struct pe_data));
373         pe->pe_header = xmalloc(sizeof(IMAGE_NT_HEADERS));
374
375         /* read PE header */
376         lseek( fd, offset, SEEK_SET);
377         read( fd, pe->pe_header, sizeof(IMAGE_NT_HEADERS));
378
379 /* FIXME: this is a *horrible* hack to make COMDLG32.DLL load OK. The
380 problem needs to be fixed properly at some stage */
381
382         if (pe->pe_header->OptionalHeader.NumberOfRvaAndSizes != 16) {
383                 printf("Short PE Header!!!\n");
384                 lseek( fd, -(16 - pe->pe_header->OptionalHeader.NumberOfRvaAndSizes) * sizeof(IMAGE_DATA_DIRECTORY), SEEK_CUR);
385         }
386
387 /* horrible hack ends !!! */
388         /* read sections */
389         pe->pe_seg = xmalloc(sizeof(IMAGE_SECTION_HEADER) * 
390                                    pe->pe_header->FileHeader.NumberOfSections);
391         read( fd, pe->pe_seg, sizeof(IMAGE_SECTION_HEADER) * 
392                         pe->pe_header->FileHeader.NumberOfSections);
393
394         load_addr = pe->pe_header->OptionalHeader.ImageBase;
395         pe->base_addr=load_addr;
396         pe->vma_size=0;
397         dprintf_win32(stddeb, "Load addr is %x\n",load_addr);
398         calc_vma_size(pe);
399
400 #if 0
401         /* We use malloc here, while a huge part of that address space does
402            not be supported by actual memory. It has to be contiguous, though.
403            I don't know if mmap("/dev/null"); would do any better.
404            What I'd really like to do is a Win32 style VirtualAlloc/MapViewOfFile
405            sequence */
406         load_addr = pe->load_addr = (int)xmalloc(pe->vma_size);
407         memset( load_addr, 0, pe->vma_size);
408 #else
409         load_addr = (int) VirtualAlloc( NULL, pe->vma_size, MEM_COMMIT,
410                                          PAGE_EXECUTE_READWRITE );
411         pe->load_addr = load_addr;
412 #endif
413
414         dprintf_win32(stddeb, "Load addr is really %x, range %x\n",
415                 pe->load_addr, pe->vma_size);
416         
417
418         for(i=0; i < pe->pe_header->FileHeader.NumberOfSections; i++)
419         {
420                 /* load only non-BSS segments */
421                 if(pe->pe_seg[i].Characteristics & 
422                         ~ IMAGE_SCN_CNT_UNINITIALIZED_DATA)
423                 if(lseek(fd,pe->pe_seg[i].PointerToRawData,SEEK_SET) == -1
424                 || read(fd,(char*)RVA(pe->pe_seg[i].VirtualAddress),
425                            pe->pe_seg[i].SizeOfRawData) != pe->pe_seg[i].SizeOfRawData)
426                 {
427                         fprintf(stderr,"Failed to load section %x\n", i);
428                         exit(0);
429                 }
430                 result = RVA (pe->pe_seg[i].VirtualAddress);
431 #if 1
432                 /* not needed, memory is zero */
433                 if(strcmp(pe->pe_seg[i].Name, ".bss") == 0)
434                     memset((void *)result, 0, 
435                            pe->pe_seg[i].Misc.VirtualSize ?
436                            pe->pe_seg[i].Misc.VirtualSize :
437                            pe->pe_seg[i].SizeOfRawData);
438 #endif
439
440                 if(strcmp(pe->pe_seg[i].Name, ".idata") == 0)
441                         pe->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) result;
442
443                 if(strcmp(pe->pe_seg[i].Name, ".edata") == 0)
444                         pe->pe_export = (LPIMAGE_EXPORT_DIRECTORY) result;
445
446                 if(strcmp(pe->pe_seg[i].Name, ".rsrc") == 0)
447                         pe->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) result;
448
449                 if(strcmp(pe->pe_seg[i].Name, ".reloc") == 0)
450                         pe->pe_reloc = (LPIMAGE_BASE_RELOCATION) result;
451
452         }
453
454         /* There is word that the actual loader does not care about the
455            section names, and only goes for the DataDirectory */
456         dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
457         if(dir.Size)
458         {
459                 if(pe->pe_export && (int)pe->pe_export!=RVA(dir.VirtualAddress))
460                         fprintf(stderr,"wrong export directory??\n");
461                 /* always trust the directory */
462                 pe->pe_export = (LPIMAGE_EXPORT_DIRECTORY) RVA(dir.VirtualAddress);
463         }
464
465         dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
466         if(dir.Size)
467         {
468                 if(pe->pe_import && (int)pe->pe_import!=RVA(dir.VirtualAddress))
469                         fprintf(stderr,"wrong import directory??\n");
470                 pe->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) RVA(dir.VirtualAddress);
471         }
472
473         dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
474         if(dir.Size)
475         {
476                 if(pe->pe_resource && (int)pe->pe_resource!=RVA(dir.VirtualAddress))
477                         fprintf(stderr,"wrong resource directory??\n");
478                 pe->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) RVA(dir.VirtualAddress);
479         }
480
481         if(pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size)
482                 dprintf_win32(stdnimp,"Exception directory ignored\n");
483
484         if(pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
485                 dprintf_win32(stdnimp,"Security directory ignored\n");
486
487
488
489         dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
490         if(dir.Size)
491         {
492                 if(pe->pe_reloc && (int)pe->pe_reloc!= RVA(dir.VirtualAddress))
493                         fprintf(stderr,"wrong relocation list??\n");
494                 pe->pe_reloc = (void *) RVA(dir.VirtualAddress);
495         }
496
497         if(pe->pe_header->OptionalHeader.DataDirectory
498                 [IMAGE_DIRECTORY_ENTRY_DEBUG].Size)
499           {
500             DEBUG_RegisterDebugInfo(fd, pe, load_addr, 
501                         pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
502                         pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
503           }
504
505         if(pe->pe_header->OptionalHeader.DataDirectory
506                 [IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size)
507                 dprintf_win32(stdnimp,"Copyright string ignored\n");
508
509         if(pe->pe_header->OptionalHeader.DataDirectory
510                 [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size)
511                 dprintf_win32(stdnimp,"Global Pointer (MIPS) ignored\n");
512
513 #ifdef NOT      /* we initialize this later */
514         if(pe->pe_header->OptionalHeader.DataDirectory
515                 [IMAGE_DIRECTORY_ENTRY_TLS].Size)
516                  dprintf_win32(stdnimp,"Thread local storage ignored\n");
517 #endif
518
519         if(pe->pe_header->OptionalHeader.DataDirectory
520                 [IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size)
521                 dprintf_win32(stdnimp,"Load Configuration directory ignored\n");
522
523         if(pe->pe_header->OptionalHeader.DataDirectory
524                 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size)
525                 dprintf_win32(stdnimp,"Bound Import directory ignored\n");
526
527         if(pe->pe_header->OptionalHeader.DataDirectory
528                 [IMAGE_DIRECTORY_ENTRY_IAT].Size)
529                 dprintf_win32(stdnimp,"Import Address Table directory ignored\n");
530         if(pe->pe_header->OptionalHeader.DataDirectory[13].Size)
531                 dprintf_win32(stdnimp,"Unknown directory 13 ignored\n");
532         if(pe->pe_header->OptionalHeader.DataDirectory[14].Size)
533                 dprintf_win32(stdnimp,"Unknown directory 14 ignored\n");
534         if(pe->pe_header->OptionalHeader.DataDirectory[15].Size)
535                 dprintf_win32(stdnimp,"Unknown directory 15 ignored\n");
536
537         if(pe->pe_reloc) do_relocations(pe);
538         if(pe->pe_import) fixup_imports(pe, hModule);
539         if(pe->pe_export) dump_exports(pe->pe_export,load_addr);
540                 
541         if (pe->pe_export) {
542                 char    *s;
543
544                 /* add start of sections as debugsymbols */
545                 for(i=0;i<pe->pe_header->FileHeader.NumberOfSections;i++) {
546                         sprintf(buffer,"%s_%s",
547                                 (char*)RVA(pe->pe_export->Name),
548                                 pe->pe_seg[i].Name
549                         );
550                         daddr.off= RVA(pe->pe_seg[i].VirtualAddress);
551                         while ((s=strchr(buffer,'.'))) *s='_';
552                         DEBUG_AddSymbol(buffer,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
553                 }
554                 /* add entry point */
555                 sprintf(buffer,"%s_EntryPoint",(char*)RVA(pe->pe_export->Name));
556                 daddr.off=RVA(pe->pe_header->OptionalHeader.AddressOfEntryPoint);
557                 while ((s=strchr(buffer,'.'))) *s='_';
558                 DEBUG_AddSymbol(buffer,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
559                 /* add start of DLL */
560                 daddr.off=load_addr;
561                 DEBUG_AddSymbol((char*) RVA(pe->pe_export->Name),&daddr,
562                                 NULL, SYM_WIN32 | SYM_FUNC);
563         }
564         return pe;
565 }
566
567 HINSTANCE16 MODULE_CreateInstance(HMODULE16 hModule,LOADPARAMS *params);
568
569 HINSTANCE16 PE_LoadModule( int fd, OFSTRUCT *ofs, LOADPARAMS* params )
570 {
571     HMODULE16 hModule;
572     HINSTANCE16 hInstance;
573     NE_MODULE *pModule;
574     struct mz_header_s mz_header;
575
576     if ((hModule = MODULE_CreateDummyModule( ofs )) < 32) return hModule;
577     pModule = (NE_MODULE *)GlobalLock16( hModule );
578     pModule->flags = NE_FFLAGS_WIN32;
579
580     lseek( fd, 0, SEEK_SET );
581     read( fd, &mz_header, sizeof(mz_header) );
582
583     pModule->pe_module = PE_LoadImage( fd, hModule, mz_header.ne_offset );
584
585     hInstance = MODULE_CreateInstance( hModule, params );
586
587     if (!(pModule->pe_module->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
588     {
589         TASK_CreateTask( hModule, hInstance, 0,
590                          params->hEnvironment,
591                          (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
592                          *((WORD*)PTR_SEG_TO_LIN(params->showCmd) + 1) );
593     }
594     return hInstance;
595 }
596
597 int PE_UnloadImage( HMODULE16 hModule )
598 {
599         printf("PEunloadImage() called!\n");
600         /* free resources, image, unmap */
601         return 1;
602 }
603
604 static void PE_InitDLL(HMODULE16 hModule)
605 {
606     NE_MODULE *pModule;
607     PE_MODULE *pe;
608     unsigned int load_addr;
609
610     hModule = GetExePtr(hModule);
611     if (!(pModule = MODULE_GetPtr(hModule))) return;
612     if (!(pModule->flags & NE_FFLAGS_WIN32) || !(pe = pModule->pe_module))
613         return;
614
615     /* FIXME: What is the correct value for parameter 3? 
616      *        (the MSDN library JAN96 says 'reserved for future use')
617      */
618         
619     /* Is this a library? And has it got an entrypoint? */
620     if (        (pe->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
621                 (pe->pe_header->OptionalHeader.AddressOfEntryPoint)
622     ) {
623         load_addr = pe->load_addr;
624         printf("InitPEDLL() called!\n");
625         CallDLLEntryProc32( 
626             (FARPROC32)RVA(pe->pe_header->OptionalHeader.AddressOfEntryPoint),
627             hModule,
628             DLL_PROCESS_ATTACH,
629             -1
630         );
631     }
632 }
633
634 void PE_InitializeDLLs(HMODULE16 hModule)
635 {
636         NE_MODULE *pModule;
637         HMODULE16 *pDLL;
638         pModule = MODULE_GetPtr( GetExePtr(hModule) );
639         if (pModule->dlls_to_init)
640         {
641                 HGLOBAL16 to_init = pModule->dlls_to_init;
642                 pModule->dlls_to_init = 0;
643                 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
644                 {
645                         PE_InitializeDLLs( *pDLL );
646                         PE_InitDLL( *pDLL );
647                 }
648                 GlobalFree16( to_init );
649         }
650         PE_InitDLL( hModule );
651 }
652
653 void PE_InitTls( PE_MODULE *module )
654 {
655    /* FIXME: tls callbacks ??? */
656    DWORD  index;
657    DWORD  datasize;
658    DWORD  size;
659    LPVOID mem;
660    LPIMAGE_TLS_DIRECTORY pdir;
661
662     if (!module->pe_header->OptionalHeader.DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress)
663         return;
664
665     pdir = (LPVOID)(module->load_addr + module->pe_header->OptionalHeader.
666                DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress);
667     index = TlsAlloc();
668     datasize = pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
669     size     = datasize + pdir->SizeOfZeroFill;
670         
671     mem = VirtualAlloc(0,size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
672     
673     memcpy(mem,(LPVOID) pdir->StartAddressOfRawData, datasize);
674     TlsSetValue(index,mem);
675     *(pdir->AddressOfIndex)=index;   
676 }
677
678 #endif /* WINELIB */