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";
10 #include <linux/unistd.h>
11 #include <linux/head.h>
12 #include <linux/ldt.h>
13 #include <linux/segment.h>
18 #include "prototypes.h"
22 extern int CallToInit16(unsigned long csip
, unsigned long sssp
,
24 extern void CallTo32();
26 char * GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
);
27 extern unsigned char ran_out
;
28 unsigned short WIN_StackSize
;
29 unsigned short WIN_HeapSize
;
31 struct w_files
* wine_files
= NULL
;
35 struct mz_header_s
*CurrentMZHeader
;
36 struct ne_header_s
*CurrentNEHeader
;
39 /**********************************************************************
43 DebugPrintString(char *str
)
49 /**********************************************************************
53 myerror(const char *s
)
57 sprintf(buffer
, "%s", Argv
[0]);
61 fprintf(stderr
, "%s: %s\n", buffer
, s
);
67 /* Load one NE format executable into memory */
68 LoadImage(char * filename
, char * modulename
)
70 unsigned int read_size
;
72 struct w_files
* wpnt
, *wpnt1
;
75 /* First allocate a spot to store the info we collect, and add it to
79 wpnt
= (struct w_files
*) malloc(sizeof(struct w_files
));
80 if(wine_files
== NULL
)
84 while(wpnt1
->next
) wpnt1
= wpnt1
->next
;
90 * Open file for reading.
92 wpnt
->fd
= open(filename
, O_RDONLY
);
98 * Establish header pointers.
100 wpnt
->filename
= strdup(filename
);
102 if(modulename
) wpnt
->name
= strdup(modulename
);
104 wpnt
->mz_header
= (struct mz_header_s
*) malloc(sizeof(struct mz_header_s
));;
105 status
= lseek(wpnt
->fd
, 0, SEEK_SET
);
106 if (read(wpnt
->fd
, wpnt
->mz_header
, sizeof(struct mz_header_s
)) !=
107 sizeof(struct mz_header_s
))
109 myerror("Unable to read MZ header from file");
111 if (wpnt
->mz_header
->must_be_0x40
!= 0x40)
112 myerror("This is not a Windows program");
114 wpnt
->ne_header
= (struct ne_header_s
*) malloc(sizeof(struct ne_header_s
));
115 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
, SEEK_SET
);
116 if (read(wpnt
->fd
, wpnt
->ne_header
, sizeof(struct ne_header_s
))
117 != sizeof(struct ne_header_s
))
119 myerror("Unable to read NE header from file");
121 if (wpnt
->ne_header
->header_type
[0] != 'N' ||
122 wpnt
->ne_header
->header_type
[1] != 'E')
123 myerror("This is not a Windows program");
125 if(wine_files
== wpnt
){
126 CurrentMZHeader
= wpnt
->mz_header
;
127 CurrentNEHeader
= wpnt
->ne_header
;
128 CurrentNEFile
= wpnt
->fd
;
130 WIN_StackSize
= wpnt
->ne_header
->stack_length
;
131 WIN_HeapSize
= wpnt
->ne_header
->local_heap_length
;
135 * Create segment selectors.
137 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
138 wpnt
->ne_header
->segment_tab_offset
,
140 read_size
= wpnt
->ne_header
->n_segment_tab
*
141 sizeof(struct ne_segment_table_entry_s
);
142 wpnt
->seg_table
= (struct ne_segment_table_entry_s
*) malloc(read_size
);
143 if (read(wpnt
->fd
, wpnt
->seg_table
, read_size
) != read_size
)
144 myerror("Unable to read segment table header from file");
145 wpnt
->selector_table
= CreateSelectors(wpnt
);
147 /* Get the lookup table. This is used for looking up the addresses
148 of functions that are exported */
150 read_size
= wpnt
->ne_header
->entry_tab_length
;
151 wpnt
->lookup_table
= (char *) malloc(read_size
);
152 lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
153 wpnt
->ne_header
->entry_tab_offset
, SEEK_SET
);
154 if (read(wpnt
->fd
, wpnt
->lookup_table
, read_size
) != read_size
)
155 myerror("Unable to read lookup table header from file");
157 /* Get the iname table. This is used for looking up the names
158 of functions that are exported */
160 status
= lseek(wpnt
->fd
, wpnt
->ne_header
->nrname_tab_offset
, SEEK_SET
);
161 read_size
= wpnt
->ne_header
->nrname_tab_length
;
162 wpnt
->nrname_table
= (char *) malloc(read_size
);
163 if (read(wpnt
->fd
, wpnt
->nrname_table
, read_size
) != read_size
)
164 myerror("Unable to read nrname table header from file");
166 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
167 wpnt
->ne_header
->rname_tab_offset
, SEEK_SET
);
168 read_size
= wpnt
->ne_header
->moduleref_tab_offset
-
169 wpnt
->ne_header
->rname_tab_offset
;
170 wpnt
->rname_table
= (char *) malloc(read_size
);
171 if (read(wpnt
->fd
, wpnt
->rname_table
, read_size
) != read_size
)
172 myerror("Unable to read rname table header from file");
174 /* Now get the module name */
176 wpnt
->name
= (char*) malloc(*wpnt
->rname_table
+ 1);
177 memcpy(wpnt
->name
, wpnt
->rname_table
+1, *wpnt
->rname_table
);
178 wpnt
->name
[*wpnt
->rname_table
] = 0;
181 * Now load any DLLs that this module refers to.
183 for(i
=0; i
<wpnt
->ne_header
->n_mod_ref_tab
; i
++){
187 GetModuleName(wpnt
, i
+ 1, buff
);
189 if(FindDLLTable(buff
)) continue; /* This module already loaded */
191 /* The next trick is to convert the case, and add the .dll
192 * extension if required to find the actual library. We may want
193 * to use a search path at some point as well. */
195 /* First try the straight name */
197 if(fd
= open(buff2
, O_RDONLY
) >= 0) {
199 LoadImage(buff2
, buff
);
203 /* OK, that did not work, try making it lower-case, and add the .dll
206 for(j
=0; j
<strlen(buff2
); j
++)
207 if(buff2
[j
] >= 'A' && buff2
[j
] <= 'Z') buff2
[j
] |= 0x20;
208 strcat(buff2
, ".dll");
210 if(fd
= open(buff2
, O_RDONLY
) >= 0) {
212 LoadImage(buff2
, buff
);
216 fprintf(stderr
,"Unable to load:%s\n", buff
);
221 /**********************************************************************
224 _WinMain(int argc
, char **argv
)
227 struct w_files
* wpnt
;
228 int cs_reg
, ds_reg
, ss_reg
, ip_reg
, sp_reg
;
237 fprintf(stderr
, "usage: %s FILENAME\n", argv
[0]);
241 LoadImage(argv
[1], NULL
);
245 GetEntryDLLName("USER", "INITAPP", 0, 0);
246 for(i
=0; i
<1024; i
++) {
248 j
= GetEntryPointFromOrdinal(wine_files
, i
);
250 fprintf(stderr
," %d %x\n", i
, j
);
257 for(wpnt
= wine_files
; wpnt
; wpnt
= wpnt
->next
)
258 for (segment
= 0; segment
< wpnt
->ne_header
->n_segment_tab
; segment
++)
260 if (FixupSegment(wpnt
, segment
) < 0)
262 myerror("fixup failed.");
267 * Fixup stack and jump to start.
269 ds_reg
= wine_files
->selector_table
[wine_files
->ne_header
->auto_data_seg
-1].selector
;
270 cs_reg
= wine_files
->selector_table
[wine_files
->ne_header
->cs
-1].selector
;
271 ip_reg
= wine_files
->ne_header
->ip
;
272 ss_reg
= wine_files
->selector_table
[wine_files
->ne_header
->ss
-1].selector
;
273 sp_reg
= wine_files
->ne_header
->sp
;
275 rv
= CallToInit16(cs_reg
<< 16 | ip_reg
, ss_reg
<< 16 | sp_reg
, ds_reg
);
276 printf ("rv = %x\n", rv
);
280 /**********************************************************************
284 GetImportedName(int fd
, struct mz_header_s
*mz_header
,
285 struct ne_header_s
*ne_header
, int name_offset
, char *buffer
)
292 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
293 name_offset
, SEEK_SET
);
295 read(fd
, &length
, 1); /* Get the length byte */
296 read(fd
, buffer
, length
);
301 /**********************************************************************
305 GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
)
308 struct mz_header_s
*mz_header
= wpnt
->mz_header
;
309 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
312 int name_offset
, status
;
315 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->moduleref_tab_offset
+
316 2*(index
- 1), SEEK_SET
);
318 read(fd
, &name_offset
, 2);
319 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
320 name_offset
, SEEK_SET
);
322 read(fd
, &length
, 1); /* Get the length byte */
323 read(fd
, buffer
, length
);
326 /* Module names are always upper case */
327 for(i
=0; i
<length
; i
++)
328 if(buffer
[i
] >= 'a' && buffer
[i
] <= 'z') buffer
[i
] &= ~0x20;
334 /**********************************************************************
338 FixupSegment(struct w_files
* wpnt
, int segment_num
)
341 struct mz_header_s
* mz_header
= wpnt
->mz_header
;
342 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
343 struct ne_segment_table_entry_s
*seg_table
= wpnt
->seg_table
;
344 struct segment_descriptor_s
*selector_table
= wpnt
->selector_table
;
346 struct relocation_entry_s
*rep
, *rep1
;
347 struct ne_segment_table_entry_s
*seg
;
348 struct segment_descriptor_s
*sel
;
349 struct dll_table_entry_s
*dll_table
;
352 unsigned int selector
, address
;
353 unsigned int next_addr
;
359 seg
= &seg_table
[segment_num
];
360 sel
= &selector_table
[segment_num
];
362 if ((seg
->seg_data_offset
== 0) ||
363 !(seg
->seg_flags
& NE_SEGFLAGS_RELOC_DATA
))
367 * Go through the relocation table on entry at a time.
369 i
= seg
->seg_data_length
;
373 status
= lseek(fd
, seg
->seg_data_offset
*
374 (1 << ne_header
->align_shift_count
) + i
, SEEK_SET
);
376 read(fd
, &n_entries
, sizeof(short int));
377 rep
= (struct relocation_entry_s
*)
378 malloc(n_entries
* sizeof(struct relocation_entry_s
));
380 if (read(fd
,rep
, n_entries
* sizeof(struct relocation_entry_s
)) !=
381 n_entries
* sizeof(struct relocation_entry_s
))
383 myerror("Unable to read relocation information");
388 for (i
= 0; i
< n_entries
; i
++, rep
++)
391 * Get the target address corresponding to this entry.
393 switch (rep
->relocation_type
)
395 case NE_RELTYPE_ORDINAL
:
396 if (GetModuleName(wpnt
, rep
->target1
,
399 fprintf(stderr
, "NE_RELTYPE_ORDINAL failed");
403 ordinal
= rep
->target2
;
405 status
= GetEntryDLLOrdinal(dll_name
, ordinal
, &selector
,
411 sprintf(s
, "Bad DLL name '%s.%d'", dll_name
, ordinal
);
417 printf("%d: %s.%d: %04.4x:%04.4x\n", i
+ 1, dll_name
, ordinal
,
422 case NE_RELTYPE_NAME
:
423 if (GetModuleName(wpnt
, rep
->target1
, dll_name
)
426 fprintf(stderr
,"NE_RELTYPE_NAME failed");
430 if (GetImportedName(fd
, mz_header
, ne_header
,
431 rep
->target2
, func_name
) == NULL
)
433 fprintf(stderr
,"getimportedname failed");
437 status
= GetEntryDLLName(dll_name
, func_name
, &selector
,
443 sprintf(s
, "Bad DLL name '%s (%s)'", dll_name
,func_name
);
449 printf("%d: %s %s.%d: %04.4x:%04.4x\n", i
+ 1, func_name
,
450 dll_name
, ordinal
, selector
, address
);
454 case NE_RELTYPE_INTERNAL
:
455 if (rep
->target1
== 0x00ff)
457 address
= GetEntryPointFromOrdinal(wpnt
, rep
->target2
);
458 selector
= (address
>> 16) & 0xffff;
463 selector
= selector_table
[rep
->target1
-1].selector
;
464 address
= rep
->target2
;
468 printf("%d: %04.4x:%04.4x\n", i
+ 1, selector
, address
);
473 /* Relocation type 7:
475 * These appear to be used as fixups for the Windows
476 * floating point emulator. Let's just ignore them and
477 * try to use the hardware floating point. Linux should
478 * successfully emulate the coprocessor if it doesn't
482 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
483 i
+ 1, rep
->address_type
, rep
->relocation_type
,
485 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
491 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
492 i
+ 1, rep
->address_type
, rep
->relocation_type
,
494 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
501 * Stuff the right size result in.
503 sp
= (unsigned short *) ((char *) sel
->base_addr
+ rep
->offset
);
504 switch (rep
->address_type
)
506 case NE_RADDR_OFFSET16
:
509 *sp
= (unsigned short) address
;
510 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
512 while (next_addr
!= 0xffff);
516 case NE_RADDR_POINTER32
:
519 *sp
= (unsigned short) address
;
520 *(sp
+1) = (unsigned short) selector
;
521 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
523 while (next_addr
!= 0xffff);
527 case NE_RADDR_SELECTOR
:
530 *sp
= (unsigned short) selector
;
531 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
533 while (next_addr
!= 0xffff);
539 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
540 i
+ 1, rep
->address_type
, rep
->relocation_type
,
542 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);