Release 0.5
[wine/multimedia.git] / loader / wine.c
blob60b606bbf4a9b748a6cda4efb74ad077d35a3d8f
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";
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #ifdef linux
11 #include <linux/unistd.h>
12 #include <linux/head.h>
13 #include <linux/ldt.h>
14 #include <linux/segment.h>
15 #endif
16 #include <string.h>
17 #include <errno.h>
18 #include "neexe.h"
19 #include "segmem.h"
20 #include "prototypes.h"
21 #include "dlls.h"
22 #include "wine.h"
23 #include "windows.h"
25 extern int CallToInit16(unsigned long csip, unsigned long sssp,
26 unsigned short ds);
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;
39 char **Argv;
40 int Argc;
41 struct mz_header_s *CurrentMZHeader;
42 struct ne_header_s *CurrentNEHeader;
43 int CurrentNEFile;
44 HINSTANCE hSysRes;
46 static char *Extensions[] = { "dll", "exe", NULL };
47 static char *WinePath = NULL;
49 /**********************************************************************
50 * DebugPrintString
52 int
53 DebugPrintString(char *str)
55 printf("%s", str);
56 return 0;
59 /**********************************************************************
60 * myerror
62 void
63 myerror(const char *s)
65 if (s == NULL)
66 perror("wine");
67 else
68 fprintf(stderr, "wine: %s\n", s);
70 exit(1);
73 /**********************************************************************
74 * GetFilenameFromInstance
76 char *
77 GetFilenameFromInstance(unsigned short instance)
79 register struct w_files *w = wine_files;
81 while (w && w->hinstance != instance)
82 w = w->next;
84 if (w)
85 return w->filename;
86 else
87 return NULL;
90 struct w_files *
91 GetFileInfo(unsigned short instance)
93 register struct w_files *w = wine_files;
95 while (w && w->hinstance != instance)
96 w = w->next;
98 return w;
101 /**********************************************************************
102 * LoadImage
103 * Load one NE format executable into memory
105 HINSTANCE LoadImage(char *modulename)
107 unsigned int read_size;
108 int i;
109 struct w_files * wpnt, *wpnt1;
110 unsigned int status;
111 char buffer[256];
113 /* First allocate a spot to store the info we collect, and add it to
114 * our linked list.
117 wpnt = (struct w_files *) malloc(sizeof(struct w_files));
118 if(wine_files == NULL)
119 wine_files = wpnt;
120 else {
121 wpnt1 = wine_files;
122 while(wpnt1->next) wpnt1 = wpnt1->next;
123 wpnt1->next = wpnt;
125 wpnt->next = NULL;
128 * search file
131 if (FindFile(buffer, sizeof(buffer), modulename, Extensions, WindowsPath)
132 ==NULL)
134 char temp[256];
136 sprintf(temp,"LoadImage: I can't find %s !\n",modulename);
137 myerror(temp);
139 fprintf(stderr,"LoadImage: loading %s (%s)\n", modulename, buffer);
142 * Open file for reading.
144 wpnt->fd = open(buffer, O_RDONLY);
145 if (wpnt->fd < 0)
147 myerror(NULL);
150 * Establish header pointers.
152 wpnt->filename = strdup(buffer);
153 wpnt->name = NULL;
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,
191 SEEK_SET);
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);
198 wpnt->hinstance
199 = 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++){
239 char buff[14];
240 char buff2[256];
241 int fd, j;
242 GetModuleName(wpnt, i + 1, buff);
244 if(FindDLLTable(buff)) continue; /* This module already loaded */
246 LoadImage(buff);
248 fprintf(stderr,"Unable to load:%s\n", buff);
251 return(wpnt->hinstance);
255 /**********************************************************************
256 * main
258 _WinMain(int argc, char **argv)
260 int segment;
261 char *p;
262 char *sysresname;
263 char syspath[256];
264 char exe_path[256];
265 #ifdef WINESTAT
266 char * cp;
267 #endif
268 struct w_files * wpnt;
269 int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg;
270 int i;
271 int rv;
273 Argc = argc - 1;
274 Argv = argv + 1;
276 if (argc < 2)
278 fprintf(stderr, "usage: %s FILENAME\n", argv[0]);
279 exit(1);
282 p = getenv("WINEPATH");
283 WinePath = malloc(256 + strlen(p));
284 getcwd(WinePath, 256);
285 strcat(WinePath, ";");
286 strcat(WinePath, p);
288 LoadImage(argv[1]);
289 hSysRes = LoadImage("sysres.dll");
290 if (hSysRes == (HINSTANCE)NULL)
291 printf("Error Loading System Resources !!!\n");
292 else
293 printf("System Resources Loaded // hSysRes='%04X'\n", hSysRes);
295 if(ran_out) exit(1);
296 #ifdef DEBUG
298 int dummy1, dummy2;
300 GetEntryDLLName("USER", "INITAPP", &dummy1, &dummy2);
302 for(i=0; i<1024; i++) {
303 int j;
304 j = GetEntryPointFromOrdinal(wine_files, i);
305 if(j == 0) break;
306 fprintf(stderr," %d %x\n", i, j);
308 #endif
310 * Fixup references.
312 wpnt = wine_files;
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;
331 #ifdef WINESTAT
332 cp = strrchr(argv[0], '/');
333 if(!cp) cp = argv[0];
334 else cp++;
335 if(strcmp(cp,"winestat") == 0) {
336 winestat();
337 exit(0);
339 #endif
341 init_wine_signals();
343 if (WineForceFail)
345 p = (char *) ((cs_reg << 16) | ip_reg);
347 *p++ = 0xcd;
348 *p++ = 0x20;
351 if (ss_reg == 0)
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 /**********************************************************************
364 * GetImportedName
366 char *
367 GetImportedName(int fd, struct mz_header_s *mz_header,
368 struct ne_header_s *ne_header, int name_offset, char *buffer)
370 char *p;
371 int length;
372 int status;
373 int i;
375 status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
376 name_offset, SEEK_SET);
377 length = 0;
378 read(fd, &length, 1); /* Get the length byte */
379 read(fd, buffer, length);
380 buffer[length] = 0;
381 return buffer;
384 /**********************************************************************
385 * GetModuleName
387 char *
388 GetModuleName(struct w_files * wpnt, int index, char *buffer)
390 int fd = wpnt->fd;
391 struct mz_header_s *mz_header = wpnt->mz_header;
392 struct ne_header_s *ne_header = wpnt->ne_header;
393 char *p;
394 int length;
395 int name_offset, status;
396 int i;
398 status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset +
399 2*(index - 1), SEEK_SET);
400 name_offset = 0;
401 read(fd, &name_offset, 2);
402 status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
403 name_offset, SEEK_SET);
404 length = 0;
405 read(fd, &length, 1); /* Get the length byte */
406 read(fd, buffer, length);
407 buffer[length] = 0;
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;
413 return buffer;
417 /**********************************************************************
418 * FixupSegment
421 FixupSegment(struct w_files * wpnt, int segment_num)
423 int fd = wpnt->fd;
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;
432 int status;
433 unsigned short *sp;
434 unsigned int selector, address;
435 unsigned int next_addr;
436 int ordinal;
437 char dll_name[257];
438 char func_name[257];
439 int i, n_entries;
440 int additive;
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))
450 return 0;
453 * Go through the relocation table on entry at a time.
455 i = seg->seg_data_length;
456 if (i == 0)
457 i = 0x10000;
459 status = lseek(fd, seg->seg_data_offset *
460 (1 << ne_header->align_shift_count) + i, SEEK_SET);
461 n_entries = 0;
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");
472 rep1 = rep;
474 for (i = 0; i < n_entries; i++, rep++)
477 * Get the target address corresponding to this entry.
479 additive = 0;
481 switch (rep->relocation_type)
483 case NE_RELTYPE_ORDINALADD:
484 additive = 1;
486 case NE_RELTYPE_ORDINAL:
487 if (GetModuleName(wpnt, rep->target1,
488 dll_name) == NULL)
490 fprintf(stderr, "NE_RELTYPE_ORDINAL failed");
491 return -1;
494 ordinal = rep->target2;
496 status = GetEntryDLLOrdinal(dll_name, ordinal, &selector,
497 &address);
498 if (status)
500 char s[80];
502 sprintf(s, "Bad DLL name '%s.%d'", dll_name, ordinal);
503 myerror(s);
504 return -1;
507 #ifdef DEBUG_FIXUP
508 printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal,
509 selector, address);
510 #endif
511 break;
513 case NE_RELTYPE_NAMEADD:
514 additive = 1;
516 case NE_RELTYPE_NAME:
517 if (GetModuleName(wpnt, rep->target1, dll_name)
518 == NULL)
520 fprintf(stderr,"NE_RELTYPE_NAME failed");
521 return -1;
524 if (GetImportedName(fd, mz_header, ne_header,
525 rep->target2, func_name) == NULL)
527 fprintf(stderr,"getimportedname failed");
528 return -1;
531 status = GetEntryDLLName(dll_name, func_name, &selector,
532 &address);
533 if (status)
535 char s[80];
537 sprintf(s, "Bad DLL name '%s (%s)'", dll_name,func_name);
538 myerror(s);
539 return -1;
542 #ifdef DEBUG_FIXUP
543 printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name,
544 dll_name, ordinal, selector, address);
545 #endif
546 break;
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;
554 address &= 0xffff;
556 else
558 selector = selector_table[rep->target1-1].selector;
559 address = rep->target2;
562 #ifdef DEBUG_FIXUP
563 printf("%d: %04.4x:%04.4x\n", i + 1, selector, address);
564 #endif
565 break;
567 case 7:
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
574 * exist.
576 #ifdef DEBUG_FIXUP
577 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
578 i + 1, rep->address_type, rep->relocation_type,
579 rep->offset);
580 printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
581 #endif
582 continue;
584 default:
585 fprintf(stderr,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
586 i + 1, rep->address_type, rep->relocation_type,
587 rep->offset);
588 fprintf(stderr,"TARGET %04.4x %04.4x\n",
589 rep->target1, rep->target2);
590 free(rep1);
591 return -1;
592 #if 0
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);
596 WineForceFail = 1;
597 continue;
598 #endif
602 * Stuff the right size result in.
604 sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
605 if (additive)
607 if (FindDLLTable(dll_name) == NULL)
608 additive = 2;
610 fprintf(stderr,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
611 i + 1, rep->address_type, rep->relocation_type,
612 rep->offset);
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:
621 do {
622 next_addr = *sp;
623 *sp = (unsigned short) address;
624 if (additive == 2)
625 *sp += next_addr;
626 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
628 while (next_addr != 0xffff && !additive);
630 break;
632 case NE_RADDR_POINTER32:
633 do {
634 next_addr = *sp;
635 *sp = (unsigned short) address;
636 if (additive == 2)
637 *sp += next_addr;
638 *(sp+1) = (unsigned short) selector;
639 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
641 while (next_addr != 0xffff && !additive);
643 break;
645 case NE_RADDR_SELECTOR:
646 do {
647 next_addr = *sp;
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);
655 break;
657 default:
658 printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ",
659 i + 1, rep->address_type, rep->relocation_type,
660 rep->offset);
661 printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
662 free(rep1);
663 return -1;
667 free(rep1);
668 return 0;
671 /**********************************************************************
672 * GetProcAddress
674 FARPROC GetProcAddress(HINSTANCE hinstance, char *proc_name)
676 if ((int) proc_name & 0xffff0000)
677 printf("GetProcAddress: %#04x, '%s'\n", hinstance, proc_name);
678 else
679 printf("GetProcAddress: %#04x, %d\n", hinstance, (int) proc_name);
681 return NULL;