Release 980104
[wine/multimedia.git] / loader / pe_image.c
blob043404dbd754e007db6e78623ba765bfc75ea2d3
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"
38 static void PE_InitDLL(PE_MODREF* modref, DWORD type, LPVOID lpReserved);
40 /* convert PE image VirtualAddress to Real Address */
41 #define RVA(x) ((unsigned int)load_addr+(unsigned int)(x))
43 void dump_exports( HMODULE32 hModule )
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;
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);
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);
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);
68 dprintf_win32(stddeb," Ord RVA Addr Name\n" );
69 for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
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" );
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
92 FARPROC32 PE_FindExportedFunction( HMODULE32 hModule, LPCSTR funcName)
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;
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;
112 load_addr = hModule;
113 exports = pem->pe_export;
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;
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;
132 if (HIWORD(funcName)) {
133 for(i=0; i<exports->NumberOfNames; i++) {
134 ename=(char*)RVA(*name);
135 if(!strcmp(ename,funcName))
137 addr = function[*ordinal];
138 if ((addr < rva_start) || (addr >= rva_end))
139 return (FARPROC32)RVA(addr);
140 forward = (char *)RVA(addr);
141 break;
143 ordinal++;
144 name++;
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;
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);
157 if (forward)
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);
166 return NULL;
169 void
170 fixup_imports (PDB32 *process,PE_MODREF *pem,HMODULE32 hModule)
172 IMAGE_IMPORT_DESCRIPTOR *pe_imp;
173 int fixup_failed = 0;
174 unsigned int load_addr = pem->module;
175 int i;
176 char *modname;
178 if (pem->pe_export)
179 modname = (char*) RVA(pem->pe_export->Name);
180 else
181 modname = "<unknown>";
183 /* OK, now dump the import list */
184 dprintf_win32 (stddeb, "\nDumping imports list\n");
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");
191 /* FIXME: should terminate on 0 Characteristics */
192 for (i = 0; pe_imp->Name; pe_imp++)
193 i++;
195 /* load the imported modules. They are automatically
196 * added to the modref list of the process.
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;
205 char *name = (char *) RVA(pe_imp->Name);
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];
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 );
219 if (res <= (HMODULE32) 32) {
220 fprintf (stderr, "Module %s not found\n", name);
221 exit (0);
223 res = MODULE_HANDLEtoHMODULE32(res);
224 xpem = pem->next;
225 while (xpem) {
226 if (xpem->module == res)
227 break;
228 xpem = xpem->next;
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.
235 /* unlink xpem from chain */
236 ypem = &(process->modref_list);
237 while (*ypem) {
238 if ((*ypem)==xpem)
239 break;
240 ypem = &((*ypem)->next);
242 *ypem = xpem->next;
244 /* link it directly before pem */
245 ypem = &(process->modref_list);
246 while (*ypem) {
247 if ((*ypem)==pem)
248 break;
249 ypem = &((*ypem)->next);
251 *ypem = xpem;
252 xpem->next = pem;
255 i++;
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;
263 Module = (char *) RVA(pe_imp->Name);
264 dprintf_win32 (stddeb, "%s\n", Module);
266 /* FIXME: forwarder entries ... */
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);
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);
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; */
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; */
296 import_list++;
297 thunk_list++;
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);
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; */
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; */
326 thunk_list++;
329 pe_imp++;
331 if (fixup_failed) exit(1);
334 static int calc_vma_size( HMODULE32 hModule )
336 int i,vma_size = 0;
337 IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(hModule);
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++)
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++;
357 return vma_size;
360 static void do_relocations(PE_MODREF *pem)
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;
368 /* int reloc_size = */
370 if(delta == 0)
371 /* Nothing to do */
372 return;
373 while(r->VirtualAddress)
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++)
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)
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;
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;
416 r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
424 /**********************************************************************
425 * PE_LoadImage
426 * Load one PE format DLL/EXE into memory
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.
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)
434 static HMODULE32 PE_LoadImage( HFILE32 hFile )
436 HMODULE32 hModule;
437 HANDLE32 mapping;
439 /* map the PE file somewhere */
440 mapping = CreateFileMapping32A( hFile, NULL, PAGE_READONLY | SEC_COMMIT,
441 0, 0, NULL );
442 if (!mapping)
444 fprintf( stderr, "PE_LoadImage: CreateFileMapping error %ld\n",
445 GetLastError() );
446 return 0;
448 hModule = (HMODULE32)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
449 CloseHandle( mapping );
450 if (!hModule)
452 fprintf( stderr, "PE_LoadImage: MapViewOfFile error %ld\n",
453 GetLastError() );
454 return 0;
457 if (PE_HEADER(hModule)->Signature != IMAGE_NT_SIGNATURE)
459 fprintf(stderr,"image doesn't have PE signature, but 0x%08lx\n",
460 PE_HEADER(hModule)->Signature );
461 goto error;
464 if (PE_HEADER(hModule)->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
466 fprintf(stderr,"trying to load PE image for unsupported architecture (");
467 switch (PE_HEADER(hModule)->FileHeader.Machine)
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;
479 fprintf(stderr,")\n");
480 goto error;
482 return hModule;
484 error:
485 UnmapViewOfFile( (LPVOID)hModule );
486 return 0;
489 /**********************************************************************
490 * This maps a loaded PE dll into the address space of the specified process.
492 static HMODULE32 PE_MapImage( HMODULE32 hModule, PDB32 *process,
493 OFSTRUCT *ofs, DWORD flags )
495 PE_MODREF *pem;
496 int i, result;
497 DWORD load_addr;
498 IMAGE_DATA_DIRECTORY dir;
499 char *modname;
500 int vma_size;
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);
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;
512 if (!(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
514 if (process->exe_modref)
515 fprintf(stderr,"overwriting old exe_modref... arrgh\n");
516 process->exe_modref = pem;
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 );
530 pem->module = (HMODULE32)load_addr;
532 dprintf_win32(stddeb, "Load addr is really %lx, range %x\n",
533 load_addr, vma_size);
535 /* Store the NT header at the load addr
536 * (FIXME: should really use mmap)
538 *(IMAGE_DOS_HEADER *)load_addr = *dos_header;
539 *(IMAGE_NT_HEADERS *)(load_addr + dos_header->e_lfanew) = *nt_header;
541 pe_seg = PE_SECTIONS(hModule);
542 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++, pe_seg++)
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.
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
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
565 if(strcmp(pe_seg->Name, ".idata") == 0)
566 pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) result;
568 if(strcmp(pe_seg->Name, ".edata") == 0)
569 pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) result;
571 if(strcmp(pe_seg->Name, ".rsrc") == 0)
572 pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) result;
574 if(strcmp(pe_seg->Name, ".reloc") == 0)
575 pem->pe_reloc = (LPIMAGE_BASE_RELOCATION) result;
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)
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);
589 dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
590 if(dir.Size)
593 if(pem->pe_import && (int)pem->pe_import!=RVA(dir.VirtualAddress))
594 fprintf(stderr,"wrong import directory??\n");
596 pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) RVA(dir.VirtualAddress);
599 dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
600 if(dir.Size)
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);
607 if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size)
608 dprintf_win32(stdnimp,"Exception directory ignored\n");
610 if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
611 dprintf_win32(stdnimp,"Security directory ignored\n");
615 dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
616 if(dir.Size)
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);
623 if(nt_header->OptionalHeader.DataDirectory
624 [IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size)
625 dprintf_win32(stdnimp,"Copyright string ignored\n");
627 if(nt_header->OptionalHeader.DataDirectory
628 [IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size)
629 dprintf_win32(stdnimp,"Global Pointer (MIPS) ignored\n");
631 if(nt_header->OptionalHeader.DataDirectory
632 [IMAGE_DIRECTORY_ENTRY_TLS].Size)
633 fprintf(stdnimp,"Thread local storage ignored\n");
635 if(nt_header->OptionalHeader.DataDirectory
636 [IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size)
637 dprintf_win32(stdnimp,"Load Configuration directory ignored\n");
639 if(nt_header->OptionalHeader.DataDirectory
640 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size)
641 dprintf_win32(stdnimp,"Bound Import directory ignored\n");
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");
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);
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';
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;
674 HINSTANCE16 MODULE_CreateInstance(HMODULE16 hModule,LOADPARAMS *params);
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)
681 HMODULE32 PE_LoadLibraryEx32A (LPCSTR name, HFILE32 hFile, DWORD flags) {
682 OFSTRUCT ofs;
683 HMODULE32 hModule;
684 NE_MODULE *pModule;
685 PE_MODREF *pem;
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;
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;
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.
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;
720 } else {
722 /* try to load builtin, enabled modules first */
723 if ((hModule = BUILTIN_LoadModule( name, FALSE )))
724 return MODULE_HANDLEtoHMODULE32( hModule );
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 );
733 return 1;
735 if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) {
736 _lclose32(hFile);
737 return hModule;
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;
745 /* recurse */
746 pModule->module32 = PE_MapImage( pModule->module32, pCurrentProcess,
747 &ofs,flags);
748 return pModule->module32;
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.
756 HINSTANCE16 PE_LoadModule( HFILE32 hFile, OFSTRUCT *ofs, LOADPARAMS* params )
758 HMODULE16 hModule16;
759 HMODULE32 hModule32;
760 HINSTANCE16 hInstance;
761 NE_MODULE *pModule;
763 if ((hModule16 = MODULE_CreateDummyModule( ofs )) < 32) return hModule16;
764 pModule = (NE_MODULE *)GlobalLock16( hModule16 );
765 pModule->flags = NE_FFLAGS_WIN32;
767 pModule->module32 = hModule32 = PE_LoadImage( hFile );
768 CloseHandle( hFile );
769 if (hModule32 < 32) return 21;
771 hInstance = MODULE_CreateInstance( hModule16, params );
772 if (!(PE_HEADER(hModule32)->FileHeader.Characteristics & IMAGE_FILE_DLL))
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) );
779 pModule->module32 = PE_MapImage( hModule32, pCurrentProcess, ofs, 0 );
780 return hInstance;
783 int PE_UnloadImage( HMODULE32 hModule )
785 printf("PEunloadImage() called!\n");
786 /* free resources, image, unmap */
787 return 1;
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)
795 static void PE_InitDLL(PE_MODREF *pem, DWORD type,LPVOID lpReserved)
797 if (type==DLL_PROCESS_ATTACH)
798 pem->flags |= PE_MODREF_PROCESS_ATTACHED;
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_*
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)
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 );
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)
823 void PE_InitializeDLLs(PDB32 *process,DWORD type,LPVOID lpReserved) {
824 PE_MODREF *pem;
826 pem = process->modref_list;
827 while (pem) {
828 if (pem->flags & PE_MODREF_NO_DLL_CALLS) {
829 pem = pem->next;
830 continue;
832 if (type==DLL_PROCESS_ATTACH) {
833 if (pem->flags & PE_MODREF_PROCESS_ATTACHED) {
834 pem = pem->next;
835 continue;
838 PE_InitDLL( pem, type, lpReserved );
839 pem = pem->next;
843 void PE_InitTls(PDB32 *pdb)
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;
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;
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;
872 /****************************************************************************
873 * DisableThreadLibraryCalls (KERNEL32.74)
874 * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
876 BOOL32 WINAPI DisableThreadLibraryCalls(HMODULE32 hModule)
878 PDB32 *process = pCurrentProcess;
879 PE_MODREF *pem = process->modref_list;
881 while (pem) {
882 if (pem->module == hModule)
883 pem->flags|=PE_MODREF_NO_DLL_CALLS;
884 pem = pem->next;
886 return TRUE;