Release 971012
[wine/multimedia.git] / loader / pe_image.c
blobf53575b25727bcbd827fff3b5e99e8a7ec5ba045
1 /*
2 * Copyright 1994 Eric Youndale & Erik Bos
3 * Copyright 1995 Martin von Löwis
4 * Copyright 1996 Marcus Meissner
6 * based on Eric Youndale's pe-test and:
8 * ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
9 * make that:
10 * ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
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 "neexe.h"
26 #include "peexe.h"
27 #include "process.h"
28 #include "pe_image.h"
29 #include "module.h"
30 #include "global.h"
31 #include "task.h"
32 #include "ldt.h"
33 #include "options.h"
34 #include "stddebug.h"
35 #include "debug.h"
36 #include "xmalloc.h"
37 #ifndef WINELIB
38 #include "debugger.h"
39 #endif
41 static void PE_InitDLL(PE_MODREF* modref, DWORD type, LPVOID lpReserved);
43 /* convert PE image VirtualAddress to Real Address */
44 #define RVA(x) ((unsigned int)load_addr+(unsigned int)(x))
46 void dump_exports(IMAGE_EXPORT_DIRECTORY * pe_exports, unsigned int load_addr)
48 #ifndef WINELIB
49 char *Module;
50 int i;
51 u_short *ordinal;
52 u_long *function,*functions;
53 u_char **name,*ename;
54 char buffer[1000];
55 DBG_ADDR daddr;
57 daddr.seg = 0;
58 daddr.type = NULL;
59 Module = (char*)RVA(pe_exports->Name);
60 dprintf_win32(stddeb,"\n*******EXPORT DATA*******\nModule name is %s, %ld functions, %ld names\n",
61 Module,
62 pe_exports->NumberOfFunctions,
63 pe_exports->NumberOfNames);
65 ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals);
66 functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions);
67 name=(u_char**) RVA(pe_exports->AddressOfNames);
69 dprintf_win32(stddeb,"%-32s Ordinal Virt Addr\n", "Function Name");
70 for (i=0;i<pe_exports->NumberOfFunctions;i++) {
71 if (i<pe_exports->NumberOfNames) {
72 ename=(char*)RVA(*name++);
73 dprintf_win32(stddeb,"%-32s %4d %8.8lx (%8.8lx)\n",ename,*ordinal,functions[*ordinal],*function);
74 sprintf(buffer,"%s_%s",Module,ename);
75 daddr.off=RVA(functions[*ordinal]);
76 ordinal++;
77 function++;
78 } else {
79 /* ordinals/names no longer valid, but we still got functions */
80 dprintf_win32(stddeb,"%-32s %4s %8s %8.8lx\n","","","",*function);
81 sprintf(buffer,"%s_%d",Module,i);
82 daddr.off=RVA(*functions);
83 function++;
85 DEBUG_AddSymbol(buffer,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
87 #endif
90 /* Look up the specified function or ordinal in the exportlist:
91 * If it is a string:
92 * - look up the name in the Name list.
93 * - look up the ordinal with that index.
94 * - use the ordinal as offset into the functionlist
95 * If it is a ordinal:
96 * - use ordinal-pe_export->Base as offset into the functionlist
98 FARPROC32 PE_FindExportedFunction(struct pe_data *pe, LPCSTR funcName)
100 IMAGE_EXPORT_DIRECTORY *exports;
101 unsigned load_addr;
102 u_short * ordinal;
103 u_long * function;
104 u_char ** name, *ename;
105 int i;
106 PDB32 *process=(PDB32*)GetCurrentProcessId();
107 PE_MODREF *pem;
109 pem = process->modref_list;
110 while (pem && (pem->pe_module != pe))
111 pem=pem->next;
112 if (!pem) {
113 fprintf(stderr,"No MODREF found for PE_MODULE %p in process %p\n",pe,process);
114 return NULL;
116 load_addr = pem->load_addr;
117 exports = pem->pe_export;
119 if (HIWORD(funcName))
120 dprintf_win32(stddeb,"PE_FindExportedFunction(%s)\n",funcName);
121 else
122 dprintf_win32(stddeb,"PE_FindExportedFunction(%d)\n",(int)funcName);
123 if (!exports) {
124 fprintf(stderr,"Module %p/MODREF %p doesn't have a exports table.\n",pe,pem);
125 return NULL;
127 ordinal = (u_short*) RVA(exports->AddressOfNameOrdinals);
128 function= (u_long*) RVA(exports->AddressOfFunctions);
129 name = (u_char **) RVA(exports->AddressOfNames);
131 if (HIWORD(funcName)) {
132 for(i=0; i<exports->NumberOfNames; i++) {
133 ename=(char*)RVA(*name);
134 if(!strcmp(ename,funcName))
135 return (FARPROC32) RVA(function[*ordinal]);
136 ordinal++;
137 name++;
139 } else {
140 if (LOWORD(funcName)-exports->Base > exports->NumberOfFunctions) {
141 dprintf_win32(stddeb," ordinal %d out of range!\n",
142 LOWORD(funcName));
143 return NULL;
145 return (FARPROC32) RVA(function[(int)funcName-exports->Base]);
147 return NULL;
150 void
151 fixup_imports (PDB32 *process,PE_MODREF *pem)
153 PE_MODULE *pe = pem->pe_module;
154 IMAGE_IMPORT_DESCRIPTOR *pe_imp;
155 int fixup_failed = 0;
156 unsigned int load_addr = pem->load_addr;
157 int i;
158 char *modname;
160 if (pem->pe_export)
161 modname = (char*) RVA(pem->pe_export->Name);
162 else
163 modname = "<unknown>";
165 /* OK, now dump the import list */
166 dprintf_win32 (stddeb, "\nDumping imports list\n");
168 /* first, count the number of imported non-internal modules */
169 pe_imp = pem->pe_import;
170 if (!pe_imp)
171 fprintf(stderr,"no import directory????\n");
173 /* FIXME: should terminate on 0 Characteristics */
174 for (i = 0; pe_imp->Name; pe_imp++)
175 i++;
177 /* load the imported modules. They are automatically
178 * added to the modref list of the process.
181 /* FIXME: should terminate on 0 Characteristics */
182 for (i = 0, pe_imp = pem->pe_import; pe_imp->Name; pe_imp++) {
183 HMODULE32 res;
184 PE_MODREF *xpem,**ypem;
187 char *name = (char *) RVA(pe_imp->Name);
189 /* don't use MODULE_Load, Win32 creates new task differently */
190 res = PE_LoadLibraryEx32A( name, 0, 0 );
191 if (res <= (HMODULE32) 32) {
192 char *p, buffer[256];
194 /* Try with prepending the path of the current module */
195 GetModuleFileName32A (pe->mappeddll, buffer, sizeof (buffer));
196 if (!(p = strrchr (buffer, '\\')))
197 p = buffer;
198 strcpy (p + 1, name);
199 res = PE_LoadLibraryEx32A( buffer, 0, 0 );
201 if (res <= (HMODULE32) 32) {
202 fprintf (stderr, "Module %s not found\n", name);
203 exit (0);
205 res = MODULE_HANDLEtoHMODULE32(res);
206 xpem = pem->next;
207 while (xpem) {
208 if (xpem->pe_module->mappeddll == res)
209 break;
210 xpem = xpem->next;
212 if (xpem) {
213 /* it has been loaded *BEFORE* us, so we have to init
214 * it before us. we just swap the two modules which should
215 * work.
217 /* unlink xpem from chain */
218 ypem = &(process->modref_list);
219 while (*ypem) {
220 if ((*ypem)==xpem)
221 break;
222 ypem = &((*ypem)->next);
224 *ypem = xpem->next;
226 /* link it directly before pem */
227 ypem = &(process->modref_list);
228 while (*ypem) {
229 if ((*ypem)==pem)
230 break;
231 ypem = &((*ypem)->next);
233 *ypem = xpem;
234 xpem->next = pem;
237 i++;
239 pe_imp = pem->pe_import;
240 while (pe_imp->Name) {
241 char *Module;
242 IMAGE_IMPORT_BY_NAME *pe_name;
243 LPIMAGE_THUNK_DATA import_list,thunk_list;
244 int ordimportwarned;
246 ordimportwarned = 0;
247 Module = (char *) RVA(pe_imp->Name);
248 dprintf_win32 (stddeb, "%s\n", Module);
250 /* FIXME: forwarder entries ... */
252 if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
253 dprintf_win32 (stddeb, "Microsoft style imports used\n");
254 import_list =(LPIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk);
255 thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
257 while (import_list->u1.Ordinal) {
258 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
259 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
261 if(!lstrncmpi32A(Module,"kernel32",8) && !ordimportwarned){
262 fprintf(stderr,"%s imports kernel32.dll by ordinal. May crash.\n",modname);
263 ordimportwarned = 1;
265 dprintf_win32 (stddeb, "--- Ordinal %s,%d\n", Module, ordinal);
266 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),(LPCSTR)ordinal);
267 if (!thunk_list->u1.Function) {
268 fprintf(stderr,"No implementation for %s.%d, setting to NULL\n",
269 Module, ordinal);
270 /* fixup_failed=1; */
272 } else { /* import by name */
273 pe_name = (LPIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
274 dprintf_win32 (stddeb, "--- %s %s.%d\n", pe_name->Name, Module, pe_name->Hint);
275 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(
276 MODULE_FindModule (Module),
277 pe_name->Name);
278 if (!thunk_list->u1.Function) {
279 fprintf(stderr,"No implementation for %s.%d(%s), setting to NULL\n",
280 Module,pe_name->Hint,pe_name->Name);
281 /* fixup_failed=1; */
284 import_list++;
285 thunk_list++;
287 } else { /* Borland style */
288 dprintf_win32 (stddeb, "Borland style imports used\n");
289 thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
290 while (thunk_list->u1.Ordinal) {
291 if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
292 /* not sure about this branch, but it seems to work */
293 int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
296 if (!lstrncmpi32A(Module,"kernel32",8) &&
297 !ordimportwarned
299 fprintf(stderr,"%s imports kernel32.dll by ordinal. May crash.\n",modname);
300 ordimportwarned = 1;
302 dprintf_win32(stddeb,"--- Ordinal %s.%d\n",Module,ordinal);
303 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),
304 (LPCSTR) ordinal);
305 if (!thunk_list->u1.Function) {
306 fprintf(stderr, "No implementation for %s.%d, setting to NULL\n",
307 Module,ordinal);
308 /* fixup_failed=1; */
310 } else {
311 pe_name=(LPIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData);
312 dprintf_win32(stddeb,"--- %s %s.%d\n",
313 pe_name->Name,Module,pe_name->Hint);
314 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),pe_name->Name);
315 if (!thunk_list->u1.Function) {
316 fprintf(stderr, "No implementation for %s.%d, setting to NULL\n",
317 Module, pe_name->Hint);
318 /* fixup_failed=1; */
321 thunk_list++;
324 pe_imp++;
326 if (fixup_failed) exit(1);
329 static int calc_vma_size(struct pe_data *pe)
331 int i,vma_size = 0;
333 dprintf_win32(stddeb, "Dump of segment table\n");
334 dprintf_win32(stddeb, " Name VSz Vaddr SzRaw Fileadr *Reloc *Lineum #Reloc #Linum Char\n");
335 for(i=0; i< pe->pe_header->FileHeader.NumberOfSections; i++)
337 dprintf_win32(stddeb, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n",
338 pe->pe_seg[i].Name,
339 pe->pe_seg[i].Misc.VirtualSize,
340 pe->pe_seg[i].VirtualAddress,
341 pe->pe_seg[i].SizeOfRawData,
342 pe->pe_seg[i].PointerToRawData,
343 pe->pe_seg[i].PointerToRelocations,
344 pe->pe_seg[i].PointerToLinenumbers,
345 pe->pe_seg[i].NumberOfRelocations,
346 pe->pe_seg[i].NumberOfLinenumbers,
347 pe->pe_seg[i].Characteristics);
348 vma_size = MAX(vma_size,
349 pe->pe_seg[i].VirtualAddress +
350 pe->pe_seg[i].SizeOfRawData);
352 return vma_size;
355 static void do_relocations(PE_MODREF *pem)
357 int delta = pem->load_addr - pem->pe_module->pe_header->OptionalHeader.ImageBase;
359 unsigned int load_addr= pem->load_addr;
360 IMAGE_BASE_RELOCATION *r = pem->pe_reloc;
361 int hdelta = (delta >> 16) & 0xFFFF;
362 int ldelta = delta & 0xFFFF;
364 /* int reloc_size = */
366 if(delta == 0)
367 /* Nothing to do */
368 return;
369 while(r->VirtualAddress)
371 char *page = (char*) RVA(r->VirtualAddress);
372 int count = (r->SizeOfBlock - 8)/2;
373 int i;
374 dprintf_fixup(stddeb, "%x relocations for page %lx\n",
375 count, r->VirtualAddress);
376 /* patching in reverse order */
377 for(i=0;i<count;i++)
379 int offset = r->TypeOffset[i] & 0xFFF;
380 int type = r->TypeOffset[i] >> 12;
381 dprintf_fixup(stddeb,"patching %x type %x\n", offset, type);
382 switch(type)
384 case IMAGE_REL_BASED_ABSOLUTE: break;
385 case IMAGE_REL_BASED_HIGH:
386 *(short*)(page+offset) += hdelta;
387 break;
388 case IMAGE_REL_BASED_LOW:
389 *(short*)(page+offset) += ldelta;
390 break;
391 case IMAGE_REL_BASED_HIGHLOW:
392 #if 1
393 *(int*)(page+offset) += delta;
394 #else
395 { int h=*(unsigned short*)(page+offset);
396 int l=r->TypeOffset[++i];
397 *(unsigned int*)(page + offset) = (h<<16) + l + delta;
399 #endif
400 break;
401 case IMAGE_REL_BASED_HIGHADJ:
402 fprintf(stderr, "Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
403 break;
404 case IMAGE_REL_BASED_MIPS_JMPADDR:
405 fprintf(stderr, "Is this a MIPS machine ???\n");
406 break;
407 default:
408 fprintf(stderr, "Unknown fixup type\n");
409 break;
412 r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
420 /**********************************************************************
421 * PE_LoadImage
422 * Load one PE format DLL/EXE into memory
424 * Unluckily we can't just mmap the sections where we want them, for
425 * (at least) Linux does only support offset with are multiples of the
426 * underlying filesystemblocksize, but PE DLLs usually have alignments of 512
427 * byte. This fails for instance when you try to map from CDROM (bsize 2048).
429 * BUT we have to map the whole image anyway, for Win32 programs sometimes
430 * want to access them. (HMODULE32 point to the start of it)
432 static PE_MODULE *PE_LoadImage( int fd )
434 struct pe_data *pe;
435 struct stat stbuf;
437 if (-1==fstat(fd,&stbuf)) {
438 perror("PE_LoadImage:fstat");
439 return NULL;
441 pe = xmalloc(sizeof(struct pe_data));
442 memset(pe,0,sizeof(struct pe_data));
444 /* map the PE image somewhere */
445 pe->mappeddll = (HMODULE32)mmap(NULL,stbuf.st_size,PROT_READ,MAP_SHARED,fd,0);
446 if (!pe->mappeddll || pe->mappeddll==-1) {
447 if (errno==ENOEXEC) {
448 int res=0,curread = 0;
450 lseek(fd,0,SEEK_SET);
451 /* linux: some filesystems don't support mmap (samba,
452 * ntfs apparently) so we have to read the image the
453 * hard way
455 pe->mappeddll = xmalloc(stbuf.st_size);
456 while (curread < stbuf.st_size) {
457 res = read(fd,pe->mappeddll+curread,stbuf.st_size-curread);
458 if (res<=0)
459 break;
460 curread+=res;
462 if (res == -1) {
463 perror("PE_LoadImage:mmap compat read");
464 free(pe->mappeddll);
465 free(pe);
466 return NULL;
469 } else {
470 perror("PE_LoadImage:mmap");
471 free(pe);
472 return NULL;
475 /* link PE header */
476 pe->pe_header = (IMAGE_NT_HEADERS*)(pe->mappeddll+(((IMAGE_DOS_HEADER*)pe->mappeddll)->e_lfanew));
477 if (pe->pe_header->Signature!=IMAGE_NT_SIGNATURE) {
478 fprintf(stderr,"image doesn't have PE signature, but 0x%08lx\n",
479 pe->pe_header->Signature
481 free(pe);
482 return NULL;
485 if (pe->pe_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
486 fprintf(stderr,"trying to load PE image for unsupported architecture (");
487 switch (pe->pe_header->FileHeader.Machine) {
488 case IMAGE_FILE_MACHINE_UNKNOWN:
489 fprintf(stderr,"Unknown");break;
490 case IMAGE_FILE_MACHINE_I860:
491 fprintf(stderr,"I860");break;
492 case IMAGE_FILE_MACHINE_R3000:
493 fprintf(stderr,"R3000");break;
494 case IMAGE_FILE_MACHINE_R4000:
495 fprintf(stderr,"R4000");break;
496 case IMAGE_FILE_MACHINE_R10000:
497 fprintf(stderr,"R10000");break;
498 case IMAGE_FILE_MACHINE_ALPHA:
499 fprintf(stderr,"Alpha");break;
500 case IMAGE_FILE_MACHINE_POWERPC:
501 fprintf(stderr,"PowerPC");break;
502 default:
503 fprintf(stderr,"Unknown-%04x",pe->pe_header->FileHeader.Machine);break;
505 fprintf(stderr,")\n");
506 return NULL;
508 pe->pe_seg = (IMAGE_SECTION_HEADER*)(((LPBYTE)(pe->pe_header+1))-
509 (16 - pe->pe_header->OptionalHeader.NumberOfRvaAndSizes) * sizeof(IMAGE_DATA_DIRECTORY));
511 /* FIXME: the (16-...) is a *horrible* hack to make COMDLG32.DLL load OK. The
512 * problem needs to be fixed properly at some stage.
514 return pe;
517 /**********************************************************************
518 * This maps a loaded PE dll into the address space of the specified process.
520 void
521 PE_MapImage(PE_MODULE *pe,PDB32 *process, OFSTRUCT *ofs, DWORD flags) {
522 PE_MODREF *pem;
523 int i, result;
524 int load_addr;
525 IMAGE_DATA_DIRECTORY dir;
526 char buffer[200];
527 char *modname;
528 int vma_size;
530 pem = (PE_MODREF*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*pem));
531 /* NOTE: fixup_imports takes care of the correct order */
532 pem->next = process->modref_list;
533 process->modref_list = pem;
535 pem->pe_module = pe;
536 if (!(pe->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
537 if (process->exe_modref)
538 fprintf(stderr,"overwriting old exe_modref... arrgh\n");
539 process->exe_modref = pem;
542 load_addr = pe->pe_header->OptionalHeader.ImageBase;
543 dprintf_win32(stddeb, "Load addr is %x\n",load_addr);
544 vma_size = calc_vma_size(pe);
545 load_addr = (int) VirtualAlloc( (void*)load_addr, vma_size, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
546 pem->load_addr = load_addr;
548 dprintf_win32(stddeb, "Load addr is really %lx, range %x\n",
549 pem->load_addr, vma_size);
552 for(i=0; i < pe->pe_header->FileHeader.NumberOfSections; i++)
554 /* memcpy only non-BSS segments */
555 /* FIXME: this should be done by mmap(..MAP_PRIVATE|MAP_FIXED..)
556 * but it is not possible for (at least) Linux needs an offset
557 * aligned to a block on the filesystem.
559 if(!(pe->pe_seg[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
560 memcpy((char*)RVA(pe->pe_seg[i].VirtualAddress),
561 (char*)(pe->mappeddll+pe->pe_seg[i].PointerToRawData),
562 pe->pe_seg[i].SizeOfRawData
565 result = RVA (pe->pe_seg[i].VirtualAddress);
566 #if 1
567 /* not needed, memory is zero */
568 if(strcmp(pe->pe_seg[i].Name, ".bss") == 0)
569 memset((void *)result, 0,
570 pe->pe_seg[i].Misc.VirtualSize ?
571 pe->pe_seg[i].Misc.VirtualSize :
572 pe->pe_seg[i].SizeOfRawData);
573 #endif
575 if(strcmp(pe->pe_seg[i].Name, ".idata") == 0)
576 pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) result;
578 if(strcmp(pe->pe_seg[i].Name, ".edata") == 0)
579 pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) result;
581 if(strcmp(pe->pe_seg[i].Name, ".rsrc") == 0)
582 pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) result;
584 if(strcmp(pe->pe_seg[i].Name, ".reloc") == 0)
585 pem->pe_reloc = (LPIMAGE_BASE_RELOCATION) result;
588 /* There is word that the actual loader does not care about the
589 section names, and only goes for the DataDirectory */
590 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
591 if(dir.Size)
593 if(pem->pe_export && (int)pem->pe_export!=RVA(dir.VirtualAddress))
594 fprintf(stderr,"wrong export directory??\n");
595 /* always trust the directory */
596 pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) RVA(dir.VirtualAddress);
599 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
600 if(dir.Size)
602 if(pem->pe_import && (int)pem->pe_import!=RVA(dir.VirtualAddress))
603 fprintf(stderr,"wrong import directory??\n");
604 pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) RVA(dir.VirtualAddress);
607 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
608 if(dir.Size)
610 if(pem->pe_resource && (int)pem->pe_resource!=RVA(dir.VirtualAddress))
611 fprintf(stderr,"wrong resource directory??\n");
612 pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) RVA(dir.VirtualAddress);
615 if(pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size)
616 dprintf_win32(stdnimp,"Exception directory ignored\n");
618 if(pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
619 dprintf_win32(stdnimp,"Security directory ignored\n");
623 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
624 if(dir.Size)
626 if(pem->pe_reloc && (int)pem->pe_reloc!= RVA(dir.VirtualAddress))
627 fprintf(stderr,"wrong relocation list??\n");
628 pem->pe_reloc = (void *) RVA(dir.VirtualAddress);
631 #ifndef WINELIB
632 if(pe->pe_header->OptionalHeader.DataDirectory
633 [IMAGE_DIRECTORY_ENTRY_DEBUG].Size)
635 DEBUG_RegisterDebugInfo(pe, load_addr,
636 pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
637 pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
639 #endif
641 if(pe->pe_header->OptionalHeader.DataDirectory
642 [IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size)
643 dprintf_win32(stdnimp,"Copyright string ignored\n");
645 if(pe->pe_header->OptionalHeader.DataDirectory
646 [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size)
647 dprintf_win32(stdnimp,"Global Pointer (MIPS) ignored\n");
649 if(pe->pe_header->OptionalHeader.DataDirectory
650 [IMAGE_DIRECTORY_ENTRY_TLS].Size)
651 fprintf(stdnimp,"Thread local storage ignored\n");
653 if(pe->pe_header->OptionalHeader.DataDirectory
654 [IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size)
655 dprintf_win32(stdnimp,"Load Configuration directory ignored\n");
657 if(pe->pe_header->OptionalHeader.DataDirectory
658 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size)
659 dprintf_win32(stdnimp,"Bound Import directory ignored\n");
661 if(pe->pe_header->OptionalHeader.DataDirectory
662 [IMAGE_DIRECTORY_ENTRY_IAT].Size)
663 dprintf_win32(stdnimp,"Import Address Table directory ignored\n");
664 if(pe->pe_header->OptionalHeader.DataDirectory[13].Size)
665 dprintf_win32(stdnimp,"Unknown directory 13 ignored\n");
666 if(pe->pe_header->OptionalHeader.DataDirectory[14].Size)
667 dprintf_win32(stdnimp,"Unknown directory 14 ignored\n");
668 if(pe->pe_header->OptionalHeader.DataDirectory[15].Size)
669 dprintf_win32(stdnimp,"Unknown directory 15 ignored\n");
671 if(pem->pe_reloc) do_relocations(pem);
672 if(pem->pe_export) dump_exports(pem->pe_export,load_addr);
673 if(pem->pe_import) fixup_imports(process,pem);
675 if (pem->pe_export)
676 modname = (char*)RVA(pem->pe_export->Name);
677 else {
678 char *s;
679 modname = s = ofs->szPathName;
680 while ((s=strchr(modname,'\\')))
681 modname = s+1;
682 if ((s=strchr(modname,'.')))
683 *s='\0';
686 #ifndef WINELIB
688 DBG_ADDR daddr = { NULL, 0, 0 };
689 /* add start of sections as debugsymbols */
690 for(i=0;i<pe->pe_header->FileHeader.NumberOfSections;i++) {
691 sprintf(buffer,"%s_%s",modname,pe->pe_seg[i].Name);
692 daddr.off= RVA(pe->pe_seg[i].VirtualAddress);
693 DEBUG_AddSymbol(buffer,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
695 /* add entry point */
696 sprintf(buffer,"%s_EntryPoint",modname);
697 daddr.off=RVA(pe->pe_header->OptionalHeader.AddressOfEntryPoint);
698 DEBUG_AddSymbol(buffer,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
699 /* add start of DLL */
700 daddr.off=load_addr;
701 DEBUG_AddSymbol(modname,&daddr, NULL, SYM_WIN32 | SYM_FUNC);
703 #endif
706 HINSTANCE16 MODULE_CreateInstance(HMODULE16 hModule,LOADPARAMS *params);
708 /******************************************************************************
709 * The PE Library Loader frontend.
710 * FIXME: handle the flags.
712 HMODULE32 PE_LoadLibraryEx32A (LPCSTR name, HFILE32 hFile, DWORD flags) {
713 OFSTRUCT ofs;
714 HMODULE32 hModule;
715 NE_MODULE *pModule;
716 PE_MODREF *pem;
718 if ((hModule = MODULE_FindModule( name ))) {
719 /* the .DLL is either loaded or internal */
720 hModule = MODULE_HANDLEtoHMODULE32(hModule);
721 if (!HIWORD(hModule)) /* internal (or bad) */
722 return hModule;
723 /* check if this module is already mapped */
724 pem = ((PDB32*)GetCurrentProcessId())->modref_list;
725 while (pem) {
726 if (pem->pe_module->mappeddll == hModule)
727 return hModule;
728 pem = pem->next;
730 pModule = MODULE_GetPtr(hModule);
731 } else {
733 /* try to load builtin, enabled modules first */
734 if ((hModule = BUILTIN_LoadModule( name, FALSE )))
735 return hModule;
737 /* try to open the specified file */
738 if (HFILE_ERROR32==(hFile=OpenFile32(name,&ofs,OF_READ))) {
739 /* Now try the built-in even if disabled */
740 if ((hModule = BUILTIN_LoadModule( name, TRUE ))) {
741 fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
742 return hModule;
744 return 1;
746 if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) {
747 _lclose32(hFile);
748 return hModule;
750 pModule = (NE_MODULE *)GlobalLock16( hModule );
751 pModule->flags = NE_FFLAGS_WIN32;
752 pModule->pe_module = PE_LoadImage( FILE_GetUnixHandle(hFile) );
753 _lclose32(hFile);
754 if (!pModule->pe_module)
755 return 21;
757 /* recurse */
758 PE_MapImage(pModule->pe_module,(PDB32*)GetCurrentProcessId(),&ofs,flags);
759 return pModule->pe_module->mappeddll;
762 /*****************************************************************************
763 * Load the PE main .EXE. All other loading is done by PE_LoadLibraryEx32A
764 * FIXME: this function should use PE_LoadLibraryEx32A, but currently can't
765 * due to the TASK_CreateTask stuff.
767 HINSTANCE16 PE_LoadModule( HFILE32 hFile, OFSTRUCT *ofs, LOADPARAMS* params )
769 HMODULE16 hModule;
770 HINSTANCE16 hInstance;
771 NE_MODULE *pModule;
773 if ((hModule = MODULE_CreateDummyModule( ofs )) < 32) return hModule;
774 pModule = (NE_MODULE *)GlobalLock16( hModule );
775 pModule->flags = NE_FFLAGS_WIN32;
777 pModule->pe_module = PE_LoadImage( FILE_GetUnixHandle(hFile) );
778 _lclose32(hFile);
779 if (!pModule->pe_module)
780 return 21;
782 hInstance = MODULE_CreateInstance( hModule, params );
783 if (!(pModule->pe_module->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
785 TASK_CreateTask( hModule, hInstance, 0,
786 params->hEnvironment,
787 (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
788 *((WORD*)PTR_SEG_TO_LIN(params->showCmd) + 1) );
790 PE_MapImage(pModule->pe_module,(PDB32*)GetCurrentProcessId(),ofs,0);
791 return hInstance;
794 int PE_UnloadImage( HMODULE32 hModule )
796 printf("PEunloadImage() called!\n");
797 /* free resources, image, unmap */
798 return 1;
801 /* Called if the library is loaded or freed.
802 * NOTE: if a thread attaches a DLL, the current thread will only do
803 * DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH
804 * (SDK)
806 static void PE_InitDLL(PE_MODREF *pem, DWORD type,LPVOID lpReserved)
808 PE_MODULE *pe = pem->pe_module;
809 unsigned int load_addr = pem->load_addr;
811 if (type==DLL_PROCESS_ATTACH)
812 pem->flags |= PE_MODREF_PROCESS_ATTACHED;
813 #ifndef WINELIB
814 if (Options.debug) {
815 DBG_ADDR addr = { NULL, 0, RVA(pe->pe_header->OptionalHeader.AddressOfEntryPoint) };
816 DEBUG_AddBreakpoint( &addr );
817 DEBUG_SetBreakpoints(TRUE);
819 #endif
821 /* DLL_ATTACH_PROCESS:
822 * lpreserved is NULL for dynamic loads, not-NULL for static loads
823 * DLL_DETACH_PROCESS:
824 * lpreserved is NULL if called by FreeLibrary, not-NULL otherwise
825 * the SDK doesn't mention anything for DLL_THREAD_*
828 /* Is this a library? And has it got an entrypoint? */
829 if ( (pe->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
830 (pe->pe_header->OptionalHeader.AddressOfEntryPoint)
832 FARPROC32 entry = (FARPROC32)RVA(pe->pe_header->OptionalHeader.AddressOfEntryPoint);
833 dprintf_relay( stddeb, "CallTo32(entryproc=%p,module=%d,type=%ld,res=%p)\n",
834 entry, pe->mappeddll, type, lpReserved );
835 entry( pe->mappeddll, type, lpReserved );
839 /* Call the DLLentry function of all dlls used by that process.
840 * (NOTE: this may recursively call this function (if a library calls
841 * LoadLibrary) ... but it won't matter)
843 void PE_InitializeDLLs(PDB32 *process,DWORD type,LPVOID lpReserved) {
844 PE_MODREF *pem;
846 pem = process->modref_list;
847 while (pem) {
848 if (pem->flags & PE_MODREF_NO_DLL_CALLS) {
849 pem = pem->next;
850 continue;
852 if (type==DLL_PROCESS_ATTACH) {
853 if (pem->flags & PE_MODREF_PROCESS_ATTACHED) {
854 pem = pem->next;
855 continue;
858 PE_InitDLL( pem, type, lpReserved );
859 pem = pem->next;
863 void PE_InitTls(PDB32 *pdb)
865 /* FIXME: tls callbacks ??? */
866 PE_MODREF *pem;
867 IMAGE_NT_HEADERS *peh;
868 DWORD size,datasize,index;
869 LPVOID mem;
870 LPIMAGE_TLS_DIRECTORY pdir;
872 pem = pdb->modref_list;
873 while (pem) {
874 peh = pem->pe_module->pe_header;
875 if (!peh->OptionalHeader.DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress) {
876 pem = pem->next;
877 continue;
879 pdir = (LPVOID)(pem->load_addr + peh->OptionalHeader.
880 DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress);
881 index = TlsAlloc();
882 datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
883 size = datasize + pdir->SizeOfZeroFill;
884 mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
885 memcpy(mem,(LPVOID) pdir->StartAddressOfRawData, datasize);
886 TlsSetValue(index,mem);
887 *(pdir->AddressOfIndex)=index;
888 pem=pem->next;
892 /****************************************************************************
893 * DisableThreadLibraryCalls (KERNEL32.74)
894 * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
896 BOOL32 WINAPI DisableThreadLibraryCalls(HMODULE32 hModule)
898 PDB32 *process = (PDB32*)GetCurrentProcessId();
899 PE_MODREF *pem = process->modref_list;
901 while (pem) {
902 if (pem->pe_module->mappeddll == hModule)
903 pem->flags|=PE_MODREF_NO_DLL_CALLS;
904 pem = pem->next;
906 return TRUE;