Release 950901
[wine] / tools / build.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  * Copyright 1995 Martin von Loewis
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include "wine.h"
12 #include "module.h"
13 #include "neexe.h"
14
15 /* ELF symbols do not have an underscore in front */
16 #ifdef __ELF__
17 #define PREFIX
18 #else
19 #define PREFIX "_"
20 #endif
21
22 #define TYPE_INVALID     0
23 #define TYPE_BYTE        1
24 #define TYPE_WORD        2
25 #define TYPE_LONG        3
26 #define TYPE_PASCAL_16   4
27 #define TYPE_PASCAL      5
28 #define TYPE_REGISTER    6
29 #define TYPE_ABS         7
30 #define TYPE_RETURN      8
31 #define TYPE_STUB        9
32 #define TYPE_STDCALL    10
33
34 #define MAX_ORDINALS    1299
35
36   /* Callback function used for stub functions */
37 #define STUB_CALLBACK  "RELAY_Unimplemented"
38
39 typedef struct ordinal_definition_s
40 {
41     int type;
42     int offset;
43     char export_name[80];
44     void *additional_data;
45 } ORDDEF;
46
47 typedef struct ordinal_variable_definition_s
48 {
49     int n_values;
50     int *values;
51 } ORDVARDEF;
52
53 typedef struct ordinal_function_definition_s
54 {
55     int  n_args;
56     char arg_types[32];
57     char internal_name[80];
58 } ORDFUNCDEF;
59
60 typedef struct ordinal_return_definition_s
61 {
62     int arg_size;
63     int ret_value;
64 } ORDRETDEF;
65
66 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
67
68 char LowerDLLName[80];
69 char UpperDLLName[80];
70 int Limit = 0;
71 int DLLId;
72 int Base = 0;
73 FILE *SpecFp;
74
75 char *ParseBuffer = NULL;
76 char *ParseNext;
77 char ParseSaveChar;
78 int Line;
79
80 static int debugging = 1;
81
82   /* Offset of register relative to the end of the context struct */
83 #define CONTEXTOFFSET(reg) \
84    ((int)&(((struct sigcontext_struct *)1)->reg) - 1 \
85     - sizeof(struct sigcontext_struct))
86
87 static int IsNumberString(char *s)
88 {
89     while (*s != '\0')
90         if (!isdigit(*s++))
91             return 0;
92
93     return 1;
94 }
95
96 static char *strlower(char *s)
97 {
98     char *p;
99     
100     for(p = s; *p != '\0'; p++)
101         *p = tolower(*p);
102
103     return s;
104 }
105
106 static char *strupper(char *s)
107 {
108     char *p;
109     
110     for(p = s; *p != '\0'; p++)
111         *p = toupper(*p);
112
113     return s;
114 }
115
116 static char * GetTokenInLine(void)
117 {
118     char *p;
119     char *token;
120
121     if (ParseNext != ParseBuffer)
122     {
123         if (ParseSaveChar == '\0')
124             return NULL;
125         *ParseNext = ParseSaveChar;
126     }
127     
128     /*
129      * Remove initial white space.
130      */
131     for (p = ParseNext; isspace(*p); p++)
132         ;
133     
134     if ((*p == '\0') || (*p == '#'))
135         return NULL;
136     
137     /*
138      * Find end of token.
139      */
140     token = p++;
141     if (*token != '(' && *token != ')')
142         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
143             p++;
144     
145     ParseSaveChar = *p;
146     ParseNext = p;
147     *p = '\0';
148
149     return token;
150 }
151
152 static char * GetToken(void)
153 {
154     char *token;
155
156     if (ParseBuffer == NULL)
157     {
158         ParseBuffer = malloc(512);
159         ParseNext = ParseBuffer;
160         Line++;
161         while (1)
162         {
163             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
164                 return NULL;
165             if (ParseBuffer[0] != '#')
166                 break;
167         }
168     }
169
170     while ((token = GetTokenInLine()) == NULL)
171     {
172         ParseNext = ParseBuffer;
173         Line++;
174         while (1)
175         {
176             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
177                 return NULL;
178             if (ParseBuffer[0] != '#')
179                 break;
180         }
181     }
182
183     return token;
184 }
185
186 static int ParseVariable(int ordinal, int type)
187 {
188     ORDDEF *odp;
189     ORDVARDEF *vdp;
190     char export_name[80];
191     char *token;
192     char *endptr;
193     int *value_array;
194     int n_values;
195     int value_array_size;
196     
197     strcpy(export_name, GetToken());
198
199     token = GetToken();
200     if (*token != '(')
201     {
202         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
203         exit(1);
204     }
205
206     n_values = 0;
207     value_array_size = 25;
208     value_array = malloc(sizeof(*value_array) * value_array_size);
209     
210     while ((token = GetToken()) != NULL)
211     {
212         if (*token == ')')
213             break;
214
215         value_array[n_values++] = strtol(token, &endptr, 0);
216         if (n_values == value_array_size)
217         {
218             value_array_size += 25;
219             value_array = realloc(value_array, 
220                                   sizeof(*value_array) * value_array_size);
221         }
222         
223         if (endptr == NULL || *endptr != '\0')
224         {
225             fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
226                     token);
227             exit(1);
228         }
229     }
230     
231     if (token == NULL)
232     {
233         fprintf(stderr, "%d: End of file in variable declaration\n", Line);
234         exit(1);
235     }
236
237     if (ordinal >= MAX_ORDINALS)
238     {
239         fprintf(stderr, "%d: Ordinal number too large\n", Line);
240         exit(1);
241     }
242     
243     odp = &OrdinalDefinitions[ordinal];
244     odp->type = type;
245     strcpy(odp->export_name, export_name);
246
247     vdp = malloc(sizeof(*vdp));
248     odp->additional_data = vdp;
249     
250     vdp->n_values = n_values;
251     vdp->values = realloc(value_array, sizeof(*value_array) * n_values);
252
253     return 0;
254 }
255
256 static int ParseExportFunction(int ordinal, int type)
257 {
258     char *token;
259     ORDDEF *odp;
260     ORDFUNCDEF *fdp;
261     int i;
262     
263     odp = &OrdinalDefinitions[ordinal];
264     strcpy(odp->export_name, GetToken());
265     odp->type = type;
266     fdp = malloc(sizeof(*fdp));
267     odp->additional_data = fdp;
268
269     token = GetToken();
270     if (*token != '(')
271     {
272         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
273         exit(1);
274     }
275
276     for (i = 0; i < 16; i++)
277     {
278         token = GetToken();
279         if (*token == ')')
280             break;
281
282         if (!strcmp(token, "byte") || !strcmp(token, "word"))
283             fdp->arg_types[i] = 'w';
284         else if (!strcmp(token, "s_byte") || !strcmp(token, "s_word"))
285             fdp->arg_types[i] = 's';
286         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
287             fdp->arg_types[i] = 'l';
288         else if (!strcmp(token, "ptr"))
289             fdp->arg_types[i] = 'p';
290         else
291         {
292             fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
293             exit(1);
294         }
295     }
296     fdp->arg_types[i] = '\0';
297
298     strcpy(fdp->internal_name, GetToken());
299     return 0;
300 }
301
302 static int ParseEquate(int ordinal)
303 {
304     ORDDEF *odp;
305     char *token;
306     char *endptr;
307     int value;
308     
309     odp = &OrdinalDefinitions[ordinal];
310     strcpy(odp->export_name, GetToken());
311
312     token = GetToken();
313     value = strtol(token, &endptr, 0);
314     if (endptr == NULL || *endptr != '\0')
315     {
316         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
317                 token);
318         exit(1);
319     }
320
321     odp->type = TYPE_ABS;
322     odp->additional_data = (void *) value;
323
324     return 0;
325 }
326
327 static int ParseReturn(int ordinal)
328 {
329     ORDDEF *odp;
330     ORDRETDEF *rdp;
331     char *token;
332     char *endptr;
333     
334     rdp = malloc(sizeof(*rdp));
335     
336     odp = &OrdinalDefinitions[ordinal];
337     strcpy(odp->export_name, GetToken());
338     odp->type = TYPE_RETURN;
339     odp->additional_data = rdp;
340
341     token = GetToken();
342     rdp->arg_size = strtol(token, &endptr, 0);
343     if (endptr == NULL || *endptr != '\0')
344     {
345         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
346                 token);
347         exit(1);
348     }
349
350     token = GetToken();
351     rdp->ret_value = strtol(token, &endptr, 0);
352     if (endptr == NULL || *endptr != '\0')
353     {
354         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
355                 token);
356         exit(1);
357     }
358
359     return 0;
360 }
361
362
363 static int ParseStub( int ordinal )
364 {
365     ORDDEF *odp;
366     ORDFUNCDEF *fdp;
367     
368     odp = &OrdinalDefinitions[ordinal];
369     strcpy( odp->export_name, GetToken() );
370     odp->type = TYPE_STUB;
371     fdp = malloc(sizeof(*fdp));
372     odp->additional_data = fdp;
373     fdp->arg_types[0] = '\0';
374     strcpy( fdp->internal_name, STUB_CALLBACK );
375     return 0;
376 }
377
378
379 static int ParseOrdinal(int ordinal)
380 {
381     char *token;
382     
383     if (ordinal >= MAX_ORDINALS)
384     {
385         fprintf(stderr, "%d: Ordinal number too large\n", Line);
386         exit(1);
387     }
388     if (ordinal > Limit) Limit = ordinal;
389
390     token = GetToken();
391     if (token == NULL)
392     {
393         fprintf(stderr, "%d: Expected type after ordinal\n", Line);
394         exit(1);
395     }
396
397     if (strcmp(token, "byte") == 0)
398         return ParseVariable(ordinal, TYPE_BYTE);
399     else if (strcmp(token, "word") == 0)
400         return ParseVariable(ordinal, TYPE_WORD);
401     else if (strcmp(token, "long") == 0)
402         return ParseVariable(ordinal, TYPE_LONG);
403     else if (strcmp(token, "p") == 0)
404         return ParseExportFunction(ordinal, TYPE_PASCAL);
405     else if (strcmp(token, "pascal") == 0)
406         return ParseExportFunction(ordinal, TYPE_PASCAL);
407     else if (strcmp(token, "pascal16") == 0)
408         return ParseExportFunction(ordinal, TYPE_PASCAL_16);
409     else if (strcmp(token, "register") == 0)
410         return ParseExportFunction(ordinal, TYPE_REGISTER);
411     else if (strcmp(token, "stdcall") == 0)
412         return ParseExportFunction(ordinal, TYPE_STDCALL);
413     else if (strcmp(token, "equate") == 0)
414         return ParseEquate(ordinal);
415     else if (strcmp(token, "return") == 0)
416         return ParseReturn(ordinal);
417     else if (strcmp(token, "stub") == 0)
418         return ParseStub(ordinal);
419     else
420     {
421         fprintf(stderr, 
422                 "%d: Expected type after ordinal, found '%s' instead\n",
423                 Line, token);
424         exit(1);
425     }
426 }
427
428 static int ParseTopLevel(void)
429 {
430     char *token;
431     
432     while ((token = GetToken()) != NULL)
433     {
434         if (strcmp(token, "name") == 0)
435         {
436             strcpy(LowerDLLName, GetToken());
437             strlower(LowerDLLName);
438
439             strcpy(UpperDLLName, LowerDLLName);
440             strupper(UpperDLLName);
441         }
442         else if (strcmp(token, "id") == 0)
443         {
444             token = GetToken();
445             if (!IsNumberString(token))
446             {
447                 fprintf(stderr, "%d: Expected number after id\n", Line);
448                 exit(1);
449             }
450             
451             DLLId = atoi(token);
452         }
453         else if (strcmp(token, "base") == 0)
454         {
455                 token = GetToken();
456                 if (!IsNumberString(token))
457                 {
458                 fprintf(stderr, "%d: Expected number after base\n", Line);
459                 exit(1);
460                 }
461
462                 Base = atoi(token);
463         }
464         else if (IsNumberString(token))
465         {
466             int ordinal;
467             int rv;
468             
469             ordinal = atoi(token);
470             if ((rv = ParseOrdinal(ordinal)) < 0)
471                 return rv;
472         }
473         else
474         {
475             fprintf(stderr, 
476                     "%d: Expected name, id, length or ordinal\n", Line);
477             exit(1);
478         }
479     }
480
481     return 0;
482 }
483
484
485 static int OutputVariableCode( char *storage, ORDDEF *odp )
486 {
487     ORDVARDEF *vdp;
488     int i;
489
490     vdp = odp->additional_data;
491     printf( "\t.data\n" );
492     for (i = 0; i < vdp->n_values; i++)
493     {
494         if ((i & 7) == 0)
495             printf( "\t%s\t", storage);
496             
497         printf( "%d", vdp->values[i]);
498         
499         if ((i & 7) == 7 || i == vdp->n_values - 1) printf( "\n");
500         else printf( ", ");
501     }
502     printf( "\n");
503     printf( "\t.text\n" );
504     return vdp->n_values;
505 }
506
507
508 /*******************************************************************
509  *         BuildModule
510  *
511  * Build the in-memory representation of the module, and dump it
512  * as a byte stream into the assembly code.
513  */
514 static void BuildModule( int max_code_offset, int max_data_offset )
515 {
516     ORDDEF *odp;
517     int i, size;
518     char *buffer;
519     NE_MODULE *pModule;
520     SEGTABLEENTRY *pSegment;
521     LOADEDFILEINFO *pFileInfo;
522     BYTE *pstr, *bundle;
523     WORD *pword;
524
525     /*   Module layout:
526      * NE_MODULE       Module
527      * LOADEDFILEINFO  File information
528      * SEGTABLEENTRY   Segment 1 (code)
529      * SEGTABLEENTRY   Segment 2 (data)
530      * WORD[2]         Resource table (empty)
531      * BYTE[2]         Imported names (empty)
532      * BYTE[n]         Resident names table
533      * BYTE[n]         Entry table
534      */
535
536     buffer = malloc( 0x10000 );
537
538     pModule = (NE_MODULE *)buffer;
539     pModule->magic = NE_SIGNATURE;
540     pModule->count = 1;
541     pModule->next = 0;
542     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_LIBMODULE;
543     pModule->dgroup = 2;
544     pModule->heap_size = 0xffff;
545     pModule->stack_size = 0;
546     pModule->ip = 0;
547     pModule->cs = 0;
548     pModule->sp = 0;
549     pModule->ss = 0;
550     pModule->seg_count = 2;
551     pModule->modref_count = 0;
552     pModule->nrname_size = 0;
553     pModule->modref_table = 0;
554     pModule->nrname_fpos = 0;
555     pModule->moveable_entries = 0;
556     pModule->alignment = 0;
557     pModule->truetype = 0;
558     pModule->os_flags = NE_OSFLAGS_WINDOWS;
559     pModule->misc_flags = 0;
560     pModule->dlls_to_init  = 0;
561     pModule->nrname_handle = 0;
562     pModule->min_swap_area = 0;
563     pModule->expected_version = 0x030a;
564
565       /* File information */
566
567     pFileInfo = (LOADEDFILEINFO *)(pModule + 1);
568     pModule->fileinfo = (int)pFileInfo - (int)pModule;
569     pFileInfo->length = sizeof(LOADEDFILEINFO) + strlen(UpperDLLName) + 3;
570     pFileInfo->fixed_media = 0;
571     pFileInfo->error = 0;
572     pFileInfo->date = 0;
573     pFileInfo->time = 0;
574     sprintf( pFileInfo->filename, "%s.DLL", UpperDLLName );
575     pstr = (char *)pFileInfo + pFileInfo->length + 1;
576         
577       /* Segment table */
578
579     pSegment = (SEGTABLEENTRY *)pstr;
580     pModule->seg_table = (int)pSegment - (int)pModule;
581     pSegment->filepos = 0;
582     pSegment->size = max_code_offset;
583     pSegment->flags = 0;
584     pSegment->minsize = max_code_offset;
585     pSegment->selector = 0;
586     pSegment++;
587
588     pModule->dgroup_entry = (int)pSegment - (int)pModule;
589     pSegment->filepos = 0;
590     pSegment->size = max_data_offset;
591     pSegment->flags = NE_SEGFLAGS_DATA;
592     pSegment->minsize = max_data_offset;
593     pSegment->selector = 0;
594     pSegment++;
595
596       /* Resource table */
597
598     pword = (WORD *)pSegment;
599     pModule->res_table = (int)pword - (int)pModule;
600     *pword++ = 0;
601     *pword++ = 0;
602
603       /* Imported names table */
604
605     pstr = (char *)pword;
606     pModule->import_table = (int)pstr - (int)pModule;
607     *pstr++ = 0;
608     *pstr++ = 0;
609
610       /* Resident names table */
611
612     pModule->name_table = (int)pstr - (int)pModule;
613     /* First entry is module name */
614     *pstr = strlen(UpperDLLName );
615     strcpy( pstr + 1, UpperDLLName );
616     pstr += *pstr + 1;
617     *(WORD *)pstr = 0;
618     pstr += sizeof(WORD);
619     /* Store all ordinals */
620     odp = OrdinalDefinitions + 1;
621     for (i = 1; i <= Limit; i++, odp++)
622     {
623         if (!odp->export_name[0]) continue;
624         *pstr = strlen( odp->export_name );
625         strcpy( pstr + 1, odp->export_name );
626         strupper( pstr + 1 );
627         pstr += *pstr + 1;
628         *(WORD *)pstr = i;
629         pstr += sizeof(WORD);
630     }
631     *pstr++ = 0;
632
633       /* Entry table */
634
635     pModule->entry_table = (int)pstr - (int)pModule;
636     bundle = NULL;
637     odp = OrdinalDefinitions + 1;
638     for (i = 1; i <= Limit; i++, odp++)
639     {
640         int selector = 0;
641
642         switch (odp->type)
643         {
644         case TYPE_INVALID:
645             selector = 0;  /* Invalid selector */
646             break;
647
648         case TYPE_PASCAL:
649         case TYPE_PASCAL_16:
650         case TYPE_REGISTER:
651         case TYPE_RETURN:
652         case TYPE_STUB:
653             selector = 1;  /* Code selector */
654             break;
655
656         case TYPE_BYTE:
657         case TYPE_WORD:
658         case TYPE_LONG:
659             selector = 2;  /* Data selector */
660             break;
661
662         case TYPE_ABS:
663             selector = 0xfe;  /* Constant selector */
664             break;
665         }
666
667           /* create a new bundle if necessary */
668         if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
669         {
670             bundle = pstr;
671             bundle[0] = 0;
672             bundle[1] = selector;
673             pstr += 2;
674         }
675
676         (*bundle)++;
677         if (selector != 0)
678         {
679             *pstr++ = 1;
680             *(WORD *)pstr = odp->offset;
681             pstr += sizeof(WORD);
682         }
683     }
684     *pstr++ = 0;
685
686       /* Dump the module content */
687
688     printf( "\t.data\n" );
689     printf( "\t.globl " PREFIX "%s_Module_Start\n", UpperDLLName );
690     printf( PREFIX "%s_Module_Start:\n", UpperDLLName );
691     size = (int)pstr - (int)pModule;
692     for (i = 0, pstr = buffer; i < size; i++, pstr++)
693     {
694         if (!(i & 7)) printf( "\t.byte " );
695         printf( "%d%c", *pstr, ((i & 7) != 7) ? ',' : '\n' );
696     }
697     if (i & 7) printf( "0\n" );
698     printf( "\t.globl " PREFIX "%s_Module_End\n", UpperDLLName );
699     printf( PREFIX "%s_Module_End:\n", UpperDLLName );
700 }
701
702
703 static void BuildSpec32Files( char *specname )
704 {
705     ORDDEF *odp;
706     ORDFUNCDEF *fdp;
707     ORDRETDEF *rdp;
708     int i;
709
710     SpecFp = fopen( specname, "r");
711     if (SpecFp == NULL)
712     {
713         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
714         exit(1);
715     }
716
717     ParseTopLevel();
718
719     printf( "/* File generated automatically, do not edit! */\n" );
720     printf( "#include <sys/types.h>\n");
721     printf( "#include \"dlls.h\"\n");
722     printf( "#include \"pe_image.h\"\n");
723     printf( "#include \"winerror.h\"\n");
724     printf( "#include \"stddebug.h\"\n");
725     printf( "#include \"debug.h\"\n");
726     printf( "\nextern int RELAY32_Unimplemented();\n\n" );
727
728     odp = OrdinalDefinitions;
729     for (i = 0; i <= Limit; i++, odp++)
730     {
731         int argno,argc;
732         fdp = odp->additional_data;
733         rdp = odp->additional_data;
734
735         switch (odp->type)
736         {
737         case TYPE_INVALID:
738         case TYPE_STUB:
739             printf( "int %s_%d()\n{\n\t", UpperDLLName, i);
740             printf( "RELAY32_Unimplemented(\"%s\",%d);\n", UpperDLLName, i);
741             printf( "\t/*NOTREACHED*/\n\treturn 0;\n}\n\n");
742             break;
743         case TYPE_STDCALL:
744             argc=strlen(fdp->arg_types);
745             printf( "void %s_%d(", UpperDLLName, i);
746             for(argno=0;argno<argc;argno++)
747             {
748                 switch(fdp->arg_types[argno])
749                 {
750                 case 'p': printf( "void *");break;
751                 case 'l': printf( "int ");break;
752                 default:
753                     fprintf(stderr, "Not supported argument type %c\n",
754                             fdp->arg_types[argno]);
755                     exit(1);
756                 }
757                 putchar( 'a'+argno );
758                 if (argno!=argc-1) putchar( ',' );
759             }
760             printf( ")\n{\n" );
761             printf( "\textern int %s();\n", fdp->internal_name );
762             printf( "\tdprintf_relay(stddeb,\"Entering %%s.%%s(");
763             for (argno=0;argno<argc;argno++) printf( "%%x ");
764             printf( ")\\n\", \"%s\", \"%s\"", UpperDLLName, odp->export_name);
765             for(argno=0;argno<argc;argno++) printf( ",%c", 'a'+argno);
766             printf( ");\n\t%s(", fdp->internal_name );
767             for(argno=0;argno<argc;argno++)
768             {
769                 putchar('a'+argno);
770                 if (argno!=argc-1) putchar(',');
771             }
772             printf( ");\n\t__asm__ __volatile__(\"movl %%ebp,%%esp;"
773                     "popl %%ebp;ret $%d\");\n}\n\n",
774                     4*argc);
775             break;
776         case TYPE_RETURN:
777             printf( "void %s_%d()\n{\n\t", UpperDLLName, i);
778             printf( "RELAY32_DebugEnter(\"%s\",\"%s\");\n\t",
779                    UpperDLLName, odp->export_name);
780             printf( "WIN32_LastError=ERROR_CALL_NOT_IMPLEMENTED;\n");
781             printf( "\t__asm__ __volatile__ (\"movl %d,%%eax\");\n", 
782                    rdp->ret_value);
783             printf( "\t__asm__ __volatile__ (\"movl %%ebp,%%esp;popl %%ebp;"
784                     "ret $%d\");\n}\n\n", rdp->arg_size);
785             break;
786         default:
787             fprintf(stderr,"build: function type %d not available for Win32\n",
788                     odp->type);
789             break;
790         }
791     }
792
793     printf( "static WIN32_function functions[%d+1]={\n", Limit);
794
795     odp = OrdinalDefinitions;
796     for (i = 0; i <= Limit; i++, odp++)
797     {
798         fdp = odp->additional_data;
799         rdp = odp->additional_data;
800
801         switch (odp->type)
802         {
803         case TYPE_INVALID:
804             printf( "{0,%s_%d},\n",UpperDLLName, i);
805             break;
806         case TYPE_RETURN:
807         case TYPE_STDCALL:
808         case TYPE_STUB:
809             printf( "{\"%s\",%s_%d},\n", odp->export_name, UpperDLLName, i);
810             break;
811         default:
812             fprintf(stderr, "build: implementation error: missing %d\n",
813                     odp->type);
814             exit(1);
815         }
816     }
817     printf("};\n\n");
818
819     printf( "static WIN32_builtin dll={\"%s\",functions,%d,0};\n",
820             UpperDLLName, Limit);
821
822     printf( "void %s_Init(void)\n{\n",UpperDLLName);
823     printf( "\tdll.next=WIN32_builtin_list;\n");
824     printf( "\tWIN32_builtin_list=&dll;\n}");
825 }
826
827
828 static void BuildSpec16Files( char *specname )
829 {
830     ORDDEF *odp;
831     ORDFUNCDEF *fdp;
832     ORDRETDEF *rdp;
833     int i;
834     int code_offset, data_offset;
835
836     SpecFp = fopen( specname, "r");
837     if (SpecFp == NULL)
838     {
839         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
840         exit(1);
841     }
842
843     ParseTopLevel();
844
845     printf( "/* File generated automatically; do not edit! */\n" );
846     printf( "\t.data\n" );
847     printf( "\t.globl " PREFIX "%s_Data_Start\n", UpperDLLName );
848     printf( PREFIX "%s_Data_Start:\n", UpperDLLName );
849     printf( "\t.word 0,0,0,0,0,0,0,0\n" );
850     data_offset = 16;
851     printf( "\t.text\n" );
852     printf( "\t.globl " PREFIX "%s_Code_Start\n", UpperDLLName );
853     printf( PREFIX "%s_Code_Start:\n", UpperDLLName );
854     code_offset = 0;
855
856     odp = OrdinalDefinitions;
857     for (i = 0; i <= Limit; i++, odp++)
858     {
859         fdp = odp->additional_data;
860         rdp = odp->additional_data;
861             
862         switch (odp->type)
863         {
864           case TYPE_INVALID:
865             odp->offset = 0xffff;
866             break;
867
868           case TYPE_ABS:
869             odp->offset = (int)odp->additional_data & 0xffff;
870             break;
871
872           case TYPE_BYTE:
873             printf( "/* %s.%d */\n", UpperDLLName, i);
874             odp->offset = data_offset;
875             data_offset += OutputVariableCode( ".byte", odp);
876             break;
877
878           case TYPE_WORD:
879             printf( "/* %s.%d */\n", UpperDLLName, i);
880             odp->offset = data_offset;
881             data_offset += 2 * OutputVariableCode( ".word", odp);
882             break;
883
884           case TYPE_LONG:
885             printf( "/* %s.%d */\n", UpperDLLName, i);
886             odp->offset = data_offset;
887             data_offset += 4 * OutputVariableCode( ".long", odp);
888             break;
889
890           case TYPE_RETURN:
891             printf( "/* %s.%d */\n", UpperDLLName, i);
892             printf( "\tmovw $%d,%%ax\n", rdp->ret_value & 0xffff );
893             printf( "\tmovw $%d,%%dx\n", (rdp->ret_value >> 16) & 0xffff);
894             printf( "\t.byte 0x66\n");
895             if (rdp->arg_size != 0)
896                 printf( "\tlret $%d\n", rdp->arg_size);
897             else
898                 printf( "\tlret\n");
899             odp->offset = code_offset;
900             code_offset += 10;  /* Assembly code is 10 bytes long */
901             if (rdp->arg_size != 0) code_offset += 2;
902             break;
903
904           case TYPE_REGISTER:
905           case TYPE_PASCAL:
906           case TYPE_PASCAL_16:
907           case TYPE_STUB:
908             printf( "/* %s.%d */\n", UpperDLLName, i);
909             printf( "\tpushw %%bp\n" );
910             printf( "\tpushl $0x%08x\n", (DLLId << 16) | i);
911             printf( "\tpushl $" PREFIX "%s\n", fdp->internal_name );
912             printf( "\tljmp $0x%04x, $" PREFIX "CallTo32_%s_%s\n\n",
913                     WINE_CODE_SELECTOR,
914                     (odp->type == TYPE_REGISTER) ? "regs" :
915                     (odp->type == TYPE_PASCAL) ? "long" : "word",
916                     fdp->arg_types );
917             printf( "\tnop\n" );
918             printf( "\tnop\n" );
919             printf( "\tnop\n" );
920             printf( "\tnop\n" );
921             printf( "\tnop\n" );
922             odp->offset = code_offset;
923             code_offset += 24;  /* Assembly code is 24 bytes long */
924             break;
925                 
926           default:
927             fprintf( stderr, "build: Unknown function type; please report.\n");
928             break;
929         }
930     }
931
932     if (!code_offset)  /* Make sure the code segment is not empty */
933     {
934         printf( "\t.byte 0\n" );
935         code_offset++;
936     }
937
938     BuildModule( code_offset, data_offset );
939 }
940
941
942 /*******************************************************************
943  *         BuildCall32LargeStack
944  *
945  * Build the function used to switch to the original 32-bit stack
946  * before calling a 32-bit function from 32-bit code. This is used for
947  * functions that need a large stack, like X bitmaps functions.
948  *
949  * The generated function has the following prototype:
950  *   int CallTo32_LargeStack( int (*func)(), int nbargs, ... )
951  *
952  * Stack layout:
953  *   ...     ...
954  * (ebp+20)  arg2
955  * (ebp+16)  arg1
956  * (ebp+12)  nbargs
957  * (ebp+8)   func
958  * (ebp+4)   ret addr
959  * (ebp)     ebp
960  */
961 static void BuildCall32LargeStack(void)
962 {
963     /* Function header */
964
965     printf( "/**********\n" );
966     printf( " * " PREFIX "CallTo32_LargeStack\n" );
967     printf( " **********/\n" );
968     printf( "\t.align 4\n" );
969     printf( "\t.globl " PREFIX "CallTo32_LargeStack\n\n" );
970     printf( PREFIX "CallTo32_LargeStack:\n" );
971     
972     /* Entry code */
973
974     printf( "\tpushl %%ebp\n" );
975     printf( "\tmovl %%esp,%%ebp\n" );
976
977     /* Save registers */
978
979     printf( "\tpushl %%ecx\n" );
980     printf( "\tpushl %%esi\n" );
981     printf( "\tpushl %%edi\n" );
982
983     /* Retrieve the original 32-bit stack pointer and switch to it if any */
984
985     printf( "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
986     printf( "\torl %%eax,%%eax\n" );
987     printf( "\tje 0f\n" );
988     printf( "\tmovl %%eax,%%esp\n" );
989     printf( "0:\n" );
990
991     /* Transfer the arguments */
992
993     printf( "\tleal 16(%%ebp),%%esi\n" );
994     printf( "\tmovl 12(%%ebp),%%ecx\n" );
995     printf( "\torl %%ecx,%%ecx\n" );
996     printf( "\tje 1f\n" );
997     printf( "\tshll $2,%%ecx\n" );
998     printf( "\tsubl %%ecx,%%esp\n" );
999     printf( "\tmovl %%esp,%%edi\n" );
1000     printf( "\tshrl $2,%%ecx\n" );
1001     printf( "\trep; movsl\n" );
1002     printf( "1:\n" );
1003
1004     /* Call the function */
1005
1006     printf( "\tcall 8(%%ebp)\n" );
1007
1008     /* Switch back to the normal stack */
1009
1010     printf( "\tleal -12(%%ebp),%%esp\n" );
1011
1012     /* Restore registers and return */
1013
1014     printf( "\tpopl %%edi\n" );
1015     printf( "\tpopl %%esi\n" );
1016     printf( "\tpopl %%ecx\n" );
1017     printf( "\tpopl %%ebp\n" );
1018     printf( "\tret\n" );
1019 }
1020
1021
1022 /*******************************************************************
1023  *         TransferArgs16To32
1024  *
1025  * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1026  * The 16-bit stack layout is:
1027  *   ...     ...
1028  *  (bp+8)    arg2
1029  *  (bp+6)    arg1
1030  *  (bp+4)    cs
1031  *  (bp+2)    ip
1032  *  (bp)      bp
1033  */
1034 static int TransferArgs16To32( char *args )
1035 {
1036     int i, pos16, pos32;
1037
1038     /* Save ebx first */
1039
1040     printf( "\tpushl %%ebx\n" );
1041
1042     /* Get the 32-bit stack pointer */
1043
1044     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1045
1046     /* Copy the arguments */
1047
1048     pos16 = 6;  /* skip bp and return address */
1049     pos32 = 0;
1050
1051     for (i = strlen(args); i > 0; i--)
1052     {
1053         pos32 -= 4;
1054         switch(args[i-1])
1055         {
1056         case 'w':  /* word */
1057             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1058             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1059             pos16 += 2;
1060             break;
1061
1062         case 's':  /* s_word */
1063             printf( "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1064             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1065             pos16 += 2;
1066             break;
1067
1068         case 'l':  /* long */
1069             printf( "\tmovl %d(%%ebp),%%eax\n", pos16 );
1070             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1071             pos16 += 4;
1072             break;
1073
1074         case 'p':  /* ptr */
1075             /* Get the selector */
1076             printf( "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1077             /* Get the selector base */
1078             printf( "\tandl $0xfff8,%%eax\n" );
1079             printf( "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1080             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1081             /* Add the offset */
1082             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1083             printf( "\taddl %%eax,%d(%%ebx)\n", pos32 );
1084             pos16 += 4;
1085             break;
1086
1087         default:
1088             fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1089         }
1090     }
1091
1092     /* Restore ebx */
1093     
1094     printf( "\tpopl %%ebx\n" );
1095
1096     return pos16 - 6;  /* Return the size of the 16-bit args */
1097 }
1098
1099
1100 /*******************************************************************
1101  *         BuildContext
1102  *
1103  * Build the context structure on the 32-bit stack.
1104  * The only valid registers in the context structure are:
1105  *   eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
1106  */
1107 static void BuildContext(void)
1108 {
1109     /* Save ebx first */
1110
1111     printf( "\tpushl %%ebx\n" );
1112
1113     /* Get the 32-bit stack pointer */
1114
1115     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1116
1117     /* Store the registers */
1118
1119     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_ebx) ); /* Get ebx from stack */
1120     printf( "\tmovl %%eax,%d(%%ebx)\n", CONTEXTOFFSET(sc_eax) );
1121     printf( "\tmovl %%ecx,%d(%%ebx)\n", CONTEXTOFFSET(sc_ecx) );
1122     printf( "\tmovl %%edx,%d(%%ebx)\n", CONTEXTOFFSET(sc_edx) );
1123     printf( "\tmovl %%esi,%d(%%ebx)\n", CONTEXTOFFSET(sc_esi) );
1124     printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(sc_edi) );
1125     printf( "\tmovw -10(%%ebp),%%ax\n" );  /* Get saved ds from stack */
1126     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(sc_ds) );
1127     printf( "\tmovw -12(%%ebp),%%ax\n" );  /* Get saved es from stack */
1128     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(sc_es) );
1129     printf( "\tpushfl\n" );
1130 #ifndef __FreeBSD__
1131     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
1132 #else    
1133     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
1134 #endif
1135 }
1136
1137
1138 /*******************************************************************
1139  *         RestoreContext
1140  *
1141  * Restore the registers from the context structure
1142  */
1143 static void RestoreContext(void)
1144 {
1145     /* Get the 32-bit stack pointer */
1146
1147     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1148
1149     /* Restore the registers */
1150
1151     printf( "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(sc_ecx) );
1152     printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(sc_edx) );
1153     printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(sc_esi) );
1154     printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(sc_edi) );
1155     printf( "\tpopl %%eax\n" );  /* Remove old ds and es from stack */
1156     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_ds) ); /* Push new ds */
1157     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_es) ); /* Push new es */
1158 #ifndef __FreeBSD__
1159     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
1160 #else    
1161     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
1162 #endif
1163     printf( "\tpopfl\n" );
1164     printf( "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(sc_eax) );
1165     printf( "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(sc_ebx) );
1166 }
1167
1168
1169 /*******************************************************************
1170  *         BuildCall32Func
1171  *
1172  * Build a 32-bit callback function. The syntax of the function
1173  * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1174  * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1175  * 'l'=long, 'p'=pointer).
1176  * For register functions, the arguments are ignored, but they are still
1177  * removed from the stack upon return.
1178  *
1179  * Stack layout upon entry to the callback function:
1180  *  ...      ...
1181  * (sp+14)  first 16-bit arg
1182  * (sp+12)  cs (word)
1183  * (sp+10)  ip (word)
1184  * (sp+8)   bp (word)
1185  * (sp+4)   dll_id+ordinal (long)
1186  * (sp)     entrypoint (long)
1187  *
1188  */
1189 static void BuildCall32Func( char *profile )
1190 {
1191     int argsize = 0;
1192     int short_ret = 0;
1193     int reg_func = 0;
1194     char *args = profile + 5;
1195
1196     /* Parse function type */
1197
1198     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1199     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1200     else if (strncmp( "long_", profile, 5 ))
1201     {
1202         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1203         return;
1204     }
1205
1206     /* Function header */
1207
1208     printf( "/**********\n" );
1209     printf( " * " PREFIX "CallTo32_%s\n", profile );
1210     printf( " **********/\n" );
1211     printf( "\t.align 4\n" );
1212     printf( "\t.globl " PREFIX "CallTo32_%s\n\n", profile );
1213     printf( PREFIX "CallTo32_%s:\n", profile );
1214
1215     /* Setup bp to point to its copy on the stack */
1216
1217     printf( "\tmovzwl %%sp,%%ebp\n" );
1218     printf( "\taddw $8,%%bp\n" );
1219
1220     /* Save 16-bit ds and es */
1221
1222     printf( "\tpushw %%ds\n" );
1223     printf( "\tpushw %%es\n" );
1224
1225     /* Restore 32-bit ds and es */
1226
1227     printf( "\tpushl $0x%04x%04x\n", WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1228     printf( "\tpopw %%ds\n" );
1229     printf( "\tpopw %%es\n" );
1230
1231
1232     /* Save the 16-bit stack */
1233
1234     printf( "\tpushw " PREFIX "IF1632_Saved16_sp\n" );
1235     printf( "\tpushw " PREFIX "IF1632_Saved16_ss\n" );
1236     printf( "\tmovw %%ss," PREFIX "IF1632_Saved16_ss\n" );
1237     printf( "\tmovw %%sp," PREFIX "IF1632_Saved16_sp\n" );
1238
1239     /* Transfer the arguments */
1240
1241     if (reg_func) BuildContext();
1242     else if (*args) argsize = TransferArgs16To32( args );
1243
1244     /* Get the address of the API function */
1245
1246     printf( "\tmovl -8(%%ebp),%%eax\n" );
1247
1248     /* If necessary, save %edx over the API function address */
1249
1250     if (!reg_func && short_ret)
1251         printf( "\tmovl %%edx,-8(%%ebp)\n" );
1252
1253     /* Switch to the 32-bit stack */
1254
1255     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebp\n" );
1256     printf( "\tpushw %%ds\n" );
1257     printf( "\tpopw %%ss\n" );
1258     printf( "\tleal -%d(%%ebp),%%esp\n",
1259             reg_func ? sizeof(struct sigcontext_struct) : 4 * strlen(args) );
1260
1261     /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1262
1263     printf( "\taddl $24,%%ebp\n" );
1264
1265     /* Print the debug information before the call */
1266
1267     if (debugging)
1268     {
1269         printf( "\tpushl %%eax\n" );
1270         printf( "\tpushl $CALL32_Str_%s\n", profile );
1271         printf( "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0) );
1272         printf( "\tcall " PREFIX "RELAY_DebugCall32\n" );
1273         printf( "\tpopl %%eax\n" );
1274         printf( "\tpopl %%eax\n" );
1275         printf( "\tpopl %%eax\n" );
1276     }
1277
1278     /* Call the entry point */
1279
1280     printf( "\tcall %%eax\n" );
1281
1282     /* Print the debug information after the call */
1283
1284     if (debugging)
1285     {
1286         printf( "\tpushl %%eax\n" );
1287         printf( "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0) );
1288         printf( "\tcall " PREFIX "RELAY_DebugReturn\n" );
1289         printf( "\tpopl %%eax\n" );
1290         printf( "\tpopl %%eax\n" );
1291     }
1292
1293     /* Restore the 16-bit stack */
1294
1295     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1296     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1297     printf( "\tpopw " PREFIX "IF1632_Saved16_ss\n" );
1298     printf( "\tpopw " PREFIX "IF1632_Saved16_sp\n" );
1299
1300     if (reg_func)
1301     {
1302         /* Restore registers from the context structure */
1303         RestoreContext();
1304         
1305         /* Calc the arguments size */
1306         while (*args)
1307         {
1308             switch(*args)
1309             {
1310             case 'w':
1311             case 's':
1312                 argsize += 2;
1313                 break;
1314             case 'p':
1315             case 'l':
1316                 argsize += 4;
1317                 break;
1318             default:
1319                 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1320             }
1321             args++;
1322         }
1323     }
1324
1325     /* Restore ds and es */
1326
1327     printf( "\tpopw %%es\n" );
1328     printf( "\tpopw %%ds\n" );
1329
1330     /* Get the return value into dx:ax and clean up the stack */
1331
1332     if (!reg_func)
1333     {
1334         if (short_ret)
1335         {
1336             printf( "\tpopl %%edx\n" );     /* Restore %edx */
1337             printf( "\taddl $4,%%esp\n" );  /* Remove DLL id and ordinal */
1338         }
1339         else
1340         {
1341             printf( "\tpushl %%eax\n" );
1342             printf( "\tpopw %%ax\n" );
1343             printf( "\tpopw %%dx\n" );
1344             /* Remove API entry point, DLL id and ordinal from the stack */
1345             printf( "\taddl $8,%%esp\n" );
1346         }
1347     }
1348     else
1349     {
1350         /* Remove API entry point, DLL id and ordinal from the stack, */
1351         /* but take care not to change the value of the carry flag.   */
1352
1353         printf( "\tpopl %%ebp\n" );
1354         printf( "\tpopl %%ebp\n" );
1355     }
1356
1357     /* Restore bp */
1358
1359     printf( "\tpopw %%bp\n" );
1360
1361     /* Remove the arguments and return */
1362
1363     if (argsize)
1364     {
1365         printf( "\t.byte 0x66\n" );
1366         printf( "\tlret $%d\n", argsize );
1367     }
1368     else
1369     {
1370         printf( "\t.byte 0x66\n" );
1371         printf( "\tlret\n" );
1372     }
1373 }
1374
1375
1376 /*******************************************************************
1377  *         BuildCall16Func
1378  *
1379  * Build a 16-bit callback function.
1380  *
1381  * Stack frame of the callback function:
1382  *  ...      ...
1383  * (ebp+24) arg2
1384  * (ebp+20) arg1
1385  * (ebp+16) 16-bit ds
1386  * (ebp+12) func to call
1387  * (ebp+8)  code selector
1388  * (ebp+4)  return address
1389  * (ebp)    previous ebp
1390  *
1391  * Prototypes for the CallTo16 functions:
1392  *   extern WORD CallTo16_word_xxx( FARPROC func, WORD ds, args... );
1393  *   extern LONG CallTo16_long_xxx( FARPROC func, WORD ds, args... );
1394  *   extern void CallTo16_regs_( FARPROC func, WORD ds, WORD es, WORD bp,
1395  *                               WORD ax, WORD bx, WORD cx, WORD dx,
1396  *                               WORD si, WORD di );
1397  */
1398 static void BuildCall16Func( char *profile )
1399 {
1400     int short_ret = 0;
1401     int reg_func = 0;
1402     char *args = profile + 5;
1403
1404     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1405     else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1406     else if (strncmp( "long_", profile, 5 ))
1407     {
1408         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1409         return;
1410     }
1411
1412     /* Function header */
1413
1414     printf( "/**********\n" );
1415     printf( " * " PREFIX "CallTo16_%s\n", profile );
1416     printf( " **********/\n" );
1417     printf( "\t.align 4\n" );
1418     printf( "\t.globl " PREFIX "CallTo16_%s\n\n", profile );
1419     printf( PREFIX "CallTo16_%s:\n", profile );
1420
1421     /* Push code selector before return address to simulate a lcall */
1422
1423     printf( "\tpopl %%eax\n" );
1424     printf( "\tpushl $0x%04x\n", WINE_CODE_SELECTOR );
1425     printf( "\tpushl %%eax\n" );
1426
1427     /* Entry code */
1428
1429     printf( "\tpushl %%ebp\n" );
1430     printf( "\tmovl %%esp,%%ebp\n" );
1431
1432     /* Save the 32-bit registers */
1433
1434     printf( "\tpushl %%ebx\n" );
1435     printf( "\tpushl %%ecx\n" );
1436     printf( "\tpushl %%edx\n" );
1437     printf( "\tpushl %%esi\n" );
1438     printf( "\tpushl %%edi\n" );
1439
1440     /* Save the 32-bit stack */
1441
1442     printf( "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1443     printf( "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1444     printf( "\tmovl %%ebp,%%ebx\n" );
1445
1446     /* Print debugging info */
1447
1448     if (debugging)
1449     {
1450         /* Push the address of the first argument */
1451         printf( "\tmovl %%ebx,%%eax\n" );
1452         printf( "\taddl $12,%%eax\n" );
1453         printf( "\tpushl $%d\n", reg_func ? 8 : strlen(args) );
1454         printf( "\tpushl %%eax\n" );
1455         printf( "\tcall " PREFIX "RELAY_DebugCall16\n" );
1456         printf( "\tpopl %%eax\n" );
1457         printf( "\tpopl %%eax\n" );
1458     }
1459
1460     /* Switch to the 16-bit stack */
1461
1462     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1463     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1464
1465     /* Transfer the arguments */
1466
1467     if (reg_func)
1468     {
1469         /* Get the registers. ebx is handled later on. */
1470         printf( "\tpushw 20(%%ebx)\n" );
1471         printf( "\tpopw %%es\n" );
1472         printf( "\tmovl 24(%%ebx),%%ebp\n" );
1473         printf( "\tmovl 28(%%ebx),%%eax\n" );
1474         printf( "\tmovl 36(%%ebx),%%ecx\n" );
1475         printf( "\tmovl 40(%%ebx),%%edx\n" );
1476         printf( "\tmovl 44(%%ebx),%%esi\n" );
1477         printf( "\tmovl 48(%%ebx),%%edi\n" );
1478     }
1479     else  /* not a register function */
1480     {
1481         int pos = 20;  /* first argument position */
1482
1483         /* Make %bp point to the previous stackframe (built by CallTo32) */
1484         printf( "\tmovw %%sp,%%bp\n" );
1485         printf( "\taddw $16,%%bp\n" );
1486
1487         while (*args)
1488         {
1489             switch(*args++)
1490             {
1491             case 'w': /* word */
1492                 printf( "\tpushw %d(%%ebx)\n", pos );
1493                 break;
1494             case 'l': /* long */
1495                 printf( "\tpushl %d(%%ebx)\n", pos );
1496                 break;
1497             }
1498             pos += 4;
1499         }
1500     }
1501
1502     /* Push the return address */
1503
1504     printf( "\tpushl " PREFIX "CALL16_RetAddr_%s\n",
1505             short_ret ? "word" : "long" );
1506
1507     /* Push the called routine address */
1508
1509     printf( "\tpushl 12(%%ebx)\n" );
1510
1511     /* Get the 16-bit ds */
1512
1513     if (reg_func)
1514     {
1515         printf( "\tpushw 16(%%ebx)\n" );
1516         printf( "\tmovl 32(%%ebx),%%ebx\n" ); /*Get ebx from the 32-bit stack*/
1517         printf( "\tpopw %%ds\n" );
1518     }
1519     else
1520     {
1521         /* Set ax equal to ds for window procedures */
1522         printf( "\tmovw 16(%%ebx),%%ax\n" );
1523         printf( "\tmovw %%ax,%%ds\n" );
1524     }
1525
1526     /* Jump to the called routine */
1527
1528     printf( "\t.byte 0x66\n" );
1529     printf( "\tlret\n" );
1530 }
1531
1532
1533 /*******************************************************************
1534  *         BuildRet16Func
1535  *
1536  * Build the return code for 16-bit callbacks
1537  */
1538 static void BuildRet16Func()
1539 {
1540     printf( "\t.globl " PREFIX "CALL16_Ret_word\n" );
1541     printf( "\t.globl " PREFIX "CALL16_Ret_long\n" );
1542
1543     /* Put return value into eax */
1544
1545     printf( PREFIX "CALL16_Ret_long:\n" );
1546     printf( "\tpushw %%dx\n" );
1547     printf( "\tpushw %%ax\n" );
1548     printf( "\tpopl %%eax\n" );
1549     printf( PREFIX "CALL16_Ret_word:\n" );
1550
1551     /* Restore 32-bit segment registers */
1552
1553     printf( "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1554     printf( "\tmovw %%bx,%%ds\n" );
1555     printf( "\tmovw %%bx,%%es\n" );
1556     printf( "\tmovw %%bx,%%ss\n" );
1557
1558     /* Restore the 32-bit stack */
1559
1560     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1561     printf( "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
1562
1563     /* Restore the 32-bit registers */
1564
1565     printf( "\tpopl %%edi\n" );
1566     printf( "\tpopl %%esi\n" );
1567     printf( "\tpopl %%edx\n" );
1568     printf( "\tpopl %%ecx\n" );
1569     printf( "\tpopl %%ebx\n" );
1570
1571     /* Return to caller */
1572
1573     printf( "\tpopl %%ebp\n" );
1574     printf( "\tlret\n" );
1575
1576     /* Declare the return address variables */
1577
1578     printf( "\t.data\n" );
1579     printf( "\t.globl " PREFIX "CALL16_RetAddr_word\n" );
1580     printf( "\t.globl " PREFIX "CALL16_RetAddr_long\n" );
1581     printf( PREFIX "CALL16_RetAddr_word:\t.long 0\n" );
1582     printf( PREFIX "CALL16_RetAddr_long:\t.long 0\n" );
1583     printf( "\t.text\n" );
1584 }
1585
1586
1587 static void usage(void)
1588 {
1589     fprintf(stderr, "usage: build -spec SPECNAMES\n"
1590                     "       build -call32 FUNCTION_PROFILES\n"
1591                     "       build -call16 FUNCTION_PROFILES\n" );
1592     exit(1);
1593 }
1594
1595
1596 int main(int argc, char **argv)
1597 {
1598     int i;
1599
1600     if (argc <= 2) usage();
1601
1602     if (!strcmp( argv[1], "-spec16" ))
1603     {
1604         for (i = 2; i < argc; i++) BuildSpec16Files( argv[i] );
1605     }
1606     else if (!strcmp( argv[1], "-spec32" ))
1607     {
1608         for (i = 2; i < argc; i++) BuildSpec32Files( argv[i] );
1609     }
1610     else if (!strcmp( argv[1], "-call32" ))  /* 32-bit callbacks */
1611     {
1612         /* File header */
1613
1614         printf( "/* File generated automatically. Do no edit! */\n\n" );
1615         printf( "\t.text\n" );
1616
1617         /* Build the 32-bit large stack callback */
1618
1619         BuildCall32LargeStack();
1620
1621         /* Build the callback functions */
1622
1623         for (i = 2; i < argc; i++) BuildCall32Func( argv[i] );
1624
1625         /* Output the argument debugging strings */
1626
1627         if (debugging)
1628         {
1629             printf( "/* Argument strings */\n" );
1630             for (i = 2; i < argc; i++)
1631             {
1632                 printf( "CALL32_Str_%s:\n", argv[i] );
1633                 printf( "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
1634             }
1635         }
1636     }
1637     else if (!strcmp( argv[1], "-call16" ))  /* 16-bit callbacks */
1638     {
1639         /* File header */
1640
1641         printf( "/* File generated automatically. Do no edit! */\n\n" );
1642         printf( "\t.text\n" );
1643         printf( "\t.globl " PREFIX "CALL16_Start\n" );
1644         printf( PREFIX "CALL16_Start:\n" );
1645
1646         /* Build the callback functions */
1647
1648         for (i = 2; i < argc; i++) BuildCall16Func( argv[i] );
1649
1650         /* Output the 16-bit return code */
1651
1652         BuildRet16Func();
1653
1654         printf( "\t.globl " PREFIX "CALL16_End\n" );
1655         printf( PREFIX "CALL16_End:\n" );
1656     }
1657     else usage();
1658
1659     return 0;
1660 }