3 * Copyright 1994 Eric Youndale & Erik Bos
4 * Copyright 1995 Martin von Löwis
6 * based on Eric Youndale's pe-test and:
8 * ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
10 * ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
18 #include <sys/types.h>
30 #include "registers.h"
35 void my_wcstombs(char * result
, u_short
* source
, int len
)
38 /* this used to be isascii, but see isascii implementation in Linux'
40 if(*source
<255) *result
++ = *source
++;
42 printf("Unable to handle unicode right now\n");
49 char * xmmap(char * vaddr
, unsigned int v_size
, unsigned int r_size
,
50 int prot
, int flags
, int fd
, unsigned int file_offset
)
53 /* .bss has no associated storage in the PE file */
57 #if defined(__svr4__) || defined(_SCO_DS)
58 fprintf(stderr
,"xmmap: %s line %d doesn't support MAP_ANON\n",__FILE__
, __LINE__
);
62 result
= mmap(vaddr
, v_size
, prot
, flags
, fd
, file_offset
);
63 if((unsigned int) result
!= 0xffffffff) return result
;
65 /* Sigh. Alignment must be wrong for mmap. Do this the hard way. */
66 if(!(flags
& MAP_FIXED
)) {
67 vaddr
= (char *)0x40000000;
71 mmap(vaddr
, v_size
, prot
, MAP_ANONYMOUS
| flags
, 0, 0);
72 lseek(fd
, file_offset
, SEEK_SET
);
73 read(fd
, vaddr
, v_size
);
78 void dump_exports(struct PE_Export_Directory
* pe_exports
, unsigned int load_addr
)
84 u_char
** name
, *ename
;
86 Module
= ((char *) load_addr
) + pe_exports
->Name
;
87 dprintf_win32(stddeb
,"\n*******EXPORT DATA*******\nModule name is %s, %ld functions, %ld names\n",
89 pe_exports
->Number_Of_Functions
,
90 pe_exports
->Number_Of_Names
);
92 ordinal
= (u_short
*) (((char *) load_addr
) + (int) pe_exports
->Address_Of_Name_Ordinals
);
93 function
= (u_long
*) (((char *) load_addr
) + (int) pe_exports
->AddressOfFunctions
);
94 name
= (u_char
**) (((char *) load_addr
) + (int) pe_exports
->AddressOfNames
);
96 dprintf_win32(stddeb
,"%-32s Ordinal Virt Addr\n", "Function Name");
97 for(i
=0; i
< pe_exports
->Number_Of_Functions
; i
++)
99 ename
= (char *) (((char *) load_addr
) + (int) *name
++);
100 dprintf_win32(stddeb
,"%-32s %4d %8.8lx\n", ename
, *ordinal
++, *function
++);
104 FARPROC32
PE_FindExportedFunction(struct pe_data
*pe
, LPCSTR funcName
)
106 struct PE_Export_Directory
* exports
= pe
->pe_export
;
107 unsigned load_addr
= pe
->load_addr
;
110 u_char
** name
, *ename
;
113 if (!exports
) return NULL
;
114 ordinal
= (u_short
*) (((char *) load_addr
) + (int) exports
->Address_Of_Name_Ordinals
);
115 function
= (u_long
*) (((char *) load_addr
) + (int) exports
->AddressOfFunctions
);
116 name
= (u_char
**) (((char *) load_addr
) + (int) exports
->AddressOfNames
);
117 for(i
=0; i
<exports
->Number_Of_Functions
; i
++)
121 ename
= (char *) (((char *) load_addr
) + (int) *name
);
122 if(strcmp(ename
,funcName
)==0)
123 return (FARPROC32
)(load_addr
+ *function
);
125 if((int)funcName
== (int)*ordinal
+ exports
->Base
)
126 return (FARPROC32
)(load_addr
+ *function
);
135 void fixup_imports(struct pe_data
*pe
, HMODULE16 hModule
)
137 struct PE_Import_Directory
* pe_imp
;
139 unsigned int load_addr
= pe
->load_addr
;
144 /* OK, now dump the import list */
145 dprintf_win32(stddeb
, "\nDumping imports list\n");
147 /* first, count the number of imported non-internal modules */
148 pe_imp
= pe
->pe_import
;
149 for(i
=0;pe_imp
->ModuleName
;pe_imp
++)
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 for(i
=0,pe_imp
= pe
->pe_import
;pe_imp
->ModuleName
;pe_imp
++)
160 char *name
= (char*)load_addr
+pe_imp
->ModuleName
;
161 mod_ptr
[i
] = LoadModule(name
,(LPVOID
)-1);
162 if(mod_ptr
[i
]<=(HMODULE16
)32)
164 char *p
, buffer
[256];
166 /* Try with prepending the path of the current module */
167 GetModuleFileName( hModule
, buffer
, sizeof(buffer
) );
168 if (!(p
= strrchr( buffer
, '\\' ))) p
= buffer
;
169 strcpy( p
+ 1, name
);
170 mod_ptr
[i
] = LoadModule( buffer
, (LPVOID
)-1 );
172 if(mod_ptr
[i
]<=(HMODULE16
)32)
174 fprintf(stderr
,"Module %s not found\n",name
);
179 pe_imp
= pe
->pe_import
;
180 while (pe_imp
->ModuleName
)
183 struct pe_import_name
* pe_name
;
184 unsigned int * import_list
, *thunk_list
;
186 Module
= ((char *) load_addr
) + pe_imp
->ModuleName
;
187 dprintf_win32(stddeb
, "%s\n", Module
);
189 if(pe_imp
->Import_List
!= 0) { /* original microsoft style */
190 dprintf_win32(stddeb
, "Microsoft style imports used\n");
191 import_list
= (unsigned int *)
192 (((unsigned int) load_addr
) + pe_imp
->Import_List
);
193 thunk_list
= (unsigned int *)
194 (((unsigned int) load_addr
) + pe_imp
->Thunk_List
);
199 pe_name
= (struct pe_import_name
*) ((int) load_addr
+ ((unsigned)*import_list
& ~0x80000000));
200 if((unsigned)*import_list
& 0x80000000)
202 int ordinal
=*import_list
& (0x80000000-1);
203 dprintf_win32(stddeb
,"--- Ordinal %s,%d\n", Module
, ordinal
);
204 *thunk_list
= GetProcAddress32(MODULE_FindModule(Module
),
208 fprintf(stderr
,"No implementation for %s.%d, setting to NULL\n",
210 /* fixup_failed=1; */
212 }else{ /* import by name */
213 dprintf_win32(stddeb
, "--- %s %s.%d\n", pe_name
->Name
, Module
, pe_name
->Hint
);
214 #ifndef WINELIB /* FIXME: JBP: Should this happen in libwine.a? */
215 *thunk_list
= GetProcAddress32(MODULE_FindModule(Module
),
219 fprintf(stderr
,"No implementation for %s.%d(%s), setting to NULL\n",
220 Module
, pe_name
->Hint
, pe_name
->Name
);
221 /* fixup_failed=1; */
225 fprintf(stderr
,"JBP: Call to RELAY32_GetEntryPoint being ignored.\n");
232 } else { /* Borland style */
233 dprintf_win32(stddeb
, "Borland style imports used\n");
234 thunk_list
= (unsigned int *)
235 (((unsigned int) load_addr
) + pe_imp
->Thunk_List
);
237 pe_name
= (struct pe_import_name
*) ((int) load_addr
+ *thunk_list
);
238 if((unsigned)pe_name
& 0x80000000) {
239 fprintf(stderr
,"Import by ordinal not supported\n");
242 dprintf_win32(stddeb
, "--- %s %s.%d\n", pe_name
->Name
, Module
, pe_name
->Hint
);
243 #ifndef WINELIB /* FIXME: JBP: Should this happen in libwine.a? */
244 *thunk_list
= GetProcAddress32(MODULE_FindModule(Module
),
247 fprintf(stderr
,"JBP: Call to RELAY32_GetEntryPoint being ignored.\n");
250 fprintf(stderr
,"No implementation for %s.%d, setting to NULL\n",
251 Module
, pe_name
->Hint
);
252 /* fixup_failed=1; */
259 if(fixup_failed
)exit(1);
262 static void calc_vma_size(struct pe_data
*pe
)
266 dprintf_win32(stddeb
, "Dump of segment table\n");
267 dprintf_win32(stddeb
, " Name VSz Vaddr SzRaw Fileadr *Reloc *Lineum #Reloc #Linum Char\n");
268 for(i
=0; i
< pe
->pe_header
->coff
.NumberOfSections
; i
++)
270 dprintf_win32(stddeb
, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n",
272 pe
->pe_seg
[i
].Virtual_Size
,
273 pe
->pe_seg
[i
].Virtual_Address
,
274 pe
->pe_seg
[i
].Size_Of_Raw_Data
,
275 pe
->pe_seg
[i
].PointerToRawData
,
276 pe
->pe_seg
[i
].PointerToRelocations
,
277 pe
->pe_seg
[i
].PointerToLinenumbers
,
278 pe
->pe_seg
[i
].NumberOfRelocations
,
279 pe
->pe_seg
[i
].NumberOfLinenumbers
,
280 pe
->pe_seg
[i
].Characteristics
);
281 pe
->vma_size
= MAX(pe
->vma_size
,
282 pe
->pe_seg
[i
].Virtual_Address
+
283 pe
->pe_seg
[i
].Size_Of_Raw_Data
);
287 static void do_relocations(struct pe_data
*pe
)
289 int delta
= pe
->load_addr
- pe
->base_addr
;
290 struct PE_Reloc_Block
*r
= pe
->pe_reloc
;
291 int hdelta
= (delta
>> 16) & 0xFFFF;
292 int ldelta
= delta
& 0xFFFF;
293 /* int reloc_size = */
299 char *page
= (char*)pe
->load_addr
+ r
->PageRVA
;
300 int count
= (r
->BlockSize
- 8)/2;
302 dprintf_fixup(stddeb
, "%x relocations for page %lx\n",
304 /* patching in reverse order */
307 int offset
= r
->Relocations
[i
] & 0xFFF;
308 int type
= r
->Relocations
[i
] >> 12;
309 dprintf_fixup(stddeb
,"patching %x type %x\n", offset
, type
);
312 case IMAGE_REL_BASED_ABSOLUTE
: break;
313 case IMAGE_REL_BASED_HIGH
:
314 *(short*)(page
+offset
) += hdelta
;
316 case IMAGE_REL_BASED_LOW
:
317 *(short*)(page
+offset
) += ldelta
;
319 case IMAGE_REL_BASED_HIGHLOW
:
321 *(int*)(page
+offset
) += delta
;
323 { int h
=*(unsigned short*)(page
+offset
);
324 int l
=r
->Relocations
[++i
];
325 *(unsigned int*)(page
+ offset
) = (h
<<16) + l
+ delta
;
329 case IMAGE_REL_BASED_HIGHADJ
:
330 fprintf(stderr
, "Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
332 case IMAGE_REL_BASED_MIPS_JMPADDR
:
333 fprintf(stderr
, "Is this a MIPS machine ???\n");
336 fprintf(stderr
, "Unknown fixup type\n");
340 r
= (struct PE_Reloc_Block
*)((char*)r
+ r
->BlockSize
);
348 /**********************************************************************
350 * Load one PE format executable into memory
352 static struct pe_data
*PE_LoadImage( int fd
, HMODULE16 hModule
, WORD offset
)
356 unsigned int load_addr
;
357 struct Directory dir
;
359 pe
= xmalloc(sizeof(struct pe_data
));
360 memset(pe
,0,sizeof(struct pe_data
));
361 pe
->pe_header
= xmalloc(sizeof(struct pe_header_s
));
364 lseek( fd
, offset
, SEEK_SET
);
365 read( fd
, pe
->pe_header
, sizeof(struct pe_header_s
));
368 pe
->pe_seg
= xmalloc(sizeof(struct pe_segment_table
) *
369 pe
->pe_header
->coff
.NumberOfSections
);
370 read( fd
, pe
->pe_seg
, sizeof(struct pe_segment_table
) *
371 pe
->pe_header
->coff
.NumberOfSections
);
373 load_addr
= pe
->pe_header
->opt_coff
.BaseOfImage
;
374 pe
->base_addr
=load_addr
;
376 dprintf_win32(stddeb
, "Load addr is %x\n",load_addr
);
379 /* We use malloc here, while a huge part of that address space does
380 not be supported by actual memory. It has to be contiguous, though.
381 I don't know if mmap("/dev/null"); would do any better.
382 What I'd really like to do is a Win32 style VirtualAlloc/MapViewOfFile
384 load_addr
= pe
->load_addr
= malloc(pe
->vma_size
);
385 dprintf_win32(stddeb
, "Load addr is really %x, range %x\n",
386 pe
->load_addr
, pe
->vma_size
);
389 for(i
=0; i
< pe
->pe_header
->coff
.NumberOfSections
; i
++)
391 /* load only non-BSS segments */
392 if(pe
->pe_seg
[i
].Characteristics
&
393 ~ IMAGE_SCN_TYPE_CNT_UNINITIALIZED_DATA
)
394 if(lseek(fd
,pe
->pe_seg
[i
].PointerToRawData
,SEEK_SET
) == -1
395 || read(fd
,load_addr
+ pe
->pe_seg
[i
].Virtual_Address
,
396 pe
->pe_seg
[i
].Size_Of_Raw_Data
)
397 != pe
->pe_seg
[i
].Size_Of_Raw_Data
)
399 fprintf(stderr
,"Failed to load section %x\n", i
);
402 result
= load_addr
+ pe
->pe_seg
[i
].Virtual_Address
;
406 result
= (int)xmmap((char *)0, pe
->pe_seg
[i
].Virtual_Size
,
407 pe
->pe_seg
[i
].Size_Of_Raw_Data
, 7,
408 MAP_PRIVATE
, fd
, pe
->pe_seg
[i
].PointerToRawData
);
409 load_addr
= (unsigned int) result
- pe
->pe_seg
[i
].Virtual_Address
;
411 result
= (int)xmmap((char *) load_addr
+ pe
->pe_seg
[i
].Virtual_Address
,
412 pe
->pe_seg
[i
].Virtual_Size
,
413 pe
->pe_seg
[i
].Size_Of_Raw_Data
, 7, MAP_PRIVATE
| MAP_FIXED
,
414 fd
, pe
->pe_seg
[i
].PointerToRawData
);
417 fprintf(stderr
,"Could not load section %x to desired address %lx\n",
418 i
, load_addr
+pe
->pe_seg
[i
].Virtual_Address
);
419 fprintf(stderr
,"Need to implement relocations now\n");
424 if(strcmp(pe
->pe_seg
[i
].Name
, ".bss") == 0)
425 memset((void *)result
, 0,
426 pe
->pe_seg
[i
].Virtual_Size
?
427 pe
->pe_seg
[i
].Virtual_Size
:
428 pe
->pe_seg
[i
].Size_Of_Raw_Data
);
430 if(strcmp(pe
->pe_seg
[i
].Name
, ".idata") == 0)
431 pe
->pe_import
= (struct PE_Import_Directory
*) result
;
433 if(strcmp(pe
->pe_seg
[i
].Name
, ".edata") == 0)
434 pe
->pe_export
= (struct PE_Export_Directory
*) result
;
436 if(strcmp(pe
->pe_seg
[i
].Name
, ".rsrc") == 0)
437 pe
->pe_resource
= (struct PE_Resource_Directory
*) result
;
439 if(strcmp(pe
->pe_seg
[i
].Name
, ".reloc") == 0)
440 pe
->pe_reloc
= (struct PE_Reloc_Block
*) result
;
444 /* There is word that the actual loader does not care about the
445 section names, and only goes for the DataDirectory */
446 dir
=pe
->pe_header
->opt_coff
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
450 pe
->pe_export
!=load_addr
+dir
.Virtual_address
)
451 fprintf(stderr
,"wrong export directory??\n");
452 /* always trust the directory */
453 pe
->pe_export
= load_addr
+dir
.Virtual_address
;
456 dir
=pe
->pe_header
->opt_coff
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
460 pe
->pe_import
!=load_addr
+dir
.Virtual_address
)
461 fprintf(stderr
,"wrong import directory??\n");
462 pe
->pe_import
= load_addr
+dir
.Virtual_address
;
465 dir
=pe
->pe_header
->opt_coff
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
468 if(pe
->pe_resource
&&
469 pe
->pe_resource
!=load_addr
+dir
.Virtual_address
)
470 fprintf(stderr
,"wrong resource directory??\n");
471 pe
->pe_resource
= load_addr
+dir
.Virtual_address
;
474 dir
=pe
->pe_header
->opt_coff
.DataDirectory
[IMAGE_FILE_BASE_RELOCATION_TABLE
];
478 pe
->pe_reloc
!=load_addr
+dir
.Virtual_address
)
479 fprintf(stderr
,"wrong relocation list??\n");
480 pe
->pe_reloc
= load_addr
+dir
.Virtual_address
;
483 if(pe
->pe_header
->opt_coff
.DataDirectory
484 [IMAGE_FILE_EXCEPTION_DIRECTORY
].Size
)
485 dprintf_win32(stdnimp
,"Exception directory ignored\n");
487 if(pe
->pe_header
->opt_coff
.DataDirectory
488 [IMAGE_FILE_SECURITY_DIRECTORY
].Size
)
489 dprintf_win32(stdnimp
,"Security directory ignored\n");
491 if(pe
->pe_header
->opt_coff
.DataDirectory
492 [IMAGE_FILE_DEBUG_DIRECTORY
].Size
)
493 dprintf_win32(stdnimp
,"Debug directory ignored\n");
495 if(pe
->pe_header
->opt_coff
.DataDirectory
496 [IMAGE_FILE_DESCRIPTION_STRING
].Size
)
497 dprintf_win32(stdnimp
,"Description string ignored\n");
499 if(pe
->pe_header
->opt_coff
.DataDirectory
500 [IMAGE_FILE_MACHINE_VALUE
].Size
)
501 dprintf_win32(stdnimp
,"Machine Value ignored\n");
503 if(pe
->pe_header
->opt_coff
.DataDirectory
504 [IMAGE_FILE_THREAD_LOCAL_STORAGE
].Size
)
505 dprintf_win32(stdnimp
,"Thread local storage ignored\n");
507 if(pe
->pe_header
->opt_coff
.DataDirectory
508 [IMAGE_FILE_CALLBACK_DIRECTORY
].Size
)
509 dprintf_win32(stdnimp
,"Callback directory ignored\n");
512 if(pe
->pe_import
) fixup_imports(pe
, hModule
);
513 if(pe
->pe_export
) dump_exports(pe
->pe_export
,load_addr
);
514 if(pe
->pe_reloc
) do_relocations(pe
);
518 HINSTANCE
MODULE_CreateInstance(HMODULE16 hModule
,LOADPARAMS
*params
);
519 void InitTask( SIGCONTEXT
*context
);
521 HINSTANCE
PE_LoadModule( int fd
, OFSTRUCT
*ofs
, LOADPARAMS
* params
)
524 HINSTANCE16 hInstance
;
526 SEGTABLEENTRY
*pSegment
;
528 struct mz_header_s mz_header
;
530 if ((hModule
= MODULE_CreateDummyModule( ofs
)) < 32) return hModule
;
531 pModule
= (NE_MODULE
*)GlobalLock16( hModule
);
532 pModule
->flags
= NE_FFLAGS_WIN32
;
534 lseek( fd
, 0, SEEK_SET
);
535 read( fd
, &mz_header
, sizeof(mz_header
) );
537 /* Set the startup address */
539 startup
= MODULE_GetWndProcEntry16("Win32CallToStart");
540 pSegment
= NE_SEG_TABLE(pModule
) + pModule
->cs
- 1;
541 pSegment
->selector
= SELECTOROF(startup
); /* FIXME */
542 pModule
->ip
= OFFSETOF(startup
);
544 pModule
->pe_module
= PE_LoadImage( fd
, hModule
, mz_header
.ne_offset
);
546 hInstance
= MODULE_CreateInstance( hModule
, params
);
548 if (!(pModule
->pe_module
->pe_header
->coff
.Characteristics
& IMAGE_FILE_DLL
))
550 TASK_CreateTask( hModule
, hInstance
, 0,
551 params
->hEnvironment
,
552 (LPSTR
)PTR_SEG_TO_LIN( params
->cmdLine
),
553 *((WORD
*)PTR_SEG_TO_LIN(params
->showCmd
) + 1) );
554 PE_InitializeDLLs( hModule
);
559 int USER_InitApp(HINSTANCE hInstance
);
560 void PE_InitTEB(int hTEB
);
562 void PE_Win32CallToStart( SIGCONTEXT
*context
)
568 dprintf_win32(stddeb
,"Going to start Win32 program\n");
570 hModule
= GetExePtr( GetCurrentTask() );
571 pModule
= MODULE_GetPtr( hModule
);
572 USER_InitApp( hModule
);
573 fs
=(int)GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, 0x10000 );
575 __asm__
__volatile__("movw %w0,%%fs"::"r" (fs
));
576 CallTaskStart32( (FARPROC32
)(pModule
->pe_module
->load_addr
+
577 pModule
->pe_module
->pe_header
->opt_coff
.AddressOfEntryPoint
) );
580 int PE_UnloadImage( HMODULE16 hModule
)
582 printf("PEunloadImage() called!\n");
583 /* free resources, image, unmap */
587 static void PE_InitDLL(HMODULE16 hModule
)
592 hModule
= GetExePtr(hModule
);
593 if (!(pModule
= MODULE_GetPtr(hModule
))) return;
594 if (!(pModule
->flags
& NE_FFLAGS_WIN32
) || !(pe
= pModule
->pe_module
))
597 /* FIXME: What are the correct values for parameters 2 and 3? */
599 /* Is this a library? */
600 if (pe
->pe_header
->coff
.Characteristics
& IMAGE_FILE_DLL
)
602 printf("InitPEDLL() called!\n");
603 CallDLLEntryProc32( (FARPROC32
)(pe
->load_addr
+
604 pe
->pe_header
->opt_coff
.AddressOfEntryPoint
),
610 /* FIXME: This stuff is all on a "well it works" basis. An implementation
611 based on some kind of documentation would be greatly appreciated :-) */
618 struct TEB
*TEBDSAlias
;
623 void PE_InitTEB(int hTEB
)
628 pTask
= (TDB
*)(GlobalLock16(GetCurrentTask() & 0xffff));
629 pTEB
= (TEB
*)(PTR_SEG_OFF_TO_LIN(hTEB
, 0));
630 pTEB
->stack
= (void *)(GlobalLock16(pTask
->hStack32
));
631 pTEB
->Except
= (void *)(-1);
632 pTEB
->TEBDSAlias
= pTEB
;
633 pTEB
->taskid
= getpid();
636 void PE_InitializeDLLs(HMODULE16 hModule
)
640 pModule
= MODULE_GetPtr( GetExePtr(hModule
) );
641 if (pModule
->dlls_to_init
)
643 HANDLE to_init
= pModule
->dlls_to_init
;
644 pModule
->dlls_to_init
= 0;
645 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
647 PE_InitializeDLLs( *pDLL
);
650 GlobalFree16( to_init
);
652 PE_InitDLL( hModule
);