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