Release 950403
[wine] / tools / build.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include "wine.h"
11
12 /* ELF symbols do not have an underscore in front */
13 #ifdef __ELF__
14 #define PREFIX
15 #else
16 #define PREFIX "_"
17 #endif
18
19 #define TYPE_INVALID     0
20 #define TYPE_BYTE        1
21 #define TYPE_WORD        2
22 #define TYPE_LONG        3
23 #define TYPE_PASCAL_16   4
24 #define TYPE_PASCAL      5
25 #define TYPE_REGISTER    6
26 #define TYPE_ABS         7
27 #define TYPE_RETURN      8
28
29 #define MAX_ORDINALS    1299
30
31 typedef struct ordinal_definition_s
32 {
33     int type;
34     int offset;
35     char export_name[80];
36     void *additional_data;
37 } ORDDEF;
38
39 typedef struct ordinal_variable_definition_s
40 {
41     int n_values;
42     int *values;
43 } ORDVARDEF;
44
45 typedef struct ordinal_function_definition_s
46 {
47     int  n_args;
48     char arg_types[32];
49     char internal_name[80];
50 } ORDFUNCDEF;
51
52 typedef struct ordinal_return_definition_s
53 {
54     int arg_size;
55     int ret_value;
56 } ORDRETDEF;
57
58 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
59
60 char LowerDLLName[80];
61 char UpperDLLName[80];
62 int Limit;
63 int DLLId;
64 FILE *SpecFp;
65
66 char *ParseBuffer = NULL;
67 char *ParseNext;
68 char ParseSaveChar;
69 int Line;
70
71 static int debugging = 1;
72
73   /* Offset of register relative to the end of the context struct */
74 #define CONTEXTOFFSET(reg) \
75    ((int)&(((struct sigcontext_struct *)1)->reg) - 1 \
76     - sizeof(struct sigcontext_struct))
77
78 static int IsNumberString(char *s)
79 {
80     while (*s != '\0')
81         if (!isdigit(*s++))
82             return 0;
83
84     return 1;
85 }
86
87 static char *strlower(char *s)
88 {
89     char *p;
90     
91     for(p = s; *p != '\0'; p++)
92         *p = tolower(*p);
93
94     return s;
95 }
96
97 static char *strupper(char *s)
98 {
99     char *p;
100     
101     for(p = s; *p != '\0'; p++)
102         *p = toupper(*p);
103
104     return s;
105 }
106
107 static char * GetTokenInLine(void)
108 {
109     char *p;
110     char *token;
111
112     if (ParseNext != ParseBuffer)
113     {
114         if (ParseSaveChar == '\0')
115             return NULL;
116         *ParseNext = ParseSaveChar;
117     }
118     
119     /*
120      * Remove initial white space.
121      */
122     for (p = ParseNext; isspace(*p); p++)
123         ;
124     
125     if (*p == '\0')
126         return NULL;
127     
128     /*
129      * Find end of token.
130      */
131     token = p++;
132     if (*token != '(' && *token != ')')
133         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
134             p++;
135     
136     ParseSaveChar = *p;
137     ParseNext = p;
138     *p = '\0';
139
140     return token;
141 }
142
143 static char * GetToken(void)
144 {
145     char *token;
146
147     if (ParseBuffer == NULL)
148     {
149         ParseBuffer = malloc(512);
150         ParseNext = ParseBuffer;
151         Line++;
152         while (1)
153         {
154             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
155                 return NULL;
156             if (ParseBuffer[0] != '#')
157                 break;
158         }
159     }
160
161     while ((token = GetTokenInLine()) == NULL)
162     {
163         ParseNext = ParseBuffer;
164         Line++;
165         while (1)
166         {
167             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
168                 return NULL;
169             if (ParseBuffer[0] != '#')
170                 break;
171         }
172     }
173
174     return token;
175 }
176
177 static int ParseVariable(int ordinal, int type)
178 {
179     ORDDEF *odp;
180     ORDVARDEF *vdp;
181     char export_name[80];
182     char *token;
183     char *endptr;
184     int *value_array;
185     int n_values;
186     int value_array_size;
187     
188     strcpy(export_name, GetToken());
189
190     token = GetToken();
191     if (*token != '(')
192     {
193         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
194         exit(1);
195     }
196
197     n_values = 0;
198     value_array_size = 25;
199     value_array = malloc(sizeof(*value_array) * value_array_size);
200     
201     while ((token = GetToken()) != NULL)
202     {
203         if (*token == ')')
204             break;
205
206         value_array[n_values++] = strtol(token, &endptr, 0);
207         if (n_values == value_array_size)
208         {
209             value_array_size += 25;
210             value_array = realloc(value_array, 
211                                   sizeof(*value_array) * value_array_size);
212         }
213         
214         if (endptr == NULL || *endptr != '\0')
215         {
216             fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
217                     token);
218             exit(1);
219         }
220     }
221     
222     if (token == NULL)
223     {
224         fprintf(stderr, "%d: End of file in variable declaration\n", Line);
225         exit(1);
226     }
227
228     if (ordinal >= MAX_ORDINALS)
229     {
230         fprintf(stderr, "%d: Ordinal number too large\n", Line);
231         exit(1);
232     }
233     
234     odp = &OrdinalDefinitions[ordinal];
235     odp->type = type;
236     strcpy(odp->export_name, export_name);
237     
238     vdp = malloc(sizeof(*vdp));
239     odp->additional_data = vdp;
240     
241     vdp->n_values = n_values;
242     vdp->values = realloc(value_array, sizeof(*value_array) * n_values);
243
244     return 0;
245 }
246
247 static int ParseExportFunction(int ordinal, int type)
248 {
249     char *token;
250     ORDDEF *odp;
251     ORDFUNCDEF *fdp;
252     int i;
253     
254     if (ordinal >= MAX_ORDINALS)
255     {
256         fprintf(stderr, "%d: Ordinal number too large\n", Line);
257         exit(1);
258     }
259     
260     odp = &OrdinalDefinitions[ordinal];
261     strcpy(odp->export_name, GetToken());
262     odp->type = type;
263     fdp = malloc(sizeof(*fdp));
264     odp->additional_data = fdp;
265
266     token = GetToken();
267     if (*token != '(')
268     {
269         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
270         exit(1);
271     }
272
273     for (i = 0; i < 16; i++)
274     {
275         token = GetToken();
276         if (*token == ')')
277             break;
278
279         if (!strcmp(token, "byte") || !strcmp(token, "word"))
280             fdp->arg_types[i] = 'w';
281         else if (!strcmp(token, "s_byte") || !strcmp(token, "s_word"))
282             fdp->arg_types[i] = 's';
283         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
284             fdp->arg_types[i] = 'l';
285         else if (!strcmp(token, "ptr"))
286             fdp->arg_types[i] = 'p';
287         else
288         {
289             fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
290             exit(1);
291         }
292     }
293     fdp->arg_types[i] = '\0';
294
295     if ((type == TYPE_REGISTER) && (i > 0))
296     {
297         fprintf( stderr, "%d: Register function can't have arguments\n", Line);
298         exit(1);
299     }
300
301     strcpy(fdp->internal_name, GetToken());
302     return 0;
303 }
304
305 static int ParseEquate(int ordinal)
306 {
307     ORDDEF *odp;
308     char *token;
309     char *endptr;
310     int value;
311     
312     if (ordinal >= MAX_ORDINALS)
313     {
314         fprintf(stderr, "%d: Ordinal number too large\n", Line);
315         exit(1);
316     }
317     
318     odp = &OrdinalDefinitions[ordinal];
319     strcpy(odp->export_name, GetToken());
320
321     token = GetToken();
322     value = strtol(token, &endptr, 0);
323     if (endptr == NULL || *endptr != '\0')
324     {
325         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
326                 token);
327         exit(1);
328     }
329
330     odp->type = TYPE_ABS;
331     odp->additional_data = (void *) value;
332
333     return 0;
334 }
335
336 static int ParseReturn(int ordinal)
337 {
338     ORDDEF *odp;
339     ORDRETDEF *rdp;
340     char *token;
341     char *endptr;
342     
343     if (ordinal >= MAX_ORDINALS)
344     {
345         fprintf(stderr, "%d: Ordinal number too large\n", Line);
346         exit(1);
347     }
348
349     rdp = malloc(sizeof(*rdp));
350     
351     odp = &OrdinalDefinitions[ordinal];
352     strcpy(odp->export_name, GetToken());
353     odp->type = TYPE_RETURN;
354     odp->additional_data = rdp;
355
356     token = GetToken();
357     rdp->arg_size = strtol(token, &endptr, 0);
358     if (endptr == NULL || *endptr != '\0')
359     {
360         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
361                 token);
362         exit(1);
363     }
364
365     token = GetToken();
366     rdp->ret_value = strtol(token, &endptr, 0);
367     if (endptr == NULL || *endptr != '\0')
368     {
369         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
370                 token);
371         exit(1);
372     }
373
374     return 0;
375 }
376
377 static int ParseOrdinal(int ordinal)
378 {
379     char *token;
380     
381     token = GetToken();
382     if (token == NULL)
383     {
384         fprintf(stderr, "%d: Expected type after ordinal\n", Line);
385         exit(1);
386     }
387
388     if (strcmp(token, "byte") == 0)
389         return ParseVariable(ordinal, TYPE_BYTE);
390     else if (strcmp(token, "word") == 0)
391         return ParseVariable(ordinal, TYPE_WORD);
392     else if (strcmp(token, "long") == 0)
393         return ParseVariable(ordinal, TYPE_LONG);
394     else if (strcmp(token, "p") == 0)
395         return ParseExportFunction(ordinal, TYPE_PASCAL);
396     else if (strcmp(token, "pascal") == 0)
397         return ParseExportFunction(ordinal, TYPE_PASCAL);
398     else if (strcmp(token, "pascal16") == 0)
399         return ParseExportFunction(ordinal, TYPE_PASCAL_16);
400     else if (strcmp(token, "register") == 0)
401         return ParseExportFunction(ordinal, TYPE_REGISTER);
402     else if (strcmp(token, "equate") == 0)
403         return ParseEquate(ordinal);
404     else if (strcmp(token, "return") == 0)
405         return ParseReturn(ordinal);
406     else
407     {
408         fprintf(stderr, 
409                 "%d: Expected type after ordinal, found '%s' instead\n",
410                 Line, token);
411         exit(1);
412     }
413 }
414
415 static int ParseTopLevel(void)
416 {
417     char *token;
418     
419     while ((token = GetToken()) != NULL)
420     {
421         if (strcmp(token, "name") == 0)
422         {
423             strcpy(LowerDLLName, GetToken());
424             strlower(LowerDLLName);
425
426             strcpy(UpperDLLName, LowerDLLName);
427             strupper(UpperDLLName);
428         }
429         else if (strcmp(token, "id") == 0)
430         {
431             token = GetToken();
432             if (!IsNumberString(token))
433             {
434                 fprintf(stderr, "%d: Expected number after id\n", Line);
435                 exit(1);
436             }
437             
438             DLLId = atoi(token);
439         }
440         else if (strcmp(token, "length") == 0)
441         {
442             token = GetToken();
443             if (!IsNumberString(token))
444             {
445                 fprintf(stderr, "%d: Expected number after length\n", Line);
446                 exit(1);
447             }
448
449             Limit = atoi(token);
450         }
451         else if (IsNumberString(token))
452         {
453             int ordinal;
454             int rv;
455             
456             ordinal = atoi(token);
457             if ((rv = ParseOrdinal(ordinal)) < 0)
458                 return rv;
459         }
460         else
461         {
462             fprintf(stderr, 
463                     "%d: Expected name, id, length or ordinal\n", Line);
464             exit(1);
465         }
466     }
467
468     return 0;
469 }
470
471
472 static int OutputVariableCode(FILE *fp, char *storage, ORDDEF *odp)
473 {
474     ORDVARDEF *vdp;
475     int i;
476
477     vdp = odp->additional_data;
478     fprintf( fp, "\t.data\n" );
479     for (i = 0; i < vdp->n_values; i++)
480     {
481         if ((i & 7) == 0)
482             fprintf(fp, "\t%s\t", storage);
483             
484         fprintf(fp, "%d", vdp->values[i]);
485         
486         if ((i & 7) == 7 || i == vdp->n_values - 1)
487             fprintf(fp, "\n");
488         else
489             fprintf(fp, ", ");
490     }
491     fprintf(fp, "\n");
492     fprintf( fp, "\t.text\n" );
493     return vdp->n_values;
494 }
495
496 static void BuildSpecFiles( char *specname)
497 {
498     ORDDEF *odp;
499     ORDFUNCDEF *fdp;
500     ORDRETDEF *rdp;
501     FILE *fp;
502     char filename[80];
503     int i;
504     int code_offset, data_offset;
505
506     SpecFp = fopen( specname, "r");
507     if (SpecFp == NULL)
508     {
509         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
510         exit(1);
511     }
512
513     ParseTopLevel();
514
515     sprintf(filename, "dll_%s.S", LowerDLLName);
516     fp = fopen(filename, "w");
517     fprintf( fp, "/* File generated automatically; do not edit! */\n" );
518     fprintf( fp, "\t.data\n" );
519     fprintf( fp, "\t.globl " PREFIX "%s_Data_Start\n", UpperDLLName );
520     fprintf( fp, PREFIX "%s_Data_Start:\n", UpperDLLName );
521     fprintf( fp, "\t.text\n" );
522     fprintf( fp, "\t.globl " PREFIX "%s_Code_Start\n", UpperDLLName );
523     fprintf( fp, PREFIX "%s_Code_Start:\n", UpperDLLName );
524     code_offset = data_offset = 0;
525
526     odp = OrdinalDefinitions;
527     for (i = 0; i <= Limit; i++, odp++)
528     {
529         fdp = odp->additional_data;
530         rdp = odp->additional_data;
531             
532         switch (odp->type)
533         {
534           case TYPE_INVALID:
535             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
536             fprintf( fp, "\tpushw %%bp\n" );
537             fprintf( fp, "\tpushl $0x%08x\n", (DLLId << 16) | i);
538             fprintf( fp, "\tpushl $" PREFIX "RELAY_Unimplemented\n" );
539             fprintf( fp, "\tljmp $0x%04x, $" PREFIX "CallTo32_word_\n",
540                          WINE_CODE_SELECTOR );
541             odp->offset = code_offset;
542             code_offset += 19;  /* Assembly code is 19 bytes long */
543             break;
544
545           case TYPE_ABS:
546             odp->offset = (int)odp->additional_data & 0xffff;
547             break;
548
549           case TYPE_BYTE:
550             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
551             odp->offset = data_offset;
552             data_offset += OutputVariableCode(fp, ".byte", odp);
553             break;
554
555           case TYPE_WORD:
556             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
557             odp->offset = data_offset;
558             data_offset += 2 * OutputVariableCode(fp, ".word", odp);
559             break;
560
561           case TYPE_LONG:
562             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
563             odp->offset = data_offset;
564             data_offset += 4 * OutputVariableCode(fp, ".long", odp);
565             break;
566
567           case TYPE_RETURN:
568             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
569             fprintf( fp, "\tmovw $%d,%%ax\n", rdp->ret_value & 0xffff );
570             fprintf( fp, "\tmovw $%d,%%dx\n", (rdp->ret_value >> 16) & 0xffff);
571             fprintf(fp, "\t.byte 0x66\n");
572             if (rdp->arg_size != 0)
573                 fprintf(fp, "\tlret $%d\n", rdp->arg_size);
574             else
575                 fprintf(fp, "\tlret\n");
576             odp->offset = code_offset;
577             code_offset += 10;  /* Assembly code is 10 bytes long */
578             if (rdp->arg_size != 0) code_offset += 2;
579             break;
580
581           case TYPE_REGISTER:
582           case TYPE_PASCAL:
583           case TYPE_PASCAL_16:
584             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
585             fprintf(fp, "\tpushw %%bp\n" );
586             fprintf(fp, "\tpushl $0x%08x\n", (DLLId << 16) | i);
587             fprintf(fp, "\tpushl $" PREFIX "%s\n", fdp->internal_name );
588             fprintf(fp, "\tljmp $0x%04x, $" PREFIX "CallTo32_%s_%s\n\n",
589                         WINE_CODE_SELECTOR,
590                         (odp->type == TYPE_REGISTER) ? "regs" :
591                         (odp->type == TYPE_PASCAL) ? "long" : "word",
592                         fdp->arg_types );
593             odp->offset = code_offset;
594             code_offset += 19;  /* Assembly code is 19 bytes long */
595             break;
596                 
597           default:
598             fprintf( stderr, "build: Unknown function type; please report.\n");
599             break;
600         }
601     }
602
603     fprintf( fp, "\t.data\n" );
604     fprintf( fp, "\t.globl " PREFIX "%s_Data_End\n", UpperDLLName );
605     fprintf( fp, PREFIX "%s_Data_End:\n", UpperDLLName );
606     fprintf( fp, "\t.text\n" );
607     fprintf( fp, "\t.globl " PREFIX "%s_Code_End\n", UpperDLLName );
608     fprintf( fp, PREFIX "%s_Code_End:\n", UpperDLLName );
609
610     fclose(fp);
611
612     sprintf(filename, "tab_%s.c", LowerDLLName);
613     fp = fopen(filename, "w");
614
615     fprintf( fp, "/* File generated automatically; do not edit! */\n\n" );
616     fprintf( fp, "#include \"dlls.h\"\n\n" );
617     fprintf( fp, "static struct dll_table_entry_s %s_table_entries[%d] =\n{\n",
618                  UpperDLLName, Limit + 1);
619     odp = OrdinalDefinitions;
620     for (i = 0; i <= Limit; i++, odp++)
621     {
622         int selector;
623
624         fdp = odp->additional_data;
625
626         switch (odp->type)
627         {
628         case TYPE_INVALID:
629         case TYPE_PASCAL:
630         case TYPE_PASCAL_16:
631         case TYPE_REGISTER:
632             selector = 1;  /* Code selector */
633             break;
634
635         case TYPE_BYTE:
636         case TYPE_WORD:
637         case TYPE_LONG:
638             selector = 2;  /* Data selector */
639             break;
640
641         case TYPE_ABS:
642             selector = 0xff;  /* Constant selector */
643             break;
644         }
645
646         fprintf(fp, "    { %d, %d, ", selector, odp->offset );
647         fprintf(fp, "\"%s\" ", odp->export_name);
648 #ifdef WINESTAT
649         fprintf(fp, ",0 ");
650 #endif      
651         fprintf(fp, "}, \n");
652     }
653
654     fprintf(fp, "};\n\n");
655
656     fprintf( fp, "extern void %s_Code_Start();\n", UpperDLLName );
657     fprintf( fp, "extern void %s_Code_End();\n", UpperDLLName );
658     fprintf( fp, "extern void %s_Data_Start();\n", UpperDLLName );
659     fprintf( fp, "extern void %s_Data_End();\n\n", UpperDLLName );
660     fprintf( fp, "struct dll_table_s %s_table =\n{\n", UpperDLLName );
661     fprintf( fp, "  %s_table_entries, %d, %d,\n",
662              UpperDLLName, Limit + 1, DLLId );
663     fprintf( fp, "  (void *)%s_Code_Start, (void *)%s_Code_End,\n",
664              UpperDLLName, UpperDLLName );
665     fprintf( fp, "  (void *)%s_Data_Start, (void *)%s_Data_End\n};\n",
666              UpperDLLName, UpperDLLName );
667     fclose(fp);
668 }
669
670
671 /*******************************************************************
672  *         TransferArgs16To32
673  *
674  * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
675  * The 16-bit stack layout is:
676  *   ...     ...
677  *  (bp+8)    arg2
678  *  (bp+6)    arg1
679  *  (bp+4)    cs
680  *  (bp+2)    ip
681  *  (bp)      bp
682  */
683 static int TransferArgs16To32( char *args )
684 {
685     int i, pos16, pos32;
686
687     /* Save ebx first */
688
689     printf( "\tpushl %%ebx\n" );
690
691     /* Get the 32-bit stack pointer */
692
693     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
694
695     /* Copy the arguments */
696
697     pos16 = 6;  /* skip bp and return address */
698     pos32 = 0;
699
700     for (i = strlen(args); i > 0; i--)
701     {
702         pos32 -= 4;
703         switch(args[i-1])
704         {
705         case 'w':  /* word */
706             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
707             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
708             pos16 += 2;
709             break;
710
711         case 's':  /* s_word */
712             printf( "\tmovswl %d(%%ebp),%%eax\n", pos16 );
713             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
714             pos16 += 2;
715             break;
716
717         case 'l':  /* long */
718             printf( "\tmovl %d(%%ebp),%%eax\n", pos16 );
719             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
720             pos16 += 4;
721             break;
722
723         case 'p':  /* ptr */
724             /* Get the selector */
725             printf( "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
726             /* Get the selector base */
727             printf( "\tandl $0xfff8,%%eax\n" );
728             printf( "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
729             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
730             /* Add the offset */
731             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
732             printf( "\taddl %%eax,%d(%%ebx)\n", pos32 );
733             pos16 += 4;
734             break;
735
736         default:
737             fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
738         }
739     }
740
741     /* Restore ebx */
742     
743     printf( "\tpopl %%ebx\n" );
744
745     return pos16 - 6;  /* Return the size of the 16-bit args */
746 }
747
748
749 /*******************************************************************
750  *         BuildContext
751  *
752  * Build the context structure on the 32-bit stack.
753  * The only valid registers in the context structure are:
754  *   eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
755  */
756 static void BuildContext(void)
757 {
758     /* Save ebx first */
759
760     printf( "\tpushl %%ebx\n" );
761
762     /* Get the 32-bit stack pointer */
763
764     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
765
766     /* Store the registers */
767
768     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_ebx) ); /* Get ebx from stack */
769     printf( "\tmovl %%eax,%d(%%ebx)\n", CONTEXTOFFSET(sc_eax) );
770     printf( "\tmovl %%ecx,%d(%%ebx)\n", CONTEXTOFFSET(sc_ecx) );
771     printf( "\tmovl %%edx,%d(%%ebx)\n", CONTEXTOFFSET(sc_edx) );
772     printf( "\tmovl %%esi,%d(%%ebx)\n", CONTEXTOFFSET(sc_esi) );
773     printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(sc_edi) );
774     printf( "\tmovw %%es,%d(%%ebx)\n", CONTEXTOFFSET(sc_es) );
775     printf( "\tmovw -10(%%ebp),%%ax\n" );  /* Get saved ds from stack */
776     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(sc_ds) );
777     printf( "\tpushfl\n" );
778 #ifndef __FreeBSD__
779     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
780 #else    
781     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
782 #endif
783 }
784
785
786 /*******************************************************************
787  *         RestoreContext
788  *
789  * Restore the registers from the context structure
790  */
791 static void RestoreContext(void)
792 {
793     /* Get the 32-bit stack pointer */
794
795     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
796
797     /* Restore the registers */
798
799     printf( "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(sc_ecx) );
800     printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(sc_edx) );
801     printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(sc_esi) );
802     printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(sc_edi) );
803     printf( "\tmovw %d(%%ebx),%%es\n", CONTEXTOFFSET(sc_es) );
804     printf( "\tpopw %%ax\n" );  /* Remove old ds from the stack */
805     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_ds) ); /* Push new ds */
806 #ifndef __FreeBSD__
807     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
808 #else    
809     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
810 #endif
811     printf( "\tpopfl\n" );
812     printf( "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(sc_eax) );
813     printf( "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(sc_ebx) );
814 }
815
816
817 /*******************************************************************
818  *         BuildCall32Func
819  *
820  * Build a 32-bit callback function. The syntax of the function
821  * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
822  * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
823  * 'l'=long, 'p'=pointer).
824  *
825  * Stack layout upon entry to the callback function:
826  *  ...      ...
827  * (sp+14)  first 16-bit arg
828  * (sp+12)  cs (word)
829  * (sp+10)  ip (word)
830  * (sp+8)   bp (word)
831  * (sp+4)   dll_id+ordinal (long)
832  * (sp)     entrypoint (long)
833  *
834  */
835 static void BuildCall32Func( char *profile )
836 {
837     int argsize = 0;
838     int short_ret = 0;
839     int reg_func = 0;
840     char *args = profile + 5;
841
842     /* Parse function type */
843
844     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
845     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
846     else if (strncmp( "long_", profile, 5 ))
847     {
848         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
849         return;
850     }
851
852     /* Function header */
853
854     printf( "/**********\n" );
855     printf( " * " PREFIX "CallTo32_%s\n", profile );
856     printf( " **********/\n" );
857     printf( "\t.align 4\n" );
858     printf( "\t.global " PREFIX "CallTo32_%s\n\n", profile );
859     printf( PREFIX "CallTo32_%s:\n", profile );
860
861     /* Setup bp to point to its copy on the stack */
862
863     printf( "\tmovzwl %%sp,%%ebp\n" );
864     printf( "\taddw $8,%%bp\n" );
865
866     /* Save 16-bit ds */
867
868     printf( "\tpushw %%ds\n" );
869
870     /* Restore 32-bit ds */
871
872     printf( "\tpushw $0x%04x\n", WINE_DATA_SELECTOR );
873     printf( "\tpopw %%ds\n" );
874
875     /* Save the 16-bit stack */
876
877     printf( "\tpushw " PREFIX "IF1632_Saved16_bp\n" );
878     printf( "\tpushw " PREFIX "IF1632_Saved16_sp\n" );
879     printf( "\tpushw " PREFIX "IF1632_Saved16_ss\n" );
880     printf( "\tmovw %%ss," PREFIX "IF1632_Saved16_ss\n" );
881     printf( "\tmovw %%sp," PREFIX "IF1632_Saved16_sp\n" );
882     printf( "\tmovw %%bp," PREFIX "IF1632_Saved16_bp\n" );
883
884     /* Transfer the arguments */
885
886     if (reg_func) BuildContext();
887     else if (*args) argsize = TransferArgs16To32( args );
888
889     /* Get the address of the API function */
890
891     printf( "\tmovl -8(%%ebp),%%eax\n" );
892
893     /* Setup es */
894
895     printf( "\tpushw %%ds\n" );
896     printf( "\tpopw %%es\n" );
897
898     /* Switch to the 32-bit stack */
899
900     printf( "\tpushw %%ds\n" );
901     printf( "\tpopw %%ss\n" );
902     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
903     printf( "\tmovl " PREFIX "IF1632_Saved32_ebp,%%ebp\n" );
904     if (reg_func)
905         printf( "\tsubl $%d,%%esp\n", sizeof(struct sigcontext_struct) );
906     else if (*args)
907         printf( "\tsubl $%d,%%esp\n", 4 * strlen(args) );
908
909     /* Call the entry point */
910
911     if (debugging)
912     {
913         printf( "\tpushl %%eax\n" );
914         printf( "\tpushl $CALL32_Str_%s\n", profile );
915         printf( "\tcall " PREFIX "RELAY_DebugCall32\n" );
916         printf( "\tpopl %%eax\n" );
917         printf( "\tpopl %%eax\n" );
918     }
919
920     printf( "\tcall %%eax\n" );
921
922     if (debugging)
923     {
924         printf( "\tpushl %%eax\n" );
925         printf( "\tpushl $%d\n", short_ret );
926         printf( "\tcall " PREFIX "RELAY_DebugReturn\n" );
927         printf( "\tpopl %%eax\n" );
928         printf( "\tpopl %%eax\n" );
929     }
930
931     if (reg_func)
932         printf( "\taddl $%d,%%esp\n", sizeof(struct sigcontext_struct) );
933     else if (*args)
934         printf( "\taddl $%d,%%esp\n", 4 * strlen(args) );
935
936     /* Restore the 16-bit stack */
937
938     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
939     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
940     printf( "\tmovw " PREFIX "IF1632_Saved16_bp,%%bp\n" );
941     printf( "\tpopw " PREFIX "IF1632_Saved16_ss\n" );
942     printf( "\tpopw " PREFIX "IF1632_Saved16_sp\n" );
943     printf( "\tpopw " PREFIX "IF1632_Saved16_bp\n" );
944
945     /* Restore registers from the context structure */
946
947     if (reg_func)
948     {
949         printf( "\tandl $0xffff,%%ebp\n" );
950         RestoreContext();
951     }
952     else  /* Store the return value in dx:ax if needed */
953     {
954         if (!short_ret)
955         {
956             printf( "\tpushl %%eax\n" );
957             printf( "\tpopw %%dx\n" );
958             printf( "\tpopw %%dx\n" );
959         }
960     }
961
962     /* Restore ds and bp */
963
964     printf( "\tpopw %%ds\n" );
965     printf( "\tmovw %%bp,%%sp\n" );
966     printf( "\tpopw %%bp\n" );
967
968     /* Remove the arguments and return */
969
970     if (argsize)
971     {
972         printf( "\t.byte 0x66\n" );
973         printf( "\tlret $%d\n", argsize );
974     }
975     else
976     {
977         printf( "\t.byte 0x66\n" );
978         printf( "\tlret\n" );
979     }
980 }
981
982
983 /*******************************************************************
984  *         BuildCall16Func
985  *
986  * Build a 16-bit callback function.
987  *
988  * Stack frame of the callback function:
989  *  ...      ...
990  * (ebp+22) arg2
991  * (ebp+18) arg1
992  * (ebp+14) 16-bit ds
993  * (ebp+10) func to call
994  * (ebp+8)  code selector
995  * (ebp+4)  return address
996  * (ebp)    previous ebp
997  *
998  * Prototypes for the CallTo16 functions:
999  *   extern WORD CallTo16_word_xxx( FARPROC func, WORD ds, args... );
1000  *   extern LONG CallTo16_long_xxx( FARPROC func, WORD ds, args... );
1001  *   extern void CallTo16_regs_( FARPROC func, WORD ds, WORD es, WORD ax,
1002  *                               WORD bx, WORD cx, WORD dx, WORD si, WORD di );
1003  */
1004 static void BuildCall16Func( char *profile )
1005 {
1006     int short_ret = 0;
1007     int reg_func = 0;
1008     char *args = profile + 5;
1009
1010     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1011     else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1012     else if (strncmp( "long_", profile, 5 ))
1013     {
1014         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1015         return;
1016     }
1017
1018     /* Function header */
1019
1020     printf( "/**********\n" );
1021     printf( " * " PREFIX "CallTo16_%s\n", profile );
1022     printf( " **********/\n" );
1023     printf( "\t.align 4\n" );
1024     printf( "\t.global " PREFIX "CallTo16_%s\n\n", profile );
1025     printf( PREFIX "CallTo16_%s:\n", profile );
1026
1027     /* Push code selector before return address to simulate a lcall */
1028
1029     printf( "\tpopl %%eax\n" );
1030     printf( "\tpushw $0x%04x\n", WINE_CODE_SELECTOR );
1031     printf( "\tpushl %%eax\n" );
1032
1033     /* Entry code */
1034
1035     printf( "\tpushl %%ebp\n" );
1036     printf( "\tmovl %%esp,%%ebp\n" );
1037
1038     /* Save the 32-bit registers */
1039
1040     printf( "\tpushl %%ebx\n" );
1041     printf( "\tpushl %%ecx\n" );
1042     printf( "\tpushl %%edx\n" );
1043     printf( "\tpushl %%esi\n" );
1044     printf( "\tpushl %%edi\n" );
1045
1046     /* Save the 32-bit stack */
1047
1048     printf( "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1049     printf( "\tpushl " PREFIX "IF1632_Saved32_ebp\n" );
1050     printf( "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1051     printf( "\tmovl %%ebp," PREFIX "IF1632_Saved32_ebp\n" );
1052     printf( "\tmovl %%ebp,%%ebx\n" );
1053
1054     /* Print debugging info */
1055
1056     if (debugging)
1057     {
1058         /* Push the address of the first argument */
1059         printf( "\tmovl %%ebx,%%eax\n" );
1060         printf( "\taddl $10,%%eax\n" );
1061         printf( "\tpushl $%d\n", reg_func ? 7 : strlen(args) );
1062         printf( "\tpushl %%eax\n" );
1063         printf( "\tcall " PREFIX "RELAY_DebugCall16\n" );
1064         printf( "\tpopl %%eax\n" );
1065         printf( "\tpopl %%eax\n" );
1066     }
1067
1068     /* Switch to the 16-bit stack */
1069
1070     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1071     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1072     printf( "\tmovzwl " PREFIX "IF1632_Saved16_bp,%%ebp\n" );
1073
1074     /* Transfer the arguments */
1075
1076     if (reg_func)
1077     {
1078         /* Get the registers. ebx is handled later on. */
1079         printf( "\tmovl 18(%%ebx),%%es\n" );
1080         printf( "\tmovl 22(%%ebx),%%eax\n" );
1081         printf( "\tmovl 30(%%ebx),%%ecx\n" );
1082         printf( "\tmovl 34(%%ebx),%%edx\n" );
1083         printf( "\tmovl 38(%%ebx),%%esi\n" );
1084         printf( "\tmovl 42(%%ebx),%%edi\n" );
1085     }
1086     else  /* not a register function */
1087     {
1088         int pos = 18;  /* first argument position */
1089         while (*args)
1090         {
1091             switch(*args++)
1092             {
1093             case 'w': /* word */
1094                 printf( "\tpushw %d(%%ebx)\n", pos );
1095                 break;
1096             case 'l': /* long */
1097                 printf( "\tpushl %d(%%ebx)\n", pos );
1098                 break;
1099             }
1100             pos += 4;
1101         }
1102     }
1103
1104     /* Push the return address */
1105
1106     printf( "\tpushl " PREFIX "CALL16_RetAddr_%s\n",
1107             short_ret ? "word" : "long" );
1108
1109     /* Push the called routine address */
1110
1111     printf( "\tpushl 10(%%ebx)\n" );
1112
1113     /* Get the 16-bit ds */
1114     /* FIXME: this shouldn't be necessary if function prologs fixup worked. */
1115
1116     printf( "\tmovw 14(%%ebx),%%ds\n" );
1117
1118     if (reg_func)
1119     {
1120         /* Retrieve ebx from the 32-bit stack */
1121         printf( "\tmovl %%fs:26(%%ebx),%%ebx\n" );
1122     }
1123     else
1124     {
1125         /* Set ax equal to ds for window procedures */
1126         printf( "\tmovw %%ds,%%ax\n" );
1127     }
1128
1129     /* Jump to the called routine */
1130
1131     printf( "\t.byte 0x66\n" );
1132     printf( "\tlret\n" );
1133 }
1134
1135
1136 /*******************************************************************
1137  *         BuildRet16Func
1138  *
1139  * Build the return code for 16-bit callbacks
1140  */
1141 static void BuildRet16Func()
1142 {
1143     printf( "\t.globl " PREFIX "CALL16_Ret_word\n" );
1144     printf( "\t.globl " PREFIX "CALL16_Ret_long\n" );
1145
1146     /* Put return value into eax */
1147
1148     printf( PREFIX "CALL16_Ret_long:\n" );
1149     printf( "\tpushw %%dx\n" );
1150     printf( "\tpushw %%ax\n" );
1151     printf( "\tpopl %%eax\n" );
1152     printf( PREFIX "CALL16_Ret_word:\n" );
1153
1154     /* Restore 32-bit segment registers */
1155
1156     printf( "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1157     printf( "\tmovw %%bx,%%ds\n" );
1158     printf( "\tmovw %%bx,%%es\n" );
1159     printf( "\tmovw %%bx,%%ss\n" );
1160
1161     /* Restore the 32-bit stack */
1162
1163     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1164     printf( "\tmovl " PREFIX "IF1632_Saved32_ebp,%%ebp\n" );
1165     printf( "\tpopl " PREFIX "IF1632_Saved32_ebp\n" );
1166     printf( "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
1167
1168     /* Restore the 32-bit registers */
1169
1170     printf( "\tpopl %%edi\n" );
1171     printf( "\tpopl %%esi\n" );
1172     printf( "\tpopl %%edx\n" );
1173     printf( "\tpopl %%ecx\n" );
1174     printf( "\tpopl %%ebx\n" );
1175
1176     /* Return to caller */
1177
1178     printf( "\tmovl %%ebp,%%esp\n" );
1179     printf( "\tpopl %%ebp\n" );
1180     printf( "\tlret\n" );
1181
1182     /* Declare the return address variables */
1183
1184     printf( "\t.data\n" );
1185     printf( "\t.globl " PREFIX "CALL16_RetAddr_word\n" );
1186     printf( "\t.globl " PREFIX "CALL16_RetAddr_long\n" );
1187     printf( PREFIX "CALL16_RetAddr_word:\t.long 0\n" );
1188     printf( PREFIX "CALL16_RetAddr_long:\t.long 0\n" );
1189     printf( "\t.text\n" );
1190 }
1191
1192
1193 static void usage(void)
1194 {
1195     fprintf(stderr, "usage: build -spec SPECNAMES\n"
1196                     "       build -call32 FUNCTION_PROFILES\n"
1197                     "       build -call16 FUNCTION_PROFILES\n" );
1198     exit(1);
1199 }
1200
1201
1202 int main(int argc, char **argv)
1203 {
1204     int i;
1205
1206     if (argc <= 2) usage();
1207
1208     if (!strcmp( argv[1], "-spec" ))
1209     {
1210         for (i = 2; i < argc; i++) BuildSpecFiles( argv[i] );
1211     }
1212     else if (!strcmp( argv[1], "-call32" ))  /* 32-bit callbacks */
1213     {
1214         /* File header */
1215
1216         printf( "/* File generated automatically. Do no edit! */\n\n" );
1217         printf( "\t.text\n" );
1218
1219         /* Build the callback functions */
1220
1221         for (i = 2; i < argc; i++) BuildCall32Func( argv[i] );
1222
1223         /* Output the argument debugging strings */
1224
1225         if (debugging)
1226         {
1227             printf( "/* Argument strings */\n" );
1228             for (i = 2; i < argc; i++)
1229             {
1230                 printf( "CALL32_Str_%s:\n", argv[i] );
1231                 printf( "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
1232             }
1233         }
1234     }
1235     else if (!strcmp( argv[1], "-call16" ))  /* 16-bit callbacks */
1236     {
1237         /* File header */
1238
1239         printf( "/* File generated automatically. Do no edit! */\n\n" );
1240         printf( "\t.text\n" );
1241         printf( "\t.globl " PREFIX "CALL16_Start\n" );
1242         printf( PREFIX "CALL16_Start:\n" );
1243
1244         /* Build the callback functions */
1245
1246         for (i = 2; i < argc; i++) BuildCall16Func( argv[i] );
1247
1248         /* Output the 16-bit return code */
1249
1250         BuildRet16Func();
1251
1252         printf( "\t.globl " PREFIX "CALL16_End\n" );
1253         printf( PREFIX "CALL16_End:\n" );
1254     }
1255     else usage();
1256
1257     return 0;
1258 }