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 extern char WindowsPath
[256];
32 unsigned short WIN_StackSize
;
33 unsigned short WIN_HeapSize
;
35 struct w_files
* wine_files
= NULL
;
37 int WineForceFail
= 0;
41 struct mz_header_s
*CurrentMZHeader
;
42 struct ne_header_s
*CurrentNEHeader
;
46 static char *Extensions
[] = { "dll", "exe", NULL
};
47 static char *WinePath
= NULL
;
49 /**********************************************************************
53 DebugPrintString(char *str
)
59 /**********************************************************************
63 myerror(const char *s
)
68 fprintf(stderr
, "wine: %s\n", s
);
73 /**********************************************************************
74 * GetFilenameFromInstance
77 GetFilenameFromInstance(unsigned short instance
)
79 register struct w_files
*w
= wine_files
;
81 while (w
&& w
->hinstance
!= instance
)
91 GetFileInfo(unsigned short instance
)
93 register struct w_files
*w
= wine_files
;
95 while (w
&& w
->hinstance
!= instance
)
101 /**********************************************************************
103 * Load one NE format executable into memory
105 HINSTANCE
LoadImage(char *modulename
)
107 unsigned int read_size
;
109 struct w_files
* wpnt
, *wpnt1
;
113 /* First allocate a spot to store the info we collect, and add it to
117 wpnt
= (struct w_files
*) malloc(sizeof(struct w_files
));
118 if(wine_files
== NULL
)
122 while(wpnt1
->next
) wpnt1
= wpnt1
->next
;
131 if (FindFile(buffer
, sizeof(buffer
), modulename
, Extensions
, WindowsPath
)
136 sprintf(temp
,"LoadImage: I can't find %s !\n",modulename
);
139 fprintf(stderr
,"LoadImage: loading %s (%s)\n", modulename
, buffer
);
142 * Open file for reading.
144 wpnt
->fd
= open(buffer
, O_RDONLY
);
150 * Establish header pointers.
152 wpnt
->filename
= strdup(buffer
);
154 if(modulename
) wpnt
->name
= strdup(modulename
);
156 wpnt
->mz_header
= (struct mz_header_s
*) malloc(sizeof(struct mz_header_s
));;
157 status
= lseek(wpnt
->fd
, 0, SEEK_SET
);
158 if (read(wpnt
->fd
, wpnt
->mz_header
, sizeof(struct mz_header_s
)) !=
159 sizeof(struct mz_header_s
))
161 myerror("Unable to read MZ header from file");
163 if (wpnt
->mz_header
->must_be_0x40
!= 0x40)
164 myerror("This is not a Windows program");
166 wpnt
->ne_header
= (struct ne_header_s
*) malloc(sizeof(struct ne_header_s
));
167 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
, SEEK_SET
);
168 if (read(wpnt
->fd
, wpnt
->ne_header
, sizeof(struct ne_header_s
))
169 != sizeof(struct ne_header_s
))
171 myerror("Unable to read NE header from file");
173 if (wpnt
->ne_header
->header_type
[0] != 'N' ||
174 wpnt
->ne_header
->header_type
[1] != 'E')
175 myerror("This is not a Windows program");
177 if(wine_files
== wpnt
){
178 CurrentMZHeader
= wpnt
->mz_header
;
179 CurrentNEHeader
= wpnt
->ne_header
;
180 CurrentNEFile
= wpnt
->fd
;
182 WIN_StackSize
= wpnt
->ne_header
->stack_length
;
183 WIN_HeapSize
= wpnt
->ne_header
->local_heap_length
;
187 * Create segment selectors.
189 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
190 wpnt
->ne_header
->segment_tab_offset
,
192 read_size
= wpnt
->ne_header
->n_segment_tab
*
193 sizeof(struct ne_segment_table_entry_s
);
194 wpnt
->seg_table
= (struct ne_segment_table_entry_s
*) malloc(read_size
);
195 if (read(wpnt
->fd
, wpnt
->seg_table
, read_size
) != read_size
)
196 myerror("Unable to read segment table header from file");
197 wpnt
->selector_table
= CreateSelectors(wpnt
);
200 selector_table
[wpnt
->ne_header
->auto_data_seg
-1].selector
;
202 /* Get the lookup table. This is used for looking up the addresses
203 of functions that are exported */
205 read_size
= wpnt
->ne_header
->entry_tab_length
;
206 wpnt
->lookup_table
= (char *) malloc(read_size
);
207 lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
208 wpnt
->ne_header
->entry_tab_offset
, SEEK_SET
);
209 if (read(wpnt
->fd
, wpnt
->lookup_table
, read_size
) != read_size
)
210 myerror("Unable to read lookup table header from file");
212 /* Get the iname table. This is used for looking up the names
213 of functions that are exported */
215 status
= lseek(wpnt
->fd
, wpnt
->ne_header
->nrname_tab_offset
, SEEK_SET
);
216 read_size
= wpnt
->ne_header
->nrname_tab_length
;
217 wpnt
->nrname_table
= (char *) malloc(read_size
);
218 if (read(wpnt
->fd
, wpnt
->nrname_table
, read_size
) != read_size
)
219 myerror("Unable to read nrname table header from file");
221 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
222 wpnt
->ne_header
->rname_tab_offset
, SEEK_SET
);
223 read_size
= wpnt
->ne_header
->moduleref_tab_offset
-
224 wpnt
->ne_header
->rname_tab_offset
;
225 wpnt
->rname_table
= (char *) malloc(read_size
);
226 if (read(wpnt
->fd
, wpnt
->rname_table
, read_size
) != read_size
)
227 myerror("Unable to read rname table header from file");
229 /* Now get the module name */
231 wpnt
->name
= (char*) malloc(*wpnt
->rname_table
+ 1);
232 memcpy(wpnt
->name
, wpnt
->rname_table
+1, *wpnt
->rname_table
);
233 wpnt
->name
[*wpnt
->rname_table
] = 0;
236 * Now load any DLLs that this module refers to.
238 for(i
=0; i
<wpnt
->ne_header
->n_mod_ref_tab
; i
++){
242 GetModuleName(wpnt
, i
+ 1, buff
);
244 if(FindDLLTable(buff
)) continue; /* This module already loaded */
248 fprintf(stderr,"Unable to load:%s\n", buff);
251 return(wpnt
->hinstance
);
255 /**********************************************************************
258 _WinMain(int argc
, char **argv
)
268 struct w_files
* wpnt
;
269 int cs_reg
, ds_reg
, ss_reg
, ip_reg
, sp_reg
;
278 fprintf(stderr
, "usage: %s FILENAME\n", argv
[0]);
282 p
= getenv("WINEPATH");
283 WinePath
= malloc(256 + strlen(p
));
284 getcwd(WinePath
, 256);
285 strcat(WinePath
, ";");
289 hSysRes
= LoadImage("sysres.dll");
290 if (hSysRes
== (HINSTANCE
)NULL
)
291 printf("Error Loading System Resources !!!\n");
293 printf("System Resources Loaded // hSysRes='%04X'\n", hSysRes
);
300 GetEntryDLLName("USER", "INITAPP", &dummy1
, &dummy2
);
302 for(i
=0; i
<1024; i
++) {
304 j
= GetEntryPointFromOrdinal(wine_files
, i
);
306 fprintf(stderr
," %d %x\n", i
, j
);
313 for(wpnt
= wine_files
; wpnt
; wpnt
= wpnt
->next
)
314 for (segment
= 0; segment
< wpnt
->ne_header
->n_segment_tab
; segment
++)
316 if (FixupSegment(wpnt
, segment
) < 0)
318 myerror("fixup failed.");
323 * Fixup stack and jump to start.
325 ds_reg
= wine_files
->selector_table
[wine_files
->ne_header
->auto_data_seg
-1].selector
;
326 cs_reg
= wine_files
->selector_table
[wine_files
->ne_header
->cs
-1].selector
;
327 ip_reg
= wine_files
->ne_header
->ip
;
328 ss_reg
= wine_files
->selector_table
[wine_files
->ne_header
->ss
-1].selector
;
329 sp_reg
= wine_files
->ne_header
->sp
;
332 cp
= strrchr(argv
[0], '/');
333 if(!cp
) cp
= argv
[0];
335 if(strcmp(cp
,"winestat") == 0) {
345 p
= (char *) ((cs_reg
<< 16) | ip_reg
);
353 fprintf(stderr
, "SS is 0. Send email to bob@amscons.com.\n");
354 fprintf(stderr
, " No. Really. I want to know what programs\n");
355 fprintf(stderr
, " do this.\n");
358 rv
= CallToInit16(cs_reg
<< 16 | ip_reg
, ss_reg
<< 16 | sp_reg
, ds_reg
);
359 printf ("rv = %x\n", rv
);
363 /**********************************************************************
367 GetImportedName(int fd
, struct mz_header_s
*mz_header
,
368 struct ne_header_s
*ne_header
, int name_offset
, char *buffer
)
375 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
376 name_offset
, SEEK_SET
);
378 read(fd
, &length
, 1); /* Get the length byte */
379 read(fd
, buffer
, length
);
384 /**********************************************************************
388 GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
)
391 struct mz_header_s
*mz_header
= wpnt
->mz_header
;
392 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
395 int name_offset
, status
;
398 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->moduleref_tab_offset
+
399 2*(index
- 1), SEEK_SET
);
401 read(fd
, &name_offset
, 2);
402 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
403 name_offset
, SEEK_SET
);
405 read(fd
, &length
, 1); /* Get the length byte */
406 read(fd
, buffer
, length
);
409 /* Module names are always upper case */
410 for(i
=0; i
<length
; i
++)
411 if(buffer
[i
] >= 'a' && buffer
[i
] <= 'z') buffer
[i
] &= ~0x20;
417 /**********************************************************************
421 FixupSegment(struct w_files
* wpnt
, int segment_num
)
424 struct mz_header_s
* mz_header
= wpnt
->mz_header
;
425 struct ne_header_s
*ne_header
= wpnt
->ne_header
;
426 struct ne_segment_table_entry_s
*seg_table
= wpnt
->seg_table
;
427 struct segment_descriptor_s
*selector_table
= wpnt
->selector_table
;
428 struct relocation_entry_s
*rep
, *rep1
;
429 struct ne_segment_table_entry_s
*seg
;
430 struct segment_descriptor_s
*sel
;
431 struct dll_table_entry_s
*dll_table
;
434 unsigned int selector
, address
;
435 unsigned int next_addr
;
442 seg
= &seg_table
[segment_num
];
443 sel
= &selector_table
[segment_num
];
445 fprintf(stderr
, "Segment fixups for %s, segment %d, selector %x\n",
446 wpnt
->name
, segment_num
, (int) sel
->base_addr
>> 16);
448 if ((seg
->seg_data_offset
== 0) ||
449 !(seg
->seg_flags
& NE_SEGFLAGS_RELOC_DATA
))
453 * Go through the relocation table on entry at a time.
455 i
= seg
->seg_data_length
;
459 status
= lseek(fd
, seg
->seg_data_offset
*
460 (1 << ne_header
->align_shift_count
) + i
, SEEK_SET
);
462 read(fd
, &n_entries
, sizeof(short int));
463 rep
= (struct relocation_entry_s
*)
464 malloc(n_entries
* sizeof(struct relocation_entry_s
));
466 if (read(fd
,rep
, n_entries
* sizeof(struct relocation_entry_s
)) !=
467 n_entries
* sizeof(struct relocation_entry_s
))
469 myerror("Unable to read relocation information");
474 for (i
= 0; i
< n_entries
; i
++, rep
++)
477 * Get the target address corresponding to this entry.
481 switch (rep
->relocation_type
)
483 case NE_RELTYPE_ORDINALADD
:
486 case NE_RELTYPE_ORDINAL
:
487 if (GetModuleName(wpnt
, rep
->target1
,
490 fprintf(stderr
, "NE_RELTYPE_ORDINAL failed");
494 ordinal
= rep
->target2
;
496 status
= GetEntryDLLOrdinal(dll_name
, ordinal
, &selector
,
502 sprintf(s
, "Bad DLL name '%s.%d'", dll_name
, ordinal
);
508 printf("%d: %s.%d: %04.4x:%04.4x\n", i
+ 1, dll_name
, ordinal
,
513 case NE_RELTYPE_NAMEADD
:
516 case NE_RELTYPE_NAME
:
517 if (GetModuleName(wpnt
, rep
->target1
, dll_name
)
520 fprintf(stderr
,"NE_RELTYPE_NAME failed");
524 if (GetImportedName(fd
, mz_header
, ne_header
,
525 rep
->target2
, func_name
) == NULL
)
527 fprintf(stderr
,"getimportedname failed");
531 status
= GetEntryDLLName(dll_name
, func_name
, &selector
,
537 sprintf(s
, "Bad DLL name '%s (%s)'", dll_name
,func_name
);
543 printf("%d: %s %s.%d: %04.4x:%04.4x\n", i
+ 1, func_name
,
544 dll_name
, ordinal
, selector
, address
);
548 case NE_RELTYPE_INTERNAL
:
549 case NE_RELTYPE_INT1
:
550 if (rep
->target1
== 0x00ff)
552 address
= GetEntryPointFromOrdinal(wpnt
, rep
->target2
);
553 selector
= (address
>> 16) & 0xffff;
558 selector
= selector_table
[rep
->target1
-1].selector
;
559 address
= rep
->target2
;
563 printf("%d: %04.4x:%04.4x\n", i
+ 1, selector
, address
);
568 /* Relocation type 7:
570 * These appear to be used as fixups for the Windows
571 * floating point emulator. Let's just ignore them and
572 * try to use the hardware floating point. Linux should
573 * successfully emulate the coprocessor if it doesn't
577 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
578 i
+ 1, rep
->address_type
, rep
->relocation_type
,
580 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
585 fprintf(stderr
,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
586 i
+ 1, rep
->address_type
, rep
->relocation_type
,
588 fprintf(stderr
,"TARGET %04.4x %04.4x\n",
589 rep
->target1
, rep
->target2
);
593 sp
= (unsigned short *) ((char *) sel
->base_addr
+ rep
->offset
);
594 fprintf(stderr
, " FIXUP ADDRESS %04.4x:%04.4x\n",
595 (int) sel
->base_addr
>> 16, rep
->offset
);
602 * Stuff the right size result in.
604 sp
= (unsigned short *) ((char *) sel
->base_addr
+ rep
->offset
);
607 if (FindDLLTable(dll_name
) == NULL
)
610 fprintf(stderr
,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
611 i
+ 1, rep
->address_type
, rep
->relocation_type
,
613 fprintf(stderr
,"TARGET %04.4x %04.4x\n",
614 rep
->target1
, rep
->target2
);
615 fprintf(stderr
, " Additive = %d\n", additive
);
618 switch (rep
->address_type
)
620 case NE_RADDR_OFFSET16
:
623 *sp
= (unsigned short) address
;
626 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
628 while (next_addr
!= 0xffff && !additive
);
632 case NE_RADDR_POINTER32
:
635 *sp
= (unsigned short) address
;
638 *(sp
+1) = (unsigned short) selector
;
639 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
641 while (next_addr
!= 0xffff && !additive
);
645 case NE_RADDR_SELECTOR
:
648 *sp
= (unsigned short) selector
;
649 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
650 if (rep
->relocation_type
== NE_RELTYPE_INT1
) break;
653 while (next_addr
!= 0xffff && !additive
);
658 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
659 i
+ 1, rep
->address_type
, rep
->relocation_type
,
661 printf("TARGET %04.4x %04.4x\n", rep
->target1
, rep
->target2
);
671 /**********************************************************************
674 FARPROC
GetProcAddress(HINSTANCE hinstance
, char *proc_name
)
676 if ((int) proc_name
& 0xffff0000)
677 printf("GetProcAddress: %#04x, '%s'\n", hinstance
, proc_name
);
679 printf("GetProcAddress: %#04x, %d\n", hinstance
, (int) proc_name
);