Release 940201
[wine] / loader / wine.c
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";
3
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"
24 #include "wineopts.h"
25
26 /* #define DEBUG_FIXUP */
27
28 extern int CallToInit16(unsigned long csip, unsigned long sssp, 
29                         unsigned short ds);
30 extern void CallTo32();
31
32 char * GetModuleName(struct w_files * wpnt, int index, char *buffer);
33 extern unsigned char ran_out;
34 extern char WindowsPath[256];
35 unsigned short WIN_StackSize;
36 unsigned short WIN_HeapSize;
37
38 struct  w_files * wine_files = NULL;
39
40 int WineForceFail = 0;
41
42 char **Argv;
43 int Argc;
44 struct mz_header_s *CurrentMZHeader;
45 struct ne_header_s *CurrentNEHeader;
46 int CurrentNEFile;
47 HINSTANCE hSysRes;
48
49 static char *Extensions[] = { "dll", "exe", NULL };
50 static char *WinePath = NULL;
51
52 FILE *SpyFp = NULL;
53
54 /**********************************************************************
55  *                                      DebugPrintString
56  */
57 int
58 DebugPrintString(char *str)
59 {
60     printf("%s", str);
61     return 0;
62 }
63
64 /**********************************************************************
65  *                                      myerror
66  */
67 void
68 myerror(const char *s)
69 {
70     if (s == NULL)
71         perror("wine");
72     else
73         fprintf(stderr, "wine: %s\n", s);
74
75     exit(1);
76 }
77 \f
78 /**********************************************************************
79  *                                      GetFilenameFromInstance
80  */
81 char *
82 GetFilenameFromInstance(unsigned short instance)
83 {
84     register struct w_files *w = wine_files;
85
86     while (w && w->hinstance != instance)
87         w = w->next;
88     
89     if (w)
90         return w->filename;
91     else
92         return NULL;
93 }
94
95 struct w_files *
96 GetFileInfo(unsigned short instance)
97 {
98     register struct w_files *w = wine_files;
99
100     while (w && w->hinstance != instance)
101         w = w->next;
102     
103     return w;
104 }
105 \f
106 /**********************************************************************
107  *                                      LoadImage
108  * Load one NE format executable into memory
109  */
110 HINSTANCE LoadImage(char *modulename)
111 {
112     unsigned int read_size;
113     int i;
114     struct w_files * wpnt, *wpnt1;
115     unsigned int status;
116     char buffer[256];
117
118     /*
119      * search file
120      */
121     if (FindFile(buffer, sizeof(buffer), modulename, Extensions, WindowsPath)
122         ==NULL)
123     {
124         
125
126         fprintf(stderr,"LoadImage: I can't find %s !\n",modulename);
127         return (HINSTANCE) NULL;
128     }
129     fprintf(stderr,"LoadImage: loading %s (%s)\n", modulename, buffer);
130
131     /* First allocate a spot to store the info we collect, and add it to
132      * our linked list.
133      */
134
135     wpnt = (struct w_files *) malloc(sizeof(struct w_files));
136     if(wine_files == NULL)
137       wine_files = wpnt;
138     else {
139       wpnt1 = wine_files;
140       while(wpnt1->next) wpnt1 =  wpnt1->next;
141       wpnt1->next  = wpnt;
142     };
143     wpnt->next = NULL;
144
145     /*
146      * Open file for reading.
147      */
148     wpnt->fd = open(buffer, O_RDONLY);
149     if (wpnt->fd < 0)
150     {
151         myerror(NULL);
152     }
153     /*
154      * Establish header pointers.
155      */
156     wpnt->filename = strdup(buffer);
157     wpnt->name = NULL;
158     if(modulename)  wpnt->name = strdup(modulename);
159
160     wpnt->mz_header = (struct mz_header_s *) malloc(sizeof(struct mz_header_s));;
161     status = lseek(wpnt->fd, 0, SEEK_SET);
162     if (read(wpnt->fd, wpnt->mz_header, sizeof(struct mz_header_s)) !=
163         sizeof(struct mz_header_s))
164     {
165         myerror("Unable to read MZ header from file");
166     }
167     if (wpnt->mz_header->must_be_0x40 != 0x40)
168         myerror("This is not a Windows program");
169     
170     wpnt->ne_header = (struct ne_header_s *) malloc(sizeof(struct ne_header_s));
171     status = lseek(wpnt->fd, wpnt->mz_header->ne_offset, SEEK_SET);
172     if (read(wpnt->fd, wpnt->ne_header, sizeof(struct ne_header_s)) 
173         != sizeof(struct ne_header_s))
174     {
175         myerror("Unable to read NE header from file");
176     }
177     if (wpnt->ne_header->header_type[0] != 'N' || 
178         wpnt->ne_header->header_type[1] != 'E')
179       myerror("This is not a Windows program");
180
181     if(wine_files ==  wpnt){
182       CurrentMZHeader = wpnt->mz_header;
183       CurrentNEHeader = wpnt->ne_header;
184       CurrentNEFile   = wpnt->fd;
185       
186       WIN_StackSize = wpnt->ne_header->stack_length;
187       WIN_HeapSize = wpnt->ne_header->local_heap_length;
188     };
189
190     /*
191      * Create segment selectors.
192      */
193     status = lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
194                    wpnt->ne_header->segment_tab_offset,
195                    SEEK_SET);
196     read_size  = wpnt->ne_header->n_segment_tab *
197                  sizeof(struct ne_segment_table_entry_s);
198     wpnt->seg_table = (struct ne_segment_table_entry_s *) malloc(read_size);
199     if (read(wpnt->fd, wpnt->seg_table, read_size) != read_size)
200         myerror("Unable to read segment table header from file");
201     wpnt->selector_table = CreateSelectors(wpnt);
202     wpnt->hinstance 
203         = wpnt->
204             selector_table[wpnt->ne_header->auto_data_seg-1].selector;
205
206     /* Get the lookup  table.  This is used for looking up the addresses
207        of functions that are exported */
208
209     read_size  = wpnt->ne_header->entry_tab_length;
210     wpnt->lookup_table = (char *) malloc(read_size);
211     lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
212           wpnt->ne_header->entry_tab_offset, SEEK_SET);
213     if (read(wpnt->fd, wpnt->lookup_table, read_size) != read_size)
214         myerror("Unable to read lookup table header from file");
215
216     /* Get the iname table.  This is used for looking up the names
217        of functions that are exported */
218
219     status = lseek(wpnt->fd, wpnt->ne_header->nrname_tab_offset,  SEEK_SET);
220     read_size  = wpnt->ne_header->nrname_tab_length;
221     wpnt->nrname_table = (char *) malloc(read_size);
222     if (read(wpnt->fd, wpnt->nrname_table, read_size) != read_size)
223         myerror("Unable to read nrname table header from file");
224
225     status = lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
226                    wpnt->ne_header->rname_tab_offset,  SEEK_SET);
227     read_size  = wpnt->ne_header->moduleref_tab_offset - 
228             wpnt->ne_header->rname_tab_offset;
229     wpnt->rname_table = (char *) malloc(read_size);
230     if (read(wpnt->fd, wpnt->rname_table, read_size) != read_size)
231         myerror("Unable to read rname table header from file");
232
233     /* Now get the module name */
234
235     wpnt->name  = (char*) malloc(*wpnt->rname_table + 1);
236     memcpy(wpnt->name, wpnt->rname_table+1, *wpnt->rname_table);
237     wpnt->name[*wpnt->rname_table] =  0;
238
239     /*
240      * Now load any DLLs that  this module refers to.
241      */
242     for(i=0; i<wpnt->ne_header->n_mod_ref_tab; i++){
243       char buff[14];
244       char buff2[256];
245       int  fd, j;
246       GetModuleName(wpnt, i + 1, buff);
247       
248       if(FindDLLTable(buff)) continue;  /* This module already loaded */
249
250       LoadImage(buff);
251 /*
252       fprintf(stderr,"Unable to load:%s\n",  buff);
253 */
254     }
255 return(wpnt->hinstance);
256 }
257 \f
258 /**********************************************************************
259  *                                      ParseArgs
260  */
261 void
262 ParseArgs(int argc, char **argv)
263 {
264     if (argc < 2)
265     {
266         fprintf(stderr, "usage: %s [-spy FILENAME] FILENAME\n", argv[0]);
267         exit(1);
268     }
269
270     Argc = argc - 1;
271     
272     for (Argv = argv + 1; **Argv == '-' && Argc > 0; Argv++)
273     {
274         if (strcmp(*Argv, "-spy") == 0)
275         {
276             if (strcmp(*(++Argv), "-") == 0)
277                 SpyFp = stdout;
278             else
279                 SpyFp = fopen(*Argv, "a");
280         }
281     }
282 }
283
284 /**********************************************************************
285  *                                      main
286  */
287 _WinMain(int argc, char **argv)
288 {
289         int segment;
290         char *p;
291         char *sysresname;
292         char filename[100];
293         char syspath[256];
294         char exe_path[256];
295 #ifdef WINESTAT
296         char * cp;
297 #endif
298         struct w_files * wpnt;
299         int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg;
300         int i;
301         int rv;
302
303         ParseArgs(argc, argv);
304
305         p = getenv("WINEPATH");
306         WinePath = malloc(256 + strlen(p));
307         getcwd(WinePath, 256);
308         strcat(WinePath, ";");
309         strcat(WinePath, p);
310
311         LoadImage(Argv[0]);
312
313         GetPrivateProfileString("wine", "SystemResources", "sysres.dll", 
314                                 filename, sizeof(filename),
315                                 WINE_INI);
316         hSysRes = LoadImage(filename);
317         if (hSysRes == (HINSTANCE)NULL)
318             printf("Error Loading System Resources !!!\n");
319         else
320             printf("System Resources Loaded // hSysRes='%04X'\n", hSysRes);
321         
322     /*
323      * Fixup references.
324      */
325     wpnt = wine_files;
326     for(wpnt = wine_files; wpnt; wpnt = wpnt->next)
327       for (segment = 0; segment < wpnt->ne_header->n_segment_tab; segment++)
328         {
329           if (FixupSegment(wpnt, segment) < 0)
330             {
331               myerror("fixup failed.");
332             }
333         }
334
335     /*
336      * Fixup stack and jump to start.
337      */
338     ds_reg = wine_files->selector_table[wine_files->ne_header->auto_data_seg-1].selector;
339     cs_reg = wine_files->selector_table[wine_files->ne_header->cs-1].selector;
340     ip_reg = wine_files->ne_header->ip;
341     ss_reg = wine_files->selector_table[wine_files->ne_header->ss-1].selector;
342     sp_reg = wine_files->ne_header->sp;
343
344 #ifdef WINESTAT
345     cp = strrchr(argv[0], '/');
346     if(!cp) cp = argv[0];
347         else cp++;
348     if(strcmp(cp,"winestat") == 0) {
349             winestat();
350             exit(0);
351     };
352 #endif
353
354     init_wine_signals();
355
356     if (WineForceFail)
357     {
358         p = (char *) ((cs_reg << 16) | ip_reg);
359         
360         *p++ = 0xcd;
361         *p++ = 0x20;
362     }
363
364     if (ss_reg == 0)
365     {
366         fprintf(stderr, "SS is 0\n");
367     }
368
369     LinearTest();
370
371     rv = CallToInit16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg);
372     printf ("rv = %x\n", rv);
373 }
374
375 \f
376 /**********************************************************************
377  *                                      GetImportedName
378  */
379 char *
380 GetImportedName(int fd, struct mz_header_s *mz_header, 
381                 struct ne_header_s *ne_header, int name_offset, char *buffer)
382 {
383     char *p;
384     int length;
385     int status;
386     int i;
387     
388     status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
389                    name_offset, SEEK_SET);
390     length = 0;
391     read(fd, &length, 1);  /* Get the length byte */
392     read(fd, buffer, length);
393     buffer[length] = 0;
394     return buffer;
395 }
396
397 /**********************************************************************
398  *                                      GetModuleName
399  */
400 char *
401 GetModuleName(struct w_files * wpnt, int index, char *buffer)
402 {
403     int fd = wpnt->fd;
404     struct mz_header_s *mz_header = wpnt->mz_header; 
405     struct ne_header_s *ne_header = wpnt->ne_header;
406     char *p;
407     int length;
408     int name_offset, status;
409     int i;
410     
411     status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset +
412                    2*(index - 1), SEEK_SET);
413     name_offset = 0;
414     read(fd, &name_offset, 2);
415     status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
416                    name_offset, SEEK_SET);
417     length = 0;
418     read(fd, &length, 1);  /* Get the length byte */
419     read(fd, buffer, length);
420     buffer[length] = 0;
421
422     /* Module names  are always upper case */
423     for(i=0; i<length; i++)
424             if(buffer[i] >= 'a' && buffer[i] <= 'z')  buffer[i] &= ~0x20;
425
426     return buffer;
427 }
428
429 \f
430 /**********************************************************************
431  *                                      FixupSegment
432  */
433 int
434 FixupSegment(struct w_files * wpnt, int segment_num)
435 {
436     int fd =  wpnt->fd;
437     struct mz_header_s * mz_header = wpnt->mz_header;
438     struct ne_header_s *ne_header =  wpnt->ne_header;
439     struct ne_segment_table_entry_s *seg_table = wpnt->seg_table;
440     struct segment_descriptor_s *selector_table = wpnt->selector_table;
441     struct relocation_entry_s *rep, *rep1;
442     struct ne_segment_table_entry_s *seg;
443     struct segment_descriptor_s *sel;
444     struct dll_table_entry_s *dll_table;
445     int status;
446     unsigned short *sp;
447     unsigned int selector, address;
448     unsigned int next_addr;
449     int ordinal;
450     char dll_name[257];
451     char func_name[257];
452     int i, n_entries;
453     int additive;
454
455     seg = &seg_table[segment_num];
456     sel = &selector_table[segment_num];
457
458 #ifdef DEBUG_FIXUP
459     printf("Segment fixups for %s, segment %d, selector %x\n", 
460            wpnt->name, segment_num, (int) sel->base_addr >> 16);
461 #endif
462
463     if ((seg->seg_data_offset == 0) ||
464         !(seg->seg_flags & NE_SEGFLAGS_RELOC_DATA))
465         return 0;
466
467     /*
468      * Go through the relocation table on entry at a time.
469      */
470     i = seg->seg_data_length;
471     if (i == 0)
472         i = 0x10000;
473
474     status = lseek(fd, seg->seg_data_offset * 
475                        (1 << ne_header->align_shift_count) + i, SEEK_SET);
476     n_entries = 0;
477     read(fd, &n_entries, sizeof(short int));
478     rep = (struct relocation_entry_s *)
479           malloc(n_entries * sizeof(struct relocation_entry_s));
480
481     if (read(fd,rep, n_entries * sizeof(struct relocation_entry_s)) !=
482         n_entries * sizeof(struct relocation_entry_s))
483     {
484         myerror("Unable to read relocation information");
485     }
486     
487     rep1 = rep;
488
489     for (i = 0; i < n_entries; i++, rep++)
490     {
491         /*
492          * Get the target address corresponding to this entry.
493          */
494         additive = 0;
495         
496         switch (rep->relocation_type)
497         {
498           case NE_RELTYPE_ORDINALADD:
499             additive = 1;
500             
501           case NE_RELTYPE_ORDINAL:
502             if (GetModuleName(wpnt, rep->target1,
503                               dll_name) == NULL)
504             {
505               fprintf(stderr, "NE_RELTYPE_ORDINAL failed");
506                 return -1;
507             }
508             
509             ordinal = rep->target2;
510
511             status = GetEntryDLLOrdinal(dll_name, ordinal, &selector,
512                                         &address);
513             if (status)
514             {
515                 char s[80];
516                 
517                 sprintf(s, "Bad DLL name '%s.%d'", dll_name, ordinal);
518                 myerror(s);
519                 return -1;
520             }
521
522 #ifdef DEBUG_FIXUP
523             printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal,
524                    selector, address);
525 #endif
526             break;
527             
528           case NE_RELTYPE_NAMEADD:
529             additive = 1;
530             
531           case NE_RELTYPE_NAME:
532             if (GetModuleName(wpnt, rep->target1, dll_name)
533                 == NULL)
534             {
535               fprintf(stderr,"NE_RELTYPE_NAME failed");
536                 return -1;
537             }
538
539             if (GetImportedName(fd, mz_header, ne_header, 
540                                 rep->target2, func_name) == NULL)
541             {
542               fprintf(stderr,"getimportedname failed");
543                 return -1;
544             }
545
546             status = GetEntryDLLName(dll_name, func_name, &selector, 
547                                            &address);
548             if (status)
549             {
550                 char s[80];
551                 
552                 sprintf(s, "Bad DLL name '%s (%s)'", dll_name,func_name);
553                 myerror(s);
554                 return -1;
555             }
556
557 #ifdef DEBUG_FIXUP
558             printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name,
559                    dll_name, ordinal, selector, address);
560 #endif
561             break;
562             
563           case NE_RELTYPE_INTERNAL:
564           case NE_RELTYPE_INT1:
565             if (rep->target1 == 0x00ff)
566             {
567                 address  = GetEntryPointFromOrdinal(wpnt, rep->target2);
568                 selector = (address >> 16) & 0xffff;
569                 address &= 0xffff;
570             }
571             else
572             {
573                 selector = selector_table[rep->target1-1].selector;
574                 address  = rep->target2;
575             }
576             
577 #ifdef DEBUG_FIXUP
578             printf("%d: %04.4x:%04.4x\n", i + 1, selector, address);
579 #endif
580             break;
581
582           case 7:
583             /* Relocation type 7:
584              *
585              *    These appear to be used as fixups for the Windows
586              * floating point emulator.  Let's just ignore them and
587              * try to use the hardware floating point.  Linux should
588              * successfully emulate the coprocessor if it doesn't
589              * exist.
590              */
591 #ifdef DEBUG_FIXUP
592             printf("%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
593                    i + 1, rep->address_type, rep->relocation_type, 
594                    rep->offset);
595             printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
596 #endif
597             continue;
598             
599           default:
600             fprintf(stderr,"%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
601                    i + 1, rep->address_type, rep->relocation_type, 
602                    rep->offset);
603             fprintf(stderr,"TARGET %04.4x %04.4x\n", 
604                     rep->target1, rep->target2);
605             free(rep1);
606             return -1;
607         }
608
609         /*
610          * Stuff the right size result in.
611          */
612         sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
613         if (additive)
614         {
615             if (FindDLLTable(dll_name) == NULL)
616                 additive = 2;
617
618             fprintf(stderr,"%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
619                    i + 1, rep->address_type, rep->relocation_type, 
620                    rep->offset);
621             fprintf(stderr,"TARGET %04.4x %04.4x\n", 
622                     rep->target1, rep->target2);
623             fprintf(stderr, "    Additive = %d\n", additive);
624         }
625         
626         switch (rep->address_type)
627         {
628           case NE_RADDR_OFFSET16:
629             do {
630 #ifdef DEBUG_FIXUP
631                 printf("    %04.4x:%04.4x:%04.4x OFFSET16\n",
632                        (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
633 #endif
634                 next_addr = *sp;
635                 *sp = (unsigned short) address;
636                 if (additive == 2)
637                     *sp += next_addr;
638                 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
639             } 
640             while (next_addr != 0xffff && !additive);
641
642             break;
643             
644           case NE_RADDR_POINTER32:
645             do {
646 #ifdef DEBUG_FIXUP
647                 printf("    %04.4x:%04.4x:%04.4x POINTER32\n",
648                        (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
649 #endif
650                 next_addr = *sp;
651                 *sp     = (unsigned short) address;
652                 if (additive == 2)
653                     *sp += next_addr;
654                 *(sp+1) = (unsigned short) selector;
655                 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
656             } 
657             while (next_addr != 0xffff && !additive);
658
659             break;
660             
661           case NE_RADDR_SELECTOR:
662             do {
663 #ifdef DEBUG_FIXUP
664                 printf("    %04.4x:%04.4x:%04.4x SELECTOR\n",
665                        (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
666 #endif
667                 next_addr = *sp;
668                 *sp     = (unsigned short) selector;
669                 sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
670                 if (rep->relocation_type == NE_RELTYPE_INT1) 
671                     break;
672             } 
673             while (next_addr != 0xffff && !additive);
674
675             break;
676             
677           default:
678             printf("%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
679                    i + 1, rep->address_type, rep->relocation_type, 
680                    rep->offset);
681             printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
682             free(rep1);
683             return -1;
684         }
685     }
686
687     free(rep1);
688     return 0;
689 }
690
691 /**********************************************************************
692  *                                      GetProcAddress
693  */
694 FARPROC GetProcAddress(HINSTANCE hinstance, char *proc_name)
695 {
696     if ((int) proc_name & 0xffff0000)
697         printf("GetProcAddress: %#04x, '%s'\n", hinstance, proc_name);
698     else
699         printf("GetProcAddress: %#04x, %d\n", hinstance, (int) proc_name);
700
701     return NULL;
702 }