3 * Copyright 1994 Eric Youndale & Erik Bos
5 * based on Eric Youndale's pe-test and:
7 * ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
15 #include <sys/types.h>
28 #include "registers.h"
29 #include "selectors.h"
34 #define MAP_ANONYMOUS 0x20
36 struct w_files
*wine_files
= NULL
;
38 unsigned int load_addr
;
40 void my_wcstombs(char * result
, u_short
* source
, int len
)
43 if(isascii(*source
)) *result
++ = *source
++;
45 printf("Unable to handle unicode right now\n");
51 char * xmmap(char * vaddr
, unsigned int v_size
, unsigned int r_size
,
52 int prot
, int flags
, int fd
, unsigned int file_offset
)
55 /* .bss has no associated storage in the PE file */
60 fprintf(stderr
,"xmmap: %s line %d doesn't support MAP_ANON\n",__FILE__
, __LINE__
);
64 result
= mmap(vaddr
, v_size
, prot
, flags
, fd
, file_offset
);
65 if((unsigned int) result
!= 0xffffffff) return result
;
67 /* Sigh. Alignment must be wrong for mmap. Do this the hard way. */
68 if(!(flags
& MAP_FIXED
)) {
69 vaddr
= (char *)0x40000000;
73 mmap(vaddr
, v_size
, prot
, MAP_ANONYMOUS
| flags
, 0, 0);
74 lseek(fd
, file_offset
, SEEK_SET
);
75 read(fd
, vaddr
, v_size
);
79 void dump_exports(struct PE_Export_Directory
* pe_exports
)
85 u_char
** name
, *ename
;
87 Module
= ((char *) load_addr
) + pe_exports
->Name
;
88 printf("\n*******EXPORT DATA*******\nModule name is %s, %ld functions, %ld names\n",
90 pe_exports
->Number_Of_Functions
,
91 pe_exports
->Number_Of_Names
);
93 ordinal
= (u_short
*) (((char *) load_addr
) + (int) pe_exports
->Address_Of_Name_Ordinals
);
94 function
= (u_long
*) (((char *) load_addr
) + (int) pe_exports
->AddressOfFunctions
);
95 name
= (u_char
**) (((char *) load_addr
) + (int) pe_exports
->AddressOfNames
);
97 printf("%-32s Ordinal Virt Addr\n", "Function Name");
98 for(i
=0; i
< pe_exports
->Number_Of_Functions
; i
++)
100 ename
= (char *) (((char *) load_addr
) + (int) *name
++);
101 printf("%-32s %4d %8.8lx\n", ename
, *ordinal
++, *function
++);
105 void fixup_imports(struct PE_Import_Directory
*pe_imports
)
107 struct PE_Import_Directory
* pe_imp
;
110 /* OK, now dump the import list */
111 dprintf_win32(stddeb
, "\nDumping imports list\n");
113 while (pe_imp
->ModuleName
)
116 struct pe_import_name
* pe_name
;
117 unsigned int * import_list
, *thunk_list
;
120 Module
= ((char *) load_addr
) + pe_imp
->ModuleName
;
121 dprintf_win32(stddeb
, "%s\n", Module
);
122 c
= strchr(Module
, '.');
125 import_list
= (unsigned int *)
126 (((unsigned int) load_addr
) + pe_imp
->Import_List
);
127 thunk_list
= (unsigned int *)
128 (((unsigned int) load_addr
) + pe_imp
->Thunk_List
);
133 pe_name
= (struct pe_import_name
*) ((int) load_addr
+ *import_list
);
134 if((unsigned)pe_name
& 0x80000000)
136 fprintf(stderr
,"Import by ordinal not supported\n");
139 dprintf_win32(stddeb
, "--- %s %s.%d\n", pe_name
->Name
, Module
, pe_name
->Hint
);
140 #ifndef WINELIB /* FIXME: JBP: Should this happen in libwine.a? */
141 *thunk_list
=(unsigned int)RELAY32_GetEntryPoint(Module
,pe_name
->Name
,pe_name
->Hint
);
143 fprintf(stderr
,"JBP: Call to RELAY32_GetEntryPoint being ignored.\n");
147 fprintf(stderr
,"No implementation for %s.%d\n",Module
, pe_name
->Hint
);
156 if(fixup_failed
)exit(1);
159 static void dump_table(struct w_files
*wpnt
)
163 dprintf_win32(stddeb
, "Dump of segment table\n");
164 dprintf_win32(stddeb
, " Name VSz Vaddr SzRaw Fileadr *Reloc *Lineum #Reloc #Linum Char\n");
165 for(i
=0; i
< wpnt
->pe
->pe_header
->coff
.NumberOfSections
; i
++)
167 dprintf_win32(stddeb
, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n",
168 wpnt
->pe
->pe_seg
[i
].Name
,
169 wpnt
->pe
->pe_seg
[i
].Virtual_Size
,
170 wpnt
->pe
->pe_seg
[i
].Virtual_Address
,
171 wpnt
->pe
->pe_seg
[i
].Size_Of_Raw_Data
,
172 wpnt
->pe
->pe_seg
[i
].PointerToRawData
,
173 wpnt
->pe
->pe_seg
[i
].PointerToRelocations
,
174 wpnt
->pe
->pe_seg
[i
].PointerToLinenumbers
,
175 wpnt
->pe
->pe_seg
[i
].NumberOfRelocations
,
176 wpnt
->pe
->pe_seg
[i
].NumberOfLinenumbers
,
177 wpnt
->pe
->pe_seg
[i
].Characteristics
);
181 /**********************************************************************
183 * Load one PE format executable into memory
185 HINSTANCE
PE_LoadImage(struct w_files
*wpnt
)
189 wpnt
->pe
= xmalloc(sizeof(struct pe_data
));
190 memset(wpnt
->pe
,0,sizeof(struct pe_data
));
191 wpnt
->pe
->pe_header
= xmalloc(sizeof(struct pe_header_s
));
194 lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
, SEEK_SET
);
195 read(wpnt
->fd
, wpnt
->pe
->pe_header
, sizeof(struct pe_header_s
));
198 wpnt
->pe
->pe_seg
= xmalloc(sizeof(struct pe_segment_table
) *
199 wpnt
->pe
->pe_header
->coff
.NumberOfSections
);
200 read(wpnt
->fd
, wpnt
->pe
->pe_seg
, sizeof(struct pe_segment_table
) *
201 wpnt
->pe
->pe_header
->coff
.NumberOfSections
);
203 load_addr
= wpnt
->pe
->pe_header
->opt_coff
.BaseOfImage
;
204 dprintf_win32(stddeb
, "Load addr is %x\n",load_addr
);
207 for(i
=0; i
< wpnt
->pe
->pe_header
->coff
.NumberOfSections
; i
++)
210 result
= (int)xmmap((char *)0, wpnt
->pe
->pe_seg
[i
].Virtual_Size
,
211 wpnt
->pe
->pe_seg
[i
].Size_Of_Raw_Data
, 7,
212 MAP_PRIVATE
, wpnt
->fd
, wpnt
->pe
->pe_seg
[i
].PointerToRawData
);
213 load_addr
= (unsigned int) result
- wpnt
->pe
->pe_seg
[i
].Virtual_Address
;
215 result
= (int)xmmap((char *) load_addr
+ wpnt
->pe
->pe_seg
[i
].Virtual_Address
,
216 wpnt
->pe
->pe_seg
[i
].Virtual_Size
,
217 wpnt
->pe
->pe_seg
[i
].Size_Of_Raw_Data
, 7, MAP_PRIVATE
| MAP_FIXED
,
218 wpnt
->fd
, wpnt
->pe
->pe_seg
[i
].PointerToRawData
);
221 fprintf(stderr
,"Could not load section %x to desired address %lx\n",
222 i
, load_addr
+wpnt
->pe
->pe_seg
[i
].Virtual_Address
);
223 fprintf(stderr
,"Need to implement relocations now\n");
227 if(strcmp(wpnt
->pe
->pe_seg
[i
].Name
, ".idata") == 0)
228 wpnt
->pe
->pe_import
= (struct PE_Import_Directory
*) result
;
230 if(strcmp(wpnt
->pe
->pe_seg
[i
].Name
, ".edata") == 0)
231 wpnt
->pe
->pe_export
= (struct PE_Export_Directory
*) result
;
233 if(strcmp(wpnt
->pe
->pe_seg
[i
].Name
, ".rsrc") == 0) {
234 wpnt
->pe
->pe_resource
= (struct PE_Resource_Directory
*) result
;
236 /* save offset for PE_FindResource */
237 wpnt
->pe
->resource_offset
= wpnt
->pe
->pe_seg
[i
].Virtual_Address
-
238 wpnt
->pe
->pe_seg
[i
].PointerToRawData
;
242 if(wpnt
->pe
->pe_import
) fixup_imports(wpnt
->pe
->pe_import
);
243 if(wpnt
->pe
->pe_export
) dump_exports(wpnt
->pe
->pe_export
);
245 wpnt
->hinstance
= (HINSTANCE
)0x8000;
246 return (wpnt
->hinstance
);
249 HINSTANCE
MODULE_CreateInstance(HMODULE hModule
,LOADPARAMS
*params
);
250 void InitTask(struct sigcontext_struct context
);
252 HINSTANCE
PE_LoadModule(int fd
, OFSTRUCT
*ofs
, LOADPARAMS
* params
)
254 struct w_files
*wpnt
;
257 LOADEDFILEINFO
*pFileInfo
;
258 SEGTABLEENTRY
*pSegment
;
266 wpnt
=xmalloc(sizeof(struct w_files
));
267 wpnt
->next
=wine_files
;
275 lseek(fd
,0,SEEK_SET
);
276 wpnt
->mz_header
=xmalloc(sizeof(struct mz_header_s
));
277 read(fd
,wpnt
->mz_header
,sizeof(struct mz_header_s
));
279 size
=sizeof(NE_MODULE
) +
280 /* loaded file info */
281 sizeof(LOADEDFILEINFO
) + strlen(ofs
->szPathName
) +
282 /* segment table: DS,CS */
283 2 * sizeof(SEGTABLEENTRY
) +
286 /* several empty tables */
289 hModule
= GlobalAlloc( GMEM_MOVEABLE
| GMEM_ZEROINIT
, size
);
290 wpnt
->hModule
=hModule
;
291 if (!hModule
) return (HINSTANCE
)11; /* invalid exe */
293 FarSetOwner( hModule
, hModule
);
295 pModule
= (NE_MODULE
*)GlobalLock(hModule
);
297 /* Set all used entries */
298 pModule
->magic
=NE_SIGNATURE
;
305 /* Who wants to LocalAlloc for a PE Module? */
306 pModule
->heap_size
=0x1000;
307 pModule
->stack_size
=0xF000;
308 pModule
->seg_count
=1;
309 pModule
->modref_count
=0;
310 pModule
->nrname_size
=0;
311 pModule
->seg_table
=sizeof(NE_MODULE
)+
312 sizeof(LOADEDFILEINFO
)+strlen(ofs
->szPathName
);
313 pModule
->fileinfo
=sizeof(NE_MODULE
);
314 pModule
->os_flags
=NE_OSFLAGS_WINDOWS
;
315 pModule
->expected_version
=0x30A;
317 pFileInfo
=(LOADEDFILEINFO
*)(pModule
+ 1);
318 pFileInfo
->length
= sizeof(LOADEDFILEINFO
)+strlen(ofs
->szPathName
)-1;
319 strcpy(pFileInfo
->filename
,ofs
->szPathName
);
321 pSegment
=(SEGTABLEENTRY
*)((char*)pFileInfo
+pFileInfo
->length
+1);
322 pModule
->dgroup_entry
=(int)pSegment
-(int)pModule
;
324 pSegment
->flags
=NE_SEGFLAGS_DATA
;
325 pSegment
->minsize
=0x1000;
328 cts
=(DWORD
)GetWndProcEntry16("Win32CallToStart");
330 pSegment
->selector
=(void*)cts
;
333 pSegment
->selector
=cts
>>16;
334 pModule
->ip
=cts
& 0xFFFF;
338 pStr
=(char*)pSegment
;
339 pModule
->name_table
=(int)pStr
-(int)pModule
;
340 strcpy(pStr
,"\x08W32SXXXX");
343 /* All tables zero terminated */
344 pModule
->res_table
=pModule
->import_table
=pModule
->entry_table
=
345 (int)pStr
-(int)pModule
;
349 pModule
->heap_size
=0x1000;
350 pModule
->stack_size
=0xE000;
352 /* CreateInstance allocates now 64KB */
353 hInstance
=MODULE_CreateInstance(hModule
,NULL
/* FIX: NULL? really? */);
354 wpnt
->hinstance
=hInstance
;
356 TASK_CreateTask(hModule
,hInstance
,0,
357 params
->hEnvironment
,(LPSTR
)PTR_SEG_TO_LIN(params
->cmdLine
),
358 *((WORD
*)PTR_SEG_TO_LIN(params
->showCmd
)+1));
363 int USER_InitApp(HINSTANCE hInstance
);
365 void PE_Win32CallToStart(struct sigcontext_struct context
)
368 struct w_files
*wpnt
=wine_files
;
369 fs
=(int)GlobalAlloc(GHND
,0x10000);
370 dprintf_win32(stddeb
,"Going to start Win32 program\n");
372 USER_InitApp(wpnt
->hModule
);
373 __asm__
__volatile__("movw %w0,%%fs"::"r" (fs
));
374 ((void(*)())(load_addr
+wpnt
->pe
->pe_header
->opt_coff
.AddressOfEntryPoint
))();
377 int PE_UnloadImage(struct w_files
*wpnt
)
379 printf("PEunloadImage() called!\n");
380 /* free resources, image, unmap */
384 void PE_InitDLL(struct w_files
*wpnt
)
386 /* Is this a library? */
387 if (wpnt
->pe
->pe_header
->coff
.Characteristics
& IMAGE_FILE_DLL
) {
388 printf("InitPEDLL() called!\n");