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