Release 950109
[wine/multimedia.git] / loader / ne_image.c
blob9e10ae924dea982e736e899aaff6a2385b736f08
1 /*
2 static char RCSId[] = "$Id: wine.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
3 static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
4 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <ctype.h>
12 #include <string.h>
13 #include <errno.h>
14 #include "neexe.h"
15 #include "segmem.h"
16 #include "dlls.h"
17 #include "windows.h"
18 #include "arch.h"
19 #include "library.h"
20 #include "if1632.h"
21 #include "selectors.h"
22 #include "ne_image.h"
23 #include "prototypes.h"
24 #include "stddebug.h"
25 #include "debug.h"
27 extern unsigned short WIN_StackSize;
28 extern unsigned short WIN_HeapSize;
30 void FixupFunctionPrologs(struct w_files *);
32 /**********************************************************************
33 * GetImportedName
35 static
36 char *NE_GetImportedName(struct w_files *wpnt, int name_offset, char *buffer)
38 BYTE length;
40 lseek(wpnt->fd, wpnt->mz_header->ne_offset +
41 wpnt->ne->ne_header->iname_tab_offset + name_offset, SEEK_SET);
42 read(wpnt->fd, &length, 1); /* Get the length byte */
43 read(wpnt->fd, buffer, length);
44 buffer[length] = 0;
46 return buffer;
49 struct w_files *current_exe;
50 WORD current_nodata=0xfd00;
51 /**********************************************************************
52 * GetModuleName
54 static char *NE_GetModuleName(struct w_files *wpnt, int index, char *buffer)
56 BYTE length;
57 WORD name_offset;
58 int i;
60 lseek(wpnt->fd, wpnt->mz_header->ne_offset +
61 wpnt->ne->ne_header->moduleref_tab_offset + 2 * (index - 1), SEEK_SET);
62 read(wpnt->fd, &name_offset, 2);
63 name_offset = CONV_SHORT (name_offset);
65 lseek(wpnt->fd, wpnt->mz_header->ne_offset +
66 wpnt->ne->ne_header->iname_tab_offset + name_offset, SEEK_SET);
67 read(wpnt->fd, &length, 1); /* Get the length byte */
68 read(wpnt->fd, buffer, length);
69 buffer[length] = 0;
71 /* Module names are always upper case */
72 for(i=0; i<length; i++)
73 if (islower(buffer[i]))
74 buffer[i] = toupper(buffer[i]);
76 return buffer;
79 #ifndef WINELIB
80 /**********************************************************************
81 * NE_FixupSegment
83 int NE_FixupSegment(struct w_files *wpnt, int segment_num)
85 struct segment_descriptor_s *selector_table = wpnt->ne->selector_table;
86 struct relocation_entry_s *rep, *rep1;
87 struct ne_segment_table_entry_s *seg;
88 struct segment_descriptor_s *sel;
89 int status, ordinal, i, n_entries, additive;
90 unsigned short *sp;
91 unsigned int selector, address, next_addr;
92 unsigned char dll_name[257], func_name[257];
94 seg = &wpnt->ne->seg_table[segment_num];
95 sel = &selector_table[segment_num];
97 dprintf_fixup(stddeb, "Segment fixups for %s, segment %d, selector %x\n",
98 wpnt->name, segment_num, (int) sel->base_addr >> 16);
100 if ((seg->seg_data_offset == 0) ||
101 !(seg->seg_flags & NE_SEGFLAGS_RELOC_DATA))
102 return 0;
105 * Go through the relocation table on entry at a time.
107 i = seg->seg_data_length;
108 if (i == 0)
109 i = 0x10000;
111 status = lseek(wpnt->fd, seg->seg_data_offset *
112 (1 << wpnt->ne->ne_header->align_shift_count) + i, SEEK_SET);
113 n_entries = 0;
114 read(wpnt->fd, &n_entries, sizeof(short int));
115 rep = (struct relocation_entry_s *)
116 malloc(n_entries * sizeof(struct relocation_entry_s));
118 if (read(wpnt->fd, rep, n_entries * sizeof(struct relocation_entry_s)) !=
119 n_entries * sizeof(struct relocation_entry_s))
121 myerror("Unable to read relocation information");
124 rep1 = rep;
126 for (i = 0; i < n_entries; i++, rep++)
129 * Get the target address corresponding to this entry.
131 additive = 0;
133 switch (rep->relocation_type)
135 case NE_RELTYPE_ORDINALADD:
136 additive = 1;
138 case NE_RELTYPE_ORDINAL:
139 if (NE_GetModuleName(wpnt, rep->target1,
140 dll_name) == NULL)
142 fprintf(stderr, "NE_RELTYPE_ORDINAL failed");
143 return -1;
146 ordinal = rep->target2;
148 status = GetEntryDLLOrdinal(dll_name, ordinal, &selector,
149 &address);
150 if (status)
152 char s[80];
154 sprintf(s, "Bad DLL name '%s.%d'", dll_name, ordinal);
155 myerror(s);
156 return -1;
159 dprintf_fixup(stddeb,"%d: %s.%d: %04x:%04x\n", i + 1,
160 dll_name, ordinal, selector, address);
161 break;
163 case NE_RELTYPE_NAMEADD:
164 additive = 1;
166 case NE_RELTYPE_NAME:
167 if (NE_GetModuleName(wpnt, rep->target1, dll_name) == NULL) {
168 fprintf(stderr,"NE_RELTYPE_NAME failed");
169 return -1;
172 if (NE_GetImportedName(wpnt, rep->target2, func_name) == NULL) {
173 fprintf(stderr,"NE_getimportedname failed");
174 return -1;
177 status = GetEntryDLLName(dll_name, func_name, &selector,
178 &address);
179 if (status)
181 char s[80];
183 sprintf(s, "Bad DLL name '%s (%s)'", dll_name,func_name);
184 myerror(s);
185 return -1;
187 /* dprintf_fixup(stddeb,"%d: %s %s.%d: %04x:%04x\n", i + 1,
188 func_name, dll_name, ordinal, selector, address);*/
189 break;
191 case NE_RELTYPE_INTERNAL:
192 case NE_RELTYPE_INT1:
193 if (rep->target1 == 0x00ff)
195 address = GetEntryPointFromOrdinal(wpnt, rep->target2);
196 selector = (address >> 16) & 0xffff;
197 address &= 0xffff;
199 else
201 selector = selector_table[rep->target1-1].selector;
202 address = rep->target2;
205 dprintf_fixup(stddeb,"%d: %04x:%04x\n",
206 i + 1, selector, address);
207 break;
209 case 7:
210 /* Relocation type 7:
212 * These appear to be used as fixups for the Windows
213 * floating point emulator. Let's just ignore them and
214 * try to use the hardware floating point. Linux should
215 * successfully emulate the coprocessor if it doesn't
216 * exist.
218 dprintf_fixup(stddeb,
219 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
220 i + 1, rep->address_type, rep->relocation_type,
221 rep->offset);
222 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
223 rep->target1, rep->target2);
224 continue;
226 default:
227 dprintf_fixup(stddeb,
228 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
229 i + 1, rep->address_type, rep->relocation_type,
230 rep->offset);
231 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
232 rep->target1, rep->target2);
233 free(rep1);
234 return -1;
238 * Stuff the right size result in.
240 sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
241 if (additive)
243 if (FindDLLTable(dll_name) == NULL)
244 additive = 2;
245 dprintf_fixup(stddeb,
246 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
247 i + 1, rep->address_type, rep->relocation_type,
248 rep->offset);
249 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
250 rep->target1, rep->target2);
251 dprintf_fixup(stddeb, " Additive = %d\n", additive);
254 switch (rep->address_type)
256 case NE_RADDR_OFFSET16:
257 do {
258 dprintf_fixup(stddeb," %04x:%04x:%04x OFFSET16\n",
259 (unsigned int) sp >> 16, (int) sp & 0xFFFF, *sp);
260 next_addr = *sp;
261 *sp = (unsigned short) address;
262 if (additive == 2)
263 *sp += next_addr;
264 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
266 while (next_addr != 0xffff && !additive);
268 break;
270 case NE_RADDR_POINTER32:
271 do {
272 dprintf_fixup(stddeb," %04x:%04x:%04x POINTER32\n",
273 (unsigned int) sp >> 16, (int) sp & 0xFFFF, *sp);
274 next_addr = *sp;
275 *sp = (unsigned short) address;
276 if (additive == 2)
277 *sp += next_addr;
278 *(sp+1) = (unsigned short) selector;
279 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
281 while (next_addr != 0xffff && !additive);
283 break;
285 case NE_RADDR_SELECTOR:
286 do {
287 dprintf_fixup(stddeb," %04x:%04x:%04x SELECTOR\n",
288 (unsigned int) sp >> 16, (int) sp & 0xFFFF, *sp);
289 next_addr = *sp;
290 *sp = (unsigned short) selector;
291 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
292 if (rep->relocation_type == NE_RELTYPE_INT1)
293 break;
295 while (next_addr != 0xffff && !additive);
297 break;
299 default:
300 dprintf_fixup(stddeb,
301 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
302 i + 1, rep->address_type, rep->relocation_type,
303 rep->offset);
304 dprintf_fixup(stddeb,
305 "TARGET %04x %04x\n", rep->target1, rep->target2);
306 free(rep1);
307 return -1;
311 free(rep1);
312 return 0;
315 int NE_unloadImage(struct w_files *wpnt)
317 dprintf_fixup(stdnimp, "NEunloadImage() called!\n");
318 /* free resources, image */
319 return 1;
322 int NE_StartProgram(struct w_files *wpnt)
324 int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg;
326 * Fixup stack and jump to start.
328 WIN_StackSize = wpnt->ne->ne_header->stack_length;
329 WIN_HeapSize = wpnt->ne->ne_header->local_heap_length;
331 ds_reg = wpnt->ne->selector_table[wpnt->ne->ne_header->auto_data_seg-1].selector;
332 cs_reg = wpnt->ne->selector_table[wpnt->ne->ne_header->cs-1].selector;
333 ip_reg = wpnt->ne->ne_header->ip;
334 ss_reg = wpnt->ne->selector_table[wpnt->ne->ne_header->ss-1].selector;
335 sp_reg = wpnt->ne->ne_header->sp;
337 return CallToInit16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg);
340 void NE_InitDLL(struct w_files *wpnt)
342 int cs_reg, ds_reg, ip_reg, cx_reg, di_reg, rv;
343 extern struct w_files *current_exe;
345 * Is this a library?
347 if (wpnt->ne->ne_header->format_flags & 0x8000)
349 if (!(wpnt->ne->ne_header->format_flags & 0x0001))
350 if(wpnt->ne->ne_header->format_flags & NE_FFLAGS_MULTIPLEDATA
351 || wpnt->ne->ne_header->auto_data_seg)
353 /* Not SINGLEDATA */
354 fprintf(stderr, "Library is not marked SINGLEDATA\n");
355 exit(1);
356 } else { /* DATA NONE DLL */
357 ds_reg = current_exe->ne->selector_table[
358 current_exe->ne->ne_header->auto_data_seg-1].selector;
359 cx_reg = 0;
360 } else { /* DATA SINGLE DLL */
361 ds_reg = wpnt->ne->selector_table[wpnt->ne->
362 ne_header->auto_data_seg-1].selector;
363 cx_reg = wpnt->ne->ne_header->local_heap_length;
366 cs_reg = wpnt->ne->selector_table[wpnt->ne->ne_header->cs-1].selector;
367 ip_reg = wpnt->ne->ne_header->ip;
369 di_reg = wpnt->hinstance;
371 if (cs_reg) {
372 dprintf_dll(stddeb,"Initializing %s, cs:ip %04x:%04x, ds %04x, cx %04x\n",
373 wpnt->name, cs_reg, ip_reg, ds_reg, cx_reg);
375 rv = CallTo16cx(cs_reg << 16 | ip_reg, ds_reg | (cx_reg<<16));
376 dprintf_exec(stddeb,"rv = %x\n", rv);
377 } else
378 dprintf_exec(stddeb,"%s skipped\n", wpnt->name);
382 /**********************************************************************
383 * NE_LoadImage
384 * Load one NE format executable into memory
386 HINSTANCE NE_LoadImage(struct w_files *wpnt)
388 unsigned int read_size, status, segment;
389 int i;
391 wpnt->ne = malloc(sizeof(struct ne_data));
392 wpnt->ne->resnamtab = NULL;
393 wpnt->ne->ne_header = malloc(sizeof(struct ne_header_s));
395 lseek(wpnt->fd, wpnt->mz_header->ne_offset, SEEK_SET);
396 if (read(wpnt->fd, wpnt->ne->ne_header, sizeof(struct ne_header_s))
397 != sizeof(struct ne_header_s))
398 myerror("Unable to read NE header from file");
399 if(!(wpnt->ne->ne_header->format_flags & NE_FFLAGS_LIBMODULE)){
400 if(current_exe)printf("Warning: more than one EXE\n");
401 current_exe=wpnt;
404 #ifndef WINELIB
406 * Create segment selectors.
408 status = lseek(wpnt->fd, wpnt->mz_header->ne_offset +
409 wpnt->ne->ne_header->segment_tab_offset,
410 SEEK_SET);
411 read_size = wpnt->ne->ne_header->n_segment_tab *
412 sizeof(struct ne_segment_table_entry_s);
413 wpnt->ne->seg_table = (struct ne_segment_table_entry_s *) malloc(read_size);
414 if (read(wpnt->fd, wpnt->ne->seg_table, read_size) != read_size)
415 myerror("Unable to read segment table header from file");
416 wpnt->ne->selector_table = CreateSelectors(wpnt);
417 if(wpnt->ne->ne_header->auto_data_seg==0)
419 printf("DATA NONE DLL %s\n",wpnt->name);
420 wpnt->hinstance=current_nodata++;
421 } else
422 wpnt->hinstance = (wpnt->ne->
423 selector_table[wpnt->ne->ne_header->auto_data_seg-1].
424 selector);
425 if (wpnt->hinstance == 0)
426 wpnt->hinstance = 0xf000;
427 #endif
428 /* Get the lookup table. This is used for looking up the addresses
429 of functions that are exported */
431 read_size = wpnt->ne->ne_header->entry_tab_length;
432 wpnt->ne->lookup_table = (char *) malloc(read_size);
433 lseek(wpnt->fd, wpnt->mz_header->ne_offset +
434 wpnt->ne->ne_header->entry_tab_offset, SEEK_SET);
435 if (read(wpnt->fd, wpnt->ne->lookup_table, read_size) != read_size)
436 myerror("Unable to read lookup table header from file");
438 /* Get the iname table. This is used for looking up the names
439 of functions that are exported */
441 status = lseek(wpnt->fd, wpnt->ne->ne_header->nrname_tab_offset, SEEK_SET);
442 read_size = wpnt->ne->ne_header->nrname_tab_length;
443 wpnt->ne->nrname_table = (char *) malloc(read_size);
444 if (read(wpnt->fd, wpnt->ne->nrname_table, read_size) != read_size)
445 myerror("Unable to read nrname table header from file");
447 status = lseek(wpnt->fd, wpnt->mz_header->ne_offset +
448 wpnt->ne->ne_header->rname_tab_offset, SEEK_SET);
449 read_size = wpnt->ne->ne_header->moduleref_tab_offset -
450 wpnt->ne->ne_header->rname_tab_offset;
451 wpnt->ne->rname_table = (char *) malloc(read_size);
452 if (read(wpnt->fd, wpnt->ne->rname_table, read_size) != read_size)
453 myerror("Unable to read rname table header from file");
456 * Now load any DLLs that this module refers to.
458 for(i=0; i<wpnt->ne->ne_header->n_mod_ref_tab; i++)
460 char buff[14];
461 NE_GetModuleName(wpnt, i + 1, buff);
463 if (strcasecmp(buff, wpnt->name) != 0 )
464 LoadImage(buff, DLL, 0);
466 #ifndef WINELIB
467 /* fixup references */
469 for (segment = 0; segment < wpnt->ne->ne_header->n_segment_tab; segment++)
470 if (NE_FixupSegment(wpnt, segment) < 0)
471 myerror("fixup failed.");
473 FixupFunctionPrologs(wpnt);
474 InitializeLoadedDLLs(wpnt);
475 #endif
476 return(wpnt->hinstance);
479 #endif /* !WINELIB */