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