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