Release 951003
[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 #if defined (__ELF__) || defined (__svr4__)
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_BUILTIN | 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 \"windows.h\"\n");
722     printf( "#include \"dlls.h\"\n");
723     printf( "#include \"pe_image.h\"\n");
724     printf( "#include \"winerror.h\"\n");
725     printf( "#include \"relay32.h\"\n");
726     printf( "#include \"stddebug.h\"\n");
727     printf( "#include \"debug.h\"\n");
728
729     odp = OrdinalDefinitions;
730     for (i = 0; i <= Limit; i++, odp++)
731     {
732         int argno,argc;
733         fdp = odp->additional_data;
734         rdp = odp->additional_data;
735
736         switch (odp->type)
737         {
738         case TYPE_INVALID:
739         case TYPE_STUB:
740             printf( "int %s_%d()\n{\n\t", UpperDLLName, i);
741             printf( "RELAY32_Unimplemented(\"%s\",%d);\n", UpperDLLName, i);
742             printf( "\t/*NOTREACHED*/\n\treturn 0;\n}\n\n");
743             break;
744         case TYPE_STDCALL:
745             argc=strlen(fdp->arg_types);
746             printf( "void %s_%d(", UpperDLLName, i);
747             for(argno=0;argno<argc;argno++)
748             {
749                 switch(fdp->arg_types[argno])
750                 {
751                 case 'p': printf( "void *");break;
752                 case 'l': printf( "int ");break;
753                 default:
754                     fprintf(stderr, "Not supported argument type %c\n",
755                             fdp->arg_types[argno]);
756                     exit(1);
757                 }
758                 putchar( 'a'+argno );
759                 if (argno!=argc-1) putchar( ',' );
760             }
761             printf( ")\n{\n" );
762             printf( "\tdprintf_relay(stddeb,\"Call %%s.%%s(");
763             for (argno=0;argno<argc;argno++)
764             {
765                 putchar( '%' );
766                 putchar( (fdp->arg_types[argno] == 'p') ? 'p' : 'x' );
767                 if (argno < argc-1) putchar( ',' );
768             }
769             printf( ")\\n\", \"%s\", \"%s\"", UpperDLLName, odp->export_name);
770             for(argno=0;argno<argc;argno++) printf( ",%c", 'a'+argno);
771             printf( ");\n\t%s(", fdp->internal_name );
772             for(argno=0;argno<argc;argno++)
773             {
774                 putchar('a'+argno);
775                 if (argno!=argc-1) putchar(',');
776             }
777             printf( ");\n\t__asm__ __volatile__(\"movl %%ebp,%%esp;"
778                     "popl %%ebp;ret $%d\");\n}\n\n",
779                     4*argc);
780             break;
781         case TYPE_RETURN:
782             printf( "void %s_%d()\n{\n\t", UpperDLLName, i);
783             printf( "RELAY32_DebugEnter(\"%s\",\"%s\");\n\t",
784                    UpperDLLName, odp->export_name);
785             printf( "WIN32_LastError=ERROR_CALL_NOT_IMPLEMENTED;\n");
786             printf( "\t__asm__ __volatile__ (\"movl %d,%%eax\");\n", 
787                    rdp->ret_value);
788             printf( "\t__asm__ __volatile__ (\"movl %%ebp,%%esp;popl %%ebp;"
789                     "ret $%d\");\n}\n\n", rdp->arg_size);
790             break;
791         default:
792             fprintf(stderr,"build: function type %d not available for Win32\n",
793                     odp->type);
794             break;
795         }
796     }
797
798     printf( "static WIN32_function functions[%d+1]={\n", Limit);
799
800     odp = OrdinalDefinitions;
801     for (i = 0; i <= Limit; i++, odp++)
802     {
803         fdp = odp->additional_data;
804         rdp = odp->additional_data;
805
806         switch (odp->type)
807         {
808         case TYPE_INVALID:
809             printf( "{0,%s_%d},\n",UpperDLLName, i);
810             break;
811         case TYPE_RETURN:
812         case TYPE_STDCALL:
813         case TYPE_STUB:
814             printf( "{\"%s\",%s_%d},\n", odp->export_name, UpperDLLName, i);
815             break;
816         default:
817             fprintf(stderr, "build: implementation error: missing %d\n",
818                     odp->type);
819             exit(1);
820         }
821     }
822     printf("};\n\n");
823
824     printf( "static WIN32_builtin dll={\"%s\",functions,%d,0};\n",
825             UpperDLLName, Limit+1);
826
827     printf( "void %s_Init(void)\n{\n",UpperDLLName);
828     printf( "\tdll.next=WIN32_builtin_list;\n");
829     printf( "\tWIN32_builtin_list=&dll;\n}");
830 }
831
832
833 static void BuildSpec16Files( char *specname )
834 {
835     ORDDEF *odp;
836     ORDFUNCDEF *fdp;
837     ORDRETDEF *rdp;
838     int i;
839     int code_offset, data_offset;
840
841     SpecFp = fopen( specname, "r");
842     if (SpecFp == NULL)
843     {
844         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
845         exit(1);
846     }
847
848     ParseTopLevel();
849
850     printf( "/* File generated automatically; do not edit! */\n" );
851     printf( "\t.data\n" );
852     printf( "\t.globl " PREFIX "%s_Data_Start\n", UpperDLLName );
853     printf( PREFIX "%s_Data_Start:\n", UpperDLLName );
854 #ifdef __svr4__
855     printf( "\t.4byte 0,0,0,0,0,0,0,0\n" );
856 #else
857     printf( "\t.word 0,0,0,0,0,0,0,0\n" );
858 #endif
859     data_offset = 16;
860     printf( "\t.text\n" );
861     printf( "\t.globl " PREFIX "%s_Code_Start\n", UpperDLLName );
862     printf( PREFIX "%s_Code_Start:\n", UpperDLLName );
863     code_offset = 0;
864
865     odp = OrdinalDefinitions;
866     for (i = 0; i <= Limit; i++, odp++)
867     {
868         fdp = odp->additional_data;
869         rdp = odp->additional_data;
870             
871         switch (odp->type)
872         {
873           case TYPE_INVALID:
874             odp->offset = 0xffff;
875             break;
876
877           case TYPE_ABS:
878             odp->offset = (int)odp->additional_data & 0xffff;
879             break;
880
881           case TYPE_BYTE:
882             printf( "/* %s.%d */\n", UpperDLLName, i);
883             odp->offset = data_offset;
884             data_offset += OutputVariableCode( ".byte", odp);
885             break;
886
887           case TYPE_WORD:
888             printf( "/* %s.%d */\n", UpperDLLName, i);
889             odp->offset = data_offset;
890 #ifdef __svr4__
891             data_offset += 2 * OutputVariableCode( ".4byte", odp);
892 #else
893             data_offset += 2 * OutputVariableCode( ".word", odp);
894 #endif
895             break;
896
897           case TYPE_LONG:
898             printf( "/* %s.%d */\n", UpperDLLName, i);
899             odp->offset = data_offset;
900             data_offset += 4 * OutputVariableCode( ".long", odp);
901             break;
902
903           case TYPE_RETURN:
904             printf( "/* %s.%d */\n", UpperDLLName, i);
905             printf( "\tmovw $%d,%%ax\n", rdp->ret_value & 0xffff );
906             printf( "\tmovw $%d,%%dx\n", (rdp->ret_value >> 16) & 0xffff);
907             printf( "\t.byte 0x66\n");
908             if (rdp->arg_size != 0)
909                 printf( "\tlret $%d\n", rdp->arg_size);
910             else
911                 printf( "\tlret\n");
912             odp->offset = code_offset;
913             code_offset += 10;  /* Assembly code is 10 bytes long */
914             if (rdp->arg_size != 0) code_offset += 2;
915             break;
916
917           case TYPE_REGISTER:
918           case TYPE_PASCAL:
919           case TYPE_PASCAL_16:
920           case TYPE_STUB:
921             printf( "/* %s.%d */\n", UpperDLLName, i);
922             printf( "\tpushw %%bp\n" );
923             printf( "\tpushl $0x%08x\n", (DLLId << 16) | i);
924             printf( "\tpushl $" PREFIX "%s\n", fdp->internal_name );
925             printf( "\tljmp $0x%04x, $" PREFIX "CallTo32_%s_%s\n\n",
926                     WINE_CODE_SELECTOR,
927                     (odp->type == TYPE_REGISTER) ? "regs" :
928                     (odp->type == TYPE_PASCAL) ? "long" : "word",
929                     fdp->arg_types );
930             printf( "\tnop\n" );
931             printf( "\tnop\n" );
932             printf( "\tnop\n" );
933             printf( "\tnop\n" );
934             printf( "\tnop\n" );
935             odp->offset = code_offset;
936             code_offset += 24;  /* Assembly code is 24 bytes long */
937             break;
938                 
939           default:
940             fprintf( stderr, "build: Unknown function type; please report.\n");
941             break;
942         }
943     }
944
945     if (!code_offset)  /* Make sure the code segment is not empty */
946     {
947         printf( "\t.byte 0\n" );
948         code_offset++;
949     }
950
951     BuildModule( code_offset, data_offset );
952 }
953
954
955 /*******************************************************************
956  *         BuildCall32LargeStack
957  *
958  * Build the function used to switch to the original 32-bit stack
959  * before calling a 32-bit function from 32-bit code. This is used for
960  * functions that need a large stack, like X bitmaps functions.
961  *
962  * The generated function has the following prototype:
963  *   int CallTo32_LargeStack( int (*func)(), int nbargs, ... )
964  *
965  * Stack layout:
966  *   ...     ...
967  * (ebp+20)  arg2
968  * (ebp+16)  arg1
969  * (ebp+12)  nbargs
970  * (ebp+8)   func
971  * (ebp+4)   ret addr
972  * (ebp)     ebp
973  */
974 static void BuildCall32LargeStack(void)
975 {
976     /* Function header */
977
978     printf( "/**********\n" );
979     printf( " * " PREFIX "CallTo32_LargeStack\n" );
980     printf( " **********/\n" );
981     printf( "\t.align 4\n" );
982     printf( "\t.globl " PREFIX "CallTo32_LargeStack\n\n" );
983     printf( PREFIX "CallTo32_LargeStack:\n" );
984     
985     /* Entry code */
986
987     printf( "\tpushl %%ebp\n" );
988     printf( "\tmovl %%esp,%%ebp\n" );
989
990     /* Save registers */
991
992     printf( "\tpushl %%ecx\n" );
993     printf( "\tpushl %%esi\n" );
994     printf( "\tpushl %%edi\n" );
995
996     /* Retrieve the original 32-bit stack pointer and switch to it if any */
997
998     printf( "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
999     printf( "\torl %%eax,%%eax\n" );
1000     printf( "\tje 0f\n" );
1001     printf( "\tmovl %%eax,%%esp\n" );
1002     printf( "0:\n" );
1003
1004     /* Transfer the arguments */
1005
1006     printf( "\tmovl 12(%%ebp),%%ecx\n" );
1007     printf( "\torl %%ecx,%%ecx\n" );
1008     printf( "\tje 1f\n" );
1009     printf( "\tleal 16(%%ebp),%%esi\n" );
1010     printf( "\tshll $2,%%ecx\n" );
1011     printf( "\tsubl %%ecx,%%esp\n" );
1012     printf( "\tmovl %%esp,%%edi\n" );
1013     printf( "\tshrl $2,%%ecx\n" );
1014     printf( "\tcld\n" );
1015     printf( "\trep; movsl\n" );
1016     printf( "1:\n" );
1017
1018     /* Call the function */
1019
1020     printf( "\tcall 8(%%ebp)\n" );
1021
1022     /* Switch back to the normal stack */
1023
1024     printf( "\tleal -12(%%ebp),%%esp\n" );
1025
1026     /* Restore registers and return */
1027
1028     printf( "\tpopl %%edi\n" );
1029     printf( "\tpopl %%esi\n" );
1030     printf( "\tpopl %%ecx\n" );
1031     printf( "\tpopl %%ebp\n" );
1032     printf( "\tret\n" );
1033 }
1034
1035
1036 /*******************************************************************
1037  *         TransferArgs16To32
1038  *
1039  * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1040  * The 16-bit stack layout is:
1041  *   ...     ...
1042  *  (bp+8)    arg2
1043  *  (bp+6)    arg1
1044  *  (bp+4)    cs
1045  *  (bp+2)    ip
1046  *  (bp)      bp
1047  */
1048 static int TransferArgs16To32( char *args )
1049 {
1050     int i, pos16, pos32;
1051
1052     /* Save ebx first */
1053
1054     printf( "\tpushl %%ebx\n" );
1055
1056     /* Get the 32-bit stack pointer */
1057
1058     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1059
1060     /* Copy the arguments */
1061
1062     pos16 = 6;  /* skip bp and return address */
1063     pos32 = 0;
1064
1065     for (i = strlen(args); i > 0; i--)
1066     {
1067         pos32 -= 4;
1068         switch(args[i-1])
1069         {
1070         case 'w':  /* word */
1071             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1072             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1073             pos16 += 2;
1074             break;
1075
1076         case 's':  /* s_word */
1077             printf( "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1078             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1079             pos16 += 2;
1080             break;
1081
1082         case 'l':  /* long */
1083             printf( "\tmovl %d(%%ebp),%%eax\n", pos16 );
1084             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1085             pos16 += 4;
1086             break;
1087
1088         case 'p':  /* ptr */
1089             /* Get the selector */
1090             printf( "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1091             /* Get the selector base */
1092             printf( "\tandl $0xfff8,%%eax\n" );
1093             printf( "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1094             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1095             /* Add the offset */
1096             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1097             printf( "\taddl %%eax,%d(%%ebx)\n", pos32 );
1098             pos16 += 4;
1099             break;
1100
1101         default:
1102             fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1103         }
1104     }
1105
1106     /* Restore ebx */
1107     
1108     printf( "\tpopl %%ebx\n" );
1109
1110     return pos16 - 6;  /* Return the size of the 16-bit args */
1111 }
1112
1113
1114 /*******************************************************************
1115  *         BuildContext
1116  *
1117  * Build the context structure on the 32-bit stack.
1118  * The only valid registers in the context structure are:
1119  *   eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
1120  */
1121 static void BuildContext(void)
1122 {
1123     /* Save ebx first */
1124
1125     printf( "\tpushl %%ebx\n" );
1126
1127     /* Get the 32-bit stack pointer */
1128
1129     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1130
1131     /* Store the registers */
1132
1133     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_ebx) ); /* Get ebx from stack */
1134     printf( "\tmovl %%eax,%d(%%ebx)\n", CONTEXTOFFSET(sc_eax) );
1135     printf( "\tmovl %%ecx,%d(%%ebx)\n", CONTEXTOFFSET(sc_ecx) );
1136     printf( "\tmovl %%edx,%d(%%ebx)\n", CONTEXTOFFSET(sc_edx) );
1137     printf( "\tmovl %%esi,%d(%%ebx)\n", CONTEXTOFFSET(sc_esi) );
1138     printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(sc_edi) );
1139     printf( "\tmovw -10(%%ebp),%%ax\n" );  /* Get saved ds from stack */
1140     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(sc_ds) );
1141     printf( "\tmovw -12(%%ebp),%%ax\n" );  /* Get saved es from stack */
1142     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(sc_es) );
1143     printf( "\tpushfl\n" );
1144 #ifndef __FreeBSD__
1145     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
1146 #else    
1147     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
1148 #endif
1149 }
1150
1151
1152 /*******************************************************************
1153  *         RestoreContext
1154  *
1155  * Restore the registers from the context structure
1156  */
1157 static void RestoreContext(void)
1158 {
1159     /* Get the 32-bit stack pointer */
1160
1161     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1162
1163     /* Restore the registers */
1164
1165     printf( "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(sc_ecx) );
1166     printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(sc_edx) );
1167     printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(sc_esi) );
1168     printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(sc_edi) );
1169     printf( "\tpopl %%eax\n" );  /* Remove old ds and es from stack */
1170     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_ds) ); /* Push new ds */
1171     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_es) ); /* Push new es */
1172 #ifndef __FreeBSD__
1173     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
1174 #else    
1175     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
1176 #endif
1177     printf( "\tpopfl\n" );
1178     printf( "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(sc_eax) );
1179     printf( "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(sc_ebx) );
1180 }
1181
1182
1183 /*******************************************************************
1184  *         BuildCall32Func
1185  *
1186  * Build a 32-bit callback function. The syntax of the function
1187  * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1188  * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1189  * 'l'=long, 'p'=pointer).
1190  * For register functions, the arguments are ignored, but they are still
1191  * removed from the stack upon return.
1192  *
1193  * Stack layout upon entry to the callback function:
1194  *  ...      ...
1195  * (sp+14)  first 16-bit arg
1196  * (sp+12)  cs (word)
1197  * (sp+10)  ip (word)
1198  * (sp+8)   bp (word)
1199  * (sp+4)   dll_id+ordinal (long)
1200  * (sp)     entrypoint (long)
1201  *
1202  */
1203 static void BuildCall32Func( char *profile )
1204 {
1205     int argsize = 0;
1206     int short_ret = 0;
1207     int reg_func = 0;
1208     char *args = profile + 5;
1209
1210     /* Parse function type */
1211
1212     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1213     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1214     else if (strncmp( "long_", profile, 5 ))
1215     {
1216         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1217         return;
1218     }
1219
1220     /* Function header */
1221
1222     printf( "/**********\n" );
1223     printf( " * " PREFIX "CallTo32_%s\n", profile );
1224     printf( " **********/\n" );
1225     printf( "\t.align 4\n" );
1226     printf( "\t.globl " PREFIX "CallTo32_%s\n\n", profile );
1227     printf( PREFIX "CallTo32_%s:\n", profile );
1228
1229     /* Setup bp to point to its copy on the stack */
1230
1231     printf( "\tmovzwl %%sp,%%ebp\n" );
1232     printf( "\taddw $8,%%bp\n" );
1233
1234     /* Save 16-bit ds and es */
1235
1236     printf( "\tpushw %%ds\n" );
1237     printf( "\tpushw %%es\n" );
1238
1239     /* Restore 32-bit ds and es */
1240
1241     printf( "\tpushl $0x%04x%04x\n", WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1242     printf( "\tpopw %%ds\n" );
1243     printf( "\tpopw %%es\n" );
1244
1245
1246     /* Save the 16-bit stack */
1247
1248     printf( "\tpushw " PREFIX "IF1632_Saved16_sp\n" );
1249     printf( "\tpushw " PREFIX "IF1632_Saved16_ss\n" );
1250     printf( "\tmovw %%ss," PREFIX "IF1632_Saved16_ss\n" );
1251     printf( "\tmovw %%sp," PREFIX "IF1632_Saved16_sp\n" );
1252
1253     /* Transfer the arguments */
1254
1255     if (reg_func) BuildContext();
1256     else if (*args) argsize = TransferArgs16To32( args );
1257
1258     /* Get the address of the API function */
1259
1260     printf( "\tmovl -8(%%ebp),%%eax\n" );
1261
1262     /* If necessary, save %edx over the API function address */
1263
1264     if (!reg_func && short_ret)
1265         printf( "\tmovl %%edx,-8(%%ebp)\n" );
1266
1267     /* Switch to the 32-bit stack */
1268
1269     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebp\n" );
1270     printf( "\tpushw %%ds\n" );
1271     printf( "\tpopw %%ss\n" );
1272     printf( "\tleal -%d(%%ebp),%%esp\n",
1273             reg_func ? sizeof(struct sigcontext_struct) : 4 * strlen(args) );
1274
1275     /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1276
1277     printf( "\taddl $24,%%ebp\n" );
1278
1279     /* Print the debug information before the call */
1280
1281     if (debugging)
1282     {
1283         printf( "\tpushl %%eax\n" );
1284         printf( "\tpushl $CALL32_Str_%s\n", profile );
1285         printf( "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0) );
1286         printf( "\tcall " PREFIX "RELAY_DebugCall32\n" );
1287         printf( "\tpopl %%eax\n" );
1288         printf( "\tpopl %%eax\n" );
1289         printf( "\tpopl %%eax\n" );
1290     }
1291
1292     /* Call the entry point */
1293
1294     printf( "\tcall %%eax\n" );
1295
1296     /* Print the debug information after the call */
1297
1298     if (debugging)
1299     {
1300         printf( "\tpushl %%eax\n" );
1301         printf( "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0) );
1302         printf( "\tcall " PREFIX "RELAY_DebugReturn\n" );
1303         printf( "\tpopl %%eax\n" );
1304         printf( "\tpopl %%eax\n" );
1305     }
1306
1307     /* Restore the 16-bit stack */
1308
1309     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1310     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1311     printf( "\tpopw " PREFIX "IF1632_Saved16_ss\n" );
1312     printf( "\tpopw " PREFIX "IF1632_Saved16_sp\n" );
1313
1314     if (reg_func)
1315     {
1316         /* Restore registers from the context structure */
1317         RestoreContext();
1318         
1319         /* Calc the arguments size */
1320         while (*args)
1321         {
1322             switch(*args)
1323             {
1324             case 'w':
1325             case 's':
1326                 argsize += 2;
1327                 break;
1328             case 'p':
1329             case 'l':
1330                 argsize += 4;
1331                 break;
1332             default:
1333                 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1334             }
1335             args++;
1336         }
1337     }
1338
1339     /* Restore ds and es */
1340
1341     printf( "\tpopw %%es\n" );
1342     printf( "\tpopw %%ds\n" );
1343
1344     /* Get the return value into dx:ax and clean up the stack */
1345
1346     if (!reg_func)
1347     {
1348         if (short_ret)
1349         {
1350             printf( "\tpopl %%edx\n" );     /* Restore %edx */
1351             printf( "\taddl $4,%%esp\n" );  /* Remove DLL id and ordinal */
1352         }
1353         else
1354         {
1355             printf( "\tpushl %%eax\n" );
1356             printf( "\tpopw %%ax\n" );
1357             printf( "\tpopw %%dx\n" );
1358             /* Remove API entry point, DLL id and ordinal from the stack */
1359             printf( "\taddl $8,%%esp\n" );
1360         }
1361     }
1362     else
1363     {
1364         /* Remove API entry point, DLL id and ordinal from the stack, */
1365         /* but take care not to change the value of the carry flag.   */
1366
1367         printf( "\tpopl %%ebp\n" );
1368         printf( "\tpopl %%ebp\n" );
1369     }
1370
1371     /* Restore bp */
1372
1373     printf( "\tpopw %%bp\n" );
1374
1375     /* Remove the arguments and return */
1376
1377     if (argsize)
1378     {
1379         printf( "\t.byte 0x66\n" );
1380         printf( "\tlret $%d\n", argsize );
1381     }
1382     else
1383     {
1384         printf( "\t.byte 0x66\n" );
1385         printf( "\tlret\n" );
1386     }
1387 }
1388
1389
1390 /*******************************************************************
1391  *         BuildCall16Func
1392  *
1393  * Build a 16-bit callback function.
1394  *
1395  * Stack frame of the callback function:
1396  *  ...      ...
1397  * (ebp+24) arg2
1398  * (ebp+20) arg1
1399  * (ebp+16) 16-bit ds
1400  * (ebp+12) func to call
1401  * (ebp+8)  code selector
1402  * (ebp+4)  return address
1403  * (ebp)    previous ebp
1404  *
1405  * Prototypes for the CallTo16 functions:
1406  *   extern WORD CallTo16_word_xxx( FARPROC func, WORD ds, args... );
1407  *   extern LONG CallTo16_long_xxx( FARPROC func, WORD ds, args... );
1408  *   extern void CallTo16_regs_( FARPROC func, WORD ds, WORD es, WORD bp,
1409  *                               WORD ax, WORD bx, WORD cx, WORD dx,
1410  *                               WORD si, WORD di );
1411  */
1412 static void BuildCall16Func( char *profile )
1413 {
1414     int short_ret = 0;
1415     int reg_func = 0;
1416     char *args = profile + 5;
1417
1418     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1419     else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1420     else if (strncmp( "long_", profile, 5 ))
1421     {
1422         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1423         return;
1424     }
1425
1426     /* Function header */
1427
1428     printf( "/**********\n" );
1429     printf( " * " PREFIX "CallTo16_%s\n", profile );
1430     printf( " **********/\n" );
1431     printf( "\t.align 4\n" );
1432     printf( "\t.globl " PREFIX "CallTo16_%s\n\n", profile );
1433     printf( PREFIX "CallTo16_%s:\n", profile );
1434
1435     /* Push code selector before return address to simulate a lcall */
1436
1437     printf( "\tpopl %%eax\n" );
1438     printf( "\tpushl $0x%04x\n", WINE_CODE_SELECTOR );
1439     printf( "\tpushl %%eax\n" );
1440
1441     /* Entry code */
1442
1443     printf( "\tpushl %%ebp\n" );
1444     printf( "\tmovl %%esp,%%ebp\n" );
1445
1446     /* Save the 32-bit registers */
1447
1448     printf( "\tpushl %%ebx\n" );
1449     printf( "\tpushl %%ecx\n" );
1450     printf( "\tpushl %%edx\n" );
1451     printf( "\tpushl %%esi\n" );
1452     printf( "\tpushl %%edi\n" );
1453
1454     /* Save the 32-bit stack */
1455
1456     printf( "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1457     printf( "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1458     printf( "\tmovl %%ebp,%%ebx\n" );
1459
1460     /* Print debugging info */
1461
1462     if (debugging)
1463     {
1464         /* Push the address of the first argument */
1465         printf( "\tmovl %%ebx,%%eax\n" );
1466         printf( "\taddl $12,%%eax\n" );
1467         printf( "\tpushl $%d\n", reg_func ? 8 : strlen(args) );
1468         printf( "\tpushl %%eax\n" );
1469         printf( "\tcall " PREFIX "RELAY_DebugCall16\n" );
1470         printf( "\tpopl %%eax\n" );
1471         printf( "\tpopl %%eax\n" );
1472     }
1473
1474     /* Switch to the 16-bit stack */
1475
1476     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1477     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1478
1479     /* Transfer the arguments */
1480
1481     if (reg_func)
1482     {
1483         /* Get the registers. ebx is handled later on. */
1484         printf( "\tpushw 20(%%ebx)\n" );
1485         printf( "\tpopw %%es\n" );
1486         printf( "\tmovl 24(%%ebx),%%ebp\n" );
1487         printf( "\tmovl 28(%%ebx),%%eax\n" );
1488         printf( "\tmovl 36(%%ebx),%%ecx\n" );
1489         printf( "\tmovl 40(%%ebx),%%edx\n" );
1490         printf( "\tmovl 44(%%ebx),%%esi\n" );
1491         printf( "\tmovl 48(%%ebx),%%edi\n" );
1492     }
1493     else  /* not a register function */
1494     {
1495         int pos = 20;  /* first argument position */
1496
1497         /* Make %bp point to the previous stackframe (built by CallTo32) */
1498         printf( "\tmovw %%sp,%%bp\n" );
1499         printf( "\taddw $16,%%bp\n" );
1500
1501         while (*args)
1502         {
1503             switch(*args++)
1504             {
1505             case 'w': /* word */
1506                 printf( "\tpushw %d(%%ebx)\n", pos );
1507                 break;
1508             case 'l': /* long */
1509                 printf( "\tpushl %d(%%ebx)\n", pos );
1510                 break;
1511             }
1512             pos += 4;
1513         }
1514     }
1515
1516     /* Push the return address */
1517
1518     printf( "\tpushl " PREFIX "CALL16_RetAddr_%s\n",
1519             short_ret ? "word" : "long" );
1520
1521     /* Push the called routine address */
1522
1523     printf( "\tpushl 12(%%ebx)\n" );
1524
1525     /* Get the 16-bit ds */
1526
1527     if (reg_func)
1528     {
1529         printf( "\tpushw 16(%%ebx)\n" );
1530         printf( "\tmovl 32(%%ebx),%%ebx\n" ); /*Get ebx from the 32-bit stack*/
1531         printf( "\tpopw %%ds\n" );
1532     }
1533     else
1534     {
1535         /* Set ax equal to ds for window procedures */
1536         printf( "\tmovw 16(%%ebx),%%ax\n" );
1537         printf( "\tmovw %%ax,%%ds\n" );
1538     }
1539
1540     /* Jump to the called routine */
1541
1542     printf( "\t.byte 0x66\n" );
1543     printf( "\tlret\n" );
1544 }
1545
1546
1547 /*******************************************************************
1548  *         BuildRet16Func
1549  *
1550  * Build the return code for 16-bit callbacks
1551  */
1552 static void BuildRet16Func()
1553 {
1554     printf( "\t.globl " PREFIX "CALL16_Ret_word\n" );
1555     printf( "\t.globl " PREFIX "CALL16_Ret_long\n" );
1556
1557     /* Put return value into eax */
1558
1559     printf( PREFIX "CALL16_Ret_long:\n" );
1560     printf( "\tpushw %%dx\n" );
1561     printf( "\tpushw %%ax\n" );
1562     printf( "\tpopl %%eax\n" );
1563     printf( PREFIX "CALL16_Ret_word:\n" );
1564
1565     /* Restore 32-bit segment registers */
1566
1567     printf( "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1568     printf( "\tmovw %%bx,%%ds\n" );
1569     printf( "\tmovw %%bx,%%es\n" );
1570     printf( "\tmovw %%bx,%%ss\n" );
1571
1572     /* Restore the 32-bit stack */
1573
1574     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1575     printf( "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
1576
1577     /* Restore the 32-bit registers */
1578
1579     printf( "\tpopl %%edi\n" );
1580     printf( "\tpopl %%esi\n" );
1581     printf( "\tpopl %%edx\n" );
1582     printf( "\tpopl %%ecx\n" );
1583     printf( "\tpopl %%ebx\n" );
1584
1585     /* Return to caller */
1586
1587     printf( "\tpopl %%ebp\n" );
1588     printf( "\tlret\n" );
1589
1590     /* Declare the return address variables */
1591
1592     printf( "\t.data\n" );
1593     printf( "\t.globl " PREFIX "CALL16_RetAddr_word\n" );
1594     printf( "\t.globl " PREFIX "CALL16_RetAddr_long\n" );
1595     printf( PREFIX "CALL16_RetAddr_word:\t.long 0\n" );
1596     printf( PREFIX "CALL16_RetAddr_long:\t.long 0\n" );
1597     printf( "\t.text\n" );
1598 }
1599
1600
1601 static void usage(void)
1602 {
1603     fprintf(stderr, "usage: build -spec SPECNAMES\n"
1604                     "       build -call32 FUNCTION_PROFILES\n"
1605                     "       build -call16 FUNCTION_PROFILES\n" );
1606     exit(1);
1607 }
1608
1609
1610 int main(int argc, char **argv)
1611 {
1612     int i;
1613
1614     if (argc <= 2) usage();
1615
1616     if (!strcmp( argv[1], "-spec16" ))
1617     {
1618         for (i = 2; i < argc; i++) BuildSpec16Files( argv[i] );
1619     }
1620     else if (!strcmp( argv[1], "-spec32" ))
1621     {
1622         for (i = 2; i < argc; i++) BuildSpec32Files( argv[i] );
1623     }
1624     else if (!strcmp( argv[1], "-call32" ))  /* 32-bit callbacks */
1625     {
1626         /* File header */
1627
1628         printf( "/* File generated automatically. Do no edit! */\n\n" );
1629         printf( "\t.text\n" );
1630
1631         /* Build the 32-bit large stack callback */
1632
1633         BuildCall32LargeStack();
1634
1635         /* Build the callback functions */
1636
1637         for (i = 2; i < argc; i++) BuildCall32Func( argv[i] );
1638
1639         /* Output the argument debugging strings */
1640
1641         if (debugging)
1642         {
1643             printf( "/* Argument strings */\n" );
1644             for (i = 2; i < argc; i++)
1645             {
1646                 printf( "CALL32_Str_%s:\n", argv[i] );
1647                 printf( "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
1648             }
1649         }
1650     }
1651     else if (!strcmp( argv[1], "-call16" ))  /* 16-bit callbacks */
1652     {
1653         /* File header */
1654
1655         printf( "/* File generated automatically. Do no edit! */\n\n" );
1656         printf( "\t.text\n" );
1657         printf( "\t.globl " PREFIX "CALL16_Start\n" );
1658         printf( PREFIX "CALL16_Start:\n" );
1659
1660         /* Build the callback functions */
1661
1662         for (i = 2; i < argc; i++) BuildCall16Func( argv[i] );
1663
1664         /* Output the 16-bit return code */
1665
1666         BuildRet16Func();
1667
1668         printf( "\t.globl " PREFIX "CALL16_End\n" );
1669         printf( PREFIX "CALL16_End:\n" );
1670     }
1671     else usage();
1672
1673     return 0;
1674 }