Release 960516
[wine] / tools / build.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Martin von Loewis
4  * Copyright 1995, 1996 Alexandre Julliard
5  */
6
7 #ifndef WINELIB
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include "registers.h"
14 #include "winerror.h"  /* for ERROR_CALL_NOT_IMPLEMENTED */
15 #include "module.h"
16 #include "neexe.h"
17 #include "windows.h"
18
19 /* ELF symbols do not have an underscore in front */
20 #if defined (__ELF__) || defined (__svr4__) || defined(_SCO_DS)
21 #define PREFIX
22 #else
23 #define PREFIX "_"
24 #endif
25
26 #define TYPE_INVALID     0
27 #define TYPE_BYTE        1
28 #define TYPE_WORD        2
29 #define TYPE_LONG        3
30 #define TYPE_PASCAL_16   4
31 #define TYPE_PASCAL      5
32 #define TYPE_REGISTER    6
33 #define TYPE_ABS         7
34 #define TYPE_RETURN      8
35 #define TYPE_STUB        9
36 #define TYPE_STDCALL    10
37
38 #define MAX_ORDINALS    1299
39
40   /* Callback function used for stub functions */
41 #define STUB_CALLBACK \
42   ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
43
44 enum SPEC_TYPE
45 {
46     SPEC_INVALID,
47     SPEC_WIN16,
48     SPEC_WIN32
49 };
50
51 typedef struct ordinal_definition_s
52 {
53     int type;
54     int offset;
55     char export_name[80];
56     void *additional_data;
57 } ORDDEF;
58
59 typedef struct ordinal_variable_definition_s
60 {
61     int n_values;
62     int *values;
63 } ORDVARDEF;
64
65 typedef struct ordinal_function_definition_s
66 {
67     int  n_args;
68     char arg_types[32];
69     char internal_name[80];
70 } ORDFUNCDEF;
71
72 typedef struct ordinal_return_definition_s
73 {
74     int arg_size;
75     int ret_value;
76 } ORDRETDEF;
77
78 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
79
80 static enum SPEC_TYPE SpecType = SPEC_INVALID;
81 char DLLName[80];
82 int Limit = 0;
83 int Base = 0;
84 int HeapSize = 0;
85 FILE *SpecFp;
86
87 char *ParseBuffer = NULL;
88 char *ParseNext;
89 char ParseSaveChar;
90 int Line;
91
92 static int debugging = 1;
93
94   /* Offset of register relative to the end of the context struct */
95 #define CONTEXTOFFSET(reg) \
96   ((int)&reg##_reg((struct sigcontext_struct *)0) \
97    - sizeof(struct sigcontext_struct))
98
99 static void *xmalloc (size_t size)
100 {
101     void *res;
102
103     res = malloc (size ? size : 1);
104     if (res == NULL)
105     {
106         fprintf (stderr, "Virtual memory exhausted.\n");
107         exit (1);
108     }
109     return res;
110 }
111
112
113 static void *xrealloc (void *ptr, size_t size)
114 {
115     void *res = realloc (ptr, size);
116     if (res == NULL)
117     {
118         fprintf (stderr, "Virtual memory exhausted.\n");
119         exit (1);
120     }
121     return res;
122 }
123
124
125 static int IsNumberString(char *s)
126 {
127     while (*s != '\0')
128         if (!isdigit(*s++))
129             return 0;
130
131     return 1;
132 }
133
134 static char *strupper(char *s)
135 {
136     char *p;
137     
138     for(p = s; *p != '\0'; p++)
139         *p = toupper(*p);
140
141     return s;
142 }
143
144 static char * GetTokenInLine(void)
145 {
146     char *p;
147     char *token;
148
149     if (ParseNext != ParseBuffer)
150     {
151         if (ParseSaveChar == '\0')
152             return NULL;
153         *ParseNext = ParseSaveChar;
154     }
155     
156     /*
157      * Remove initial white space.
158      */
159     for (p = ParseNext; isspace(*p); p++)
160         ;
161     
162     if ((*p == '\0') || (*p == '#'))
163         return NULL;
164     
165     /*
166      * Find end of token.
167      */
168     token = p++;
169     if (*token != '(' && *token != ')')
170         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
171             p++;
172     
173     ParseSaveChar = *p;
174     ParseNext = p;
175     *p = '\0';
176
177     return token;
178 }
179
180 static char * GetToken(void)
181 {
182     char *token;
183
184     if (ParseBuffer == NULL)
185     {
186         ParseBuffer = xmalloc(512);
187         ParseNext = ParseBuffer;
188         Line++;
189         while (1)
190         {
191             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
192                 return NULL;
193             if (ParseBuffer[0] != '#')
194                 break;
195         }
196     }
197
198     while ((token = GetTokenInLine()) == NULL)
199     {
200         ParseNext = ParseBuffer;
201         Line++;
202         while (1)
203         {
204             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
205                 return NULL;
206             if (ParseBuffer[0] != '#')
207                 break;
208         }
209     }
210
211     return token;
212 }
213
214 static int ParseVariable(int ordinal, int type)
215 {
216     ORDDEF *odp;
217     ORDVARDEF *vdp;
218     char export_name[80];
219     char *token;
220     char *endptr;
221     int *value_array;
222     int n_values;
223     int value_array_size;
224     
225     strcpy(export_name, GetToken());
226
227     token = GetToken();
228     if (*token != '(')
229     {
230         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
231         exit(1);
232     }
233
234     n_values = 0;
235     value_array_size = 25;
236     value_array = xmalloc(sizeof(*value_array) * value_array_size);
237     
238     while ((token = GetToken()) != NULL)
239     {
240         if (*token == ')')
241             break;
242
243         value_array[n_values++] = strtol(token, &endptr, 0);
244         if (n_values == value_array_size)
245         {
246             value_array_size += 25;
247             value_array = xrealloc(value_array, 
248                                    sizeof(*value_array) * value_array_size);
249         }
250         
251         if (endptr == NULL || *endptr != '\0')
252         {
253             fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
254                     token);
255             exit(1);
256         }
257     }
258     
259     if (token == NULL)
260     {
261         fprintf(stderr, "%d: End of file in variable declaration\n", Line);
262         exit(1);
263     }
264
265     if (ordinal >= MAX_ORDINALS)
266     {
267         fprintf(stderr, "%d: Ordinal number too large\n", Line);
268         exit(1);
269     }
270     
271     odp = &OrdinalDefinitions[ordinal];
272     odp->type = type;
273     strcpy(odp->export_name, export_name);
274
275     vdp = xmalloc(sizeof(*vdp));
276     odp->additional_data = vdp;
277     
278     vdp->n_values = n_values;
279     vdp->values = xrealloc(value_array, sizeof(*value_array) * n_values);
280
281     return 0;
282 }
283
284 static int ParseExportFunction(int ordinal, int type)
285 {
286     char *token;
287     ORDDEF *odp;
288     ORDFUNCDEF *fdp;
289     int i;
290     
291     odp = &OrdinalDefinitions[ordinal];
292     strcpy(odp->export_name, GetToken());
293     odp->type = type;
294     fdp = xmalloc(sizeof(*fdp));
295     odp->additional_data = fdp;
296
297     token = GetToken();
298     if (*token != '(')
299     {
300         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
301         exit(1);
302     }
303
304     for (i = 0; i < 16; i++)
305     {
306         token = GetToken();
307         if (*token == ')')
308             break;
309
310         if (!strcmp(token, "byte") || !strcmp(token, "word"))
311             fdp->arg_types[i] = 'w';
312         else if (!strcmp(token, "s_byte") || !strcmp(token, "s_word"))
313             fdp->arg_types[i] = 's';
314         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
315             fdp->arg_types[i] = 'l';
316         else if (!strcmp(token, "ptr"))
317             fdp->arg_types[i] = 'p';
318         else
319         {
320             fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
321             exit(1);
322         }
323     }
324     fdp->arg_types[i] = '\0';
325
326     strcpy(fdp->internal_name, GetToken());
327     return 0;
328 }
329
330 static int ParseEquate(int ordinal)
331 {
332     ORDDEF *odp;
333     char *token;
334     char *endptr;
335     int value;
336     
337     odp = &OrdinalDefinitions[ordinal];
338     strcpy(odp->export_name, GetToken());
339
340     token = GetToken();
341     value = strtol(token, &endptr, 0);
342     if (endptr == NULL || *endptr != '\0')
343     {
344         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
345                 token);
346         exit(1);
347     }
348
349     odp->type = TYPE_ABS;
350     odp->additional_data = (void *) value;
351
352     return 0;
353 }
354
355 static int ParseReturn(int ordinal)
356 {
357     ORDDEF *odp;
358     ORDRETDEF *rdp;
359     char *token;
360     char *endptr;
361     
362     rdp = xmalloc(sizeof(*rdp));
363     
364     odp = &OrdinalDefinitions[ordinal];
365     strcpy(odp->export_name, GetToken());
366     odp->type = TYPE_RETURN;
367     odp->additional_data = rdp;
368
369     token = GetToken();
370     rdp->arg_size = strtol(token, &endptr, 0);
371     if (endptr == NULL || *endptr != '\0')
372     {
373         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
374                 token);
375         exit(1);
376     }
377
378     token = GetToken();
379     rdp->ret_value = strtol(token, &endptr, 0);
380     if (endptr == NULL || *endptr != '\0')
381     {
382         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
383                 token);
384         exit(1);
385     }
386
387     return 0;
388 }
389
390
391 static int ParseStub( int ordinal )
392 {
393     ORDDEF *odp;
394     ORDFUNCDEF *fdp;
395     
396     odp = &OrdinalDefinitions[ordinal];
397     strcpy( odp->export_name, GetToken() );
398     odp->type = TYPE_STUB;
399     fdp = xmalloc(sizeof(*fdp));
400     odp->additional_data = fdp;
401     fdp->arg_types[0] = '\0';
402     strcpy( fdp->internal_name, STUB_CALLBACK );
403     return 0;
404 }
405
406
407 static int ParseOrdinal(int ordinal)
408 {
409     char *token;
410     
411     if (ordinal >= MAX_ORDINALS)
412     {
413         fprintf(stderr, "%d: Ordinal number too large\n", Line);
414         exit(1);
415     }
416     if (ordinal > Limit) Limit = ordinal;
417
418     token = GetToken();
419     if (token == NULL)
420     {
421         fprintf(stderr, "%d: Expected type after ordinal\n", Line);
422         exit(1);
423     }
424
425     if (strcmp(token, "byte") == 0)
426         return ParseVariable(ordinal, TYPE_BYTE);
427     else if (strcmp(token, "word") == 0)
428         return ParseVariable(ordinal, TYPE_WORD);
429     else if (strcmp(token, "long") == 0)
430         return ParseVariable(ordinal, TYPE_LONG);
431     else if (strcmp(token, "p") == 0)
432         return ParseExportFunction(ordinal, TYPE_PASCAL);
433     else if (strcmp(token, "pascal") == 0)
434         return ParseExportFunction(ordinal, TYPE_PASCAL);
435     else if (strcmp(token, "pascal16") == 0)
436         return ParseExportFunction(ordinal, TYPE_PASCAL_16);
437     else if (strcmp(token, "register") == 0)
438         return ParseExportFunction(ordinal, TYPE_REGISTER);
439     else if (strcmp(token, "stdcall") == 0)
440         return ParseExportFunction(ordinal, TYPE_STDCALL);
441     else if (strcmp(token, "equate") == 0)
442         return ParseEquate(ordinal);
443     else if (strcmp(token, "return") == 0)
444         return ParseReturn(ordinal);
445     else if (strcmp(token, "stub") == 0)
446         return ParseStub(ordinal);
447     else
448     {
449         fprintf(stderr, 
450                 "%d: Expected type after ordinal, found '%s' instead\n",
451                 Line, token);
452         exit(1);
453     }
454 }
455
456 static int ParseTopLevel(void)
457 {
458     char *token;
459     
460     while ((token = GetToken()) != NULL)
461     {
462         if (strcmp(token, "name") == 0)
463         {
464             strcpy(DLLName, GetToken());
465             strupper(DLLName);
466         }
467         else if (strcmp(token, "type") == 0)
468         {
469             token = GetToken();
470             if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
471             else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
472             else
473             {
474                 fprintf(stderr, "%d: Type must be 'win16' or 'win32'\n", Line);
475                 exit(1);
476             }
477         }
478         else if (strcmp(token, "base") == 0)
479         {
480             token = GetToken();
481             if (!IsNumberString(token))
482             {
483                 fprintf(stderr, "%d: Expected number after base\n", Line);
484                 exit(1);
485             }
486             Base = atoi(token);
487         }
488         else if (strcmp(token, "heap") == 0)
489         {
490             token = GetToken();
491             if (!IsNumberString(token))
492             {
493                 fprintf(stderr, "%d: Expected number after heap\n", Line);
494                 exit(1);
495             }
496             HeapSize = atoi(token);
497         }
498         else if (IsNumberString(token))
499         {
500             int ordinal;
501             int rv;
502             
503             ordinal = atoi(token);
504             if ((rv = ParseOrdinal(ordinal)) < 0)
505                 return rv;
506         }
507         else
508         {
509             fprintf(stderr, 
510                     "%d: Expected name, id, length or ordinal\n", Line);
511             exit(1);
512         }
513     }
514
515     return 0;
516 }
517
518
519 /*******************************************************************
520  *         StoreVariableCode
521  *
522  * Store a list of ints into a byte array.
523  */
524 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
525 {
526     ORDVARDEF *vdp;
527     int i;
528
529     vdp = odp->additional_data;
530     switch(size)
531     {
532     case 1:
533         for (i = 0; i < vdp->n_values; i++)
534             buffer[i] = vdp->values[i];
535         break;
536     case 2:
537         for (i = 0; i < vdp->n_values; i++)
538             ((unsigned short *)buffer)[i] = vdp->values[i];
539         break;
540     case 4:
541         for (i = 0; i < vdp->n_values; i++)
542             ((unsigned int *)buffer)[i] = vdp->values[i];
543         break;
544     }
545     return vdp->n_values * size;
546 }
547
548
549 /*******************************************************************
550  *         DumpBytes
551  *
552  * Dump a byte stream into the assembly code.
553  */
554 static void DumpBytes( const unsigned char *data, int len,
555                        const char *section, const char *label_start )
556 {
557     int i;
558     if (section) printf( "\t%s\n", section );
559     if (label_start) printf( "%s:\n", label_start );
560     for (i = 0; i < len; i++)
561     {
562         if (!(i & 0x0f)) printf( "\t.byte " );
563         printf( "%d", *data++ );
564         if (i < len - 1) printf( "%c", ((i & 0x0f) != 0x0f) ? ',' : '\n' );
565     }
566     printf( "\n" );
567 }
568
569
570 /*******************************************************************
571  *         BuildModule16
572  *
573  * Build the in-memory representation of a 16-bit NE module, and dump it
574  * as a byte stream into the assembly code.
575  */
576 static int BuildModule16( int max_code_offset, int max_data_offset )
577 {
578     ORDDEF *odp;
579     int i;
580     char *buffer;
581     NE_MODULE *pModule;
582     SEGTABLEENTRY *pSegment;
583     OFSTRUCT *pFileInfo;
584     BYTE *pstr, *bundle;
585     WORD *pword;
586
587     /*   Module layout:
588      * NE_MODULE       Module
589      * OFSTRUCT        File information
590      * SEGTABLEENTRY   Segment 1 (code)
591      * SEGTABLEENTRY   Segment 2 (data)
592      * WORD[2]         Resource table (empty)
593      * BYTE[2]         Imported names (empty)
594      * BYTE[n]         Resident names table
595      * BYTE[n]         Entry table
596      */
597
598     buffer = xmalloc( 0x10000 );
599
600     pModule = (NE_MODULE *)buffer;
601     pModule->magic = NE_SIGNATURE;
602     pModule->count = 1;
603     pModule->next = 0;
604     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
605     pModule->dgroup = 2;
606     pModule->heap_size = HeapSize;
607     pModule->stack_size = 0;
608     pModule->ip = 0;
609     pModule->cs = 0;
610     pModule->sp = 0;
611     pModule->ss = 0;
612     pModule->seg_count = 2;
613     pModule->modref_count = 0;
614     pModule->nrname_size = 0;
615     pModule->modref_table = 0;
616     pModule->nrname_fpos = 0;
617     pModule->moveable_entries = 0;
618     pModule->alignment = 0;
619     pModule->truetype = 0;
620     pModule->os_flags = NE_OSFLAGS_WINDOWS;
621     pModule->misc_flags = 0;
622     pModule->dlls_to_init  = 0;
623     pModule->nrname_handle = 0;
624     pModule->min_swap_area = 0;
625     pModule->expected_version = 0x030a;
626     pModule->pe_module = NULL;
627     pModule->self = 0;
628     pModule->self_loading_sel = 0;
629
630       /* File information */
631
632     pFileInfo = (OFSTRUCT *)(pModule + 1);
633     pModule->fileinfo = (int)pFileInfo - (int)pModule;
634     memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
635     pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
636                         + strlen(DLLName) + 4;
637     sprintf( pFileInfo->szPathName, "%s.DLL", DLLName );
638     pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
639         
640       /* Segment table */
641
642     pSegment = (SEGTABLEENTRY *)pstr;
643     pModule->seg_table = (int)pSegment - (int)pModule;
644     pSegment->filepos = 0;
645     pSegment->size = max_code_offset;
646     pSegment->flags = 0;
647     pSegment->minsize = max_code_offset;
648     pSegment->selector = 0;
649     pSegment++;
650
651     pModule->dgroup_entry = (int)pSegment - (int)pModule;
652     pSegment->filepos = 0;
653     pSegment->size = max_data_offset;
654     pSegment->flags = NE_SEGFLAGS_DATA;
655     pSegment->minsize = max_data_offset;
656     pSegment->selector = 0;
657     pSegment++;
658
659       /* Resource table */
660
661     pword = (WORD *)pSegment;
662     pModule->res_table = (int)pword - (int)pModule;
663     *pword++ = 0;
664     *pword++ = 0;
665
666       /* Imported names table */
667
668     pstr = (char *)pword;
669     pModule->import_table = (int)pstr - (int)pModule;
670     *pstr++ = 0;
671     *pstr++ = 0;
672
673       /* Resident names table */
674
675     pModule->name_table = (int)pstr - (int)pModule;
676     /* First entry is module name */
677     *pstr = strlen(DLLName );
678     strcpy( pstr + 1, DLLName );
679     pstr += *pstr + 1;
680     *(WORD *)pstr = 0;
681     pstr += sizeof(WORD);
682     /* Store all ordinals */
683     odp = OrdinalDefinitions + 1;
684     for (i = 1; i <= Limit; i++, odp++)
685     {
686         if (!odp->export_name[0]) continue;
687         *pstr = strlen( odp->export_name );
688         strcpy( pstr + 1, odp->export_name );
689         strupper( pstr + 1 );
690         pstr += *pstr + 1;
691         *(WORD *)pstr = i;
692         pstr += sizeof(WORD);
693     }
694     *pstr++ = 0;
695
696       /* Entry table */
697
698     pModule->entry_table = (int)pstr - (int)pModule;
699     bundle = NULL;
700     odp = OrdinalDefinitions + 1;
701     for (i = 1; i <= Limit; i++, odp++)
702     {
703         int selector = 0;
704
705         switch (odp->type)
706         {
707         case TYPE_INVALID:
708             selector = 0;  /* Invalid selector */
709             break;
710
711         case TYPE_PASCAL:
712         case TYPE_PASCAL_16:
713         case TYPE_REGISTER:
714         case TYPE_RETURN:
715         case TYPE_STUB:
716             selector = 1;  /* Code selector */
717             break;
718
719         case TYPE_BYTE:
720         case TYPE_WORD:
721         case TYPE_LONG:
722             selector = 2;  /* Data selector */
723             break;
724
725         case TYPE_ABS:
726             selector = 0xfe;  /* Constant selector */
727             break;
728         }
729
730           /* create a new bundle if necessary */
731         if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
732         {
733             bundle = pstr;
734             bundle[0] = 0;
735             bundle[1] = selector;
736             pstr += 2;
737         }
738
739         (*bundle)++;
740         if (selector != 0)
741         {
742             *pstr++ = 1;
743             *(WORD *)pstr = odp->offset;
744             pstr += sizeof(WORD);
745         }
746     }
747     *pstr++ = 0;
748
749       /* Dump the module content */
750
751     DumpBytes( (char *)pModule, (int)pstr - (int)pModule,
752                ".data", "Module_Start" );
753     return (int)pstr - (int)pModule;
754 }
755
756
757 /*******************************************************************
758  *         BuildModule32
759  *
760  * Build the in-memory representation of a 32-bit pseudo-NE module, and dump it
761  * as a byte stream into the assembly code.
762  */
763 static int BuildModule32(void)
764 {
765     char *buffer;
766     NE_MODULE *pModule;
767     OFSTRUCT *pFileInfo;
768     BYTE *pstr;
769     WORD *pword;
770
771     /*   Module layout:
772      * NE_MODULE            Module
773      * OFSTRUCT             File information
774      * SEGTABLEENTRY        Segment table (empty)
775      * WORD[2]              Resource table (empty)
776      * BYTE[2]              Imported names (empty)
777      * BYTE[n]              Resident names table (1 entry)
778      * BYTE[n]              Entry table (empty)
779      */
780
781     buffer = xmalloc( 0x10000 );
782
783     pModule = (NE_MODULE *)buffer;
784     pModule->magic = NE_SIGNATURE;
785     pModule->count = 1;
786     pModule->next = 0;
787     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN |
788                      NE_FFLAGS_LIBMODULE | NE_FFLAGS_WIN32;
789     pModule->dgroup = 0;
790     pModule->heap_size = HeapSize;
791     pModule->stack_size = 0;
792     pModule->ip = 0;
793     pModule->cs = 0;
794     pModule->sp = 0;
795     pModule->ss = 0;
796     pModule->seg_count = 0;
797     pModule->modref_count = 0;
798     pModule->nrname_size = 0;
799     pModule->modref_table = 0;
800     pModule->nrname_fpos = 0;
801     pModule->moveable_entries = 0;
802     pModule->alignment = 0;
803     pModule->truetype = 0;
804     pModule->os_flags = NE_OSFLAGS_WINDOWS;
805     pModule->misc_flags = 0;
806     pModule->dlls_to_init  = 0;
807     pModule->nrname_handle = 0;
808     pModule->min_swap_area = 0;
809     pModule->expected_version = 0x030a;
810     pModule->pe_module = NULL;
811     pModule->self = 0;
812     pModule->self_loading_sel = 0;
813
814       /* File information */
815
816     pFileInfo = (OFSTRUCT *)(pModule + 1);
817     pModule->fileinfo = (int)pFileInfo - (int)pModule;
818     memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
819     pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
820                         + strlen(DLLName) + 4;
821     sprintf( pFileInfo->szPathName, "%s.DLL", DLLName );
822     pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
823         
824       /* Segment table */
825
826     pModule->seg_table = (int)pstr - (int)pModule;
827
828       /* Resource table */
829
830     pword = (WORD *)pstr;
831     pModule->res_table = (int)pword - (int)pModule;
832     *pword++ = 0;
833     *pword++ = 0;
834
835       /* Imported names table */
836
837     pstr = (char *)pword;
838     pModule->import_table = (int)pstr - (int)pModule;
839     *pstr++ = 0;
840     *pstr++ = 0;
841
842       /* Resident names table */
843
844     pModule->name_table = (int)pstr - (int)pModule;
845     /* First entry is module name */
846     *pstr = strlen(DLLName );
847     strcpy( pstr + 1, DLLName );
848     pstr += *pstr + 1;
849     *(WORD *)pstr = 0;
850     pstr += sizeof(WORD);
851     *pstr++ = 0;
852
853       /* Entry table */
854
855     pModule->entry_table = (int)pstr - (int)pModule;
856     *pstr++ = 0;
857
858       /* Dump the module content */
859
860     DumpBytes( (char *)pModule, (int)pstr - (int)pModule,
861                ".data", "Module_Start" );
862     return (int)pstr - (int)pModule;
863 }
864
865
866 /*******************************************************************
867  *         BuildSpec32Files
868  *
869  * Build a Win32 assembly file from a spec file.
870  */
871 static void BuildSpec32Files(void)
872 {
873     ORDDEF *odp;
874     ORDFUNCDEF *fdp;
875     ORDRETDEF *rdp;
876     int i, module_size;
877
878     printf( "/* File generated automatically; do not edit! */\n" );
879     printf( "\t.text\n" );
880     printf( "\t.align 4\n" );
881     printf( "Code_Start:\n\n" );
882
883     odp = OrdinalDefinitions;
884     for (i = 0; i <= Limit; i++, odp++)
885     {
886         fdp = odp->additional_data;
887         rdp = odp->additional_data;
888
889         switch (odp->type)
890         {
891         case TYPE_INVALID:
892             printf( "/* %s.%d */\n", DLLName, i );
893             printf( "\t.align 4\n" );
894             printf( "%s_%d:\n", DLLName, i );
895             printf( "\tpushl %%ebp\n" );
896             printf( "\tpushl $Name_%d\n", i );
897             printf( "\tpushl $" PREFIX "%s\n", STUB_CALLBACK );
898             printf( "\tjmp " PREFIX "CallFrom32_0\n" );
899             break;
900
901         case TYPE_STDCALL:
902         case TYPE_STUB:
903             printf( "/* %s.%d (%s) */\n",
904                      DLLName, i, odp->export_name);
905             printf( "\t.align 4\n" );
906             printf( "%s_%d:\n", DLLName, i );
907             printf( "\tpushl %%ebp\n" );
908             printf( "\tpushl $Name_%d\n", i );
909             printf( "\tpushl $" PREFIX "%s\n", fdp->internal_name );
910             printf( "\tjmp " PREFIX "CallFrom32_%d\n", strlen(fdp->arg_types));
911             break;
912
913         case TYPE_RETURN:
914             printf( "/* %s.%d (%s) */\n",
915                      DLLName, i, odp->export_name);
916             printf( "\t.align 4\n" );
917             printf( "%s_%d:\n", DLLName, i );
918             printf( "\tmovl $%d,%%eax\n", ERROR_CALL_NOT_IMPLEMENTED );
919             printf( "\tmovl %%eax," PREFIX "WIN32_LastError\n" );
920             printf( "\tmovl $%d,%%eax\n", rdp->ret_value );
921             if (rdp->arg_size) printf( "\tret $%d\n", rdp->arg_size );
922             else printf( "\tret\n" );
923             break;
924
925         default:
926             fprintf(stderr,"build: function type %d not available for Win32\n",
927                     odp->type);
928             exit(1);
929         }
930     }
931
932     module_size = BuildModule32();
933
934     /* Output the DLL functions table */
935
936     printf( "\t.text\n" );
937     printf( "\t.align 4\n" );
938     printf( "Functions:\n" );
939     odp = OrdinalDefinitions;
940     for (i = 0; i <= Limit; i++, odp++) printf("\t.long %s_%d\n", DLLName, i);
941
942     /* Output the DLL names table */
943
944     printf( "FuncNames:\n" );
945     odp = OrdinalDefinitions;
946     for (i = 0; i <= Limit; i++, odp++)
947     {
948         if (odp->type == TYPE_INVALID) printf( "\t.long 0\n" );
949         else printf( "\t.long Name_%d\n", i );
950     }
951
952     /* Output the DLL names */
953
954     for (i = 0, odp = OrdinalDefinitions; i <= Limit; i++, odp++)
955     {
956         printf( "Name_%d:\t", i );
957         if (odp->type == TYPE_INVALID)
958             printf( ".ascii \"%s.%d\\0\"\n", DLLName, i );
959         else
960             printf( ".ascii \"%s\\0\"\n", odp->export_name );
961     }
962
963     /* Output the DLL descriptor */
964
965     printf( "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
966     printf( "\t.align 4\n" );
967     printf( "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
968     printf( PREFIX "%s_Descriptor:\n", DLLName );
969     printf( "\t.long DLLName\n" );          /* Name */
970     printf( "\t.long Module_Start\n" );     /* Module start */
971     printf( "\t.long %d\n", module_size );  /* Module size */
972     printf( "\t.long %d\n", Base );         /* Base */
973     printf( "\t.long %d\n", Limit );        /* Limit */
974     printf( "\t.long Functions\n" );        /* Functions */
975     printf( "\t.long FuncNames\n" );        /* Function names */
976 }
977
978
979 /*******************************************************************
980  *         BuildSpec16Files
981  *
982  * Build a Win16 assembly file from a spec file.
983  */
984 static void BuildSpec16Files(void)
985 {
986     ORDDEF *odp;
987     ORDFUNCDEF *fdp;
988     ORDRETDEF *rdp;
989     int i;
990     int code_offset, data_offset, module_size;
991     unsigned char *data;
992
993     data = (unsigned char *)xmalloc( 0x10000 );
994     memset( data, 0, 16 );
995     data_offset = 16;
996
997     printf( "/* File generated automatically; do not edit! */\n" );
998     printf( "\t.text\n" );
999     printf( "Code_Start:\n" );
1000     code_offset = 0;
1001
1002     odp = OrdinalDefinitions;
1003     for (i = 0; i <= Limit; i++, odp++)
1004     {
1005         fdp = odp->additional_data;
1006         rdp = odp->additional_data;
1007             
1008         switch (odp->type)
1009         {
1010           case TYPE_INVALID:
1011             odp->offset = 0xffff;
1012             break;
1013
1014           case TYPE_ABS:
1015             odp->offset = (int)odp->additional_data & 0xffff;
1016             break;
1017
1018           case TYPE_BYTE:
1019             printf( "/* %s.%d */\n", DLLName, i);
1020             odp->offset = data_offset;
1021             data_offset += StoreVariableCode( data, 1, odp);
1022             break;
1023
1024           case TYPE_WORD:
1025             printf( "/* %s.%d */\n", DLLName, i);
1026             odp->offset = data_offset;
1027             data_offset += StoreVariableCode( data, 2, odp);
1028             break;
1029
1030           case TYPE_LONG:
1031             printf( "/* %s.%d */\n", DLLName, i);
1032             odp->offset = data_offset;
1033             data_offset += StoreVariableCode( data, 4, odp);
1034             break;
1035
1036           case TYPE_RETURN:
1037             printf( "/* %s.%d */\n", DLLName, i);
1038             printf( "\tmovw $%d,%%ax\n", rdp->ret_value & 0xffff );
1039             printf( "\tmovw $%d,%%dx\n", (rdp->ret_value >> 16) & 0xffff);
1040             printf( "\t.byte 0x66\n");
1041             if (rdp->arg_size != 0)
1042                 printf( "\tlret $%d\n\n", rdp->arg_size);
1043             else
1044             {
1045                 printf( "\tlret\n");
1046                 printf( "\tnop\n");
1047                 printf( "\tnop\n\n");
1048             }
1049             odp->offset = code_offset;
1050             code_offset += 12;  /* Assembly code is 12 bytes long */
1051             break;
1052
1053           case TYPE_REGISTER:
1054           case TYPE_PASCAL:
1055           case TYPE_PASCAL_16:
1056           case TYPE_STUB:
1057             printf( "/* %s.%d */\n", DLLName, i);
1058             printf( "\tpushw %%bp\n" );
1059             printf( "\tpushl $" PREFIX "%s\n", fdp->internal_name );
1060             /* FreeBSD does not understand lcall, so do it the hard way */
1061             printf( "\t.byte 0x9a /*lcall*/\n" );
1062             printf( "\t.long " PREFIX "CallFrom16_%s_%s\n",
1063                     (odp->type == TYPE_REGISTER) ? "regs" :
1064                     (odp->type == TYPE_PASCAL) ? "long" : "word",
1065                     fdp->arg_types );
1066             printf( "\t.byte 0x%02x,0x%02x\n", /* Some asms don't have .word */
1067                     LOBYTE(WINE_CODE_SELECTOR), HIBYTE(WINE_CODE_SELECTOR) );
1068             printf( "\tnop\n" );
1069             printf( "\tnop\n\n" );
1070             odp->offset = code_offset;
1071             code_offset += 16;  /* Assembly code is 16 bytes long */
1072             break;
1073                 
1074           default:
1075             fprintf(stderr,"build: function type %d not available for Win16\n",
1076                     odp->type);
1077             exit(1);
1078         }
1079     }
1080
1081     if (!code_offset)  /* Make sure the code segment is not empty */
1082     {
1083         printf( "\t.byte 0\n" );
1084         code_offset++;
1085     }
1086
1087     /* Output data segment */
1088
1089     DumpBytes( data, data_offset, NULL, "Data_Start" );
1090
1091     /* Build the module */
1092
1093     module_size = BuildModule16( code_offset, data_offset );
1094
1095     /* Output the DLL descriptor */
1096
1097     printf( "\t.text\n" );
1098     printf( "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1099     printf( "\t.align 4\n" );
1100     printf( "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1101     printf( PREFIX "%s_Descriptor:\n", DLLName );
1102     printf( "\t.long DLLName\n" );          /* Name */
1103     printf( "\t.long Module_Start\n" );     /* Module start */
1104     printf( "\t.long %d\n", module_size );  /* Module size */
1105     printf( "\t.long Code_Start\n" );       /* Code start */
1106     printf( "\t.long Data_Start\n" );       /* Data start */
1107 }
1108
1109
1110 /*******************************************************************
1111  *         BuildSpecFiles
1112  *
1113  * Build an assembly file from a spec file.
1114  */
1115 static void BuildSpecFiles( char *specname )
1116 {
1117     SpecFp = fopen( specname, "r");
1118     if (SpecFp == NULL)
1119     {
1120         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
1121         exit(1);
1122     }
1123
1124     ParseTopLevel();
1125     switch(SpecType)
1126     {
1127     case SPEC_INVALID:
1128         fprintf( stderr, "%s: Missing 'type' declaration\n", specname );
1129         exit(1);
1130     case SPEC_WIN16:
1131         BuildSpec16Files();
1132         break;
1133     case SPEC_WIN32:
1134         BuildSpec32Files();
1135         break;
1136     }
1137 }
1138
1139
1140 /*******************************************************************
1141  *         BuildCall32LargeStack
1142  *
1143  * Build the function used to switch to the original 32-bit stack
1144  * before calling a 32-bit function from 32-bit code. This is used for
1145  * functions that need a large stack, like X bitmaps functions.
1146  *
1147  * The generated function has the following prototype:
1148  *   int CallTo32_LargeStack( int (*func)(), int nbargs, ... )
1149  *
1150  * Stack layout:
1151  *   ...     ...
1152  * (ebp+20)  arg2
1153  * (ebp+16)  arg1
1154  * (ebp+12)  nbargs
1155  * (ebp+8)   func
1156  * (ebp+4)   ret addr
1157  * (ebp)     ebp
1158  */
1159 static void BuildCall32LargeStack(void)
1160 {
1161     /* Function header */
1162
1163     printf( "/**********\n" );
1164     printf( " * " PREFIX "CallTo32_LargeStack\n" );
1165     printf( " **********/\n" );
1166     printf( "\t.align 4\n" );
1167     printf( "\t.globl " PREFIX "CallTo32_LargeStack\n\n" );
1168     printf( PREFIX "CallTo32_LargeStack:\n" );
1169     
1170     /* Entry code */
1171
1172     printf( "\tpushl %%ebp\n" );
1173     printf( "\tmovl %%esp,%%ebp\n" );
1174
1175     /* Save registers */
1176
1177     printf( "\tpushl %%ecx\n" );
1178     printf( "\tpushl %%esi\n" );
1179     printf( "\tpushl %%edi\n" );
1180
1181     /* Retrieve the original 32-bit stack pointer and switch to it if any */
1182
1183     printf( "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
1184     printf( "\torl %%eax,%%eax\n" );
1185     printf( "\tje no_orig_esp\n" );
1186     printf( "\tmovl %%eax,%%esp\n" );
1187     printf( "no_orig_esp:\n" );
1188
1189     /* Transfer the arguments */
1190
1191     printf( "\tmovl 12(%%ebp),%%ecx\n" );
1192     printf( "\torl %%ecx,%%ecx\n" );
1193     printf( "\tje no_args\n" );
1194     printf( "\tleal 16(%%ebp),%%esi\n" );
1195     printf( "\tshll $2,%%ecx\n" );
1196     printf( "\tsubl %%ecx,%%esp\n" );
1197     printf( "\tmovl %%esp,%%edi\n" );
1198     printf( "\tshrl $2,%%ecx\n" );
1199     printf( "\tcld\n" );
1200     printf( "\trep; movsl\n" );
1201     printf( "no_args:\n" );
1202
1203     /* Call the function */
1204
1205     printf( "\tcall 8(%%ebp)\n" );
1206
1207     /* Switch back to the normal stack */
1208
1209     printf( "\tleal -12(%%ebp),%%esp\n" );
1210
1211     /* Restore registers and return */
1212
1213     printf( "\tpopl %%edi\n" );
1214     printf( "\tpopl %%esi\n" );
1215     printf( "\tpopl %%ecx\n" );
1216     printf( "\tpopl %%ebp\n" );
1217     printf( "\tret\n" );
1218 }
1219
1220
1221 /*******************************************************************
1222  *         TransferArgs16To32
1223  *
1224  * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1225  * The 16-bit stack layout is:
1226  *   ...     ...
1227  *  (bp+8)    arg2
1228  *  (bp+6)    arg1
1229  *  (bp+4)    cs
1230  *  (bp+2)    ip
1231  *  (bp)      bp
1232  */
1233 static int TransferArgs16To32( char *args )
1234 {
1235     int i, pos16, pos32;
1236
1237     /* Save ebx first */
1238
1239     printf( "\tpushl %%ebx\n" );
1240
1241     /* Get the 32-bit stack pointer */
1242
1243     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1244
1245     /* Copy the arguments */
1246
1247     pos16 = 6;  /* skip bp and return address */
1248     pos32 = 0;
1249
1250     for (i = strlen(args); i > 0; i--)
1251     {
1252         pos32 -= 4;
1253         switch(args[i-1])
1254         {
1255         case 'w':  /* word */
1256             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1257             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1258             pos16 += 2;
1259             break;
1260
1261         case 's':  /* s_word */
1262             printf( "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1263             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1264             pos16 += 2;
1265             break;
1266
1267         case 'l':  /* long */
1268             printf( "\tmovl %d(%%ebp),%%eax\n", pos16 );
1269             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1270             pos16 += 4;
1271             break;
1272
1273         case 'p':  /* ptr */
1274             /* Get the selector */
1275             printf( "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1276             /* Get the selector base */
1277             printf( "\tandl $0xfff8,%%eax\n" );
1278             printf( "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1279             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1280             /* Add the offset */
1281             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1282             printf( "\taddl %%eax,%d(%%ebx)\n", pos32 );
1283             pos16 += 4;
1284             break;
1285
1286         default:
1287             fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1288         }
1289     }
1290
1291     /* Restore ebx */
1292     
1293     printf( "\tpopl %%ebx\n" );
1294
1295     return pos16 - 6;  /* Return the size of the 16-bit args */
1296 }
1297
1298
1299 /*******************************************************************
1300  *         BuildContext
1301  *
1302  * Build the context structure on the 32-bit stack.
1303  * The only valid registers in the context structure are:
1304  *   eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
1305  */
1306 static void BuildContext(void)
1307 {
1308     /* Save ebx first */
1309
1310     printf( "\tpushl %%ebx\n" );
1311
1312     /* Get the 32-bit stack pointer */
1313
1314     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1315
1316     /* Store the registers */
1317
1318     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(EBX) ); /* Get ebx from stack*/
1319     printf( "\tmovl %%eax,%d(%%ebx)\n", CONTEXTOFFSET(EAX) );
1320     printf( "\tmovl %%ecx,%d(%%ebx)\n", CONTEXTOFFSET(ECX) );
1321     printf( "\tmovl %%edx,%d(%%ebx)\n", CONTEXTOFFSET(EDX) );
1322     printf( "\tmovl %%esi,%d(%%ebx)\n", CONTEXTOFFSET(ESI) );
1323     printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(EDI) );
1324     printf( "\tmovw -10(%%ebp),%%ax\n" );  /* Get saved ds from stack */
1325     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(DS) );
1326     printf( "\tmovw -6(%%ebp),%%ax\n" );  /* Get saved es from stack */
1327     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(ES) );
1328     printf( "\tpushfl\n" );
1329     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(EFL) );
1330 }
1331
1332
1333 /*******************************************************************
1334  *         RestoreContext
1335  *
1336  * Restore the registers from the context structure
1337  */
1338 static void RestoreContext(void)
1339 {
1340     /* Get the 32-bit stack pointer */
1341
1342     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1343
1344     /* Restore the registers */
1345
1346     printf( "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(ECX) );
1347     printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(EDX) );
1348     printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(ESI) );
1349     printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(EDI) );
1350     printf( "\tpopl %%eax\n" );  /* Remove old ds and ip from stack */
1351     printf( "\tpopl %%eax\n" );  /* Remove old cs and es from stack */
1352     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(DS) ); /* Push new ds */
1353     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(ES) ); /* Push new es */
1354     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(EFL) );
1355     printf( "\tpopfl\n" );
1356     printf( "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(EAX) );
1357     printf( "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(EBX) );
1358 }
1359
1360
1361 /*******************************************************************
1362  *         BuildCallFrom16Func
1363  *
1364  * Build a 16-bit-to-Wine callback function. The syntax of the function
1365  * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1366  * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1367  * 'l'=long, 'p'=pointer).
1368  * For register functions, the arguments are ignored, but they are still
1369  * removed from the stack upon return.
1370  *
1371  * Stack layout upon entry to the callback function:
1372  *  ...           ...
1373  * (sp+18) word   first 16-bit arg
1374  * (sp+16) word   cs
1375  * (sp+14) word   ip
1376  * (sp+12) word   bp
1377  * (sp+8)  long   32-bit entry point
1378  * (sp+6)  word   high word of cs (always 0, used to store es)
1379  * (sp+4)  word   low word of cs of 16-bit entry point
1380  * (sp+2)  word   high word of ip (always 0, used to store ds)
1381  * (sp)    word   low word of ip of 16-bit entry point
1382  *
1383  */
1384 static void BuildCallFrom16Func( char *profile )
1385 {
1386     int argsize = 0;
1387     int short_ret = 0;
1388     int reg_func = 0;
1389     char *args = profile + 5;
1390
1391     /* Parse function type */
1392
1393     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1394     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1395     else if (strncmp( "long_", profile, 5 ))
1396     {
1397         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1398         return;
1399     }
1400
1401     /* Function header */
1402
1403     printf( "/**********\n" );
1404     printf( " * " PREFIX "CallFrom16_%s\n", profile );
1405     printf( " **********/\n" );
1406     printf( "\t.align 4\n" );
1407     printf( "\t.globl " PREFIX "CallFrom16_%s\n\n", profile );
1408     printf( PREFIX "CallFrom16_%s:\n", profile );
1409
1410     /* Setup bp to point to its copy on the stack */
1411
1412     printf( "\tmovzwl %%sp,%%ebp\n" );
1413     printf( "\taddw $12,%%bp\n" );
1414
1415     /* Save 16-bit ds and es */
1416
1417     /* Stupid FreeBSD assembler doesn't know these either */
1418     /* printf( "\tmovw %%ds,-10(%%ebp)\n" ); */
1419     printf( "\t.byte 0x66,0x8c,0x5d,0xf6\n" );
1420     /* printf( "\tmovw %%es,-6(%%ebp)\n" ); */
1421     printf( "\t.byte 0x66,0x8c,0x45,0xfa\n" );
1422
1423     /* Restore 32-bit ds and es */
1424
1425     printf( "\tpushl $0x%04x%04x\n", WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1426     printf( "\tpopw %%ds\n" );
1427     printf( "\tpopw %%es\n" );
1428
1429
1430     /* Save the 16-bit stack */
1431
1432     printf( "\tpushw " PREFIX "IF1632_Saved16_sp\n" );
1433     printf( "\tpushw " PREFIX "IF1632_Saved16_ss\n" );
1434 #ifdef __svr4__
1435     printf("\tdata16\n");
1436 #endif
1437     printf( "\tmovw %%ss," PREFIX "IF1632_Saved16_ss\n" );
1438     printf( "\tmovw %%sp," PREFIX "IF1632_Saved16_sp\n" );
1439
1440     /* Transfer the arguments */
1441
1442     if (reg_func) BuildContext();
1443     else if (*args) argsize = TransferArgs16To32( args );
1444
1445     /* Get the address of the API function */
1446
1447     printf( "\tmovl -4(%%ebp),%%eax\n" );
1448
1449     /* If necessary, save %edx over the API function address */
1450
1451     if (!reg_func && short_ret)
1452         printf( "\tmovl %%edx,-4(%%ebp)\n" );
1453
1454     /* Switch to the 32-bit stack */
1455
1456     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebp\n" );
1457     printf( "\tpushw %%ds\n" );
1458     printf( "\tpopw %%ss\n" );
1459     printf( "\tleal -%d(%%ebp),%%esp\n",
1460             reg_func ? sizeof(struct sigcontext_struct) : 4 * strlen(args) );
1461
1462     /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1463
1464     printf( "\taddl $24,%%ebp\n" );
1465
1466     /* Print the debug information before the call */
1467
1468     if (debugging)
1469     {
1470         printf( "\tpushl %%eax\n" );
1471         printf( "\tpushl $Profile_%s\n", profile );
1472         printf( "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0) );
1473         printf( "\tcall " PREFIX "RELAY_DebugCallFrom16\n" );
1474         printf( "\tpopl %%eax\n" );
1475         printf( "\tpopl %%eax\n" );
1476         printf( "\tpopl %%eax\n" );
1477     }
1478
1479     /* Call the entry point */
1480
1481     printf( "\tcall %%eax\n" );
1482
1483     /* Print the debug information after the call */
1484
1485     if (debugging)
1486     {
1487         printf( "\tpushl %%eax\n" );
1488         printf( "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0) );
1489         printf( "\tcall " PREFIX "RELAY_DebugCallFrom16Ret\n" );
1490         printf( "\tpopl %%eax\n" );
1491         printf( "\tpopl %%eax\n" );
1492     }
1493
1494     /* Restore the 16-bit stack */
1495
1496 #ifdef __svr4__
1497     printf( "\tdata16\n");
1498 #endif
1499     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1500     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1501 #ifdef __svr4__
1502     printf( "\tdata16\n");
1503 #endif
1504     printf( "\tpopw " PREFIX "IF1632_Saved16_ss\n" );
1505 #ifdef __svr4__
1506     printf( "\tdata16\n");
1507 #endif
1508     printf( "\tpopw " PREFIX "IF1632_Saved16_sp\n" );
1509
1510     if (reg_func)
1511     {
1512         /* Restore registers from the context structure */
1513         RestoreContext();
1514         
1515         /* Calc the arguments size */
1516         while (*args)
1517         {
1518             switch(*args)
1519             {
1520             case 'w':
1521             case 's':
1522                 argsize += 2;
1523                 break;
1524             case 'p':
1525             case 'l':
1526                 argsize += 4;
1527                 break;
1528             default:
1529                 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1530             }
1531             args++;
1532         }
1533
1534         /* Restore ds and es */
1535         printf( "\tpopw %%es\n" );
1536         printf( "\tpopw %%ds\n" );
1537
1538         /* Remove the entry point from the stack */
1539         /* (we don't use add to avoid modifying the carry flag) */
1540         printf( "\tpopl %%ebp\n" );
1541     }
1542     else
1543     {
1544         /* Restore ds and es */
1545         printf( "\tpopw %%bp\n" );       /* Remove ip */
1546         printf( "\tpopl %%ebp\n" );      /* Remove ds and cs */
1547         printf( "\tmovw %%bp,%%ds\n" );  /* Restore ds */
1548         printf( "\tpopw %%es\n" );       /* Restore es */
1549
1550         if (short_ret) printf( "\tpopl %%edx\n" );     /* Restore edx */
1551         else
1552         {
1553             /* Get the return value into dx:ax */
1554             printf( "\tpushl %%eax\n" );
1555             printf( "\tpopw %%ax\n" );
1556             printf( "\tpopw %%dx\n" );
1557             /* Remove API entry point */
1558             printf( "\taddl $4,%%esp\n" );
1559         }
1560     }
1561
1562     /* Restore bp */
1563
1564     printf( "\tpopw %%bp\n" );
1565
1566     /* Remove the arguments and return */
1567
1568     if (argsize)
1569     {
1570         printf( "\t.byte 0x66\n" );
1571         printf( "\tlret $%d\n", argsize );
1572     }
1573     else
1574     {
1575         printf( "\t.byte 0x66\n" );
1576         printf( "\tlret\n" );
1577     }
1578 }
1579
1580
1581 /*******************************************************************
1582  *         BuildCallTo16Func
1583  *
1584  * Build a Wine-to-16-bit callback function.
1585  *
1586  * Stack frame of the callback function:
1587  *  ...      ...
1588  * (ebp+24) arg2
1589  * (ebp+20) arg1
1590  * (ebp+16) 16-bit ds
1591  * (ebp+12) func to call
1592  * (ebp+8)  code selector
1593  * (ebp+4)  return address
1594  * (ebp)    previous ebp
1595  *
1596  * Prototypes for the CallTo16 functions:
1597  *   extern WORD CallTo16_word_xxx( FARPROC func, WORD ds, args... );
1598  *   extern LONG CallTo16_long_xxx( FARPROC func, WORD ds, args... );
1599  *   extern void CallTo16_regs_( FARPROC func, WORD ds, WORD es, WORD bp,
1600  *                               WORD ax, WORD bx, WORD cx, WORD dx,
1601  *                               WORD si, WORD di );
1602  */
1603 static void BuildCallTo16Func( char *profile )
1604 {
1605     int short_ret = 0;
1606     int reg_func = 0;
1607     char *args = profile + 5;
1608
1609     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1610     else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1611     else if (strncmp( "long_", profile, 5 ))
1612     {
1613         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1614         return;
1615     }
1616
1617     /* Function header */
1618
1619     printf( "/**********\n" );
1620     printf( " * " PREFIX "CallTo16_%s\n", profile );
1621     printf( " **********/\n" );
1622     printf( "\t.align 4\n" );
1623     printf( "\t.globl " PREFIX "CallTo16_%s\n\n", profile );
1624     printf( PREFIX "CallTo16_%s:\n", profile );
1625
1626     /* Push code selector before return address to simulate a lcall */
1627
1628     printf( "\tpopl %%eax\n" );
1629     printf( "\tpushl $0x%04x\n", WINE_CODE_SELECTOR );
1630     printf( "\tpushl %%eax\n" );
1631
1632     /* Entry code */
1633
1634     printf( "\tpushl %%ebp\n" );
1635     printf( "\tmovl %%esp,%%ebp\n" );
1636
1637     /* Save the 32-bit registers */
1638
1639     printf( "\tpushl %%ebx\n" );
1640     printf( "\tpushl %%ecx\n" );
1641     printf( "\tpushl %%edx\n" );
1642     printf( "\tpushl %%esi\n" );
1643     printf( "\tpushl %%edi\n" );
1644
1645     /* Save the 32-bit stack */
1646
1647     printf( "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1648     printf( "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1649     printf( "\tmovl %%ebp,%%ebx\n" );
1650
1651     /* Print debugging info */
1652
1653     if (debugging)
1654     {
1655         /* Push the address of the first argument */
1656         printf( "\tmovl %%ebx,%%eax\n" );
1657         printf( "\taddl $12,%%eax\n" );
1658         printf( "\tpushl $%d\n", reg_func ? 8 : strlen(args) );
1659         printf( "\tpushl %%eax\n" );
1660         printf( "\tcall " PREFIX "RELAY_DebugCallTo16\n" );
1661         printf( "\tpopl %%eax\n" );
1662         printf( "\tpopl %%eax\n" );
1663     }
1664
1665     /* Switch to the 16-bit stack */
1666
1667 #ifdef __svr4__
1668     printf("\tdata16\n");
1669 #endif
1670     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1671     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1672
1673     /* Transfer the arguments */
1674
1675     if (reg_func)
1676     {
1677         /* Get the registers. ebx is handled later on. */
1678         printf( "\tpushw 20(%%ebx)\n" );
1679         printf( "\tpopw %%es\n" );
1680         printf( "\tmovl 24(%%ebx),%%ebp\n" );
1681         printf( "\tmovl 28(%%ebx),%%eax\n" );
1682         printf( "\tmovl 36(%%ebx),%%ecx\n" );
1683         printf( "\tmovl 40(%%ebx),%%edx\n" );
1684         printf( "\tmovl 44(%%ebx),%%esi\n" );
1685         printf( "\tmovl 48(%%ebx),%%edi\n" );
1686     }
1687     else  /* not a register function */
1688     {
1689         int pos = 20;  /* first argument position */
1690
1691         /* Make %bp point to the previous stackframe (built by CallFrom16) */
1692         printf( "\tmovw %%sp,%%bp\n" );
1693         printf( "\taddw $16,%%bp\n" );
1694
1695         while (*args)
1696         {
1697             switch(*args++)
1698             {
1699             case 'w': /* word */
1700                 printf( "\tpushw %d(%%ebx)\n", pos );
1701                 break;
1702             case 'l': /* long */
1703                 printf( "\tpushl %d(%%ebx)\n", pos );
1704                 break;
1705             }
1706             pos += 4;
1707         }
1708     }
1709
1710     /* Push the return address */
1711
1712     printf( "\tpushl " PREFIX "CALLTO16_RetAddr_%s\n",
1713             short_ret ? "word" : "long" );
1714
1715     /* Push the called routine address */
1716
1717     printf( "\tpushl 12(%%ebx)\n" );
1718
1719     /* Get the 16-bit ds */
1720
1721     if (reg_func)
1722     {
1723         printf( "\tpushw 16(%%ebx)\n" );
1724         printf( "\tmovl 32(%%ebx),%%ebx\n" ); /*Get ebx from the 32-bit stack*/
1725         printf( "\tpopw %%ds\n" );
1726     }
1727     else
1728     {
1729         /* Set ax equal to ds for window procedures */
1730         printf( "\tmovw 16(%%ebx),%%ax\n" );
1731 #ifdef __svr4__
1732         printf( "\tdata16\n");
1733 #endif
1734         printf( "\tmovw %%ax,%%ds\n" );
1735     }
1736
1737     /* Jump to the called routine */
1738
1739     printf( "\t.byte 0x66\n" );
1740     printf( "\tlret\n" );
1741 }
1742
1743
1744 /*******************************************************************
1745  *         BuildRet16Func
1746  *
1747  * Build the return code for 16-bit callbacks
1748  */
1749 static void BuildRet16Func()
1750 {
1751     printf( "\t.globl " PREFIX "CALLTO16_Ret_word\n" );
1752     printf( "\t.globl " PREFIX "CALLTO16_Ret_long\n" );
1753
1754     /* Put return value into eax */
1755
1756     printf( PREFIX "CALLTO16_Ret_long:\n" );
1757     printf( "\tpushw %%dx\n" );
1758     printf( "\tpushw %%ax\n" );
1759     printf( "\tpopl %%eax\n" );
1760     printf( PREFIX "CALLTO16_Ret_word:\n" );
1761
1762     /* Restore 32-bit segment registers */
1763
1764     printf( "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1765 #ifdef __svr4__
1766     printf( "\tdata16\n");
1767 #endif
1768     printf( "\tmovw %%bx,%%ds\n" );
1769 #ifdef __svr4__
1770     printf( "\tdata16\n");
1771 #endif
1772     printf( "\tmovw %%bx,%%es\n" );
1773 #ifdef __svr4__
1774     printf( "\tdata16\n");
1775 #endif
1776     printf( "\tmovw %%bx,%%ss\n" );
1777
1778     /* Restore the 32-bit stack */
1779
1780     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1781     printf( "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
1782
1783     /* Restore the 32-bit registers */
1784
1785     printf( "\tpopl %%edi\n" );
1786     printf( "\tpopl %%esi\n" );
1787     printf( "\tpopl %%edx\n" );
1788     printf( "\tpopl %%ecx\n" );
1789     printf( "\tpopl %%ebx\n" );
1790
1791     /* Return to caller */
1792
1793     printf( "\tpopl %%ebp\n" );
1794     printf( "\tlret\n" );
1795
1796     /* Declare the return address variables */
1797
1798     printf( "\t.data\n" );
1799     printf( "\t.globl " PREFIX "CALLTO16_RetAddr_word\n" );
1800     printf( "\t.globl " PREFIX "CALLTO16_RetAddr_long\n" );
1801     printf( PREFIX "CALLTO16_RetAddr_word:\t.long 0\n" );
1802     printf( PREFIX "CALLTO16_RetAddr_long:\t.long 0\n" );
1803     printf( "\t.text\n" );
1804 }
1805
1806
1807 /*******************************************************************
1808  *         BuildCallFrom32Func
1809  *
1810  * Build a 32-bit-to-Wine call-back function.
1811  * 'args' is the number of dword arguments.
1812  *
1813  * Stack layout:
1814  *   ...     ...
1815  * (ebp+12)  arg2
1816  * (ebp+8)   arg1
1817  * (ebp+4)   ret addr
1818  * (ebp)     ebp
1819  * (ebp-4)   func name
1820  * (ebp-8)   entry point
1821  */
1822 static void BuildCallFrom32Func( int args )
1823 {
1824     /* Function header */
1825
1826     printf( "/**********\n" );
1827     printf( " * " PREFIX "CallFrom32_%d\n", args );
1828     printf( " **********/\n" );
1829     printf( "\t.align 4\n" );
1830     printf( "\t.globl " PREFIX "CallFrom32_%d\n\n", args );
1831     printf( PREFIX "CallFrom32_%d:\n", args );
1832
1833     /* Entry code */
1834
1835     printf( "\tleal 8(%%esp),%%ebp\n" );
1836
1837     /* Print the debugging info */
1838
1839     if (debugging)
1840     {
1841         printf( "\tpushl $%d\n", args );
1842         printf( "\tcall " PREFIX "RELAY_DebugCallFrom32\n" );
1843         printf( "\tadd $4, %%esp\n" );
1844     }
1845
1846     /* Transfer the arguments */
1847
1848     if (args)
1849     {
1850         int i;
1851         for (i = args; i > 0; i--) printf( "\tpushl %d(%%ebp)\n", 4 * i + 4 );
1852     }
1853     else
1854     {
1855         /* Push the address of the arguments. The called function will */
1856         /* ignore this if it really takes no arguments. */
1857         printf( "\tleal 8(%%ebp),%%eax\n" );
1858         printf( "\tpushl %%eax\n" );
1859     }
1860
1861     /* Call the function */
1862
1863     printf( "\tcall -8(%%ebp)\n" );
1864
1865     /* Print the debugging info */
1866
1867     if (debugging)
1868     {
1869         printf( "\tadd $%d,%%esp\n", args ? (args * 4) : 4 );
1870         printf( "\tpushl %%eax\n" );
1871         printf( "\tcall " PREFIX "RELAY_DebugCallFrom32Ret\n" );
1872         printf( "\tpopl %%eax\n" );
1873     }
1874
1875     printf( "\tmovl %%ebp,%%esp\n" );
1876     printf( "\tpopl %%ebp\n" );
1877
1878     /* Return, removing arguments */
1879
1880     if (args) printf( "\tret $%d\n", args * 4 );
1881     else printf( "\tret\n" );
1882 }
1883
1884
1885 /*******************************************************************
1886  *         BuildCallTo32Func
1887  *
1888  * Build a Wine-to-32-bit callback function.
1889  *
1890  * Stack frame of the callback function:
1891  *  ...      ...
1892  * (ebp+16) arg2
1893  * (ebp+12) arg1
1894  * (ebp+8)  func to call
1895  * (ebp+4)  return address
1896  * (ebp)    previous ebp
1897  *
1898  * Prototype for the CallTo32 functions:
1899  *   extern LONG CallTo32_nn( FARPROC func, args... );
1900  */
1901 static void BuildCallTo32Func( int args )
1902 {
1903     /* Function header */
1904
1905     printf( "/**********\n" );
1906     printf( " * " PREFIX "CallTo32_%d\n", args );
1907     printf( " **********/\n" );
1908     printf( "\t.align 4\n" );
1909     printf( "\t.globl " PREFIX "CallTo32_%d\n\n", args );
1910     printf( PREFIX "CallTo32_%d:\n", args );
1911
1912     /* Entry code */
1913
1914     printf( "\tpushl %%ebp\n" );
1915     printf( "\tmovl %%esp,%%ebp\n" );
1916
1917     /* Transfer arguments */
1918
1919     if (args)
1920     {
1921         int i;
1922         for (i = args; i > 0; i--) printf( "\tpushl %d(%%ebp)\n", 4 * i + 8 );
1923     }
1924
1925     /* Print the debugging output */
1926
1927     if (debugging)
1928     {
1929         printf( "\tpushl $%d\n", args );
1930         printf( "\tpushl 8(%%ebp)\n" );
1931         printf( "\tcall " PREFIX "RELAY_DebugCallTo32\n" );
1932         printf( "\taddl $8,%%esp\n" );
1933     }
1934
1935     /* Call the function */
1936
1937     printf( "\tcall 8(%%ebp)\n" );
1938
1939     /* Return to Wine */
1940
1941     printf( "\tmovl %%ebp,%%esp\n" );
1942     printf( "\tpopl %%ebp\n" );
1943     printf( "\tret\n" );
1944 }
1945
1946
1947 static void usage(void)
1948 {
1949     fprintf(stderr, "usage: build -spec SPECNAMES\n"
1950                     "       build -callfrom16 FUNCTION_PROFILES\n"
1951                     "       build -callto16 FUNCTION_PROFILES\n"
1952                     "       build -callfrom32 FUNCTION_PROFILES\n"
1953                     "       build -callto32 FUNCTION_PROFILES\n" );
1954     exit(1);
1955 }
1956
1957
1958 int main(int argc, char **argv)
1959 {
1960     int i;
1961
1962     if (argc <= 2) usage();
1963
1964     if (!strcmp( argv[1], "-spec" ))
1965     {
1966         for (i = 2; i < argc; i++) BuildSpecFiles( argv[i] );
1967     }
1968     else if (!strcmp( argv[1], "-callfrom16" ))  /* 16-bit-to-Wine callbacks */
1969     {
1970         /* File header */
1971
1972         printf( "/* File generated automatically. Do not edit! */\n\n" );
1973         printf( "\t.text\n" );
1974
1975         /* Build the 32-bit large stack callback */
1976
1977         BuildCall32LargeStack();
1978
1979         /* Build the callback functions */
1980
1981         for (i = 2; i < argc; i++) BuildCallFrom16Func( argv[i] );
1982
1983         /* Output the argument debugging strings */
1984
1985         if (debugging)
1986         {
1987             printf( "/* Argument strings */\n" );
1988             for (i = 2; i < argc; i++)
1989             {
1990                 printf( "Profile_%s:\n", argv[i] );
1991                 printf( "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
1992             }
1993         }
1994     }
1995     else if (!strcmp( argv[1], "-callto16" ))  /* Wine-to-16-bit callbacks */
1996     {
1997         /* File header */
1998
1999         printf( "/* File generated automatically. Do not edit! */\n\n" );
2000         printf( "\t.text\n" );
2001         printf( "\t.globl " PREFIX "CALLTO16_Start\n" );
2002         printf( PREFIX "CALLTO16_Start:\n" );
2003
2004         /* Build the callback functions */
2005
2006         for (i = 2; i < argc; i++) BuildCallTo16Func( argv[i] );
2007
2008         /* Output the 16-bit return code */
2009
2010         BuildRet16Func();
2011
2012         printf( "\t.globl " PREFIX "CALLTO16_End\n" );
2013         printf( PREFIX "CALLTO16_End:\n" );
2014     }
2015     else if (!strcmp( argv[1], "-callfrom32" ))  /* 32-bit-to-Wine callbacks */
2016     {
2017         /* File header */
2018
2019         printf( "/* File generated automatically. Do not edit! */\n\n" );
2020         printf( "\t.text\n" );
2021
2022         /* Build the callback functions */
2023
2024         for (i = 2; i < argc; i++) BuildCallFrom32Func( atoi(argv[i]) );
2025     }
2026     else if (!strcmp( argv[1], "-callto32" ))  /* Wine-to-32-bit callbacks */
2027     {
2028         /* File header */
2029
2030         printf( "/* File generated automatically. Do not edit! */\n\n" );
2031         printf( "\t.text\n" );
2032
2033         /* Build the callback functions */
2034
2035         for (i = 2; i < argc; i++) BuildCallTo32Func( atoi(argv[i]) );
2036     }
2037     else usage();
2038
2039     return 0;
2040 }
2041
2042 #endif  /* WINELIB */