Release 971101
[wine/testsucceed.git] / loader / pe_image.c
blob07b147c250ceea73f4c6592be14150fd9f42c0bf
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 "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 #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 char *Module;
49 int i, j;
50 u_short *ordinal;
51 u_long *function,*functions;
52 u_char **name,*ename;
54 Module = (char*)RVA(pe_exports->Name);
55 dprintf_win32(stddeb,"\n*******EXPORT DATA*******\nModule name is %s, %ld functions, %ld names\n",
56 Module,
57 pe_exports->NumberOfFunctions,
58 pe_exports->NumberOfNames);
60 ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals);
61 functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions);
62 name=(u_char**) RVA(pe_exports->AddressOfNames);
64 dprintf_win32(stddeb," Ord Virt Addr Name\n" );
65 for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
67 if (!*function) continue; /* No such function */
68 dprintf_win32( stddeb,"%4d %08lx", i + pe_exports->Base, *function );
69 /* Check if we have a name for it */
70 for (j = 0; j < pe_exports->NumberOfNames; j++)
71 if (ordinal[j] == i)
72 dprintf_win32( stddeb, " %s", (char*)RVA(name[j]) );
73 dprintf_win32( stddeb,"\n" );
77 /* Look up the specified function or ordinal in the exportlist:
78 * If it is a string:
79 * - look up the name in the Name list.
80 * - look up the ordinal with that index.
81 * - use the ordinal as offset into the functionlist
82 * If it is a ordinal:
83 * - use ordinal-pe_export->Base as offset into the functionlist
85 FARPROC32 PE_FindExportedFunction(struct pe_data *pe, LPCSTR funcName)
87 IMAGE_EXPORT_DIRECTORY *exports;
88 unsigned load_addr;
89 u_short * ordinal;
90 u_long * function;
91 u_char ** name, *ename;
92 int i;
93 PDB32 *process=(PDB32*)GetCurrentProcessId();
94 PE_MODREF *pem;
96 pem = process->modref_list;
97 while (pem && (pem->pe_module != pe))
98 pem=pem->next;
99 if (!pem) {
100 fprintf(stderr,"No MODREF found for PE_MODULE %p in process %p\n",pe,process);
101 return NULL;
103 load_addr = pem->load_addr;
104 exports = pem->pe_export;
106 if (HIWORD(funcName))
107 dprintf_win32(stddeb,"PE_FindExportedFunction(%s)\n",funcName);
108 else
109 dprintf_win32(stddeb,"PE_FindExportedFunction(%d)\n",(int)funcName);
110 if (!exports) {
111 fprintf(stderr,"Module %p/MODREF %p doesn't have a exports table.\n",pe,pem);
112 return NULL;
114 ordinal = (u_short*) RVA(exports->AddressOfNameOrdinals);
115 function= (u_long*) RVA(exports->AddressOfFunctions);
116 name = (u_char **) RVA(exports->AddressOfNames);
118 if (HIWORD(funcName)) {
119 for(i=0; i<exports->NumberOfNames; i++) {
120 ename=(char*)RVA(*name);
121 if(!strcmp(ename,funcName))
122 return (FARPROC32) RVA(function[*ordinal]);
123 ordinal++;
124 name++;
126 } else {
127 if (LOWORD(funcName)-exports->Base > exports->NumberOfFunctions) {
128 dprintf_win32(stddeb," ordinal %d out of range!\n",
129 LOWORD(funcName));
130 return NULL;
132 return (FARPROC32) RVA(function[(int)funcName-exports->Base]);
134 return NULL;
137 void
138 fixup_imports (PDB32 *process,PE_MODREF *pem)
140 PE_MODULE *pe = pem->pe_module;
141 IMAGE_IMPORT_DESCRIPTOR *pe_imp;
142 int fixup_failed = 0;
143 unsigned int load_addr = pem->load_addr;
144 int i;
145 char *modname;
147 if (pem->pe_export)
148 modname = (char*) RVA(pem->pe_export->Name);
149 else
150 modname = "<unknown>";
152 /* OK, now dump the import list */
153 dprintf_win32 (stddeb, "\nDumping imports list\n");
155 /* first, count the number of imported non-internal modules */
156 pe_imp = pem->pe_import;
157 if (!pe_imp)
158 fprintf(stderr,"no import directory????\n");
160 /* FIXME: should terminate on 0 Characteristics */
161 for (i = 0; pe_imp->Name; pe_imp++)
162 i++;
164 /* load the imported modules. They are automatically
165 * added to the modref list of the process.
168 /* FIXME: should terminate on 0 Characteristics */
169 for (i = 0, pe_imp = pem->pe_import; pe_imp->Name; pe_imp++) {
170 HMODULE32 res;
171 PE_MODREF *xpem,**ypem;
174 char *name = (char *) RVA(pe_imp->Name);
176 /* don't use MODULE_Load, Win32 creates new task differently */
177 res = PE_LoadLibraryEx32A( name, 0, 0 );
178 if (res <= (HMODULE32) 32) {
179 char *p, buffer[256];
181 /* Try with prepending the path of the current module */
182 GetModuleFileName32A (pe->mappeddll, buffer, sizeof (buffer));
183 if (!(p = strrchr (buffer, '\\')))
184 p = buffer;
185 strcpy (p + 1, name);
186 res = PE_LoadLibraryEx32A( buffer, 0, 0 );
188 if (res <= (HMODULE32) 32) {
189 fprintf (stderr, "Module %s not found\n", name);
190 exit (0);
192 res = MODULE_HANDLEtoHMODULE32(res);
193 xpem = pem->next;
194 while (xpem) {
195 if (xpem->pe_module->mappeddll == res)
196 break;
197 xpem = xpem->next;
199 if (xpem) {
200 /* it has been loaded *BEFORE* us, so we have to init
201 * it before us. we just swap the two modules which should
202 * work.
204 /* unlink xpem from chain */
205 ypem = &(process->modref_list);
206 while (*ypem) {
207 if ((*ypem)==xpem)
208 break;
209 ypem = &((*ypem)->next);
211 *ypem = xpem->next;
213 /* link it directly before pem */
214 ypem = &(process->modref_list);
215 while (*ypem) {
216 if ((*ypem)==pem)
217 break;
218 ypem = &((*ypem)->next);
220 *ypem = xpem;
221 xpem->next = pem;
224 i++;
226 pe_imp = pem->pe_import;
227 while (pe_imp->Name) {
228 char *Module;
229 IMAGE_IMPORT_BY_NAME *pe_name;
230 LPIMAGE_THUNK_DATA import_list,thunk_list;
232 Module = (char *) RVA(pe_imp->Name);
233 dprintf_win32 (stddeb, "%s\n", Module);
235 /* FIXME: forwarder entries ... */
237 if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
238 dprintf_win32 (stddeb, "Microsoft style imports used\n");
239 import_list =(LPIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk);
240 thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
242 while (import_list->u1.Ordinal) {
243 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
244 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
246 dprintf_win32 (stddeb, "--- Ordinal %s,%d\n", Module, ordinal);
247 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),(LPCSTR)ordinal);
248 if (!thunk_list->u1.Function) {
249 fprintf(stderr,"No implementation for %s.%d, setting to NULL\n",
250 Module, ordinal);
251 /* fixup_failed=1; */
253 } else { /* import by name */
254 pe_name = (LPIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
255 dprintf_win32 (stddeb, "--- %s %s.%d\n", pe_name->Name, Module, pe_name->Hint);
256 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(
257 MODULE_FindModule (Module),
258 pe_name->Name);
259 if (!thunk_list->u1.Function) {
260 fprintf(stderr,"No implementation for %s.%d(%s), setting to NULL\n",
261 Module,pe_name->Hint,pe_name->Name);
262 /* fixup_failed=1; */
265 import_list++;
266 thunk_list++;
268 } else { /* Borland style */
269 dprintf_win32 (stddeb, "Borland style imports used\n");
270 thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
271 while (thunk_list->u1.Ordinal) {
272 if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
273 /* not sure about this branch, but it seems to work */
274 int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
276 dprintf_win32(stddeb,"--- Ordinal %s.%d\n",Module,ordinal);
277 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),
278 (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; */
284 } else {
285 pe_name=(LPIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData);
286 dprintf_win32(stddeb,"--- %s %s.%d\n",
287 pe_name->Name,Module,pe_name->Hint);
288 thunk_list->u1.Function=(LPDWORD)GetProcAddress32(MODULE_FindModule(Module),pe_name->Name);
289 if (!thunk_list->u1.Function) {
290 fprintf(stderr, "No implementation for %s.%d, setting to NULL\n",
291 Module, pe_name->Hint);
292 /* fixup_failed=1; */
295 thunk_list++;
298 pe_imp++;
300 if (fixup_failed) exit(1);
303 static int calc_vma_size(struct pe_data *pe)
305 int i,vma_size = 0;
307 dprintf_win32(stddeb, "Dump of segment table\n");
308 dprintf_win32(stddeb, " Name VSz Vaddr SzRaw Fileadr *Reloc *Lineum #Reloc #Linum Char\n");
309 for(i=0; i< pe->pe_header->FileHeader.NumberOfSections; i++)
311 dprintf_win32(stddeb, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n",
312 pe->pe_seg[i].Name,
313 pe->pe_seg[i].Misc.VirtualSize,
314 pe->pe_seg[i].VirtualAddress,
315 pe->pe_seg[i].SizeOfRawData,
316 pe->pe_seg[i].PointerToRawData,
317 pe->pe_seg[i].PointerToRelocations,
318 pe->pe_seg[i].PointerToLinenumbers,
319 pe->pe_seg[i].NumberOfRelocations,
320 pe->pe_seg[i].NumberOfLinenumbers,
321 pe->pe_seg[i].Characteristics);
322 vma_size = MAX(vma_size,
323 pe->pe_seg[i].VirtualAddress +
324 pe->pe_seg[i].SizeOfRawData);
326 return vma_size;
329 static void do_relocations(PE_MODREF *pem)
331 int delta = pem->load_addr - pem->pe_module->pe_header->OptionalHeader.ImageBase;
333 unsigned int load_addr= pem->load_addr;
334 IMAGE_BASE_RELOCATION *r = pem->pe_reloc;
335 int hdelta = (delta >> 16) & 0xFFFF;
336 int ldelta = delta & 0xFFFF;
338 /* int reloc_size = */
340 if(delta == 0)
341 /* Nothing to do */
342 return;
343 while(r->VirtualAddress)
345 char *page = (char*) RVA(r->VirtualAddress);
346 int count = (r->SizeOfBlock - 8)/2;
347 int i;
348 dprintf_fixup(stddeb, "%x relocations for page %lx\n",
349 count, r->VirtualAddress);
350 /* patching in reverse order */
351 for(i=0;i<count;i++)
353 int offset = r->TypeOffset[i] & 0xFFF;
354 int type = r->TypeOffset[i] >> 12;
355 dprintf_fixup(stddeb,"patching %x type %x\n", offset, type);
356 switch(type)
358 case IMAGE_REL_BASED_ABSOLUTE: break;
359 case IMAGE_REL_BASED_HIGH:
360 *(short*)(page+offset) += hdelta;
361 break;
362 case IMAGE_REL_BASED_LOW:
363 *(short*)(page+offset) += ldelta;
364 break;
365 case IMAGE_REL_BASED_HIGHLOW:
366 #if 1
367 *(int*)(page+offset) += delta;
368 #else
369 { int h=*(unsigned short*)(page+offset);
370 int l=r->TypeOffset[++i];
371 *(unsigned int*)(page + offset) = (h<<16) + l + delta;
373 #endif
374 break;
375 case IMAGE_REL_BASED_HIGHADJ:
376 fprintf(stderr, "Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
377 break;
378 case IMAGE_REL_BASED_MIPS_JMPADDR:
379 fprintf(stderr, "Is this a MIPS machine ???\n");
380 break;
381 default:
382 fprintf(stderr, "Unknown fixup type\n");
383 break;
386 r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
394 /**********************************************************************
395 * PE_LoadImage
396 * Load one PE format DLL/EXE into memory
398 * Unluckily we can't just mmap the sections where we want them, for
399 * (at least) Linux does only support offsets which are page-aligned.
401 * BUT we have to map the whole image anyway, for Win32 programs sometimes
402 * want to access them. (HMODULE32 point to the start of it)
404 static PE_MODULE *PE_LoadImage( HFILE32 hFile )
406 struct pe_data *pe;
407 HMODULE32 hModule;
408 HANDLE32 mapping;
410 /* map the PE file somewhere */
411 mapping = CreateFileMapping32A( hFile, NULL, PAGE_READONLY | SEC_COMMIT,
412 0, 0, NULL );
413 if (!mapping)
415 fprintf( stderr, "PE_LoadImage: CreateFileMapping error %ld\n",
416 GetLastError() );
417 return NULL;
419 hModule = (HMODULE32)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
420 CloseHandle( mapping );
421 if (!hModule)
423 fprintf( stderr, "PE_LoadImage: MapViewOfFile error %ld\n",
424 GetLastError() );
425 return NULL;
428 /* build PE header */
429 pe = xmalloc(sizeof(struct pe_data));
430 pe->mappeddll = hModule;
431 pe->pe_header = (IMAGE_NT_HEADERS*)(pe->mappeddll+(((IMAGE_DOS_HEADER*)pe->mappeddll)->e_lfanew));
432 if (pe->pe_header->Signature!=IMAGE_NT_SIGNATURE)
434 fprintf(stderr,"image doesn't have PE signature, but 0x%08lx\n",
435 pe->pe_header->Signature );
436 free(pe);
437 return NULL;
440 if (pe->pe_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
441 fprintf(stderr,"trying to load PE image for unsupported architecture (");
442 switch (pe->pe_header->FileHeader.Machine) {
443 case IMAGE_FILE_MACHINE_UNKNOWN:
444 fprintf(stderr,"Unknown");break;
445 case IMAGE_FILE_MACHINE_I860:
446 fprintf(stderr,"I860");break;
447 case IMAGE_FILE_MACHINE_R3000:
448 fprintf(stderr,"R3000");break;
449 case IMAGE_FILE_MACHINE_R4000:
450 fprintf(stderr,"R4000");break;
451 case IMAGE_FILE_MACHINE_R10000:
452 fprintf(stderr,"R10000");break;
453 case IMAGE_FILE_MACHINE_ALPHA:
454 fprintf(stderr,"Alpha");break;
455 case IMAGE_FILE_MACHINE_POWERPC:
456 fprintf(stderr,"PowerPC");break;
457 default:
458 fprintf(stderr,"Unknown-%04x",pe->pe_header->FileHeader.Machine);break;
460 fprintf(stderr,")\n");
461 return NULL;
463 pe->pe_seg = (IMAGE_SECTION_HEADER*)(((LPBYTE)(pe->pe_header+1))-
464 (16 - pe->pe_header->OptionalHeader.NumberOfRvaAndSizes) * sizeof(IMAGE_DATA_DIRECTORY));
466 /* FIXME: the (16-...) is a *horrible* hack to make COMDLG32.DLL load OK. The
467 * problem needs to be fixed properly at some stage.
469 return pe;
472 /**********************************************************************
473 * This maps a loaded PE dll into the address space of the specified process.
475 void
476 PE_MapImage(PE_MODULE *pe,PDB32 *process, OFSTRUCT *ofs, DWORD flags) {
477 PE_MODREF *pem;
478 int i, result;
479 int load_addr;
480 IMAGE_DATA_DIRECTORY dir;
481 char *modname;
482 int vma_size;
484 pem = (PE_MODREF*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*pem));
485 /* NOTE: fixup_imports takes care of the correct order */
486 pem->next = process->modref_list;
487 process->modref_list = pem;
489 pem->pe_module = pe;
490 if (!(pe->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
491 if (process->exe_modref)
492 fprintf(stderr,"overwriting old exe_modref... arrgh\n");
493 process->exe_modref = pem;
496 load_addr = pe->pe_header->OptionalHeader.ImageBase;
497 dprintf_win32(stddeb, "Load addr is %x\n",load_addr);
498 vma_size = calc_vma_size(pe);
499 load_addr = (int) VirtualAlloc( (void*)load_addr, vma_size, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
500 pem->load_addr = load_addr;
502 dprintf_win32(stddeb, "Load addr is really %lx, range %x\n",
503 pem->load_addr, vma_size);
506 for(i=0; i < pe->pe_header->FileHeader.NumberOfSections; i++)
508 /* memcpy only non-BSS segments */
509 /* FIXME: this should be done by mmap(..MAP_PRIVATE|MAP_FIXED..)
510 * but it is not possible for (at least) Linux needs
511 * a page-aligned offset.
513 if(!(pe->pe_seg[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
514 memcpy((char*)RVA(pe->pe_seg[i].VirtualAddress),
515 (char*)(pe->mappeddll+pe->pe_seg[i].PointerToRawData),
516 pe->pe_seg[i].SizeOfRawData
519 result = RVA (pe->pe_seg[i].VirtualAddress);
520 #if 1
521 /* not needed, memory is zero */
522 if(strcmp(pe->pe_seg[i].Name, ".bss") == 0)
523 memset((void *)result, 0,
524 pe->pe_seg[i].Misc.VirtualSize ?
525 pe->pe_seg[i].Misc.VirtualSize :
526 pe->pe_seg[i].SizeOfRawData);
527 #endif
529 if(strcmp(pe->pe_seg[i].Name, ".idata") == 0)
530 pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) result;
532 if(strcmp(pe->pe_seg[i].Name, ".edata") == 0)
533 pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) result;
535 if(strcmp(pe->pe_seg[i].Name, ".rsrc") == 0)
536 pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) result;
538 if(strcmp(pe->pe_seg[i].Name, ".reloc") == 0)
539 pem->pe_reloc = (LPIMAGE_BASE_RELOCATION) result;
542 /* There is word that the actual loader does not care about the
543 section names, and only goes for the DataDirectory */
544 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
545 if(dir.Size)
547 if(pem->pe_export && (int)pem->pe_export!=RVA(dir.VirtualAddress))
548 fprintf(stderr,"wrong export directory??\n");
549 /* always trust the directory */
550 pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) RVA(dir.VirtualAddress);
553 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
554 if(dir.Size)
557 if(pem->pe_import && (int)pem->pe_import!=RVA(dir.VirtualAddress))
558 fprintf(stderr,"wrong import directory??\n");
560 pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) RVA(dir.VirtualAddress);
563 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
564 if(dir.Size)
566 if(pem->pe_resource && (int)pem->pe_resource!=RVA(dir.VirtualAddress))
567 fprintf(stderr,"wrong resource directory??\n");
568 pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) RVA(dir.VirtualAddress);
571 if(pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size)
572 dprintf_win32(stdnimp,"Exception directory ignored\n");
574 if(pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
575 dprintf_win32(stdnimp,"Security directory ignored\n");
579 dir=pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
580 if(dir.Size)
582 if(pem->pe_reloc && (int)pem->pe_reloc!= RVA(dir.VirtualAddress))
583 fprintf(stderr,"wrong relocation list??\n");
584 pem->pe_reloc = (void *) RVA(dir.VirtualAddress);
587 #ifndef WINELIB
588 if(pe->pe_header->OptionalHeader.DataDirectory
589 [IMAGE_DIRECTORY_ENTRY_DEBUG].Size)
591 DEBUG_RegisterDebugInfo(pe, load_addr,
592 pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
593 pe->pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
595 #endif
597 if(pe->pe_header->OptionalHeader.DataDirectory
598 [IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size)
599 dprintf_win32(stdnimp,"Copyright string ignored\n");
601 if(pe->pe_header->OptionalHeader.DataDirectory
602 [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size)
603 dprintf_win32(stdnimp,"Global Pointer (MIPS) ignored\n");
605 if(pe->pe_header->OptionalHeader.DataDirectory
606 [IMAGE_DIRECTORY_ENTRY_TLS].Size)
607 fprintf(stdnimp,"Thread local storage ignored\n");
609 if(pe->pe_header->OptionalHeader.DataDirectory
610 [IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size)
611 dprintf_win32(stdnimp,"Load Configuration directory ignored\n");
613 if(pe->pe_header->OptionalHeader.DataDirectory
614 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size)
615 dprintf_win32(stdnimp,"Bound Import directory ignored\n");
617 if(pe->pe_header->OptionalHeader.DataDirectory
618 [IMAGE_DIRECTORY_ENTRY_IAT].Size)
619 dprintf_win32(stdnimp,"Import Address Table directory ignored\n");
620 if(pe->pe_header->OptionalHeader.DataDirectory[13].Size)
621 dprintf_win32(stdnimp,"Unknown directory 13 ignored\n");
622 if(pe->pe_header->OptionalHeader.DataDirectory[14].Size)
623 dprintf_win32(stdnimp,"Unknown directory 14 ignored\n");
624 if(pe->pe_header->OptionalHeader.DataDirectory[15].Size)
625 dprintf_win32(stdnimp,"Unknown directory 15 ignored\n");
627 if(pem->pe_reloc) do_relocations(pem);
628 if(pem->pe_export) dump_exports(pem->pe_export,load_addr);
629 if(pem->pe_import) fixup_imports(process,pem);
631 if (pem->pe_export)
632 modname = (char*)RVA(pem->pe_export->Name);
633 else {
634 char *s;
635 modname = s = ofs->szPathName;
636 while ((s=strchr(modname,'\\')))
637 modname = s+1;
638 if ((s=strchr(modname,'.')))
639 *s='\0';
643 HINSTANCE16 MODULE_CreateInstance(HMODULE16 hModule,LOADPARAMS *params);
645 /******************************************************************************
646 * The PE Library Loader frontend.
647 * FIXME: handle the flags.
649 HMODULE32 PE_LoadLibraryEx32A (LPCSTR name, HFILE32 hFile, DWORD flags) {
650 OFSTRUCT ofs;
651 HMODULE32 hModule;
652 NE_MODULE *pModule;
653 PE_MODREF *pem;
655 if ((hModule = MODULE_FindModule( name ))) {
656 /* the .DLL is either loaded or internal */
657 hModule = MODULE_HANDLEtoHMODULE32(hModule);
658 if (!HIWORD(hModule)) /* internal (or bad) */
659 return hModule;
660 /* check if this module is already mapped */
661 pem = ((PDB32*)GetCurrentProcessId())->modref_list;
662 while (pem) {
663 if (pem->pe_module->mappeddll == hModule)
664 return hModule;
665 pem = pem->next;
667 pModule = MODULE_GetPtr(hModule);
668 } else {
670 #ifndef WINELIB
671 /* try to load builtin, enabled modules first */
672 if ((hModule = BUILTIN_LoadModule( name, FALSE )))
673 return hModule;
674 #endif
675 /* try to open the specified file */
676 if (HFILE_ERROR32==(hFile=OpenFile32(name,&ofs,OF_READ))) {
677 #ifndef WINELIB
678 /* Now try the built-in even if disabled */
679 if ((hModule = BUILTIN_LoadModule( name, TRUE ))) {
680 fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
681 return hModule;
683 #endif
684 return 1;
686 if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) {
687 _lclose32(hFile);
688 return hModule;
690 pModule = (NE_MODULE *)GlobalLock16( hModule );
691 pModule->flags = NE_FFLAGS_WIN32;
692 pModule->pe_module = PE_LoadImage( hFile );
693 CloseHandle( hFile );
694 if (!pModule->pe_module)
695 return 21;
697 /* recurse */
698 PE_MapImage(pModule->pe_module,(PDB32*)GetCurrentProcessId(),&ofs,flags);
699 return pModule->pe_module->mappeddll;
702 /*****************************************************************************
703 * Load the PE main .EXE. All other loading is done by PE_LoadLibraryEx32A
704 * FIXME: this function should use PE_LoadLibraryEx32A, but currently can't
705 * due to the TASK_CreateTask stuff.
707 HINSTANCE16 PE_LoadModule( HFILE32 hFile, OFSTRUCT *ofs, LOADPARAMS* params )
709 HMODULE16 hModule;
710 HINSTANCE16 hInstance;
711 NE_MODULE *pModule;
713 if ((hModule = MODULE_CreateDummyModule( ofs )) < 32) return hModule;
714 pModule = (NE_MODULE *)GlobalLock16( hModule );
715 pModule->flags = NE_FFLAGS_WIN32;
717 pModule->pe_module = PE_LoadImage( hFile );
718 CloseHandle( hFile );
719 if (!pModule->pe_module)
720 return 21;
722 hInstance = MODULE_CreateInstance( hModule, params );
723 if (!(pModule->pe_module->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
725 TASK_CreateTask( hModule, hInstance, 0,
726 params->hEnvironment,
727 (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
728 *((WORD*)PTR_SEG_TO_LIN(params->showCmd) + 1) );
730 PE_MapImage(pModule->pe_module,(PDB32*)GetCurrentProcessId(),ofs,0);
731 return hInstance;
734 int PE_UnloadImage( HMODULE32 hModule )
736 printf("PEunloadImage() called!\n");
737 /* free resources, image, unmap */
738 return 1;
741 /* Called if the library is loaded or freed.
742 * NOTE: if a thread attaches a DLL, the current thread will only do
743 * DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH
744 * (SDK)
746 static void PE_InitDLL(PE_MODREF *pem, DWORD type,LPVOID lpReserved)
748 PE_MODULE *pe = pem->pe_module;
749 unsigned int load_addr = pem->load_addr;
751 if (type==DLL_PROCESS_ATTACH)
752 pem->flags |= PE_MODREF_PROCESS_ATTACHED;
754 /* DLL_ATTACH_PROCESS:
755 * lpreserved is NULL for dynamic loads, not-NULL for static loads
756 * DLL_DETACH_PROCESS:
757 * lpreserved is NULL if called by FreeLibrary, not-NULL otherwise
758 * the SDK doesn't mention anything for DLL_THREAD_*
761 /* Is this a library? And has it got an entrypoint? */
762 if ( (pe->pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
763 (pe->pe_header->OptionalHeader.AddressOfEntryPoint)
765 FARPROC32 entry = (FARPROC32)RVA(pe->pe_header->OptionalHeader.AddressOfEntryPoint);
766 dprintf_relay( stddeb, "CallTo32(entryproc=%p,module=%d,type=%ld,res=%p)\n",
767 entry, pe->mappeddll, type, lpReserved );
768 entry( pe->mappeddll, type, lpReserved );
772 /* Call the DLLentry function of all dlls used by that process.
773 * (NOTE: this may recursively call this function (if a library calls
774 * LoadLibrary) ... but it won't matter)
776 void PE_InitializeDLLs(PDB32 *process,DWORD type,LPVOID lpReserved) {
777 PE_MODREF *pem;
779 pem = process->modref_list;
780 while (pem) {
781 if (pem->flags & PE_MODREF_NO_DLL_CALLS) {
782 pem = pem->next;
783 continue;
785 if (type==DLL_PROCESS_ATTACH) {
786 if (pem->flags & PE_MODREF_PROCESS_ATTACHED) {
787 pem = pem->next;
788 continue;
791 PE_InitDLL( pem, type, lpReserved );
792 pem = pem->next;
796 void PE_InitTls(PDB32 *pdb)
798 /* FIXME: tls callbacks ??? */
799 PE_MODREF *pem;
800 IMAGE_NT_HEADERS *peh;
801 DWORD size,datasize,index;
802 LPVOID mem;
803 LPIMAGE_TLS_DIRECTORY pdir;
805 pem = pdb->modref_list;
806 while (pem) {
807 peh = pem->pe_module->pe_header;
808 if (!peh->OptionalHeader.DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress) {
809 pem = pem->next;
810 continue;
812 pdir = (LPVOID)(pem->load_addr + peh->OptionalHeader.
813 DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress);
814 index = TlsAlloc();
815 datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
816 size = datasize + pdir->SizeOfZeroFill;
817 mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
818 memcpy(mem,(LPVOID) pdir->StartAddressOfRawData, datasize);
819 TlsSetValue(index,mem);
820 *(pdir->AddressOfIndex)=index;
821 pem=pem->next;
825 /****************************************************************************
826 * DisableThreadLibraryCalls (KERNEL32.74)
827 * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
829 BOOL32 WINAPI DisableThreadLibraryCalls(HMODULE32 hModule)
831 PDB32 *process = (PDB32*)GetCurrentProcessId();
832 PE_MODREF *pem = process->modref_list;
834 while (pem) {
835 if (pem->pe_module->mappeddll == hModule)
836 pem->flags|=PE_MODREF_NO_DLL_CALLS;
837 pem = pem->next;
839 return TRUE;