1 static char RCSId
[] = "$Id: wine.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright
[] = "Copyright Robert J. Amstadt, 1993";
11 #include <linux/unistd.h>
12 #include <linux/head.h>
13 #include <linux/ldt.h>
14 #include <linux/segment.h>
20 #include "prototypes.h"
25 extern int CallToInit16(unsigned long csip
, unsigned long sssp
,
27 extern void CallTo32();
29 char * GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
);
30 extern unsigned char ran_out
;
31 unsigned short WIN_StackSize
;
32 unsigned short WIN_HeapSize
;
34 struct w_files
* wine_files
= NULL
;
38 struct mz_header_s
*CurrentMZHeader
;
39 struct ne_header_s
*CurrentNEHeader
;
42 static char *dllExtensions
[] = { "dll", "exe", NULL
};
43 static char *exeExtensions
[] = { "exe", NULL
};
44 static char *WinePath
= NULL
;
46 /**********************************************************************
50 DebugPrintString(char *str
)
56 /**********************************************************************
60 myerror(const char *s
)
65 fprintf(stderr
, "wine: %s\n", s
);
70 /**********************************************************************
71 * GetFilenameFromInstance
74 GetFilenameFromInstance(unsigned short instance
)
76 register struct w_files
*w
= wine_files
;
78 while (w
&& w
->hinstance
!= instance
)
88 GetFileInfo(unsigned short instance
)
90 register struct w_files
*w
= wine_files
;
92 while (w
&& w
->hinstance
!= instance
)
98 /**********************************************************************
100 * Load one NE format executable into memory
102 LoadImage(char * filename
, char * modulename
)
104 unsigned int read_size
;
106 struct w_files
* wpnt
, *wpnt1
;
109 /* First allocate a spot to store the info we collect, and add it to
113 wpnt
= (struct w_files
*) malloc(sizeof(struct w_files
));
114 if(wine_files
== NULL
)
118 while(wpnt1
->next
) wpnt1
= wpnt1
->next
;
124 * Open file for reading.
126 wpnt
->fd
= open(filename
, O_RDONLY
);
132 * Establish header pointers.
134 wpnt
->filename
= strdup(filename
);
136 if(modulename
) wpnt
->name
= strdup(modulename
);
138 wpnt
->mz_header
= (struct mz_header_s
*) malloc(sizeof(struct mz_header_s
));;
139 status
= lseek(wpnt
->fd
, 0, SEEK_SET
);
140 if (read(wpnt
->fd
, wpnt
->mz_header
, sizeof(struct mz_header_s
)) !=
141 sizeof(struct mz_header_s
))
143 myerror("Unable to read MZ header from file");
145 if (wpnt
->mz_header
->must_be_0x40
!= 0x40)
146 myerror("This is not a Windows program");
148 wpnt
->ne_header
= (struct ne_header_s
*) malloc(sizeof(struct ne_header_s
));
149 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
, SEEK_SET
);
150 if (read(wpnt
->fd
, wpnt
->ne_header
, sizeof(struct ne_header_s
))
151 != sizeof(struct ne_header_s
))
153 myerror("Unable to read NE header from file");
155 if (wpnt
->ne_header
->header_type
[0] != 'N' ||
156 wpnt
->ne_header
->header_type
[1] != 'E')
157 myerror("This is not a Windows program");
159 if(wine_files
== wpnt
){
160 CurrentMZHeader
= wpnt
->mz_header
;
161 CurrentNEHeader
= wpnt
->ne_header
;
162 CurrentNEFile
= wpnt
->fd
;
164 WIN_StackSize
= wpnt
->ne_header
->stack_length
;
165 WIN_HeapSize
= wpnt
->ne_header
->local_heap_length
;
169 * Create segment selectors.
171 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
172 wpnt
->ne_header
->segment_tab_offset
,
174 read_size
= wpnt
->ne_header
->n_segment_tab
*
175 sizeof(struct ne_segment_table_entry_s
);
176 wpnt
->seg_table
= (struct ne_segment_table_entry_s
*) malloc(read_size
);
177 if (read(wpnt
->fd
, wpnt
->seg_table
, read_size
) != read_size
)
178 myerror("Unable to read segment table header from file");
179 wpnt
->selector_table
= CreateSelectors(wpnt
);
182 selector_table
[wine_files
->ne_header
->auto_data_seg
-1].selector
;
184 /* Get the lookup table. This is used for looking up the addresses
185 of functions that are exported */
187 read_size
= wpnt
->ne_header
->entry_tab_length
;
188 wpnt
->lookup_table
= (char *) malloc(read_size
);
189 lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
190 wpnt
->ne_header
->entry_tab_offset
, SEEK_SET
);
191 if (read(wpnt
->fd
, wpnt
->lookup_table
, read_size
) != read_size
)
192 myerror("Unable to read lookup table header from file");
194 /* Get the iname table. This is used for looking up the names
195 of functions that are exported */
197 status
= lseek(wpnt
->fd
, wpnt
->ne_header
->nrname_tab_offset
, SEEK_SET
);
198 read_size
= wpnt
->ne_header
->nrname_tab_length
;
199 wpnt
->nrname_table
= (char *) malloc(read_size
);
200 if (read(wpnt
->fd
, wpnt
->nrname_table
, read_size
) != read_size
)
201 myerror("Unable to read nrname table header from file");
203 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
204 wpnt
->ne_header
->rname_tab_offset
, SEEK_SET
);
205 read_size
= wpnt
->ne_header
->moduleref_tab_offset
-
206 wpnt
->ne_header
->rname_tab_offset
;
207 wpnt
->rname_table
= (char *) malloc(read_size
);
208 if (read(wpnt
->fd
, wpnt
->rname_table
, read_size
) != read_size
)
209 myerror("Unable to read rname table header from file");
211 /* Now get the module name */
213 wpnt
->name
= (char*) malloc(*wpnt
->rname_table
+ 1);
214 memcpy(wpnt
->name
, wpnt
->rname_table
+1, *wpnt
->rname_table
);
215 wpnt
->name
[*wpnt
->rname_table
] = 0;
218 * Now load any DLLs that this module refers to.
220 for(i
=0; i
<wpnt
->ne_header
->n_mod_ref_tab
; i
++){
224 GetModuleName(wpnt
, i
+ 1, buff
);
226 if(FindDLLTable(buff
)) continue; /* This module already loaded */
228 if (FindFileInPath(buff2
, sizeof(buff2
),
229 buff
, dllExtensions
, WinePath
) != NULL
&&
230 (fd
= open(buff2
, O_RDONLY
)) >= 0)
233 LoadImage(buff2
, buff
);
237 fprintf(stderr
,"Unable to load:%s\n", buff
);
242 /**********************************************************************
245 _WinMain(int argc
, char **argv
)
253 struct w_files
* wpnt
;
254 int cs_reg
, ds_reg
, ss_reg
, ip_reg
, sp_reg
;
263 fprintf(stderr
, "usage: %s FILENAME\n", argv
[0]);
267 p
= getenv("WINEPATH");
268 WinePath
= malloc(256 + strlen(p
));
269 getcwd(WinePath
, 256);
270 strcat(WinePath
, ";");
273 if (FindFileInPath(exe_path
, 256, argv
[1], exeExtensions
, WinePath
)
276 fprintf(stderr
, "Could not find file '%s'\n", argv
[1]);
280 LoadImage(exe_path
, NULL
);
284 GetEntryDLLName("USER", "INITAPP", 0, 0);
285 for(i
=0; i
<1024; i
++) {
287 j
= GetEntryPointFromOrdinal(wine_files
, i
);
289 fprintf(stderr
," %d %x\n", i
, j
);
296 for(wpnt
= wine_files
; wpnt
; wpnt
= wpnt
->next
)
297 for (segment
= 0; segment
< wpnt
->ne_header
->n_segment_tab
; segment
++)
299 if (FixupSegment(wpnt
, segment
) < 0)
301 myerror("fixup failed.");
306 * Fixup stack and jump to start.
308 ds_reg
= wine_files
->selector_table
[wine_files
->ne_header
->auto_data_seg
-1].selector
;
309 cs_reg
= wine_files
->selector_table
[wine_files
->ne_header
->cs
-1].selector
;
310 ip_reg
= wine_files
->ne_header
->ip
;
311 ss_reg
= wine_files
->selector_table
[wine_files
->ne_header
->ss
-1].selector
;
312 sp_reg
= wine_files
->ne_header
->sp
;
315 cp
= strrchr(argv
[0], '/');
316 if(!cp
) cp
= argv
[0];
318 if(strcmp(cp
,"winestat") == 0) {
326 rv
= CallToInit16(cs_reg
<< 16 | ip_reg
, ss_reg
<< 16 | sp_reg
, ds_reg
);
327 printf ("rv = %x\n", rv
);
331 /**********************************************************************
335 GetImportedName(int fd
, struct mz_header_s
*mz_header
,
336 struct ne_header_s
*ne_header
, int name_offset
, char *buffer
)
343 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
344 name_offset
, SEEK_SET
);
346 read(fd
, &length
, 1); /* Get the length byte */
347 read(fd
, buffer
, length
);
352 /**********************************************************************
356 GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
)
359 struct mz_header_s
*mz_header
= wpnt
->mz_header
;
360 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
363 int name_offset
, status
;
366 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->moduleref_tab_offset
+
367 2*(index
- 1), SEEK_SET
);
369 read(fd
, &name_offset
, 2);
370 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
371 name_offset
, SEEK_SET
);
373 read(fd
, &length
, 1); /* Get the length byte */
374 read(fd
, buffer
, length
);
377 /* Module names are always upper case */
378 for(i
=0; i
<length
; i
++)
379 if(buffer
[i
] >= 'a' && buffer
[i
] <= 'z') buffer
[i
] &= ~0x20;
385 /**********************************************************************
389 FixupSegment(struct w_files
* wpnt
, int segment_num
)
392 struct mz_header_s
* mz_header
= wpnt
->mz_header
;
393 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
394 struct ne_segment_table_entry_s
*seg_table
= wpnt
->seg_table
;
395 struct segment_descriptor_s
*selector_table
= wpnt
->selector_table
;
397 struct relocation_entry_s
*rep
, *rep1
;
398 struct ne_segment_table_entry_s
*seg
;
399 struct segment_descriptor_s
*sel
;
400 struct dll_table_entry_s
*dll_table
;
403 unsigned int selector
, address
;
404 unsigned int next_addr
;
410 seg
= &seg_table
[segment_num
];
411 sel
= &selector_table
[segment_num
];
413 if ((seg
->seg_data_offset
== 0) ||
414 !(seg
->seg_flags
& NE_SEGFLAGS_RELOC_DATA
))
418 * Go through the relocation table on entry at a time.
420 i
= seg
->seg_data_length
;
424 status
= lseek(fd
, seg
->seg_data_offset
*
425 (1 << ne_header
->align_shift_count
) + i
, SEEK_SET
);
427 read(fd
, &n_entries
, sizeof(short int));
428 rep
= (struct relocation_entry_s
*)
429 malloc(n_entries
* sizeof(struct relocation_entry_s
));
431 if (read(fd
,rep
, n_entries
* sizeof(struct relocation_entry_s
)) !=
432 n_entries
* sizeof(struct relocation_entry_s
))
434 myerror("Unable to read relocation information");
439 for (i
= 0; i
< n_entries
; i
++, rep
++)
442 * Get the target address corresponding to this entry.
444 switch (rep
->relocation_type
)
446 case NE_RELTYPE_ORDINAL
:
447 if (GetModuleName(wpnt
, rep
->target1
,
450 fprintf(stderr
, "NE_RELTYPE_ORDINAL failed");
454 ordinal
= rep
->target2
;
456 status
= GetEntryDLLOrdinal(dll_name
, ordinal
, &selector
,
462 sprintf(s
, "Bad DLL name '%s.%d'", dll_name
, ordinal
);
468 printf("%d: %s.%d: %04.4x:%04.4x\n", i
+ 1, dll_name
, ordinal
,
473 case NE_RELTYPE_NAME
:
474 if (GetModuleName(wpnt
, rep
->target1
, dll_name
)
477 fprintf(stderr
,"NE_RELTYPE_NAME failed");
481 if (GetImportedName(fd
, mz_header
, ne_header
,
482 rep
->target2
, func_name
) == NULL
)
484 fprintf(stderr
,"getimportedname failed");
488 status
= GetEntryDLLName(dll_name
, func_name
, &selector
,
494 sprintf(s
, "Bad DLL name '%s (%s)'", dll_name
,func_name
);
500 printf("%d: %s %s.%d: %04.4x:%04.4x\n", i
+ 1, func_name
,
501 dll_name
, ordinal
, selector
, address
);
505 case NE_RELTYPE_INTERNAL
:
506 case NE_RELTYPE_INT1
:
507 if (rep
->target1
== 0x00ff)
509 address
= GetEntryPointFromOrdinal(wpnt
, rep
->target2
);
510 selector
= (address
>> 16) & 0xffff;
515 selector
= selector_table
[rep
->target1
-1].selector
;
516 address
= rep
->target2
;
520 printf("%d: %04.4x:%04.4x\n", i
+ 1, selector
, address
);
525 /* Relocation type 7:
527 * These appear to be used as fixups for the Windows
528 * floating point emulator. Let's just ignore them and
529 * try to use the hardware floating point. Linux should
530 * successfully emulate the coprocessor if it doesn't
534 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
535 i
+ 1, rep
->address_type
, rep
->relocation_type
,
537 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
543 fprintf(stderr
,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
544 i
+ 1, rep
->address_type
, rep
->relocation_type
,
546 fprintf(stderr
,"TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
554 * Stuff the right size result in.
556 sp
= (unsigned short *) ((char *) sel
->base_addr
+ rep
->offset
);
557 switch (rep
->address_type
)
559 case NE_RADDR_OFFSET16
:
562 *sp
= (unsigned short) address
;
563 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
565 while (next_addr
!= 0xffff);
569 case NE_RADDR_POINTER32
:
572 *sp
= (unsigned short) address
;
573 *(sp
+1) = (unsigned short) selector
;
574 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
576 while (next_addr
!= 0xffff);
580 case NE_RADDR_SELECTOR
:
583 *sp
= (unsigned short) selector
;
584 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
585 if (rep
->relocation_type
== NE_RELTYPE_INT1
) break;
588 while (next_addr
!= 0xffff);
594 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
595 i
+ 1, rep
->address_type
, rep
->relocation_type
,
597 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
608 /**********************************************************************
611 FARPROC
GetProcAddress(HINSTANCE hinstance
, char *proc_name
)
613 if ((int) proc_name
& 0xffff0000)
614 printf("GetProcAddress: %#04x, '%s'\n", hinstance
, proc_name
);
616 printf("GetProcAddress: %#04x, %d\n", hinstance
, (int) proc_name
);