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";
12 #include <linux/head.h>
13 #include <linux/ldt.h>
14 #include <linux/segment.h>
20 #include "prototypes.h"
30 extern HANDLE
CreateNewTask(HINSTANCE hInst
);
31 extern void InitializeLoadedDLLs(struct w_files
*wpnt
);
32 extern int CallToInit16(unsigned long csip
, unsigned long sssp
,
34 extern int CallTo16cx(unsigned long csip
, unsigned long dscx
);
35 extern void CallTo32();
36 extern char WindowsPath
[256];
37 extern unsigned short WIN_StackSize
;
38 extern unsigned short WIN_HeapSize
;
40 int FixupSegment(struct w_files
*, int);
41 void FixupFunctionPrologs(struct w_files
*);
42 char *GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
);
46 /**********************************************************************/
48 void load_ne_header (int fd
, struct ne_header_s
*ne_header
)
50 if (read(fd
, ne_header
, sizeof(struct ne_header_s
))
51 != sizeof(struct ne_header_s
))
53 myerror("Unable to read NE header from file");
58 /**********************************************************************
60 * Load one NE format executable into memory
62 HINSTANCE
LoadNEImage(struct w_files
*wpnt
)
64 unsigned int read_size
, status
, segment
;
67 wpnt
->ne
= malloc(sizeof(struct ne_data
));
68 wpnt
->ne
->resnamtab
= NULL
;
69 wpnt
->ne
->ne_header
= malloc(sizeof(struct ne_header_s
));
70 lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
, SEEK_SET
);
71 load_ne_header(wpnt
->fd
, wpnt
->ne
->ne_header
);
75 * Create segment selectors.
77 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
78 wpnt
->ne
->ne_header
->segment_tab_offset
,
80 read_size
= wpnt
->ne
->ne_header
->n_segment_tab
*
81 sizeof(struct ne_segment_table_entry_s
);
82 wpnt
->ne
->seg_table
= (struct ne_segment_table_entry_s
*) malloc(read_size
);
83 if (read(wpnt
->fd
, wpnt
->ne
->seg_table
, read_size
) != read_size
)
84 myerror("Unable to read segment table header from file");
85 wpnt
->ne
->selector_table
= CreateSelectors(wpnt
);
86 wpnt
->hinstance
= (wpnt
->ne
->
87 selector_table
[wpnt
->ne
->ne_header
->auto_data_seg
-1].
90 /* Get the lookup table. This is used for looking up the addresses
91 of functions that are exported */
93 read_size
= wpnt
->ne
->ne_header
->entry_tab_length
;
94 wpnt
->ne
->lookup_table
= (char *) malloc(read_size
);
95 lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
96 wpnt
->ne
->ne_header
->entry_tab_offset
, SEEK_SET
);
97 if (read(wpnt
->fd
, wpnt
->ne
->lookup_table
, read_size
) != read_size
)
98 myerror("Unable to read lookup table header from file");
100 /* Get the iname table. This is used for looking up the names
101 of functions that are exported */
103 status
= lseek(wpnt
->fd
, wpnt
->ne
->ne_header
->nrname_tab_offset
, SEEK_SET
);
104 read_size
= wpnt
->ne
->ne_header
->nrname_tab_length
;
105 wpnt
->ne
->nrname_table
= (char *) malloc(read_size
);
106 if (read(wpnt
->fd
, wpnt
->ne
->nrname_table
, read_size
) != read_size
)
107 myerror("Unable to read nrname table header from file");
109 status
= lseek(wpnt
->fd
, wpnt
->mz_header
->ne_offset
+
110 wpnt
->ne
->ne_header
->rname_tab_offset
, SEEK_SET
);
111 read_size
= wpnt
->ne
->ne_header
->moduleref_tab_offset
-
112 wpnt
->ne
->ne_header
->rname_tab_offset
;
113 wpnt
->ne
->rname_table
= (char *) malloc(read_size
);
114 if (read(wpnt
->fd
, wpnt
->ne
->rname_table
, read_size
) != read_size
)
115 myerror("Unable to read rname table header from file");
118 * Now load any DLLs that this module refers to.
120 for(i
=0; i
<wpnt
->ne
->ne_header
->n_mod_ref_tab
; i
++)
123 GetModuleName(wpnt
, i
+ 1, buff
);
125 if (strcasecmp(buff
, wpnt
->name
) != 0 )
126 LoadImage(buff
, DLL
, 0);
129 /* fixup references */
131 for (segment
= 0; segment
< wpnt
->ne
->ne_header
->n_segment_tab
; segment
++)
132 if (FixupSegment(wpnt
, segment
) < 0)
133 myerror("fixup failed.");
135 FixupFunctionPrologs(wpnt
);
136 InitializeLoadedDLLs(wpnt
);
138 return(wpnt
->hinstance
);
141 /**********************************************************************
145 GetImportedName(int fd
, struct mz_header_s
*mz_header
,
146 struct ne_header_s
*ne_header
, int name_offset
, char *buffer
)
151 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
152 name_offset
, SEEK_SET
);
154 read(fd
, &length
, 1); /* Get the length byte */
155 length
= CONV_CHAR_TO_LONG (length
);
156 read(fd
, buffer
, length
);
161 /**********************************************************************
165 GetModuleName(struct w_files
* wpnt
, int index
, char *buffer
)
168 struct mz_header_s
*mz_header
= wpnt
->mz_header
;
169 struct ne_header_s
*ne_header
= wpnt
->ne
->ne_header
;
171 WORD name_offset
, status
;
174 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->moduleref_tab_offset
+
175 2*(index
- 1), SEEK_SET
);
177 read(fd
, &name_offset
, 2);
178 name_offset
= CONV_SHORT (name_offset
);
179 status
= lseek(fd
, mz_header
->ne_offset
+ ne_header
->iname_tab_offset
+
180 name_offset
, SEEK_SET
);
182 read(fd
, &length
, 1); /* Get the length byte */
183 length
= CONV_CHAR_TO_LONG (length
);
184 read(fd
, buffer
, length
);
187 /* Module names are always upper case */
188 for(i
=0; i
<length
; i
++)
189 if (islower(buffer
[i
]))
190 buffer
[i
] = toupper(buffer
[i
]);
197 /**********************************************************************
201 FixupSegment(struct w_files
* wpnt
, int segment_num
)
203 struct mz_header_s
*mz_header
= wpnt
->mz_header
;
204 struct ne_header_s
*ne_header
= wpnt
->ne
->ne_header
;
205 struct ne_segment_table_entry_s
*seg_table
= wpnt
->ne
->seg_table
;
206 struct segment_descriptor_s
*selector_table
= wpnt
->ne
->selector_table
;
207 struct relocation_entry_s
*rep
, *rep1
;
208 struct ne_segment_table_entry_s
*seg
;
209 struct segment_descriptor_s
*sel
;
212 unsigned int selector
, address
;
213 unsigned int next_addr
;
220 seg
= &seg_table
[segment_num
];
221 sel
= &selector_table
[segment_num
];
223 dprintf_fixup(stddeb
, "Segment fixups for %s, segment %d, selector %x\n",
224 wpnt
->name
, segment_num
, (int) sel
->base_addr
>> 16);
226 if ((seg
->seg_data_offset
== 0) ||
227 !(seg
->seg_flags
& NE_SEGFLAGS_RELOC_DATA
))
231 * Go through the relocation table on entry at a time.
233 i
= seg
->seg_data_length
;
237 status
= lseek(wpnt
->fd
, seg
->seg_data_offset
*
238 (1 << ne_header
->align_shift_count
) + i
, SEEK_SET
);
240 read(wpnt
->fd
, &n_entries
, sizeof(short int));
241 rep
= (struct relocation_entry_s
*)
242 malloc(n_entries
* sizeof(struct relocation_entry_s
));
244 if (read(wpnt
->fd
, rep
, n_entries
* sizeof(struct relocation_entry_s
)) !=
245 n_entries
* sizeof(struct relocation_entry_s
))
247 myerror("Unable to read relocation information");
252 for (i
= 0; i
< n_entries
; i
++, rep
++)
255 * Get the target address corresponding to this entry.
259 switch (rep
->relocation_type
)
261 case NE_RELTYPE_ORDINALADD
:
264 case NE_RELTYPE_ORDINAL
:
265 if (GetModuleName(wpnt
, rep
->target1
,
268 fprintf(stderr
, "NE_RELTYPE_ORDINAL failed");
272 ordinal
= rep
->target2
;
274 status
= GetEntryDLLOrdinal(dll_name
, ordinal
, &selector
,
280 sprintf(s
, "Bad DLL name '%s.%d'", dll_name
, ordinal
);
285 dprintf_fixup(stddeb
,"%d: %s.%d: %04x:%04x\n", i
+ 1,
286 dll_name
, ordinal
, selector
, address
);
289 case NE_RELTYPE_NAMEADD
:
292 case NE_RELTYPE_NAME
:
293 if (GetModuleName(wpnt
, rep
->target1
, dll_name
)
296 fprintf(stderr
,"NE_RELTYPE_NAME failed");
300 if (GetImportedName(wpnt
->fd
, mz_header
, ne_header
,
301 rep
->target2
, func_name
) == NULL
)
303 fprintf(stderr
,"getimportedname failed");
307 status
= GetEntryDLLName(dll_name
, func_name
, &selector
,
313 sprintf(s
, "Bad DLL name '%s (%s)'", dll_name
,func_name
);
318 dprintf_fixup(stddeb
,"%d: %s %s.%d: %04x:%04x\n", i
+ 1,
319 func_name
, dll_name
, ordinal
, selector
, address
);
322 case NE_RELTYPE_INTERNAL
:
323 case NE_RELTYPE_INT1
:
324 if (rep
->target1
== 0x00ff)
326 address
= GetEntryPointFromOrdinal(wpnt
, rep
->target2
);
327 selector
= (address
>> 16) & 0xffff;
332 selector
= selector_table
[rep
->target1
-1].selector
;
333 address
= rep
->target2
;
336 dprintf_fixup(stddeb
,"%d: %04x:%04x\n",
337 i
+ 1, selector
, address
);
341 /* Relocation type 7:
343 * These appear to be used as fixups for the Windows
344 * floating point emulator. Let's just ignore them and
345 * try to use the hardware floating point. Linux should
346 * successfully emulate the coprocessor if it doesn't
349 dprintf_fixup(stddeb
,
350 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
351 i
+ 1, rep
->address_type
, rep
->relocation_type
,
353 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
354 rep
->target1
, rep
->target2
);
358 dprintf_fixup(stddeb
,
359 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
360 i
+ 1, rep
->address_type
, rep
->relocation_type
,
362 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
363 rep
->target1
, rep
->target2
);
369 * Stuff the right size result in.
371 sp
= (unsigned short *) ((char *) sel
->base_addr
+ rep
->offset
);
374 if (FindDLLTable(dll_name
) == NULL
)
376 dprintf_fixup(stddeb
,
377 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
378 i
+ 1, rep
->address_type
, rep
->relocation_type
,
380 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
381 rep
->target1
, rep
->target2
);
382 dprintf_fixup(stddeb
, " Additive = %d\n", additive
);
385 switch (rep
->address_type
)
387 case NE_RADDR_OFFSET16
:
389 dprintf_fixup(stddeb
," %04x:%04x:%04x OFFSET16\n",
390 (unsigned int) sp
>> 16, (int) sp
& 0xFFFF, *sp
);
392 *sp
= (unsigned short) address
;
395 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
397 while (next_addr
!= 0xffff && !additive
);
401 case NE_RADDR_POINTER32
:
403 dprintf_fixup(stddeb
," %04x:%04x:%04x POINTER32\n",
404 (unsigned int) sp
>> 16, (int) sp
& 0xFFFF, *sp
);
406 *sp
= (unsigned short) address
;
409 *(sp
+1) = (unsigned short) selector
;
410 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
412 while (next_addr
!= 0xffff && !additive
);
416 case NE_RADDR_SELECTOR
:
418 dprintf_fixup(stddeb
," %04x:%04x:%04x SELECTOR\n",
419 (unsigned int) sp
>> 16, (int) sp
& 0xFFFF, *sp
);
421 *sp
= (unsigned short) selector
;
422 sp
= (unsigned short *) ((char *) sel
->base_addr
+ next_addr
);
423 if (rep
->relocation_type
== NE_RELTYPE_INT1
)
426 while (next_addr
!= 0xffff && !additive
);
431 dprintf_fixup(stddeb
,
432 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
433 i
+ 1, rep
->address_type
, rep
->relocation_type
,
435 dprintf_fixup(stddeb
,
436 "TARGET %04x %04x\n", rep
->target1
, rep
->target2
);
446 int NEunloadImage(struct w_files
*wpnt
)
448 dprintf_fixup(stdnimp
, "NEunloadImage() called!\n");
449 /* free resources, image */
453 int StartNEprogram(struct w_files
*wpnt
)
455 int cs_reg
, ds_reg
, ss_reg
, ip_reg
, sp_reg
;
457 * Fixup stack and jump to start.
459 WIN_StackSize
= wpnt
->ne
->ne_header
->stack_length
;
460 WIN_HeapSize
= wpnt
->ne
->ne_header
->local_heap_length
;
462 ds_reg
= wpnt
->ne
->selector_table
[wpnt
->ne
->ne_header
->auto_data_seg
-1].selector
;
463 cs_reg
= wpnt
->ne
->selector_table
[wpnt
->ne
->ne_header
->cs
-1].selector
;
464 ip_reg
= wpnt
->ne
->ne_header
->ip
;
465 ss_reg
= wpnt
->ne
->selector_table
[wpnt
->ne
->ne_header
->ss
-1].selector
;
466 sp_reg
= wpnt
->ne
->ne_header
->sp
;
468 return CallToInit16(cs_reg
<< 16 | ip_reg
, ss_reg
<< 16 | sp_reg
, ds_reg
);
471 void InitNEDLL(struct w_files
*wpnt
)
473 int cs_reg
, ds_reg
, ip_reg
, cx_reg
, rv
;
477 if (wpnt
->ne
->ne_header
->format_flags
& 0x8000)
479 if (!(wpnt
->ne
->ne_header
->format_flags
& 0x0001))
482 fprintf(stderr
, "Library is not marked SINGLEDATA\n");
486 ds_reg
= wpnt
->ne
->selector_table
[wpnt
->ne
->
487 ne_header
->auto_data_seg
-1].selector
;
488 cs_reg
= wpnt
->ne
->selector_table
[wpnt
->ne
->ne_header
->cs
-1].selector
;
489 ip_reg
= wpnt
->ne
->ne_header
->ip
;
491 cx_reg
= wpnt
->ne
->ne_header
->local_heap_length
;
494 dprintf_dll(stddeb
,"Initializing %s, cs:ip %04x:%04x, ds %04x, cx %04x\n",
495 wpnt
->name
, cs_reg
, ip_reg
, ds_reg
, cx_reg
);
497 rv
= CallTo16cx(cs_reg
<< 16 | ip_reg
, ds_reg
| (cx_reg
<<16));
498 dprintf_exec(stddeb
,"rv = %x\n", rv
);
500 dprintf_exec(stddeb
,"%s skipped\n", wpnt
->name
);
504 #endif /* !WINELIB */