- Minor API files fixes
[wine] / tools / build.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Martin von Loewis
4  * Copyright 1995, 1996, 1997 Alexandre Julliard
5  * Copyright 1997 Eric Youngdale
6  * Copyright 1999 Ulrich Weigand
7  */
8
9 #include "config.h"
10
11 #include <assert.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <unistd.h>
18
19 #include "winbase.h"
20 #include "winnt.h"
21 #include "module.h"
22 #include "neexe.h"
23 #include "stackframe.h"
24 #include "builtin16.h"
25 #include "thread.h"
26
27 #ifdef NEED_UNDERSCORE_PREFIX
28 # define PREFIX "_"
29 #else
30 # define PREFIX
31 #endif
32
33 #ifdef HAVE_ASM_STRING
34 # define STRING ".string"
35 #else
36 # define STRING ".ascii"
37 #endif
38
39 #if defined(__GNUC__) && !defined(__svr4__)
40 # define USE_STABS
41 #else
42 # undef USE_STABS
43 #endif
44
45 #ifdef __i386__
46 extern WORD __get_cs(void);
47 extern WORD __get_ds(void);
48 __ASM_GLOBAL_FUNC( __get_cs, "movw %cs,%ax\n\tret" );
49 __ASM_GLOBAL_FUNC( __get_ds, "movw %ds,%ax\n\tret" );
50 #else
51 static inline WORD __get_cs(void) { return 0; }
52 static inline WORD __get_ds(void) { return 0; }
53 #endif
54
55 typedef enum
56 {
57     TYPE_BYTE,         /* byte variable (Win16) */
58     TYPE_WORD,         /* word variable (Win16) */
59     TYPE_LONG,         /* long variable (Win16) */
60     TYPE_PASCAL_16,    /* pascal function with 16-bit return (Win16) */
61     TYPE_PASCAL,       /* pascal function with 32-bit return (Win16) */
62     TYPE_ABS,          /* absolute value (Win16) */
63     TYPE_REGISTER,     /* register function */
64     TYPE_INTERRUPT,    /* interrupt handler function (Win16) */
65     TYPE_STUB,         /* unimplemented stub */
66     TYPE_STDCALL,      /* stdcall function (Win32) */
67     TYPE_CDECL,        /* cdecl function (Win32) */
68     TYPE_VARARGS,      /* varargs function (Win32) */
69     TYPE_EXTERN,       /* external symbol (Win32) */
70     TYPE_FORWARD,      /* forwarded function (Win32) */
71     TYPE_NBTYPES
72 } ORD_TYPE;
73
74 static const char * const TypeNames[TYPE_NBTYPES] =
75 {
76     "byte",         /* TYPE_BYTE */
77     "word",         /* TYPE_WORD */
78     "long",         /* TYPE_LONG */
79     "pascal16",     /* TYPE_PASCAL_16 */
80     "pascal",       /* TYPE_PASCAL */
81     "equate",       /* TYPE_ABS */
82     "register",     /* TYPE_REGISTER */
83     "interrupt",    /* TYPE_INTERRUPT */
84     "stub",         /* TYPE_STUB */
85     "stdcall",      /* TYPE_STDCALL */
86     "cdecl",        /* TYPE_CDECL */
87     "varargs",      /* TYPE_VARARGS */
88     "extern",       /* TYPE_EXTERN */
89     "forward"       /* TYPE_FORWARD */
90 };
91
92 #define MAX_ORDINALS    2048
93 #define MAX_IMPORTS       16
94
95   /* Callback function used for stub functions */
96 #define STUB_CALLBACK \
97   ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
98
99 typedef enum
100 {
101     SPEC_INVALID,
102     SPEC_WIN16,
103     SPEC_WIN32
104 } SPEC_TYPE;
105
106 typedef enum
107 {
108     SPEC_MODE_DLL,
109     SPEC_MODE_GUIEXE,
110     SPEC_MODE_CUIEXE
111 } SPEC_MODE;
112
113 typedef struct
114 {
115     int n_values;
116     int *values;
117 } ORD_VARIABLE;
118
119 typedef struct
120 {
121     int  n_args;
122     char arg_types[32];
123     char link_name[80];
124 } ORD_FUNCTION;
125
126 typedef struct
127 {
128     int value;
129 } ORD_ABS;
130
131 typedef struct
132 {
133     char link_name[80];
134 } ORD_EXTERN;
135
136 typedef struct
137 {
138     char link_name[80];
139 } ORD_FORWARD;
140
141 typedef struct
142 {
143     ORD_TYPE    type;
144     int         ordinal;
145     int         offset;
146     int         lineno;
147     char        name[80];
148     union
149     {
150         ORD_VARIABLE   var;
151         ORD_FUNCTION   func;
152         ORD_ABS        abs;
153         ORD_EXTERN     ext;
154         ORD_FORWARD    fwd;
155     } u;
156 } ORDDEF;
157
158 static ORDDEF EntryPoints[MAX_ORDINALS];
159 static ORDDEF *Ordinals[MAX_ORDINALS];
160 static ORDDEF *Names[MAX_ORDINALS];
161
162 static SPEC_TYPE SpecType = SPEC_INVALID;
163 static SPEC_MODE SpecMode = SPEC_MODE_DLL;
164 static char DLLName[80];
165 static char DLLFileName[80];
166 static int Limit = 0;
167 static int Base = MAX_ORDINALS;
168 static int DLLHeapSize = 0;
169 static FILE *SpecFp;
170 static WORD Code_Selector, Data_Selector;
171 static char DLLInitFunc[80];
172 static char *DLLImports[MAX_IMPORTS];
173 static char rsrc_name[80];
174 static int nb_imports;
175 static int nb_entry_points;
176 static int nb_names;
177 static const char *input_file_name;
178 static const char *output_file_name;
179
180 char *ParseBuffer = NULL;
181 char *ParseNext;
182 char ParseSaveChar;
183 int Line;
184
185 static int UsePIC = 0;
186
187 static int debugging = 1;
188
189   /* Offset of a structure field relative to the start of the struct */
190 #define STRUCTOFFSET(type,field) ((int)&((type *)0)->field)
191
192   /* Offset of register relative to the start of the CONTEXT struct */
193 #define CONTEXTOFFSET(reg)  STRUCTOFFSET(CONTEXT86,reg)
194
195   /* Offset of register relative to the start of the STACK16FRAME struct */
196 #define STACK16OFFSET(reg)  STRUCTOFFSET(STACK16FRAME,reg)
197
198   /* Offset of register relative to the start of the STACK32FRAME struct */
199 #define STACK32OFFSET(reg)  STRUCTOFFSET(STACK32FRAME,reg)
200
201   /* Offset of the stack pointer relative to %fs:(0) */
202 #define STACKOFFSET (STRUCTOFFSET(TEB,cur_stack))
203
204 static void BuildCallFrom16Func( FILE *outfile, char *profile, char *prefix, int local );
205
206 static void *xmalloc (size_t size)
207 {
208     void *res;
209
210     res = malloc (size ? size : 1);
211     if (res == NULL)
212     {
213         fprintf (stderr, "Virtual memory exhausted.\n");
214         if (output_file_name) unlink( output_file_name );
215         exit (1);
216     }
217     return res;
218 }
219
220
221 static void *xrealloc (void *ptr, size_t size)
222 {
223     void *res = realloc (ptr, size);
224     if (res == NULL)
225     {
226         fprintf (stderr, "Virtual memory exhausted.\n");
227         if (output_file_name) unlink( output_file_name );
228         exit (1);
229     }
230     return res;
231 }
232
233 static char *xstrdup( const char *str )
234 {
235     char *res = strdup( str );
236     if (!res)
237     {
238         fprintf (stderr, "Virtual memory exhausted.\n");
239         if (output_file_name) unlink( output_file_name );
240         exit (1);
241     }
242     return res;
243 }
244
245 static void fatal_error( const char *msg, ... )
246 {
247     va_list valist;
248     va_start( valist, msg );
249     fprintf( stderr, "%s:%d: ", input_file_name, Line );
250     vfprintf( stderr, msg, valist );
251     va_end( valist );
252     if (output_file_name) unlink( output_file_name );
253     exit(1);
254 }
255
256 static int IsNumberString(char *s)
257 {
258     while (*s != '\0')
259         if (!isdigit(*s++))
260             return 0;
261
262     return 1;
263 }
264
265 static char *strupper(char *s)
266 {
267     char *p;
268     
269     for(p = s; *p != '\0'; p++)
270         *p = toupper(*p);
271
272     return s;
273 }
274
275 static char * GetTokenInLine(void)
276 {
277     char *p;
278     char *token;
279
280     if (ParseNext != ParseBuffer)
281     {
282         if (ParseSaveChar == '\0')
283             return NULL;
284         *ParseNext = ParseSaveChar;
285     }
286     
287     /*
288      * Remove initial white space.
289      */
290     for (p = ParseNext; isspace(*p); p++)
291         ;
292     
293     if ((*p == '\0') || (*p == '#'))
294         return NULL;
295     
296     /*
297      * Find end of token.
298      */
299     token = p++;
300     if (*token != '(' && *token != ')')
301         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
302             p++;
303     
304     ParseSaveChar = *p;
305     ParseNext = p;
306     *p = '\0';
307
308     return token;
309 }
310
311 static char * GetToken(void)
312 {
313     char *token;
314
315     if (ParseBuffer == NULL)
316     {
317         ParseBuffer = xmalloc(512);
318         ParseNext = ParseBuffer;
319         while (1)
320         {
321             Line++;
322             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
323                 return NULL;
324             if (ParseBuffer[0] != '#')
325                 break;
326         }
327     }
328
329     while ((token = GetTokenInLine()) == NULL)
330     {
331         ParseNext = ParseBuffer;
332         while (1)
333         {
334             Line++;
335             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
336                 return NULL;
337             if (ParseBuffer[0] != '#')
338                 break;
339         }
340     }
341
342     return token;
343 }
344
345
346 static int name_compare( const void *name1, const void *name2 )
347 {
348     ORDDEF *odp1 = *(ORDDEF **)name1;
349     ORDDEF *odp2 = *(ORDDEF **)name2;
350     return strcmp( odp1->name, odp2->name );
351 }
352
353 /*******************************************************************
354  *         AssignOrdinals
355  *
356  * Assign ordinals to all entry points.
357  */
358 static void AssignOrdinals(void)
359 {
360     int i, ordinal;
361
362     if ( !nb_names ) return;
363
364     /* sort the list of names */
365     qsort( Names, nb_names, sizeof(Names[0]), name_compare );
366
367     /* check for duplicate names */
368     for (i = 0; i < nb_names - 1; i++)
369     {
370         if (!strcmp( Names[i]->name, Names[i+1]->name ))
371         {
372             Line = max( Names[i]->lineno, Names[i+1]->lineno );
373             fatal_error( "'%s' redefined (previous definition at line %d)\n",
374                          Names[i]->name, min( Names[i]->lineno, Names[i+1]->lineno ) );
375         }
376     }
377
378     /* start assigning from Base, or from 1 if no ordinal defined yet */
379     if (Base == MAX_ORDINALS) Base = 1;
380     for (i = 0, ordinal = Base; i < nb_names; i++)
381     {
382         if (Names[i]->ordinal != -1) continue;  /* already has an ordinal */
383         while (Ordinals[ordinal]) ordinal++;
384         if (ordinal >= MAX_ORDINALS)
385         {
386             Line = Names[i]->lineno;
387             fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
388         }
389         Names[i]->ordinal = ordinal;
390         Ordinals[ordinal] = Names[i];
391     }
392     if (ordinal > Limit) Limit = ordinal;
393 }
394
395
396 /*******************************************************************
397  *         ParseVariable
398  *
399  * Parse a variable definition.
400  */
401 static void ParseVariable( ORDDEF *odp )
402 {
403     char *endptr;
404     int *value_array;
405     int n_values;
406     int value_array_size;
407     
408     char *token = GetToken();
409     if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
410
411     n_values = 0;
412     value_array_size = 25;
413     value_array = xmalloc(sizeof(*value_array) * value_array_size);
414     
415     while ((token = GetToken()) != NULL)
416     {
417         if (*token == ')')
418             break;
419
420         value_array[n_values++] = strtol(token, &endptr, 0);
421         if (n_values == value_array_size)
422         {
423             value_array_size += 25;
424             value_array = xrealloc(value_array, 
425                                    sizeof(*value_array) * value_array_size);
426         }
427         
428         if (endptr == NULL || *endptr != '\0')
429             fatal_error( "Expected number value, got '%s'\n", token );
430     }
431     
432     if (token == NULL)
433         fatal_error( "End of file in variable declaration\n" );
434
435     odp->u.var.n_values = n_values;
436     odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
437 }
438
439
440 /*******************************************************************
441  *         ParseExportFunction
442  *
443  * Parse a function definition.
444  */
445 static void ParseExportFunction( ORDDEF *odp )
446 {
447     char *token;
448     int i;
449
450     switch(SpecType)
451     {
452     case SPEC_WIN16:
453         if (odp->type == TYPE_STDCALL)
454             fatal_error( "'stdcall' not supported for Win16\n" );
455         if (odp->type == TYPE_VARARGS)
456             fatal_error( "'varargs' not supported for Win16\n" );
457         break;
458     case SPEC_WIN32:
459         if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
460             fatal_error( "'pascal' not supported for Win32\n" );
461         break;
462     default:
463         break;
464     }
465
466     token = GetToken();
467     if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
468
469     for (i = 0; i < sizeof(odp->u.func.arg_types)-1; i++)
470     {
471         token = GetToken();
472         if (*token == ')')
473             break;
474
475         if (!strcmp(token, "word"))
476             odp->u.func.arg_types[i] = 'w';
477         else if (!strcmp(token, "s_word"))
478             odp->u.func.arg_types[i] = 's';
479         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
480             odp->u.func.arg_types[i] = 'l';
481         else if (!strcmp(token, "ptr"))
482             odp->u.func.arg_types[i] = 'p';
483         else if (!strcmp(token, "str"))
484             odp->u.func.arg_types[i] = 't';
485         else if (!strcmp(token, "wstr"))
486             odp->u.func.arg_types[i] = 'W';
487         else if (!strcmp(token, "segstr"))
488             odp->u.func.arg_types[i] = 'T';
489         else if (!strcmp(token, "double"))
490         {
491             odp->u.func.arg_types[i++] = 'l';
492             odp->u.func.arg_types[i] = 'l';
493         }
494         else fatal_error( "Unknown variable type '%s'\n", token );
495
496         if (SpecType == SPEC_WIN32)
497         {
498             if (strcmp(token, "long") &&
499                 strcmp(token, "ptr") &&
500                 strcmp(token, "str") &&
501                 strcmp(token, "wstr") &&
502                 strcmp(token, "double"))
503             {
504                 fatal_error( "Type '%s' not supported for Win32\n", token );
505             }
506         }
507     }
508     if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
509         fatal_error( "Too many arguments\n" );
510
511     odp->u.func.arg_types[i] = '\0';
512     if ((odp->type == TYPE_STDCALL) && !i)
513         odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
514     strcpy(odp->u.func.link_name, GetToken());
515 }
516
517
518 /*******************************************************************
519  *         ParseEquate
520  *
521  * Parse an 'equate' definition.
522  */
523 static void ParseEquate( ORDDEF *odp )
524 {
525     char *endptr;
526     
527     char *token = GetToken();
528     int value = strtol(token, &endptr, 0);
529     if (endptr == NULL || *endptr != '\0')
530         fatal_error( "Expected number value, got '%s'\n", token );
531     if (SpecType == SPEC_WIN32)
532         fatal_error( "'equate' not supported for Win32\n" );
533     odp->u.abs.value = value;
534 }
535
536
537 /*******************************************************************
538  *         ParseStub
539  *
540  * Parse a 'stub' definition.
541  */
542 static void ParseStub( ORDDEF *odp )
543 {
544     odp->u.func.arg_types[0] = '\0';
545     strcpy( odp->u.func.link_name, STUB_CALLBACK );
546 }
547
548
549 /*******************************************************************
550  *         ParseInterrupt
551  *
552  * Parse an 'interrupt' definition.
553  */
554 static void ParseInterrupt( ORDDEF *odp )
555 {
556     char *token;
557
558     if (SpecType == SPEC_WIN32)
559         fatal_error( "'interrupt' not supported for Win32\n" );
560
561     token = GetToken();
562     if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
563
564     token = GetToken();
565     if (*token != ')') fatal_error( "Expected ')' got '%s'\n", token );
566
567     odp->u.func.arg_types[0] = '\0';
568     strcpy( odp->u.func.link_name, GetToken() );
569 }
570
571
572 /*******************************************************************
573  *         ParseExtern
574  *
575  * Parse an 'extern' definition.
576  */
577 static void ParseExtern( ORDDEF *odp )
578 {
579     if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
580     strcpy( odp->u.ext.link_name, GetToken() );
581 }
582
583
584 /*******************************************************************
585  *         ParseForward
586  *
587  * Parse a 'forward' definition.
588  */
589 static void ParseForward( ORDDEF *odp )
590 {
591     if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
592     strcpy( odp->u.fwd.link_name, GetToken() );
593 }
594
595
596 /*******************************************************************
597  *         ParseOrdinal
598  *
599  * Parse an ordinal definition.
600  */
601 static void ParseOrdinal(int ordinal)
602 {
603     char *token;
604
605     ORDDEF *odp = &EntryPoints[nb_entry_points++];
606
607     if (!(token = GetToken())) fatal_error( "Expected type after ordinal\n" );
608
609     for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
610         if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
611             break;
612
613     if (odp->type >= TYPE_NBTYPES)
614         fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
615
616     if (!(token = GetToken())) fatal_error( "Expected name after type\n" );
617
618     strcpy( odp->name, token );
619     odp->lineno = Line;
620     odp->ordinal = ordinal;
621
622     switch(odp->type)
623     {
624     case TYPE_BYTE:
625     case TYPE_WORD:
626     case TYPE_LONG:
627         ParseVariable( odp );
628         break;
629     case TYPE_REGISTER:
630         ParseExportFunction( odp );
631 #ifndef __i386__
632         /* ignore Win32 'register' routines on non-Intel archs */
633         if (SpecType == SPEC_WIN32)
634         {
635             nb_entry_points--;
636             return;
637         }
638 #endif
639         break;
640     case TYPE_PASCAL_16:
641     case TYPE_PASCAL:
642     case TYPE_STDCALL:
643     case TYPE_VARARGS:
644     case TYPE_CDECL:
645         ParseExportFunction( odp );
646         break;
647     case TYPE_INTERRUPT:
648         ParseInterrupt( odp );
649         break;
650     case TYPE_ABS:
651         ParseEquate( odp );
652         break;
653     case TYPE_STUB:
654         ParseStub( odp );
655         break;
656     case TYPE_EXTERN:
657         ParseExtern( odp );
658         break;
659     case TYPE_FORWARD:
660         ParseForward( odp );
661         break;
662     default:
663         assert( 0 );
664     }
665
666     if (ordinal != -1)
667     {
668         if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
669         if (ordinal > Limit) Limit = ordinal;
670         if (ordinal < Base) Base = ordinal;
671         odp->ordinal = ordinal;
672         Ordinals[ordinal] = odp;
673     }
674
675     if (!strcmp( odp->name, "@" ))
676     {
677         if (ordinal == -1)
678             fatal_error( "Nameless function needs an explicit ordinal number\n" );
679         if (SpecType != SPEC_WIN32)
680             fatal_error( "Nameless functions not supported for Win16\n" );
681         odp->name[0] = 0;
682     }
683     else Names[nb_names++] = odp;
684 }
685
686
687 /*******************************************************************
688  *         ParseTopLevel
689  *
690  * Parse a spec file.
691  */
692 static void ParseTopLevel(void)
693 {
694     char *token;
695     
696     while ((token = GetToken()) != NULL)
697     {
698         if (strcmp(token, "name") == 0)
699         {
700             strcpy(DLLName, GetToken());
701         }
702         else if (strcmp(token, "file") == 0)
703         {
704             strcpy(DLLFileName, GetToken());
705             strupper(DLLFileName);
706         }
707         else if (strcmp(token, "type") == 0)
708         {
709             token = GetToken();
710             if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
711             else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
712             else fatal_error( "Type must be 'win16' or 'win32'\n" );
713         }
714         else if (strcmp(token, "mode") == 0)
715         {
716             token = GetToken();
717             if (!strcmp(token, "dll" )) SpecMode = SPEC_MODE_DLL;
718             else if (!strcmp(token, "guiexe" )) SpecMode = SPEC_MODE_GUIEXE;
719             else if (!strcmp(token, "cuiexe" )) SpecMode = SPEC_MODE_CUIEXE;
720             else fatal_error( "Mode must be 'dll', 'guiexe' or 'cuiexe'\n" );
721         }
722         else if (strcmp(token, "heap") == 0)
723         {
724             token = GetToken();
725             if (!IsNumberString(token)) fatal_error( "Expected number after heap\n" );
726             DLLHeapSize = atoi(token);
727         }
728         else if (strcmp(token, "init") == 0)
729         {
730             strcpy(DLLInitFunc, GetToken());
731             if (SpecType == SPEC_WIN16)
732                 fatal_error( "init cannot be used for Win16 spec files\n" );
733             if (!DLLInitFunc[0])
734                 fatal_error( "Expected function name after init\n" );
735             if (!strcmp(DLLInitFunc, "main"))
736                 fatal_error( "The init function cannot be named 'main'\n" );
737         }
738         else if (strcmp(token, "import") == 0)
739         {
740             if (nb_imports >= MAX_IMPORTS)
741                 fatal_error( "Too many imports (limit %d)\n", MAX_IMPORTS );
742             if (SpecType != SPEC_WIN32)
743                 fatal_error( "Imports not supported for Win16\n" );
744             DLLImports[nb_imports++] = xstrdup(GetToken());
745         }
746         else if (strcmp(token, "rsrc") == 0)
747         {
748             strcpy( rsrc_name, GetToken() );
749             strcat( rsrc_name, "_ResourceDescriptor" );
750         }
751         else if (strcmp(token, "@") == 0)
752         {
753             if (SpecType != SPEC_WIN32)
754                 fatal_error( "'@' ordinals not supported for Win16\n" );
755             ParseOrdinal( -1 );
756         }
757         else if (IsNumberString(token))
758         {
759             ParseOrdinal( atoi(token) );
760         }
761         else
762             fatal_error( "Expected name, id, length or ordinal\n" );
763     }
764
765     if (!DLLFileName[0])
766     {
767         if (SpecMode == SPEC_MODE_DLL)
768             sprintf( DLLFileName, "%s.dll", DLLName );
769         else
770             sprintf( DLLFileName, "%s.exe", DLLName );
771     }
772 }
773
774
775 /*******************************************************************
776  *         StoreVariableCode
777  *
778  * Store a list of ints into a byte array.
779  */
780 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
781 {
782     int i;
783
784     switch(size)
785     {
786     case 1:
787         for (i = 0; i < odp->u.var.n_values; i++)
788             buffer[i] = odp->u.var.values[i];
789         break;
790     case 2:
791         for (i = 0; i < odp->u.var.n_values; i++)
792             ((unsigned short *)buffer)[i] = odp->u.var.values[i];
793         break;
794     case 4:
795         for (i = 0; i < odp->u.var.n_values; i++)
796             ((unsigned int *)buffer)[i] = odp->u.var.values[i];
797         break;
798     }
799     return odp->u.var.n_values * size;
800 }
801
802
803 /*******************************************************************
804  *         DumpBytes
805  *
806  * Dump a byte stream into the assembly code.
807  */
808 static void DumpBytes( FILE *outfile, const unsigned char *data, int len,
809                        const char *label )
810 {
811     int i;
812
813     fprintf( outfile, "\nstatic BYTE %s[] = \n{", label );
814
815     for (i = 0; i < len; i++)
816     {
817         if (!(i & 0x0f)) fprintf( outfile, "\n    " );
818         fprintf( outfile, "%d", *data++ );
819         if (i < len - 1) fprintf( outfile, ", " );
820     }
821     fprintf( outfile, "\n};\n" );
822 }
823
824
825 /*******************************************************************
826  *         BuildModule16
827  *
828  * Build the in-memory representation of a 16-bit NE module, and dump it
829  * as a byte stream into the assembly code.
830  */
831 static int BuildModule16( FILE *outfile, int max_code_offset,
832                           int max_data_offset )
833 {
834     int i;
835     char *buffer;
836     NE_MODULE *pModule;
837     SEGTABLEENTRY *pSegment;
838     OFSTRUCT *pFileInfo;
839     BYTE *pstr;
840     WORD *pword;
841     ET_BUNDLE *bundle = 0;
842     ET_ENTRY *entry = 0;
843
844     /*   Module layout:
845      * NE_MODULE       Module
846      * OFSTRUCT        File information
847      * SEGTABLEENTRY   Segment 1 (code)
848      * SEGTABLEENTRY   Segment 2 (data)
849      * WORD[2]         Resource table (empty)
850      * BYTE[2]         Imported names (empty)
851      * BYTE[n]         Resident names table
852      * BYTE[n]         Entry table
853      */
854
855     buffer = xmalloc( 0x10000 );
856
857     pModule = (NE_MODULE *)buffer;
858     memset( pModule, 0, sizeof(*pModule) );
859     pModule->magic = IMAGE_OS2_SIGNATURE;
860     pModule->count = 1;
861     pModule->next = 0;
862     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
863     pModule->dgroup = 2;
864     pModule->heap_size = DLLHeapSize;
865     pModule->stack_size = 0;
866     pModule->ip = 0;
867     pModule->cs = 0;
868     pModule->sp = 0;
869     pModule->ss = 0;
870     pModule->seg_count = 2;
871     pModule->modref_count = 0;
872     pModule->nrname_size = 0;
873     pModule->modref_table = 0;
874     pModule->nrname_fpos = 0;
875     pModule->moveable_entries = 0;
876     pModule->alignment = 0;
877     pModule->truetype = 0;
878     pModule->os_flags = NE_OSFLAGS_WINDOWS;
879     pModule->misc_flags = 0;
880     pModule->dlls_to_init  = 0;
881     pModule->nrname_handle = 0;
882     pModule->min_swap_area = 0;
883     pModule->expected_version = 0;
884     pModule->module32 = 0;
885     pModule->self = 0;
886     pModule->self_loading_sel = 0;
887
888       /* File information */
889
890     pFileInfo = (OFSTRUCT *)(pModule + 1);
891     pModule->fileinfo = (int)pFileInfo - (int)pModule;
892     memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
893     pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
894                         + strlen(DLLFileName);
895     strcpy( pFileInfo->szPathName, DLLFileName );
896     pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
897         
898 #ifdef __i386__  /* FIXME: Alignment problems! */
899
900       /* Segment table */
901
902     pSegment = (SEGTABLEENTRY *)pstr;
903     pModule->seg_table = (int)pSegment - (int)pModule;
904     pSegment->filepos = 0;
905     pSegment->size = max_code_offset;
906     pSegment->flags = 0;
907     pSegment->minsize = max_code_offset;
908     pSegment->hSeg = 0;
909     pSegment++;
910
911     pModule->dgroup_entry = (int)pSegment - (int)pModule;
912     pSegment->filepos = 0;
913     pSegment->size = max_data_offset;
914     pSegment->flags = NE_SEGFLAGS_DATA;
915     pSegment->minsize = max_data_offset;
916     pSegment->hSeg = 0;
917     pSegment++;
918
919       /* Resource table */
920
921     pword = (WORD *)pSegment;
922     pModule->res_table = (int)pword - (int)pModule;
923     *pword++ = 0;
924     *pword++ = 0;
925
926       /* Imported names table */
927
928     pstr = (char *)pword;
929     pModule->import_table = (int)pstr - (int)pModule;
930     *pstr++ = 0;
931     *pstr++ = 0;
932
933       /* Resident names table */
934
935     pModule->name_table = (int)pstr - (int)pModule;
936     /* First entry is module name */
937     *pstr = strlen(DLLName );
938     strcpy( pstr + 1, DLLName );
939     pstr += *pstr + 1;
940     *(WORD *)pstr = 0;
941     pstr += sizeof(WORD);
942     /* Store all ordinals */
943     for (i = 1; i <= Limit; i++)
944     {
945         ORDDEF *odp = Ordinals[i];
946         if (!odp || !odp->name[0]) continue;
947         *pstr = strlen( odp->name );
948         strcpy( pstr + 1, odp->name );
949         strupper( pstr + 1 );
950         pstr += *pstr + 1;
951         *(WORD *)pstr = i;
952         pstr += sizeof(WORD);
953     }
954     *pstr++ = 0;
955
956       /* Entry table */
957
958     pModule->entry_table = (int)pstr - (int)pModule;
959     for (i = 1; i <= Limit; i++)
960     {
961         int selector = 0;
962         ORDDEF *odp = Ordinals[i];
963         if (!odp) continue;
964
965         switch (odp->type)
966         {
967         case TYPE_CDECL:
968         case TYPE_PASCAL:
969         case TYPE_PASCAL_16:
970         case TYPE_REGISTER:
971         case TYPE_INTERRUPT:
972         case TYPE_STUB:
973             selector = 1;  /* Code selector */
974             break;
975
976         case TYPE_BYTE:
977         case TYPE_WORD:
978         case TYPE_LONG:
979             selector = 2;  /* Data selector */
980             break;
981
982         case TYPE_ABS:
983             selector = 0xfe;  /* Constant selector */
984             break;
985
986         default:
987             selector = 0;  /* Invalid selector */
988             break;
989         }
990
991         if ( !selector )
992            continue;
993
994         if ( bundle && bundle->last+1 == i )
995             bundle->last++;
996         else
997         {
998             if ( bundle )
999                 bundle->next = (char *)pstr - (char *)pModule;
1000
1001             bundle = (ET_BUNDLE *)pstr;
1002             bundle->first = i-1;
1003             bundle->last = i;
1004             bundle->next = 0;
1005             pstr += sizeof(ET_BUNDLE);
1006         }
1007
1008         /* FIXME: is this really correct ?? */
1009         entry = (ET_ENTRY *)pstr;
1010         entry->type = 0xff;  /* movable */
1011         entry->flags = 3; /* exported & public data */
1012         entry->segnum = selector;
1013         entry->offs = odp->offset;
1014         pstr += sizeof(ET_ENTRY);
1015     }
1016     *pstr++ = 0;
1017 #endif
1018
1019       /* Dump the module content */
1020
1021     DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
1022                "Module" );
1023     return (int)pstr - (int)pModule;
1024 }
1025
1026
1027 /*******************************************************************
1028  *         output_exports
1029  *
1030  * Output the export table for a Win32 module.
1031  */
1032 static void output_exports( FILE *outfile, int nr_exports, int nr_names, int fwd_size )
1033 {
1034     int i, fwd_pos = 0;
1035
1036     if (!nr_exports) return;
1037
1038     fprintf( outfile, "typedef void (*func_ptr)();\n" );
1039     fprintf( outfile, "static struct {\n" );
1040     fprintf( outfile, "  struct {\n" );
1041     fprintf( outfile, "    unsigned int    Characteristics;\n" );
1042     fprintf( outfile, "    unsigned int    TimeDateStamp;\n" );
1043     fprintf( outfile, "    unsigned short  MajorVersion;\n" );
1044     fprintf( outfile, "    unsigned short  MinorVersion;\n" );
1045     fprintf( outfile, "    const char     *Name;\n" );
1046     fprintf( outfile, "    unsigned int    Base;\n" );
1047     fprintf( outfile, "    unsigned int    NumberOfFunctions;\n" );
1048     fprintf( outfile, "    unsigned int    NumberOfNames;\n" );
1049     fprintf( outfile, "    func_ptr       *AddressOfFunctions;\n" );
1050     fprintf( outfile, "    const char    **AddressOfNames;\n" );
1051     fprintf( outfile, "    unsigned short *AddressOfNameOrdinals;\n" );
1052     fprintf( outfile, "    func_ptr        functions[%d];\n", nr_exports );
1053     if (nb_names)
1054     {
1055         fprintf( outfile, "    const char     *names[%d];\n", nb_names );
1056         fprintf( outfile, "    unsigned short  ordinals[%d];\n", nb_names );
1057         if (nb_names % 2) fprintf( outfile, "    unsigned short  pad1;\n" );
1058     }
1059     if (fwd_size)
1060     {
1061         fprintf( outfile, "    char            forwards[%d];\n", (fwd_size + 3) & ~3 );
1062     }
1063     fprintf( outfile, "  } exp;\n" );
1064
1065 #ifdef __i386__
1066     fprintf( outfile, "  struct {\n" );
1067     fprintf( outfile, "    unsigned char  jmp;\n" );
1068     fprintf( outfile, "    unsigned char  addr[4];\n" );
1069     fprintf( outfile, "    unsigned char  ret;\n" );
1070     fprintf( outfile, "    unsigned short args;\n" );
1071     fprintf( outfile, "    func_ptr       orig;\n" );
1072     fprintf( outfile, "    unsigned int   argtypes;\n" );
1073     fprintf( outfile, "  } relay[%d];\n", nr_exports );
1074 #endif  /* __i386__ */
1075
1076     fprintf( outfile, "} exports = {\n  {\n" );
1077     fprintf( outfile, "    0,\n" );                 /* Characteristics */
1078     fprintf( outfile, "    0,\n" );                 /* TimeDateStamp */
1079     fprintf( outfile, "    0,\n" );                 /* MajorVersion */
1080     fprintf( outfile, "    0,\n" );                 /* MinorVersion */
1081     fprintf( outfile, "    dllname,\n" );           /* Name */
1082     fprintf( outfile, "    %d,\n", Base );          /* Base */
1083     fprintf( outfile, "    %d,\n", nr_exports );    /* NumberOfFunctions */
1084     fprintf( outfile, "    %d,\n", nb_names );      /* NumberOfNames */
1085     fprintf( outfile, "    exports.exp.functions,\n" ); /* AddressOfFunctions */
1086     if (nb_names)
1087     {
1088         fprintf( outfile, "    exports.exp.names,\n" );     /* AddressOfNames */
1089         fprintf( outfile, "    exports.exp.ordinals,\n" );  /* AddressOfNameOrdinals */
1090     }
1091     else
1092     {
1093         fprintf( outfile, "    0,\n" );  /* AddressOfNames */
1094         fprintf( outfile, "    0,\n" );  /* AddressOfNameOrdinals */
1095     }
1096
1097     /* output the function addresses */
1098
1099     fprintf( outfile, "    {\n      " );
1100     for (i = Base; i <= Limit; i++)
1101     {
1102         ORDDEF *odp = Ordinals[i];
1103         if (!odp) fprintf( outfile, "0" );
1104         else switch(odp->type)
1105         {
1106         case TYPE_EXTERN:
1107             fprintf( outfile, "%s", odp->u.ext.link_name );
1108             break;
1109         case TYPE_STDCALL:
1110         case TYPE_VARARGS:
1111         case TYPE_CDECL:
1112             fprintf( outfile, "%s", odp->u.func.link_name);
1113             break;
1114         case TYPE_STUB:
1115             fprintf( outfile, "__stub_%d", i );
1116             break;
1117         case TYPE_REGISTER:
1118             fprintf( outfile, "__regs_%d", i );
1119             break;
1120         case TYPE_FORWARD:
1121             fprintf( outfile, "(func_ptr)&exports.exp.forwards[%d] /* %s */",
1122                      fwd_pos, odp->u.fwd.link_name );
1123             fwd_pos += strlen(odp->u.fwd.link_name) + 1;
1124             break;
1125         default:
1126             assert(0);
1127         }
1128         if (i < Limit) fprintf( outfile, ",\n      " );
1129         else fprintf( outfile, "\n    },\n" );
1130     }
1131
1132     if (nb_names)
1133     {
1134         /* output the function names */
1135
1136         fprintf( outfile, "    {\n" );
1137         for (i = 0; i < nb_names; i++)
1138         {
1139             if (i) fprintf( outfile, ",\n" );
1140             fprintf( outfile, "      \"%s\"", Names[i]->name );
1141         }
1142         fprintf( outfile, "\n    },\n" );
1143
1144         /* output the function ordinals */
1145
1146         fprintf( outfile, "    {\n     " );
1147         for (i = 0; i < nb_names; i++)
1148         {
1149             fprintf( outfile, "%4d", Names[i]->ordinal - Base );
1150             if (i < nb_names-1)
1151             {
1152                 fputc( ',', outfile );
1153                 if ((i % 8) == 7) fprintf( outfile, "\n     " );
1154             }
1155         }
1156         fprintf( outfile, "\n    },\n" );
1157         if (nb_names % 2) fprintf( outfile, "    0,\n" );
1158     }
1159
1160     /* output forwards */
1161
1162     if (fwd_size)
1163     {
1164         for (i = Base; i <= Limit; i++)
1165         {
1166             ORDDEF *odp = Ordinals[i];
1167             if (odp && odp->type == TYPE_FORWARD)
1168                 fprintf( outfile, "    \"%s\\0\"\n", odp->u.fwd.link_name );
1169         }
1170     }
1171
1172     /* output relays */
1173
1174 #ifdef __i386__
1175     fprintf( outfile, "  },\n  {\n" );
1176     for (i = Base; i <= Limit; i++)
1177     {
1178         ORDDEF *odp = Ordinals[i];
1179
1180         if (odp && ((odp->type == TYPE_STDCALL) ||
1181                     (odp->type == TYPE_CDECL) ||
1182                     (odp->type == TYPE_REGISTER)))
1183         {
1184             unsigned int j, mask = 0;
1185             for (j = 0; odp->u.func.arg_types[j]; j++)
1186             {
1187                 if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
1188                 if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
1189             }
1190
1191             switch(odp->type)
1192             {
1193             case TYPE_STDCALL:
1194                 fprintf( outfile, "    { 0xe9, { 0,0,0,0 }, 0xc2, 0x%04x, %s, 0x%08x }",
1195                          strlen(odp->u.func.arg_types) * sizeof(int),
1196                          odp->u.func.link_name, mask );
1197                 break;
1198             case TYPE_CDECL:
1199                 fprintf( outfile, "    { 0xe9, { 0,0,0,0 }, 0xc3, 0x%04x, %s, 0x%08x }",
1200                          strlen(odp->u.func.arg_types) * sizeof(int),
1201                          odp->u.func.link_name, mask );
1202                 break;
1203             case TYPE_REGISTER:
1204                 fprintf( outfile, "    { 0xe9, { 0,0,0,0 }, 0xc3, 0x%04x, __regs_%d, 0x%08x }",
1205                          0x8000 | (strlen(odp->u.func.arg_types) * sizeof(int)), i, mask );
1206                 break;
1207             default:
1208                 assert(0);
1209             }
1210         }
1211         else fprintf( outfile, "    { 0, }" );
1212
1213         if (i < Limit) fprintf( outfile, ",\n" );
1214     }
1215 #endif  /* __i386__ */
1216
1217     fprintf( outfile, "  }\n};\n" );
1218 }
1219
1220
1221 /*******************************************************************
1222  *         BuildSpec32File
1223  *
1224  * Build a Win32 C file from a spec file.
1225  */
1226 static int BuildSpec32File( FILE *outfile )
1227 {
1228     ORDDEF *odp;
1229     int i, fwd_size = 0, have_regs = FALSE;
1230     int nr_exports;
1231     const char *init_func;
1232     DWORD page_size;
1233
1234 #ifdef HAVE_GETPAGESIZE
1235     page_size = getpagesize();
1236 #else
1237 # ifdef __svr4__
1238     page_size = sysconf(_SC_PAGESIZE);
1239 # else
1240 #   error Cannot get the page size on this platform
1241 # endif
1242 #endif
1243
1244     AssignOrdinals();
1245     nr_exports = Base <= Limit ? Limit - Base + 1 : 0;
1246
1247     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
1248              input_file_name );
1249     fprintf( outfile, "#include \"builtin32.h\"\n\n" );
1250
1251     /* Reserve some space for the PE header */
1252
1253     fprintf( outfile, "extern char pe_header[];\n" );
1254     fprintf( outfile, "asm(\".section .text\\n\\t\"\n" );
1255     fprintf( outfile, "    \".align %d\\n\"\n", page_size );
1256     fprintf( outfile, "    \"pe_header:\\t.fill %d,1,0\\n\\t\");\n", page_size );
1257
1258     fprintf( outfile, "static const char dllname[] = \"%s\";\n", DLLName );
1259
1260     /* Output the DLL functions prototypes */
1261
1262     for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
1263     {
1264         switch(odp->type)
1265         {
1266         case TYPE_EXTERN:
1267             fprintf( outfile, "extern void %s();\n", odp->u.ext.link_name );
1268             break;
1269         case TYPE_STDCALL:
1270         case TYPE_VARARGS:
1271         case TYPE_CDECL:
1272             fprintf( outfile, "extern void %s();\n", odp->u.func.link_name );
1273             break;
1274         case TYPE_FORWARD:
1275             fwd_size += strlen(odp->u.fwd.link_name) + 1;
1276             break;
1277         case TYPE_REGISTER:
1278             fprintf( outfile, "extern void __regs_%d();\n", odp->ordinal );
1279             have_regs = TRUE;
1280             break;
1281         case TYPE_STUB:
1282             if (odp->name[0])
1283                 fprintf( outfile,
1284                          "static void __stub_%d() { BUILTIN32_Unimplemented(dllname,\"%s\"); }\n",
1285                          odp->ordinal, odp->name );
1286             else
1287                 fprintf( outfile,
1288                          "static void __stub_%d() { BUILTIN32_Unimplemented(dllname,\"%d\"); }\n",
1289                          odp->ordinal, odp->ordinal );
1290             
1291             break;
1292         default:
1293             fprintf(stderr,"build: function type %d not available for Win32\n",
1294                     odp->type);
1295             return -1;
1296         }
1297     }
1298
1299     /* Output code for all register functions */
1300
1301     if ( have_regs )
1302     { 
1303         fprintf( outfile, "#ifndef __GNUC__\n" );
1304         fprintf( outfile, "static void __asm__dummy(void) {\n" );
1305         fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
1306         for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
1307         {
1308             if (odp->type != TYPE_REGISTER) continue;
1309             fprintf( outfile,
1310                      "asm(\".align 4\\n\\t\"\n"
1311                      "    \".type " PREFIX "__regs_%d,@function\\n\\t\"\n"
1312                      "    \"" PREFIX "__regs_%d:\\n\\t\"\n"
1313                      "    \"call " PREFIX "CALL32_Regs\\n\\t\"\n"
1314                      "    \".long " PREFIX "%s\\n\\t\"\n"
1315                      "    \".byte %d,%d\");\n",
1316                      odp->ordinal, odp->ordinal, odp->u.func.link_name,
1317                      4 * strlen(odp->u.func.arg_types),
1318                      4 * strlen(odp->u.func.arg_types) );
1319         }
1320         fprintf( outfile, "#ifndef __GNUC__\n" );
1321         fprintf( outfile, "}\n" );
1322         fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
1323     }
1324
1325     /* Output the exports and relay entry points */
1326
1327     output_exports( outfile, nr_exports, nb_names, fwd_size );
1328
1329     /* Output the DLL imports */
1330
1331     if (nb_imports)
1332     {
1333         fprintf( outfile, "static const char * const Imports[%d] =\n{\n", nb_imports );
1334         for (i = 0; i < nb_imports; i++)
1335         {
1336             fprintf( outfile, "    \"%s\"", DLLImports[i] );
1337             if (i < nb_imports-1) fprintf( outfile, ",\n" );
1338         }
1339         fprintf( outfile, "\n};\n\n" );
1340     }
1341
1342     /* Output LibMain function */
1343
1344     init_func = DLLInitFunc[0] ? DLLInitFunc : NULL;
1345     switch(SpecMode)
1346     {
1347     case SPEC_MODE_DLL:
1348         if (init_func) fprintf( outfile, "extern void %s();\n", init_func );
1349         break;
1350     case SPEC_MODE_GUIEXE:
1351         if (!init_func) init_func = "WinMain";
1352         fprintf( outfile,
1353                  "\n#include <winbase.h>\n"
1354                  "static void exe_main(void)\n"
1355                  "{\n"
1356                  "    extern int PASCAL %s(HINSTANCE,HINSTANCE,LPCSTR,INT);\n"
1357                  "    STARTUPINFOA info;\n"
1358                  "    const char *cmdline = GetCommandLineA();\n"
1359                  "    while (*cmdline && *cmdline != ' ') cmdline++;\n"
1360                  "    if (*cmdline) cmdline++;\n"
1361                  "    GetStartupInfoA( &info );\n"
1362                  "    if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = 1;\n"
1363                  "    ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
1364                  "}\n\n", init_func, init_func );
1365         fprintf( outfile,
1366                  "int main( int argc, char *argv[] )\n"
1367                  "{\n"
1368                  "    extern void PROCESS_InitWinelib( int, char ** );\n"
1369                  "    PROCESS_InitWinelib( argc, argv );\n"
1370                  "    return 1;\n"
1371                  "}\n\n" );
1372         init_func = "exe_main";
1373         break;
1374     case SPEC_MODE_CUIEXE:
1375         if (!init_func) init_func = "wine_main";
1376         fprintf( outfile,
1377                  "\n#include <winbase.h>\n"
1378                  "static void exe_main(void)\n"
1379                  "{\n"
1380                  "    extern int %s( int argc, char *argv[] );\n"
1381                  "    extern int _ARGC;\n"
1382                  "    extern char **_ARGV;\n"
1383                  "    ExitProcess( %s( _ARGC, _ARGV ) );\n"
1384                  "}\n\n", init_func, init_func );
1385         fprintf( outfile,
1386                  "int main( int argc, char *argv[] )\n"
1387                  "{\n"
1388                  "    extern void PROCESS_InitWinelib( int, char ** );\n"
1389                  "    PROCESS_InitWinelib( argc, argv );\n"
1390                  "    return 1;\n"
1391                  "}\n\n" );
1392         init_func = "exe_main";
1393         break;
1394     }
1395
1396     /* Output the DLL descriptor */
1397
1398     if (rsrc_name[0]) fprintf( outfile, "extern char %s[];\n\n", rsrc_name );
1399
1400     fprintf( outfile, "static const BUILTIN32_DESCRIPTOR descriptor =\n{\n" );
1401     fprintf( outfile, "    \"%s\",\n", DLLFileName );
1402     fprintf( outfile, "    %d,\n", nb_imports );
1403     fprintf( outfile, "    pe_header,\n" );
1404     fprintf( outfile, "    %s,\n", nr_exports ? "&exports" : "0" );
1405     fprintf( outfile, "    %s,\n", nr_exports ? "sizeof(exports.exp)" : "0" );
1406     fprintf( outfile, "    %s,\n", nb_imports ? "Imports" : "0" );
1407     fprintf( outfile, "    %s,\n", init_func ? init_func : "0" );
1408     fprintf( outfile, "    %d,\n", SpecMode == SPEC_MODE_DLL ? IMAGE_FILE_DLL : 0 );
1409     fprintf( outfile, "    %s\n", rsrc_name[0] ? rsrc_name : "0" );
1410     fprintf( outfile, "};\n" );
1411
1412     /* Output the DLL constructor */
1413
1414     fprintf( outfile, "#ifdef __GNUC__\n" );
1415     fprintf( outfile, "static void %s_init(void) __attribute__((constructor));\n", DLLName );
1416     fprintf( outfile, "#else /* defined(__GNUC__) */\n" );
1417     fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
1418     fprintf( outfile, "asm(\"\\t.section\t.init ,\\\"ax\\\"\\n\"\n" );
1419     fprintf( outfile, "    \"\\tcall %s_init\\n\"\n", DLLName );
1420     fprintf( outfile, "    \"\\t.previous\\n\");\n" );
1421     fprintf( outfile, "}\n" );
1422     fprintf( outfile, "#endif /* defined(__GNUC__) */\n" );
1423     fprintf( outfile, "static void %s_init(void) { BUILTIN32_RegisterDLL( &descriptor ); }\n",
1424              DLLName );
1425
1426     return 0;
1427 }
1428
1429 /*******************************************************************
1430  *         Spec16TypeCompare
1431  */
1432 static int Spec16TypeCompare( const void *e1, const void *e2 )
1433 {
1434     const ORDDEF *odp1 = *(const ORDDEF **)e1;
1435     const ORDDEF *odp2 = *(const ORDDEF **)e2;
1436
1437     int type1 = (odp1->type == TYPE_CDECL) ? 0
1438               : (odp1->type == TYPE_REGISTER) ? 3
1439               : (odp1->type == TYPE_INTERRUPT) ? 4
1440               : (odp1->type == TYPE_PASCAL_16) ? 1 : 2;
1441
1442     int type2 = (odp2->type == TYPE_CDECL) ? 0
1443               : (odp2->type == TYPE_REGISTER) ? 3
1444               : (odp2->type == TYPE_INTERRUPT) ? 4
1445               : (odp2->type == TYPE_PASCAL_16) ? 1 : 2;
1446
1447     int retval = type1 - type2;
1448     if ( !retval )
1449         retval = strcmp( odp1->u.func.arg_types, odp2->u.func.arg_types );
1450
1451     return retval;
1452 }
1453
1454 /*******************************************************************
1455  *         BuildSpec16File
1456  *
1457  * Build a Win16 assembly file from a spec file.
1458  */
1459 static int BuildSpec16File( FILE *outfile )
1460 {
1461     ORDDEF **type, **typelist;
1462     int i, nFuncs, nTypes;
1463     int code_offset, data_offset, module_size;
1464     unsigned char *data;
1465
1466     /* File header */
1467
1468     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
1469              input_file_name );
1470     fprintf( outfile, "#define __FLATCS__ 0x%04x\n", Code_Selector );
1471     fprintf( outfile, "#include \"builtin16.h\"\n\n" );
1472
1473     data = (unsigned char *)xmalloc( 0x10000 );
1474     memset( data, 0, 16 );
1475     data_offset = 16;
1476     strupper( DLLName );
1477
1478     /* Build sorted list of all argument types, without duplicates */
1479
1480     typelist = (ORDDEF **)calloc( Limit+1, sizeof(ORDDEF *) );
1481
1482     for (i = nFuncs = 0; i <= Limit; i++)
1483     {
1484         ORDDEF *odp = Ordinals[i];
1485         if (!odp) continue;
1486         switch (odp->type)
1487         {
1488           case TYPE_REGISTER:
1489           case TYPE_INTERRUPT:
1490           case TYPE_CDECL:
1491           case TYPE_PASCAL:
1492           case TYPE_PASCAL_16:
1493           case TYPE_STUB:
1494             typelist[nFuncs++] = odp;
1495
1496           default:
1497             break;
1498         }
1499     }
1500
1501     qsort( typelist, nFuncs, sizeof(ORDDEF *), Spec16TypeCompare );
1502
1503     i = nTypes = 0;
1504     while ( i < nFuncs )
1505     {
1506         typelist[nTypes++] = typelist[i++];
1507         while ( i < nFuncs && Spec16TypeCompare( typelist + i, typelist + nTypes-1 ) == 0 )
1508             i++;
1509     }
1510
1511     /* Output CallFrom16 routines needed by this .spec file */
1512
1513     for ( i = 0; i < nTypes; i++ )
1514     {
1515         char profile[101];
1516
1517         sprintf( profile, "%s_%s_%s",
1518                  (typelist[i]->type == TYPE_CDECL) ? "c" : "p",
1519                  (typelist[i]->type == TYPE_REGISTER) ? "regs" :
1520                  (typelist[i]->type == TYPE_INTERRUPT) ? "intr" :
1521                  (typelist[i]->type == TYPE_PASCAL_16) ? "word" : "long",
1522                  typelist[i]->u.func.arg_types );
1523
1524         BuildCallFrom16Func( outfile, profile, DLLName, TRUE );
1525     }
1526
1527     /* Output the DLL functions prototypes */
1528
1529     for (i = 0; i <= Limit; i++)
1530     {
1531         ORDDEF *odp = Ordinals[i];
1532         if (!odp) continue;
1533         switch(odp->type)
1534         {
1535         case TYPE_REGISTER:
1536         case TYPE_INTERRUPT:
1537         case TYPE_CDECL:
1538         case TYPE_PASCAL:
1539         case TYPE_PASCAL_16:
1540             fprintf( outfile, "extern void %s();\n", odp->u.func.link_name );
1541             break;
1542         default:
1543             break;
1544         }
1545     }
1546
1547     /* Output code segment */
1548
1549     fprintf( outfile, "\nstatic struct\n{\n    CALLFROM16   call[%d];\n"
1550                       "    ENTRYPOINT16 entry[%d];\n} Code_Segment = \n{\n    {\n",
1551                       nTypes, nFuncs );
1552     code_offset = 0;
1553
1554     for ( i = 0; i < nTypes; i++ )
1555     {
1556         char profile[101], *arg;
1557         int argsize = 0;
1558
1559         sprintf( profile, "%s_%s_%s", 
1560                           (typelist[i]->type == TYPE_CDECL) ? "c" : "p",
1561                           (typelist[i]->type == TYPE_REGISTER) ? "regs" :
1562                           (typelist[i]->type == TYPE_INTERRUPT) ? "intr" :
1563                           (typelist[i]->type == TYPE_PASCAL_16) ? "word" : "long",
1564                           typelist[i]->u.func.arg_types );
1565
1566         if ( typelist[i]->type != TYPE_CDECL )
1567             for ( arg = typelist[i]->u.func.arg_types; *arg; arg++ )
1568                 switch ( *arg )
1569                 {
1570                 case 'w':  /* word */
1571                 case 's':  /* s_word */
1572                     argsize += 2;
1573                     break;
1574         
1575                 case 'l':  /* long or segmented pointer */
1576                 case 'T':  /* segmented pointer to null-terminated string */
1577                 case 'p':  /* linear pointer */
1578                 case 't':  /* linear pointer to null-terminated string */
1579                     argsize += 4;
1580                     break;
1581                 }
1582
1583         if ( typelist[i]->type == TYPE_INTERRUPT )
1584             argsize += 2;
1585
1586         fprintf( outfile, "        CF16_%s( %s_CallFrom16_%s, %d, \"%s\" ),\n",
1587                  (   typelist[i]->type == TYPE_REGISTER 
1588                   || typelist[i]->type == TYPE_INTERRUPT)? "REGS":
1589                  typelist[i]->type == TYPE_PASCAL_16? "WORD" : "LONG",
1590                  DLLName, profile, argsize, profile );
1591
1592         code_offset += sizeof(CALLFROM16);
1593     }
1594     fprintf( outfile, "    },\n    {\n" );
1595
1596     for (i = 0; i <= Limit; i++)
1597     {
1598         ORDDEF *odp = Ordinals[i];
1599         if (!odp) continue;
1600         switch (odp->type)
1601         {
1602           case TYPE_ABS:
1603             odp->offset = LOWORD(odp->u.abs.value);
1604             break;
1605
1606           case TYPE_BYTE:
1607             odp->offset = data_offset;
1608             data_offset += StoreVariableCode( data + data_offset, 1, odp);
1609             break;
1610
1611           case TYPE_WORD:
1612             odp->offset = data_offset;
1613             data_offset += StoreVariableCode( data + data_offset, 2, odp);
1614             break;
1615
1616           case TYPE_LONG:
1617             odp->offset = data_offset;
1618             data_offset += StoreVariableCode( data + data_offset, 4, odp);
1619             break;
1620
1621           case TYPE_REGISTER:
1622           case TYPE_INTERRUPT:
1623           case TYPE_CDECL:
1624           case TYPE_PASCAL:
1625           case TYPE_PASCAL_16:
1626           case TYPE_STUB:
1627             type = bsearch( &odp, typelist, nTypes, sizeof(ORDDEF *), Spec16TypeCompare );
1628             assert( type );
1629
1630             fprintf( outfile, "        /* %s.%d */ ", DLLName, i );
1631             fprintf( outfile, "EP( %s, %d /* %s_%s_%s */ ),\n",
1632                               odp->u.func.link_name,
1633                               (type-typelist)*sizeof(CALLFROM16) - 
1634                               (code_offset + sizeof(ENTRYPOINT16)),
1635                               (odp->type == TYPE_CDECL) ? "c" : "p",
1636                               (odp->type == TYPE_REGISTER) ? "regs" :
1637                               (odp->type == TYPE_INTERRUPT) ? "intr" :
1638                               (odp->type == TYPE_PASCAL_16) ? "word" : "long",
1639                               odp->u.func.arg_types );
1640                                  
1641             odp->offset = code_offset;
1642             code_offset += sizeof(ENTRYPOINT16);
1643             break;
1644                 
1645           default:
1646             fprintf(stderr,"build: function type %d not available for Win16\n",
1647                     odp->type);
1648             return -1;
1649         }
1650     }
1651
1652     fprintf( outfile, "    }\n};\n" );
1653
1654     /* Output data segment */
1655
1656     DumpBytes( outfile, data, data_offset, "Data_Segment" );
1657
1658     /* Build the module */
1659
1660     module_size = BuildModule16( outfile, code_offset, data_offset );
1661
1662     /* Output the DLL descriptor */
1663
1664     if (rsrc_name[0]) fprintf( outfile, "extern const char %s[];\n\n", rsrc_name );
1665
1666     fprintf( outfile, "\nstatic const BUILTIN16_DESCRIPTOR descriptor = \n{\n" );
1667     fprintf( outfile, "    \"%s\",\n", DLLName );
1668     fprintf( outfile, "    Module,\n" );
1669     fprintf( outfile, "    sizeof(Module),\n" );
1670     fprintf( outfile, "    (BYTE *)&Code_Segment,\n" );
1671     fprintf( outfile, "    (BYTE *)Data_Segment,\n" );
1672     fprintf( outfile, "    %s\n", rsrc_name[0] ? rsrc_name : "0" );
1673     fprintf( outfile, "};\n" );
1674     
1675     /* Output the DLL constructor */
1676
1677     fprintf( outfile, "#ifdef __GNUC__\n" );
1678     fprintf( outfile, "static void %s_init(void) __attribute__((constructor));\n", DLLName );
1679     fprintf( outfile, "#else /* defined(__GNUC__) */\n" );
1680     fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
1681     fprintf( outfile, "asm(\"\\t.section\t.init ,\\\"ax\\\"\\n\"\n" );
1682     fprintf( outfile, "    \"\\tcall %s_init\\n\"\n", DLLName );
1683     fprintf( outfile, "    \"\\t.previous\\n\");\n" );
1684     fprintf( outfile, "}\n" );
1685     fprintf( outfile, "#endif /* defined(__GNUC__) */\n" );
1686     fprintf( outfile, "static void %s_init(void) { BUILTIN_RegisterDLL( &descriptor ); }\n",
1687              DLLName );
1688
1689     return 0;
1690 }
1691
1692
1693 /*******************************************************************
1694  *         BuildSpecFile
1695  *
1696  * Build an assembly file from a spec file.
1697  */
1698 static void BuildSpecFile( FILE *outfile, FILE *infile )
1699 {
1700     SpecFp = infile;
1701     ParseTopLevel();
1702
1703     switch(SpecType)
1704     {
1705     case SPEC_WIN16:
1706         BuildSpec16File( outfile );
1707         break;
1708     case SPEC_WIN32:
1709         BuildSpec32File( outfile );
1710         break;
1711     default:
1712         fatal_error( "Missing 'type' declaration\n" );
1713     }
1714 }
1715
1716
1717 /*******************************************************************
1718  *         BuildCallFrom16Func
1719  *
1720  * Build a 16-bit-to-Wine callback glue function. 
1721  *
1722  * The generated routines are intended to be used as argument conversion 
1723  * routines to be called by the CallFrom16... core. Thus, the prototypes of
1724  * the generated routines are (see also CallFrom16):
1725  *
1726  *  extern WORD WINAPI PREFIX_CallFrom16_C_word_xxx( FARPROC func, LPBYTE args );
1727  *  extern LONG WINAPI PREFIX_CallFrom16_C_long_xxx( FARPROC func, LPBYTE args );
1728  *  extern void WINAPI PREFIX_CallFrom16_C_regs_xxx( FARPROC func, LPBYTE args, 
1729  *                                                   CONTEXT86 *context );
1730  *  extern void WINAPI PREFIX_CallFrom16_C_intr_xxx( FARPROC func, LPBYTE args, 
1731  *                                                   CONTEXT86 *context );
1732  *
1733  * where 'C' is the calling convention ('p' for pascal or 'c' for cdecl), 
1734  * and each 'x' is an argument  ('w'=word, 's'=signed word, 'l'=long, 
1735  * 'p'=linear pointer, 't'=linear pointer to null-terminated string,
1736  * 'T'=segmented pointer to null-terminated string).
1737  *
1738  * The generated routines fetch the arguments from the 16-bit stack (pointed
1739  * to by 'args'); the offsets of the single argument values are computed 
1740  * according to the calling convention and the argument types.  Then, the
1741  * 32-bit entry point is called with these arguments.
1742  * 
1743  * For register functions, the arguments (if present) are converted just
1744  * the same as for normal functions, but in addition the CONTEXT86 pointer 
1745  * filled with the current register values is passed to the 32-bit routine.
1746  * (An 'intr' interrupt handler routine is treated exactly like a register 
1747  * routine, except that upon return, the flags word pushed onto the stack 
1748  * by the interrupt is removed by the 16-bit call stub.)
1749  *
1750  */
1751 static void BuildCallFrom16Func( FILE *outfile, char *profile, char *prefix, int local )
1752 {
1753     int i, pos, argsize = 0;
1754     int short_ret = 0;
1755     int reg_func = 0;
1756     int usecdecl = 0;
1757     char *args = profile + 7;
1758     char *ret_type;
1759
1760     /* Parse function type */
1761
1762     if (!strncmp( "c_", profile, 2 )) usecdecl = 1;
1763     else if (strncmp( "p_", profile, 2 ))
1764     {
1765         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1766         return;
1767     }
1768
1769     if (!strncmp( "word_", profile + 2, 5 )) short_ret = 1;
1770     else if (!strncmp( "regs_", profile + 2, 5 )) reg_func = 1;
1771     else if (!strncmp( "intr_", profile + 2, 5 )) reg_func = 2;
1772     else if (strncmp( "long_", profile + 2, 5 ))
1773     {
1774         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1775         return;
1776     }
1777
1778     for ( i = 0; args[i]; i++ )
1779         switch ( args[i] )
1780         {
1781         case 'w':  /* word */
1782         case 's':  /* s_word */
1783             argsize += 2;
1784             break;
1785         
1786         case 'l':  /* long or segmented pointer */
1787         case 'T':  /* segmented pointer to null-terminated string */
1788         case 'p':  /* linear pointer */
1789         case 't':  /* linear pointer to null-terminated string */
1790             argsize += 4;
1791             break;
1792         }
1793
1794     ret_type = reg_func? "void" : short_ret? "WORD" : "LONG";
1795
1796     fprintf( outfile, "typedef %s WINAPI (*proc_%s_t)( ", 
1797                       ret_type, profile );
1798     args = profile + 7;
1799     for ( i = 0; args[i]; i++ )
1800     {
1801         if ( i ) fprintf( outfile, ", " );
1802         switch (args[i])
1803         {
1804         case 'w':           fprintf( outfile, "WORD" ); break;
1805         case 's':           fprintf( outfile, "INT16" ); break;
1806         case 'l': case 'T': fprintf( outfile, "LONG" ); break;
1807         case 'p': case 't': fprintf( outfile, "LPVOID" ); break;
1808         }
1809     }
1810     if ( reg_func )
1811         fprintf( outfile, "%sstruct _CONTEXT86 *", i? ", " : "" );
1812     else if ( !i )
1813         fprintf( outfile, "void" );
1814     fprintf( outfile, " );\n" );
1815     
1816     fprintf( outfile, "%s%s WINAPI %s_CallFrom16_%s( FARPROC proc, LPBYTE args%s )\n{\n",
1817              local? "static " : "", ret_type, prefix, profile,
1818              reg_func? ", struct _CONTEXT86 *context" : "" );
1819
1820     fprintf( outfile, "    %s((proc_%s_t) proc) (\n",
1821              reg_func? "" : "return ", profile );
1822     args = profile + 7;
1823     pos = !usecdecl? argsize : 0;
1824     for ( i = 0; args[i]; i++ )
1825     {
1826         if ( i ) fprintf( outfile, ",\n" );
1827         fprintf( outfile, "        " );
1828         switch (args[i])
1829         {
1830         case 'w':  /* word */
1831             if ( !usecdecl ) pos -= 2;
1832             fprintf( outfile, "*(WORD *)(args+%d)", pos );
1833             if (  usecdecl ) pos += 2;
1834             break;
1835
1836         case 's':  /* s_word */
1837             if ( !usecdecl ) pos -= 2;
1838             fprintf( outfile, "*(INT16 *)(args+%d)", pos );
1839             if (  usecdecl ) pos += 2;
1840             break;
1841
1842         case 'l':  /* long or segmented pointer */
1843         case 'T':  /* segmented pointer to null-terminated string */
1844             if ( !usecdecl ) pos -= 4;
1845             fprintf( outfile, "*(LONG *)(args+%d)", pos );
1846             if (  usecdecl ) pos += 4;
1847             break;
1848
1849         case 'p':  /* linear pointer */
1850         case 't':  /* linear pointer to null-terminated string */
1851             if ( !usecdecl ) pos -= 4;
1852             fprintf( outfile, "PTR_SEG_TO_LIN( *(SEGPTR *)(args+%d) )", pos );
1853             if (  usecdecl ) pos += 4;
1854             break;
1855
1856         default:
1857             fprintf( stderr, "Unknown arg type '%c'\n", args[i] );
1858         }
1859     }
1860     if ( reg_func )
1861         fprintf( outfile, "%s        context", i? ",\n" : "" );
1862     fprintf( outfile, " );\n}\n\n" );
1863 }
1864
1865 /*******************************************************************
1866  *         BuildCallTo16Func
1867  *
1868  * Build a Wine-to-16-bit callback glue function. 
1869  *
1870  * Prototypes for the CallTo16 functions:
1871  *   extern WORD CALLBACK PREFIX_CallTo16_word_xxx( FARPROC16 func, args... );
1872  *   extern LONG CALLBACK PREFIX_CallTo16_long_xxx( FARPROC16 func, args... );
1873  * 
1874  * These routines are provided solely for convenience; they simply
1875  * write the arguments onto the 16-bit stack, and call the appropriate
1876  * CallTo16... core routine.
1877  *
1878  * If you have more sophisticated argument conversion requirements than
1879  * are provided by these routines, you might as well call the core 
1880  * routines by yourself.
1881  *
1882  */
1883 static void BuildCallTo16Func( FILE *outfile, char *profile, char *prefix )
1884 {
1885     char *args = profile + 5;
1886     int i, argsize = 0, short_ret = 0;
1887
1888     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1889     else if (strncmp( "long_", profile, 5 ))
1890     {
1891         fprintf( stderr, "Invalid function name '%s'.\n", profile );
1892         exit(1);
1893     }
1894
1895     fprintf( outfile, "%s %s_CallTo16_%s( FARPROC16 proc",
1896              short_ret? "WORD" : "LONG", prefix, profile );
1897     args = profile + 5;
1898     for ( i = 0; args[i]; i++ )
1899     {
1900         fprintf( outfile, ", " );
1901         switch (args[i])
1902         {
1903         case 'w': fprintf( outfile, "WORD" ); argsize += 2; break;
1904         case 'l': fprintf( outfile, "LONG" ); argsize += 4; break;
1905         }
1906         fprintf( outfile, " arg%d", i+1 );
1907     }
1908     fprintf( outfile, " )\n{\n" );
1909
1910     if ( argsize > 0 )
1911         fprintf( outfile, "    LPBYTE args = (LPBYTE)CURRENT_STACK16;\n" );
1912
1913     args = profile + 5;
1914     for ( i = 0; args[i]; i++ )
1915     {
1916         switch (args[i])
1917         {
1918         case 'w': fprintf( outfile, "    args -= sizeof(WORD); *(WORD" ); break;
1919         case 'l': fprintf( outfile, "    args -= sizeof(LONG); *(LONG" ); break;
1920         default:  fprintf( stderr, "Unexpected case '%c' in BuildCallTo16Func\n",
1921                                    args[i] );
1922         }
1923         fprintf( outfile, " *)args = arg%d;\n", i+1 );
1924     }
1925
1926     fprintf( outfile, "    return CallTo16%s( proc, %d );\n}\n\n",
1927              short_ret? "Word" : "Long", argsize );
1928 }
1929
1930
1931
1932 /*******************************************************************
1933  *         BuildCallFrom16Core
1934  *
1935  * This routine builds the core routines used in 16->32 thunks:
1936  * CallFrom16Word, CallFrom16Long, CallFrom16Register, and CallFrom16Thunk.
1937  *
1938  * These routines are intended to be called via a far call (with 32-bit
1939  * operand size) from 16-bit code.  The 16-bit code stub must push %bp,
1940  * the 32-bit entry point to be called, and the argument conversion 
1941  * routine to be used (see stack layout below).  
1942  *
1943  * The core routine completes the STACK16FRAME on the 16-bit stack and
1944  * switches to the 32-bit stack.  Then, the argument conversion routine 
1945  * is called; it gets passed the 32-bit entry point and a pointer to the 
1946  * 16-bit arguments (on the 16-bit stack) as parameters. (You can either 
1947  * use conversion routines automatically generated by BuildCallFrom16, 
1948  * or write your own for special purposes.)
1949  * 
1950  * The conversion routine must call the 32-bit entry point, passing it
1951  * the converted arguments, and return its return value to the core.  
1952  * After the conversion routine has returned, the core switches back
1953  * to the 16-bit stack, converts the return value to the DX:AX format
1954  * (CallFrom16Long), and returns to the 16-bit call stub.  All parameters,
1955  * including %bp, are popped off the stack.
1956  *
1957  * The 16-bit call stub now returns to the caller, popping the 16-bit
1958  * arguments if necessary (pascal calling convention).
1959  *
1960  * In the case of a 'register' function, CallFrom16Register fills a
1961  * CONTEXT86 structure with the values all registers had at the point
1962  * the first instruction of the 16-bit call stub was about to be 
1963  * executed.  A pointer to this CONTEXT86 is passed as third parameter 
1964  * to the argument conversion routine, which typically passes it on
1965  * to the called 32-bit entry point.
1966  *
1967  * CallFrom16Thunk is a special variant used by the implementation of 
1968  * the Win95 16->32 thunk functions C16ThkSL and C16ThkSL01 and is 
1969  * implemented as follows:
1970  * On entry, the EBX register is set up to contain a flat pointer to the
1971  * 16-bit stack such that EBX+22 points to the first argument.
1972  * Then, the entry point is called, while EBP is set up to point
1973  * to the return address (on the 32-bit stack).
1974  * The called function returns with CX set to the number of bytes
1975  * to be popped of the caller's stack.
1976  *
1977  * Stack layout upon entry to the core routine (STACK16FRAME):
1978  *  ...           ...
1979  * (sp+24) word   first 16-bit arg
1980  * (sp+22) word   cs
1981  * (sp+20) word   ip
1982  * (sp+18) word   bp
1983  * (sp+14) long   32-bit entry point (reused for Win16 mutex recursion count)
1984  * (sp+12) word   ip of actual entry point (necessary for relay debugging)
1985  * (sp+8)  long   relay (argument conversion) function entry point
1986  * (sp+4)  long   cs of 16-bit entry point
1987  * (sp)    long   ip of 16-bit entry point
1988  *
1989  * Added on the stack:
1990  * (sp-2)  word   saved gs
1991  * (sp-4)  word   saved fs
1992  * (sp-6)  word   saved es
1993  * (sp-8)  word   saved ds
1994  * (sp-12) long   saved ebp
1995  * (sp-16) long   saved ecx
1996  * (sp-20) long   saved edx
1997  * (sp-24) long   saved previous stack
1998  */
1999 static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int short_ret )
2000 {
2001     char *name = thunk? "Thunk" : reg_func? "Register" : short_ret? "Word" : "Long";
2002
2003     /* Function header */
2004     fprintf( outfile, "\n\t.align 4\n" );
2005 #ifdef USE_STABS
2006     fprintf( outfile, ".stabs \"CallFrom16%s:F1\",36,0,0," PREFIX "CallFrom16%s\n", 
2007              name, name);
2008 #endif
2009     fprintf( outfile, "\t.type " PREFIX "CallFrom16%s,@function\n", name );
2010     fprintf( outfile, "\t.globl " PREFIX "CallFrom16%s\n", name );
2011     fprintf( outfile, PREFIX "CallFrom16%s:\n", name );
2012
2013     /* Create STACK16FRAME (except STACK32FRAME link) */
2014     fprintf( outfile, "\tpushw %%gs\n" );
2015     fprintf( outfile, "\tpushw %%fs\n" );
2016     fprintf( outfile, "\tpushw %%es\n" );
2017     fprintf( outfile, "\tpushw %%ds\n" );
2018     fprintf( outfile, "\tpushl %%ebp\n" );
2019     fprintf( outfile, "\tpushl %%ecx\n" );
2020     fprintf( outfile, "\tpushl %%edx\n" );
2021
2022     /* Save original EFlags register */
2023     fprintf( outfile, "\tpushfl\n" );
2024
2025     if ( UsePIC )
2026     {
2027         /* Get Global Offset Table into %ecx */
2028         fprintf( outfile, "\tcall .LCallFrom16%s.getgot1\n", name );
2029         fprintf( outfile, ".LCallFrom16%s.getgot1:\n", name );
2030         fprintf( outfile, "\tpopl %%ecx\n" );
2031         fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.LCallFrom16%s.getgot1], %%ecx\n", name );
2032     }
2033
2034     /* Load 32-bit segment registers */
2035     fprintf( outfile, "\tmovw $0x%04x, %%dx\n", Data_Selector );
2036 #ifdef __svr4__
2037     fprintf( outfile, "\tdata16\n");
2038 #endif
2039     fprintf( outfile, "\tmovw %%dx, %%ds\n" );
2040 #ifdef __svr4__
2041     fprintf( outfile, "\tdata16\n");
2042 #endif
2043     fprintf( outfile, "\tmovw %%dx, %%es\n" );
2044
2045     if ( UsePIC )
2046     {
2047         fprintf( outfile, "\tmovl " PREFIX "SYSLEVEL_Win16CurrentTeb@GOT(%%ecx), %%edx\n" );
2048         fprintf( outfile, "\tmovw (%%edx), %%fs\n" );
2049     }
2050     else
2051         fprintf( outfile, "\tmovw " PREFIX "SYSLEVEL_Win16CurrentTeb, %%fs\n" );
2052
2053     /* Get address of ldt_copy array into %ecx */
2054     if ( UsePIC )
2055         fprintf( outfile, "\tmovl " PREFIX "ldt_copy@GOT(%%ecx), %%ecx\n" );
2056     else
2057         fprintf( outfile, "\tmovl $" PREFIX "ldt_copy, %%ecx\n" );
2058
2059     /* Translate STACK16FRAME base to flat offset in %edx */
2060     fprintf( outfile, "\tmovw %%ss, %%dx\n" );
2061     fprintf( outfile, "\tandl $0xfff8, %%edx\n" );
2062     fprintf( outfile, "\tmovl (%%ecx,%%edx), %%edx\n" );
2063     fprintf( outfile, "\tmovzwl %%sp, %%ebp\n" );
2064     fprintf( outfile, "\tleal (%%ebp,%%edx), %%edx\n" );  
2065
2066     /* Get saved flags into %ecx */
2067     fprintf( outfile, "\tpopl %%ecx\n" );
2068
2069     /* Get the 32-bit stack pointer from the TEB and complete STACK16FRAME */
2070     fprintf( outfile, "\t.byte 0x64\n\tmovl (%d), %%ebp\n", STACKOFFSET );
2071     fprintf( outfile, "\tpushl %%ebp\n" );
2072
2073     /* Switch stacks */
2074 #ifdef __svr4__
2075     fprintf( outfile,"\tdata16\n");
2076 #endif
2077     fprintf( outfile, "\t.byte 0x64\n\tmovw %%ss, (%d)\n", STACKOFFSET + 2 );
2078     fprintf( outfile, "\t.byte 0x64\n\tmovw %%sp, (%d)\n", STACKOFFSET );
2079     fprintf( outfile, "\tpushl %%ds\n" );
2080     fprintf( outfile, "\tpopl %%ss\n" );
2081     fprintf( outfile, "\tmovl %%ebp, %%esp\n" );
2082     fprintf( outfile, "\taddl $%d, %%ebp\n", STRUCTOFFSET(STACK32FRAME, ebp) );
2083
2084
2085     /* At this point:
2086        STACK16FRAME is completely set up
2087        DS, ES, SS: flat data segment
2088        FS: current TEB
2089        ESP: points to last STACK32FRAME
2090        EBP: points to ebp member of last STACK32FRAME
2091        EDX: points to current STACK16FRAME
2092        ECX: contains saved flags
2093        all other registers: unchanged */
2094
2095     /* Special case: C16ThkSL stub */
2096     if ( thunk )
2097     {
2098         /* Set up registers as expected and call thunk */
2099         fprintf( outfile, "\tleal %d(%%edx), %%ebx\n", sizeof(STACK16FRAME)-22 );
2100         fprintf( outfile, "\tleal -4(%%esp), %%ebp\n" );
2101
2102         fprintf( outfile, "\tcall *%d(%%edx)\n", STACK16OFFSET(entry_point) );
2103
2104         /* Switch stack back */
2105         /* fprintf( outfile, "\t.byte 0x64\n\tlssw (%d), %%sp\n", STACKOFFSET ); */
2106         fprintf( outfile, "\t.byte 0x64,0x66,0x0f,0xb2,0x25\n\t.long %d\n", STACKOFFSET );
2107         fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
2108
2109         /* Restore registers and return directly to caller */
2110         fprintf( outfile, "\taddl $8, %%esp\n" );
2111         fprintf( outfile, "\tpopl %%ebp\n" );
2112         fprintf( outfile, "\tpopw %%ds\n" );
2113         fprintf( outfile, "\tpopw %%es\n" );
2114         fprintf( outfile, "\tpopw %%fs\n" );
2115         fprintf( outfile, "\tpopw %%gs\n" );
2116         fprintf( outfile, "\taddl $20, %%esp\n" );
2117
2118         fprintf( outfile, "\txorb %%ch, %%ch\n" );
2119         fprintf( outfile, "\tpopl %%ebx\n" );
2120         fprintf( outfile, "\taddw %%cx, %%sp\n" );
2121         fprintf( outfile, "\tpush %%ebx\n" );
2122
2123         fprintf( outfile, "\t.byte 0x66\n" );
2124         fprintf( outfile, "\tlret\n" );
2125
2126         return;
2127     }
2128
2129
2130     /* Build register CONTEXT */
2131     if ( reg_func )
2132     {
2133         fprintf( outfile, "\tsubl $%d, %%esp\n", sizeof(CONTEXT86) );
2134
2135         fprintf( outfile, "\tmovl %%ecx, %d(%%esp)\n", CONTEXTOFFSET(EFlags) );  
2136
2137         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(Eax) );
2138         fprintf( outfile, "\tmovl %%ebx, %d(%%esp)\n", CONTEXTOFFSET(Ebx) );
2139         fprintf( outfile, "\tmovl %%esi, %d(%%esp)\n", CONTEXTOFFSET(Esi) );
2140         fprintf( outfile, "\tmovl %%edi, %d(%%esp)\n", CONTEXTOFFSET(Edi) );
2141
2142         fprintf( outfile, "\tmovl %d(%%edx), %%eax\n", STACK16OFFSET(ebp) );
2143         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(Ebp) );
2144         fprintf( outfile, "\tmovl %d(%%edx), %%eax\n", STACK16OFFSET(ecx) );
2145         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(Ecx) );
2146         fprintf( outfile, "\tmovl %d(%%edx), %%eax\n", STACK16OFFSET(edx) );
2147         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(Edx) );
2148
2149         fprintf( outfile, "\tmovzwl %d(%%edx), %%eax\n", STACK16OFFSET(ds) );
2150         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(SegDs) );
2151         fprintf( outfile, "\tmovzwl %d(%%edx), %%eax\n", STACK16OFFSET(es) );
2152         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(SegEs) );
2153         fprintf( outfile, "\tmovzwl %d(%%edx), %%eax\n", STACK16OFFSET(fs) );
2154         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(SegFs) );
2155         fprintf( outfile, "\tmovzwl %d(%%edx), %%eax\n", STACK16OFFSET(gs) );
2156         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(SegGs) );
2157
2158         fprintf( outfile, "\tmovzwl %d(%%edx), %%eax\n", STACK16OFFSET(cs) );
2159         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(SegCs) );
2160         fprintf( outfile, "\tmovzwl %d(%%edx), %%eax\n", STACK16OFFSET(ip) );
2161         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(Eip) );
2162
2163         fprintf( outfile, "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET+2 );
2164         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(SegSs) );
2165         fprintf( outfile, "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET );
2166         fprintf( outfile, "\taddl $%d, %%eax\n", STACK16OFFSET(ip) );
2167         fprintf( outfile, "\tmovl %%eax, %d(%%esp)\n", CONTEXTOFFSET(Esp) );
2168 #if 0
2169         fprintf( outfile, "\tfsave %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2170 #endif
2171
2172         /* Push address of CONTEXT86 structure -- popped by the relay routine */
2173         fprintf( outfile, "\tpushl %%esp\n" );
2174     }
2175
2176
2177     /* Print debug info before call */
2178     if ( debugging )
2179     {
2180         if ( UsePIC )
2181         {
2182             fprintf( outfile, "\tpushl %%ebx\n" );
2183
2184             /* Get Global Offset Table into %ebx (for PLT call) */
2185             fprintf( outfile, "\tcall .LCallFrom16%s.getgot2\n", name );
2186             fprintf( outfile, ".LCallFrom16%s.getgot2:\n", name );
2187             fprintf( outfile, "\tpopl %%ebx\n" );
2188             fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.LCallFrom16%s.getgot2], %%ebx\n", name );
2189         }
2190
2191         fprintf( outfile, "\tpushl %%edx\n" );
2192         if ( reg_func )
2193             fprintf( outfile, "\tleal -%d(%%ebp), %%eax\n\tpushl %%eax\n",
2194                               sizeof(CONTEXT) + STRUCTOFFSET(STACK32FRAME, ebp) );
2195         else
2196             fprintf( outfile, "\tpushl $0\n" );
2197
2198         if ( UsePIC )
2199             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16@PLT\n ");
2200         else
2201             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16\n ");
2202
2203         fprintf( outfile, "\tpopl %%edx\n" );
2204         fprintf( outfile, "\tpopl %%edx\n" );
2205
2206         if ( UsePIC )
2207             fprintf( outfile, "\tpopl %%ebx\n" );
2208     }
2209
2210     /* Call relay routine (which will call the API entry point) */
2211     fprintf( outfile, "\tleal %d(%%edx), %%eax\n", sizeof(STACK16FRAME) );
2212     fprintf( outfile, "\tpushl %%eax\n" );
2213     fprintf( outfile, "\tpushl %d(%%edx)\n", STACK16OFFSET(entry_point) );
2214     fprintf( outfile, "\tcall *%d(%%edx)\n", STACK16OFFSET(relay) );
2215
2216     /* Print debug info after call */
2217     if ( debugging )
2218     {
2219         if ( UsePIC )
2220         {
2221             fprintf( outfile, "\tpushl %%ebx\n" );
2222
2223             /* Get Global Offset Table into %ebx (for PLT call) */
2224             fprintf( outfile, "\tcall .LCallFrom16%s.getgot3\n", name );
2225             fprintf( outfile, ".LCallFrom16%s.getgot3:\n", name );
2226             fprintf( outfile, "\tpopl %%ebx\n" );
2227             fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.LCallFrom16%s.getgot3], %%ebx\n", name );
2228         }
2229
2230         fprintf( outfile, "\tpushl %%eax\n" );
2231         if ( reg_func )
2232             fprintf( outfile, "\tleal -%d(%%ebp), %%eax\n\tpushl %%eax\n",
2233                               sizeof(CONTEXT) + STRUCTOFFSET(STACK32FRAME, ebp) );
2234         else
2235             fprintf( outfile, "\tpushl $0\n" );
2236
2237         if ( UsePIC )
2238             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16Ret@PLT\n ");
2239         else
2240             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16Ret\n ");
2241
2242         fprintf( outfile, "\tpopl %%eax\n" );
2243         fprintf( outfile, "\tpopl %%eax\n" );
2244
2245         if ( UsePIC )
2246             fprintf( outfile, "\tpopl %%ebx\n" );
2247     }
2248
2249
2250     if ( reg_func )
2251     {
2252         fprintf( outfile, "\tmovl %%esp, %%ebx\n" );
2253
2254         /* Switch stack back */
2255         /* fprintf( outfile, "\t.byte 0x64\n\tlssw (%d), %%sp\n", STACKOFFSET ); */
2256         fprintf( outfile, "\t.byte 0x64,0x66,0x0f,0xb2,0x25\n\t.long %d\n", STACKOFFSET );
2257         fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
2258
2259         /* Get return address to CallFrom16 stub */
2260         fprintf( outfile, "\taddw $%d, %%sp\n", STACK16OFFSET(callfrom_ip)-4 );
2261         fprintf( outfile, "\tpopl %%eax\n" );
2262         fprintf( outfile, "\tpopl %%edx\n" );
2263
2264         /* Restore all registers from CONTEXT */
2265         fprintf( outfile, "\tmovw %d(%%ebx), %%ss\n", CONTEXTOFFSET(SegSs) );
2266         fprintf( outfile, "\tmovl %d(%%ebx), %%esp\n", CONTEXTOFFSET(Esp) );
2267         fprintf( outfile, "\taddl $4, %%esp\n" );  /* room for final return address */
2268
2269         fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegCs) );
2270         fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(Eip) );
2271         fprintf( outfile, "\tpushl %%edx\n" );
2272         fprintf( outfile, "\tpushl %%eax\n" );
2273         fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(EFlags) );
2274         fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(SegDs) );
2275
2276         fprintf( outfile, "\tmovw %d(%%ebx), %%es\n", CONTEXTOFFSET(SegEs) );
2277         fprintf( outfile, "\tmovw %d(%%ebx), %%fs\n", CONTEXTOFFSET(SegFs) );
2278         fprintf( outfile, "\tmovw %d(%%ebx), %%gs\n", CONTEXTOFFSET(SegGs) );
2279
2280         fprintf( outfile, "\tmovl %d(%%ebx), %%ebp\n", CONTEXTOFFSET(Ebp) );
2281         fprintf( outfile, "\tmovl %d(%%ebx), %%esi\n", CONTEXTOFFSET(Esi) );
2282         fprintf( outfile, "\tmovl %d(%%ebx), %%edi\n", CONTEXTOFFSET(Edi) );
2283         fprintf( outfile, "\tmovl %d(%%ebx), %%eax\n", CONTEXTOFFSET(Eax) );
2284         fprintf( outfile, "\tmovl %d(%%ebx), %%edx\n", CONTEXTOFFSET(Edx) );
2285         fprintf( outfile, "\tmovl %d(%%ebx), %%ecx\n", CONTEXTOFFSET(Ecx) );
2286         fprintf( outfile, "\tmovl %d(%%ebx), %%ebx\n", CONTEXTOFFSET(Ebx) );
2287   
2288         fprintf( outfile, "\tpopl %%ds\n" );
2289         fprintf( outfile, "\tpopfl\n" );
2290         fprintf( outfile, "\tlret\n" );
2291     }
2292     else
2293     {
2294         /* Switch stack back */
2295         /* fprintf( outfile, "\t.byte 0x64\n\tlssw (%d), %%sp\n", STACKOFFSET ); */
2296         fprintf( outfile, "\t.byte 0x64,0x66,0x0f,0xb2,0x25\n\t.long %d\n", STACKOFFSET );
2297         fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
2298
2299         /* Restore registers */
2300         fprintf( outfile, "\tpopl %%edx\n" );
2301         fprintf( outfile, "\tpopl %%ecx\n" );
2302         fprintf( outfile, "\tpopl %%ebp\n" );
2303         fprintf( outfile, "\tpopw %%ds\n" );
2304         fprintf( outfile, "\tpopw %%es\n" );
2305         fprintf( outfile, "\tpopw %%fs\n" );
2306         fprintf( outfile, "\tpopw %%gs\n" );
2307
2308         /* Prepare return value and set flags accordingly */
2309         if ( !short_ret )
2310             fprintf( outfile, "\tshldl $16, %%eax, %%edx\n" );
2311         fprintf( outfile, "\torl %%eax, %%eax\n" );
2312
2313         /* Return to return stub which will return to caller */
2314         fprintf( outfile, "\tlret $12\n" );
2315     }
2316 }
2317   
2318
2319 /*******************************************************************
2320  *         BuildCallTo16Core
2321  *
2322  * This routine builds the core routines used in 32->16 thunks:
2323  *
2324  *   extern void CALLBACK CallTo16Word( SEGPTR target, int nb_args );
2325  *   extern void CALLBACK CallTo16Long( SEGPTR target, int nb_args );
2326  *   extern void CALLBACK CallTo16RegisterShort( const CONTEXT86 *context, int nb_args );
2327  *   extern void CALLBACK CallTo16RegisterLong ( const CONTEXT86 *context, int nb_args );
2328  *
2329  * These routines can be called directly from 32-bit code. 
2330  *
2331  * All routines expect that the 16-bit stack contents (arguments) were 
2332  * already set up by the caller; nb_args must contain the number of bytes 
2333  * to be conserved.  The 16-bit SS:SP will be set accordinly.
2334  *
2335  * All other registers are either taken from the CONTEXT86 structure 
2336  * or else set to default values.  The target routine address is either
2337  * given directly or taken from the CONTEXT86.
2338  *
2339  * If you want to call a 16-bit routine taking only standard argument types 
2340  * (WORD and LONG), you can also have an appropriate argument conversion 
2341  * stub automatically generated (see BuildCallTo16); you'd then call this
2342  * stub, which in turn would prepare the 16-bit stack and call the appropiate
2343  * core routine.
2344  *
2345  */
2346
2347 static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func )
2348 {
2349     char *name = reg_func == 2 ? "RegisterLong" : 
2350                  reg_func == 1 ? "RegisterShort" :
2351                  short_ret? "Word" : "Long";
2352
2353     /* Function header */
2354     fprintf( outfile, "\n\t.align 4\n" );
2355 #ifdef USE_STABS
2356     fprintf( outfile, ".stabs \"CallTo16%s:F1\",36,0,0," PREFIX "CallTo16%s\n", 
2357              name, name);
2358 #endif
2359     fprintf( outfile, "\t.type " PREFIX "CallTo16%s,@function\n", name );
2360     fprintf( outfile, "\t.globl " PREFIX "CallTo16%s\n", name );
2361     fprintf( outfile, PREFIX "CallTo16%s:\n", name );
2362
2363     /* Function entry sequence */
2364     fprintf( outfile, "\tpushl %%ebp\n" );
2365     fprintf( outfile, "\tmovl %%esp, %%ebp\n" );
2366
2367     /* Save the 32-bit registers */
2368     fprintf( outfile, "\tpushl %%ebx\n" );
2369     fprintf( outfile, "\tpushl %%ecx\n" );
2370     fprintf( outfile, "\tpushl %%edx\n" );
2371     fprintf( outfile, "\tpushl %%esi\n" );
2372     fprintf( outfile, "\tpushl %%edi\n" );
2373
2374     if ( UsePIC )
2375     {
2376         /* Get Global Offset Table into %ebx */
2377         fprintf( outfile, "\tcall .LCallTo16%s.getgot1\n", name );
2378         fprintf( outfile, ".LCallTo16%s.getgot1:\n", name );
2379         fprintf( outfile, "\tpopl %%ebx\n" );
2380         fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.LCallTo16%s.getgot1], %%ebx\n", name );
2381     }
2382
2383     /* Enter Win16 Mutex */
2384     if ( UsePIC )
2385         fprintf( outfile, "\tcall " PREFIX "SYSLEVEL_EnterWin16Lock@PLT\n" );
2386     else
2387         fprintf( outfile, "\tcall " PREFIX "SYSLEVEL_EnterWin16Lock\n" );
2388
2389     /* Print debugging info */
2390     if (debugging)
2391     {
2392         /* Push flags, number of arguments, and target */
2393         fprintf( outfile, "\tpushl $%d\n", reg_func );
2394         fprintf( outfile, "\tpushl 12(%%ebp)\n" );
2395         fprintf( outfile, "\tpushl  8(%%ebp)\n" );
2396
2397         if ( UsePIC )
2398             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16@PLT\n" );
2399         else
2400             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16\n" );
2401
2402         fprintf( outfile, "\taddl $12, %%esp\n" );
2403     }
2404
2405     /* Get return address */
2406     if ( UsePIC )
2407     {
2408         fprintf( outfile, "\tmovl " PREFIX "CallTo16_RetAddr@GOT(%%ebx), %%ecx\n" );
2409         fprintf( outfile, "\tmovl " PREFIX "(%%ecx), %%ecx\n" );
2410     }
2411     else
2412         fprintf( outfile, "\tmovl " PREFIX "CallTo16_RetAddr, %%ecx\n" );
2413
2414     /* Call the actual CallTo16 routine (simulate a lcall) */
2415     fprintf( outfile, "\tpushl %%cs\n" );
2416     fprintf( outfile, "\tcall .LCallTo16%s\n", name );
2417
2418     /* Convert and push return value */
2419     if ( short_ret )
2420     {
2421         fprintf( outfile, "\tmovzwl %%ax, %%eax\n" );
2422         fprintf( outfile, "\tpushl %%eax\n" );
2423     }
2424     else if ( reg_func != 2 )
2425     {
2426         fprintf( outfile, "\tshll $16,%%edx\n" );
2427         fprintf( outfile, "\tmovw %%ax,%%dx\n" );
2428         fprintf( outfile, "\tpushl %%edx\n" );
2429     }
2430     else
2431         fprintf( outfile, "\tpushl %%eax\n" );
2432
2433     if ( UsePIC )
2434     {
2435         /* Get Global Offset Table into %ebx (might have been overwritten) */
2436         fprintf( outfile, "\tcall .LCallTo16%s.getgot2\n", name );
2437         fprintf( outfile, ".LCallTo16%s.getgot2:\n", name );
2438         fprintf( outfile, "\tpopl %%ebx\n" );
2439         fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.LCallTo16%s.getgot2], %%ebx\n", name );
2440     }
2441
2442     /* Print debugging info */
2443     if (debugging)
2444     {
2445         if ( UsePIC )
2446             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16Ret@PLT\n" );
2447         else
2448             fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16Ret\n" );
2449     }
2450
2451     /* Leave Win16 Mutex */
2452     if ( UsePIC )
2453         fprintf( outfile, "\tcall " PREFIX "SYSLEVEL_LeaveWin16Lock@PLT\n" );
2454     else
2455         fprintf( outfile, "\tcall " PREFIX "SYSLEVEL_LeaveWin16Lock\n" );
2456
2457     /* Get return value */
2458     fprintf( outfile, "\tpopl %%eax\n" );
2459
2460     /* Restore the 32-bit registers */
2461     fprintf( outfile, "\tpopl %%edi\n" );
2462     fprintf( outfile, "\tpopl %%esi\n" );
2463     fprintf( outfile, "\tpopl %%edx\n" );
2464     fprintf( outfile, "\tpopl %%ecx\n" );
2465     fprintf( outfile, "\tpopl %%ebx\n" );
2466
2467     /* Function exit sequence */
2468     fprintf( outfile, "\tpopl %%ebp\n" );
2469     fprintf( outfile, "\tret $8\n" );
2470
2471
2472     /* Start of the actual CallTo16 routine */
2473
2474     fprintf( outfile, ".LCallTo16%s:\n", name );
2475
2476     /* Complete STACK32FRAME */
2477     fprintf( outfile, "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET );
2478     fprintf( outfile, "\tmovl %%esp,%%edx\n" );
2479
2480     /* Switch to the 16-bit stack */
2481 #ifdef __svr4__
2482     fprintf( outfile,"\tdata16\n");
2483 #endif
2484     fprintf( outfile, "\t.byte 0x64\n\tmovw (%d),%%ss\n", STACKOFFSET + 2);
2485     fprintf( outfile, "\t.byte 0x64\n\tmovw (%d),%%sp\n", STACKOFFSET );
2486     fprintf( outfile, "\t.byte 0x64\n\tmovl %%edx,(%d)\n", STACKOFFSET );
2487
2488     /* Make %bp point to the previous stackframe (built by CallFrom16) */
2489     fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
2490     fprintf( outfile, "\tleal %d(%%ebp),%%ebp\n", STACK16OFFSET(bp) );
2491
2492     /* Add the specified offset to the new sp */
2493     fprintf( outfile, "\tsubw %d(%%edx), %%sp\n", STACK32OFFSET(nb_args) );
2494
2495     /* Push the return address 
2496      * With sreg suffix, we push 16:16 address (normal lret)
2497      * With lreg suffix, we push 16:32 address (0x66 lret, for KERNEL32_45)
2498      */
2499     if (reg_func != 2)
2500         fprintf( outfile, "\tpushl %%ecx\n" );
2501     else 
2502     {
2503         fprintf( outfile, "\tshldl $16, %%ecx, %%eax\n" );
2504         fprintf( outfile, "\tpushw $0\n" );
2505         fprintf( outfile, "\tpushw %%ax\n" );
2506         fprintf( outfile, "\tpushw $0\n" );
2507         fprintf( outfile, "\tpushw %%cx\n" );
2508     }
2509
2510     if (reg_func)
2511     {
2512         /* Push the called routine address */
2513         fprintf( outfile, "\tmovl %d(%%edx),%%edx\n", STACK32OFFSET(target) );
2514         fprintf( outfile, "\tpushw %d(%%edx)\n", CONTEXTOFFSET(SegCs) );
2515         fprintf( outfile, "\tpushw %d(%%edx)\n", CONTEXTOFFSET(Eip) );
2516
2517         /* Get the registers */
2518         fprintf( outfile, "\tpushw %d(%%edx)\n", CONTEXTOFFSET(SegDs) );
2519         fprintf( outfile, "\tmovl %d(%%edx),%%eax\n", CONTEXTOFFSET(SegEs) );
2520         fprintf( outfile, "\tmovw %%ax,%%es\n" );
2521         fprintf( outfile, "\tmovl %d(%%edx),%%eax\n", CONTEXTOFFSET(SegFs) );
2522         fprintf( outfile, "\tmovw %%ax,%%fs\n" );
2523         fprintf( outfile, "\tmovl %d(%%edx),%%ebp\n", CONTEXTOFFSET(Ebp) );
2524         fprintf( outfile, "\tmovl %d(%%edx),%%esi\n", CONTEXTOFFSET(Esi) );
2525         fprintf( outfile, "\tmovl %d(%%edx),%%edi\n", CONTEXTOFFSET(Edi) );
2526         fprintf( outfile, "\tmovl %d(%%edx),%%eax\n", CONTEXTOFFSET(Eax) );
2527         fprintf( outfile, "\tmovl %d(%%edx),%%ebx\n", CONTEXTOFFSET(Ebx) );
2528         fprintf( outfile, "\tmovl %d(%%edx),%%ecx\n", CONTEXTOFFSET(Ecx) );
2529         fprintf( outfile, "\tmovl %d(%%edx),%%edx\n", CONTEXTOFFSET(Edx) );
2530
2531         /* Get the 16-bit ds */
2532         fprintf( outfile, "\tpopw %%ds\n" );
2533     }
2534     else  /* not a register function */
2535     {
2536         /* Push the called routine address */
2537         fprintf( outfile, "\tpushl %d(%%edx)\n", STACK32OFFSET(target) );
2538
2539         /* Set %fs to the value saved by the last CallFrom16 */
2540         fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", STACK16OFFSET(fs)-STACK16OFFSET(bp) );
2541         fprintf( outfile, "\tmovw %%ax,%%fs\n" );
2542
2543         /* Set %ds and %es (and %ax just in case) equal to %ss */
2544         fprintf( outfile, "\tmovw %%ss,%%ax\n" );
2545         fprintf( outfile, "\tmovw %%ax,%%ds\n" );
2546         fprintf( outfile, "\tmovw %%ax,%%es\n" );
2547     }
2548
2549     /* Jump to the called routine */
2550     fprintf( outfile, "\t.byte 0x66\n" );
2551     fprintf( outfile, "\tlret\n" );
2552 }
2553
2554 /*******************************************************************
2555  *         BuildRet16Func
2556  *
2557  * Build the return code for 16-bit callbacks
2558  */
2559 static void BuildRet16Func( FILE *outfile )
2560 {
2561     /* 
2562      *  Note: This must reside in the .data section to allow
2563      *        run-time relocation of the SYSLEVEL_Win16CurrentTeb symbol
2564      */
2565
2566     fprintf( outfile, "\n\t.type " PREFIX "CallTo16_Ret,@function\n" );
2567     fprintf( outfile, "\t.globl " PREFIX "CallTo16_Ret\n" );
2568     fprintf( outfile, PREFIX "CallTo16_Ret:\n" );
2569
2570     /* Restore 32-bit segment registers */
2571
2572     fprintf( outfile, "\tmovw $0x%04x,%%bx\n", Data_Selector );
2573 #ifdef __svr4__
2574     fprintf( outfile, "\tdata16\n");
2575 #endif
2576     fprintf( outfile, "\tmovw %%bx,%%ds\n" );
2577 #ifdef __svr4__
2578     fprintf( outfile, "\tdata16\n");
2579 #endif
2580     fprintf( outfile, "\tmovw %%bx,%%es\n" );
2581
2582     fprintf( outfile, "\tmovw " PREFIX "SYSLEVEL_Win16CurrentTeb,%%fs\n" );
2583
2584     /* Restore the 32-bit stack */
2585
2586 #ifdef __svr4__
2587     fprintf( outfile, "\tdata16\n");
2588 #endif
2589     fprintf( outfile, "\tmovw %%bx,%%ss\n" );
2590     fprintf( outfile, "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET );
2591     fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
2592
2593     /* Return to caller */
2594
2595     fprintf( outfile, "\tlret\n" );
2596
2597     /* Declare the return address variable */
2598
2599     fprintf( outfile, "\n\t.globl " PREFIX "CallTo16_RetAddr\n" );
2600     fprintf( outfile, PREFIX "CallTo16_RetAddr:\t.long 0\n" );
2601 }
2602
2603 /*******************************************************************
2604  *         BuildCallTo32CBClient
2605  *
2606  * Call a CBClient relay stub from 32-bit code (KERNEL.620).
2607  *
2608  * Since the relay stub is itself 32-bit, this should not be a problem;
2609  * unfortunately, the relay stubs are expected to switch back to a 
2610  * 16-bit stack (and 16-bit code) after completion :-(
2611  *
2612  * This would conflict with our 16- vs. 32-bit stack handling, so
2613  * we simply switch *back* to our 32-bit stack before returning to
2614  * the caller ...
2615  *
2616  * The CBClient relay stub expects to be called with the following
2617  * 16-bit stack layout, and with ebp and ebx pointing into the 16-bit
2618  * stack at the designated places:
2619  *
2620  *    ...
2621  *  (ebp+14) original arguments to the callback routine
2622  *  (ebp+10) far return address to original caller
2623  *  (ebp+6)  Thunklet target address
2624  *  (ebp+2)  Thunklet relay ID code
2625  *  (ebp)    BP (saved by CBClientGlueSL)
2626  *  (ebp-2)  SI (saved by CBClientGlueSL)
2627  *  (ebp-4)  DI (saved by CBClientGlueSL)
2628  *  (ebp-6)  DS (saved by CBClientGlueSL)
2629  *
2630  *   ...     buffer space used by the 16-bit side glue for temp copies
2631  *
2632  *  (ebx+4)  far return address to 16-bit side glue code
2633  *  (ebx)    saved 16-bit ss:sp (pointing to ebx+4)
2634  *
2635  * The 32-bit side glue code accesses both the original arguments (via ebp)
2636  * and the temporary copies prepared by the 16-bit side glue (via ebx).
2637  * After completion, the stub will load ss:sp from the buffer at ebx
2638  * and perform a far return to 16-bit code.  
2639  *
2640  * To trick the relay stub into returning to us, we replace the 16-bit
2641  * return address to the glue code by a cs:ip pair pointing to our
2642  * return entry point (the original return address is saved first).
2643  * Our return stub thus called will then reload the 32-bit ss:esp and
2644  * return to 32-bit code (by using and ss:esp value that we have also
2645  * pushed onto the 16-bit stack before and a cs:eip values found at
2646  * that position on the 32-bit stack).  The ss:esp to be restored is
2647  * found relative to the 16-bit stack pointer at:
2648  *
2649  *  (ebx-4)   ss  (flat)
2650  *  (ebx-8)   sp  (32-bit stack pointer)
2651  *
2652  * The second variant of this routine, CALL32_CBClientEx, which is used
2653  * to implement KERNEL.621, has to cope with yet another problem: Here,
2654  * the 32-bit side directly returns to the caller of the CBClient thunklet,
2655  * restoring registers saved by CBClientGlueSL and cleaning up the stack.
2656  * As we have to return to our 32-bit code first, we have to adapt the
2657  * layout of our temporary area so as to include values for the registers
2658  * that are to be restored, and later (in the implementation of KERNEL.621)
2659  * we *really* restore them. The return stub restores DS, DI, SI, and BP
2660  * from the stack, skips the next 8 bytes (CBClient relay code / target),
2661  * and then performs a lret NN, where NN is the number of arguments to be
2662  * removed. Thus, we prepare our temporary area as follows:
2663  *
2664  *     (ebx+22) 16-bit cs  (this segment)
2665  *     (ebx+20) 16-bit ip  ('16-bit' return entry point)
2666  *     (ebx+16) 32-bit ss  (flat)
2667  *     (ebx+12) 32-bit sp  (32-bit stack pointer)
2668  *     (ebx+10) 16-bit bp  (points to ebx+24)
2669  *     (ebx+8)  16-bit si  (ignored)
2670  *     (ebx+6)  16-bit di  (ignored)
2671  *     (ebx+4)  16-bit ds  (we actually use the flat DS here)
2672  *     (ebx+2)  16-bit ss  (16-bit stack segment)
2673  *     (ebx+0)  16-bit sp  (points to ebx+4)
2674  *
2675  * Note that we ensure that DS is not changed and remains the flat segment,
2676  * and the 32-bit stack pointer our own return stub needs fits just 
2677  * perfectly into the 8 bytes that are skipped by the Windows stub.
2678  * One problem is that we have to determine the number of removed arguments,
2679  * as these have to be really removed in KERNEL.621. Thus, the BP value 
2680  * that we place in the temporary area to be restored, contains the value 
2681  * that SP would have if no arguments were removed. By comparing the actual
2682  * value of SP with this value in our return stub we can compute the number
2683  * of removed arguments. This is then returned to KERNEL.621.
2684  *
2685  * The stack layout of this function:
2686  * (ebp+20)  nArgs     pointer to variable receiving nr. of args (Ex only)
2687  * (ebp+16)  esi       pointer to caller's esi value
2688  * (ebp+12)  arg       ebp value to be set for relay stub
2689  * (ebp+8)   func      CBClient relay stub address
2690  * (ebp+4)   ret addr
2691  * (ebp)     ebp
2692  */
2693 static void BuildCallTo32CBClient( FILE *outfile, BOOL isEx )
2694 {
2695     char *name = isEx? "CBClientEx" : "CBClient";
2696     int size = isEx? 24 : 12;
2697
2698     /* Function header */
2699
2700     fprintf( outfile, "\n\t.align 4\n" );
2701 #ifdef USE_STABS
2702     fprintf( outfile, ".stabs \"CALL32_%s:F1\",36,0,0," PREFIX "CALL32_%s\n",
2703                       name, name );
2704 #endif
2705     fprintf( outfile, "\t.globl " PREFIX "CALL32_%s\n", name );
2706     fprintf( outfile, PREFIX "CALL32_%s:\n", name );
2707
2708     /* Entry code */
2709
2710     fprintf( outfile, "\tpushl %%ebp\n" );
2711     fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
2712     fprintf( outfile, "\tpushl %%edi\n" );
2713     fprintf( outfile, "\tpushl %%esi\n" );
2714     fprintf( outfile, "\tpushl %%ebx\n" );
2715
2716     /* Get the 16-bit stack */
2717
2718     fprintf( outfile, "\t.byte 0x64\n\tmovl (%d),%%ebx\n", STACKOFFSET);
2719     
2720     /* Convert it to a flat address */
2721
2722     fprintf( outfile, "\tshldl $16,%%ebx,%%eax\n" );
2723     fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
2724     fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%esi\n" );
2725     fprintf( outfile, "\tmovw %%bx,%%ax\n" );
2726     fprintf( outfile, "\taddl %%eax,%%esi\n" );
2727
2728     /* Allocate temporary area (simulate STACK16_PUSH) */
2729
2730     fprintf( outfile, "\tpushf\n" );
2731     fprintf( outfile, "\tcld\n" );
2732     fprintf( outfile, "\tleal -%d(%%esi), %%edi\n", size );
2733     fprintf( outfile, "\tmovl $%d, %%ecx\n", sizeof(STACK16FRAME) );
2734     fprintf( outfile, "\trep\n\tmovsb\n" );
2735     fprintf( outfile, "\tpopf\n" );
2736
2737     fprintf( outfile, "\t.byte 0x64\n\tsubw $%d,(%d)\n", size, STACKOFFSET );
2738
2739     fprintf( outfile, "\tpushl %%edi\n" );  /* remember address */
2740
2741     /* Set up temporary area */
2742
2743     if ( !isEx )
2744     {
2745         fprintf( outfile, "\tleal 4(%%edi), %%edi\n" );
2746
2747         fprintf( outfile, "\tleal -8(%%esp), %%eax\n" );
2748         fprintf( outfile, "\tmovl %%eax, -8(%%edi)\n" );    /* 32-bit sp */
2749
2750         fprintf( outfile, "\tmovw %%ss, %%ax\n" );
2751         fprintf( outfile, "\tandl $0x0000ffff, %%eax\n" );
2752         fprintf( outfile, "\tmovl %%eax, -4(%%edi)\n" );    /* 32-bit ss */
2753
2754         fprintf( outfile, "\taddl $%d, %%ebx\n", sizeof(STACK16FRAME)-size+4 + 4 );
2755         fprintf( outfile, "\tmovl %%ebx, 0(%%edi)\n" );    /* 16-bit ss:sp */
2756
2757         fprintf( outfile, "\tmovl " PREFIX "CALL32_%s_RetAddr, %%eax\n", name );
2758         fprintf( outfile, "\tmovl %%eax, 4(%%edi)\n" );   /* overwrite return address */
2759     }
2760     else
2761     {
2762         fprintf( outfile, "\taddl $%d, %%ebx\n", sizeof(STACK16FRAME)-size+4 );
2763         fprintf( outfile, "\tmovl %%ebx, 0(%%edi)\n" );
2764
2765         fprintf( outfile, "\tmovw %%ds, %%ax\n" );
2766         fprintf( outfile, "\tmovw %%ax, 4(%%edi)\n" );
2767
2768         fprintf( outfile, "\taddl $20, %%ebx\n" );
2769         fprintf( outfile, "\tmovw %%bx, 10(%%edi)\n" );
2770
2771         fprintf( outfile, "\tleal -8(%%esp), %%eax\n" );
2772         fprintf( outfile, "\tmovl %%eax, 12(%%edi)\n" );
2773
2774         fprintf( outfile, "\tmovw %%ss, %%ax\n" );
2775         fprintf( outfile, "\tandl $0x0000ffff, %%eax\n" );
2776         fprintf( outfile, "\tmovl %%eax, 16(%%edi)\n" );
2777
2778         fprintf( outfile, "\tmovl " PREFIX "CALL32_%s_RetAddr, %%eax\n", name );
2779         fprintf( outfile, "\tmovl %%eax, 20(%%edi)\n" );
2780     }
2781
2782     /* Set up registers and call CBClient relay stub (simulating a far call) */
2783
2784     fprintf( outfile, "\tmovl 16(%%ebp), %%esi\n" );
2785     fprintf( outfile, "\tmovl (%%esi), %%esi\n" );
2786
2787     fprintf( outfile, "\tmovl %%edi, %%ebx\n" );
2788     fprintf( outfile, "\tmovl 8(%%ebp), %%eax\n" );
2789     fprintf( outfile, "\tmovl 12(%%ebp), %%ebp\n" );
2790
2791     fprintf( outfile, "\tpushl %%cs\n" );
2792     fprintf( outfile, "\tcall *%%eax\n" );
2793
2794     /* Return new esi value to caller */
2795
2796     fprintf( outfile, "\tmovl 32(%%esp), %%edi\n" );
2797     fprintf( outfile, "\tmovl %%esi, (%%edi)\n" );
2798
2799     /* Cleanup temporary area (simulate STACK16_POP) */
2800
2801     fprintf( outfile, "\tpop %%esi\n" );
2802
2803     fprintf( outfile, "\tpushf\n" );
2804     fprintf( outfile, "\tstd\n" );
2805     fprintf( outfile, "\tdec %%esi\n" );
2806     fprintf( outfile, "\tleal %d(%%esi), %%edi\n", size );
2807     fprintf( outfile, "\tmovl $%d, %%ecx\n", sizeof(STACK16FRAME) );
2808     fprintf( outfile, "\trep\n\tmovsb\n" );
2809     fprintf( outfile, "\tpopf\n" );
2810
2811     fprintf( outfile, "\t.byte 0x64\n\taddw $%d,(%d)\n", size, STACKOFFSET );
2812
2813     /* Return argument size to caller */
2814     if ( isEx )
2815     {
2816         fprintf( outfile, "\tmovl 32(%%esp), %%ebx\n" );
2817         fprintf( outfile, "\tmovl %%ebp, (%%ebx)\n" );
2818     }
2819
2820     /* Restore registers and return */
2821
2822     fprintf( outfile, "\tpopl %%ebx\n" );
2823     fprintf( outfile, "\tpopl %%esi\n" );
2824     fprintf( outfile, "\tpopl %%edi\n" );
2825     fprintf( outfile, "\tpopl %%ebp\n" );
2826     fprintf( outfile, "\tret\n" );
2827 }
2828
2829 static void BuildCallTo32CBClientRet( FILE *outfile, BOOL isEx )
2830 {
2831     char *name = isEx? "CBClientEx" : "CBClient";
2832
2833     /* '16-bit' return stub */
2834
2835     fprintf( outfile, "\n\t.globl " PREFIX "CALL32_%s_Ret\n", name );
2836     fprintf( outfile, PREFIX "CALL32_%s_Ret:\n", name );
2837
2838     if ( !isEx )
2839     {
2840         fprintf( outfile, "\tmovzwl %%sp, %%ebx\n" );
2841         fprintf( outfile, "\tlssl %%ss:-16(%%ebx), %%esp\n" );
2842     }
2843     else
2844     {
2845         fprintf( outfile, "\tmovzwl %%bp, %%ebx\n" );
2846         fprintf( outfile, "\tsubw %%bp, %%sp\n" );
2847         fprintf( outfile, "\tmovzwl %%sp, %%ebp\n" );
2848         fprintf( outfile, "\tlssl %%ss:-12(%%ebx), %%esp\n" );
2849     }
2850     fprintf( outfile, "\tlret\n" );
2851
2852     /* Declare the return address variable */
2853
2854     fprintf( outfile, "\n\t.globl " PREFIX "CALL32_%s_RetAddr\n", name );
2855     fprintf( outfile, PREFIX "CALL32_%s_RetAddr:\t.long 0\n", name );
2856 }
2857
2858
2859
2860 /*******************************************************************
2861  *         BuildCallFrom32Regs
2862  *
2863  * Build a 32-bit-to-Wine call-back function for a 'register' function.
2864  * 'args' is the number of dword arguments.
2865  *
2866  * Stack layout:
2867  *   ...
2868  * (ebp+12)  first arg
2869  * (ebp+8)   ret addr to user code
2870  * (ebp+4)   ret addr to relay code
2871  * (ebp+0)   saved ebp
2872  * (ebp-128) buffer area to allow stack frame manipulation
2873  * (ebp-332) CONTEXT86 struct
2874  * (ebp-336) CONTEXT86 *argument
2875  *  ....     other arguments copied from (ebp+12)
2876  *
2877  * The entry point routine is called with a CONTEXT* extra argument,
2878  * following the normal args. In this context structure, EIP_reg
2879  * contains the return address to user code, and ESP_reg the stack
2880  * pointer on return (with the return address and arguments already
2881  * removed).
2882  */
2883 static void BuildCallFrom32Regs( FILE *outfile )
2884 {
2885     static const int STACK_SPACE = 128 + sizeof(CONTEXT86);
2886
2887     /* Function header */
2888
2889     fprintf( outfile, "\n\t.align 4\n" );
2890 #ifdef USE_STABS
2891     fprintf( outfile, ".stabs \"CALL32_Regs:F1\",36,0,0," PREFIX "CALL32_Regs\n" );
2892 #endif
2893     fprintf( outfile, "\t.globl " PREFIX "CALL32_Regs\n" );
2894     fprintf( outfile, PREFIX "CALL32_Regs:\n" );
2895
2896     /* Allocate some buffer space on the stack */
2897
2898     fprintf( outfile, "\tpushl %%ebp\n" );
2899     fprintf( outfile, "\tmovl %%esp,%%ebp\n ");
2900     fprintf( outfile, "\tleal -%d(%%esp), %%esp\n", STACK_SPACE );
2901     
2902     /* Build the context structure */
2903
2904     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
2905     fprintf( outfile, "\tpushfl\n" );
2906     fprintf( outfile, "\tpopl %%eax\n" );
2907     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(EFlags) - STACK_SPACE );
2908     fprintf( outfile, "\tmovl 0(%%ebp),%%eax\n" );
2909     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Ebp) - STACK_SPACE );
2910     fprintf( outfile, "\tmovl %%ebx,%d(%%ebp)\n", CONTEXTOFFSET(Ebx) - STACK_SPACE );
2911     fprintf( outfile, "\tmovl %%ecx,%d(%%ebp)\n", CONTEXTOFFSET(Ecx) - STACK_SPACE );
2912     fprintf( outfile, "\tmovl %%edx,%d(%%ebp)\n", CONTEXTOFFSET(Edx) - STACK_SPACE );
2913     fprintf( outfile, "\tmovl %%esi,%d(%%ebp)\n", CONTEXTOFFSET(Esi) - STACK_SPACE );
2914     fprintf( outfile, "\tmovl %%edi,%d(%%ebp)\n", CONTEXTOFFSET(Edi) - STACK_SPACE );
2915
2916     fprintf( outfile, "\txorl %%eax,%%eax\n" );
2917     fprintf( outfile, "\tmovw %%cs,%%ax\n" );
2918     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegCs) - STACK_SPACE );
2919     fprintf( outfile, "\tmovw %%es,%%ax\n" );
2920     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegEs) - STACK_SPACE );
2921     fprintf( outfile, "\tmovw %%fs,%%ax\n" );
2922     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegFs) - STACK_SPACE );
2923     fprintf( outfile, "\tmovw %%gs,%%ax\n" );
2924     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegGs) - STACK_SPACE );
2925     fprintf( outfile, "\tmovw %%ss,%%ax\n" );
2926     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegSs) - STACK_SPACE );
2927     fprintf( outfile, "\tmovw %%ds,%%ax\n" );
2928     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegDs) - STACK_SPACE );
2929     fprintf( outfile, "\tmovw %%ax,%%es\n" );  /* set %es equal to %ds just in case */
2930
2931     fprintf( outfile, "\tmovl $0x%x,%%eax\n", CONTEXT86_FULL );
2932     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(ContextFlags) - STACK_SPACE );
2933
2934     fprintf( outfile, "\tmovl 8(%%ebp),%%eax\n" ); /* Get %eip at time of call */
2935     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eip) - STACK_SPACE );
2936
2937     /* Transfer the arguments */
2938
2939     fprintf( outfile, "\tmovl 4(%%ebp),%%ebx\n" );   /* get relay code addr */
2940     fprintf( outfile, "\tpushl %%esp\n" );           /* push ptr to context struct */
2941     fprintf( outfile, "\tmovzbl 4(%%ebx),%%ecx\n" ); /* fetch number of args to copy */
2942     fprintf( outfile, "\tjecxz 1f\n" );
2943     fprintf( outfile, "\tsubl %%ecx,%%esp\n" );
2944     fprintf( outfile, "\tleal 12(%%ebp),%%esi\n" );  /* get %esp at time of call */
2945     fprintf( outfile, "\tmovl %%esp,%%edi\n" );
2946     fprintf( outfile, "\tshrl $2,%%ecx\n" );
2947     fprintf( outfile, "\tcld\n" );
2948     fprintf( outfile, "\trep\n\tmovsl\n" );  /* copy args */
2949
2950     fprintf( outfile, "1:\tmovzbl 5(%%ebx),%%eax\n" ); /* fetch number of args to remove */
2951     fprintf( outfile, "\tleal 12(%%ebp,%%eax),%%eax\n" );
2952     fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
2953
2954     /* Call the entry point */
2955
2956     fprintf( outfile, "\tcall *0(%%ebx)\n" );
2957
2958     /* Store %eip and %ebp onto the new stack */
2959
2960     fprintf( outfile, "\tmovl %d(%%ebp),%%edx\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
2961     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eip) - STACK_SPACE );
2962     fprintf( outfile, "\tmovl %%eax,-4(%%edx)\n" );
2963     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Ebp) - STACK_SPACE );
2964     fprintf( outfile, "\tmovl %%eax,-8(%%edx)\n" );
2965
2966     /* Restore the context structure */
2967
2968     /* Note: we don't bother to restore %cs, %ds and %ss
2969      *       changing them in 32-bit code is a recipe for disaster anyway
2970      */
2971     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegEs) - STACK_SPACE );
2972     fprintf( outfile, "\tmovw %%ax,%%es\n" );
2973     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegFs) - STACK_SPACE );
2974     fprintf( outfile, "\tmovw %%ax,%%fs\n" );
2975     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegGs) - STACK_SPACE );
2976     fprintf( outfile, "\tmovw %%ax,%%gs\n" );
2977
2978     fprintf( outfile, "\tmovl %d(%%ebp),%%edi\n", CONTEXTOFFSET(Edi) - STACK_SPACE );
2979     fprintf( outfile, "\tmovl %d(%%ebp),%%esi\n", CONTEXTOFFSET(Esi) - STACK_SPACE );
2980     fprintf( outfile, "\tmovl %d(%%ebp),%%edx\n", CONTEXTOFFSET(Edx) - STACK_SPACE );
2981     fprintf( outfile, "\tmovl %d(%%ebp),%%ecx\n", CONTEXTOFFSET(Ecx) - STACK_SPACE );
2982     fprintf( outfile, "\tmovl %d(%%ebp),%%ebx\n", CONTEXTOFFSET(Ebx) - STACK_SPACE );
2983
2984     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(EFlags) - STACK_SPACE );
2985     fprintf( outfile, "\tpushl %%eax\n" );
2986     fprintf( outfile, "\tpopfl\n" );
2987     fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
2988
2989     fprintf( outfile, "\tmovl %d(%%ebp),%%ebp\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
2990     fprintf( outfile, "\tleal -8(%%ebp),%%esp\n" );
2991     fprintf( outfile, "\tpopl %%ebp\n" );
2992     fprintf( outfile, "\tret\n" );
2993 }
2994
2995
2996 /*******************************************************************
2997  *         BuildGlue
2998  *
2999  * Build the 16-bit-to-Wine/Wine-to-16-bit callback glue code
3000  */
3001 static void BuildGlue( FILE *outfile, FILE *infile )
3002 {
3003     char buffer[1024];
3004
3005     /* File header */
3006
3007     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
3008              input_file_name );
3009     fprintf( outfile, "#include \"builtin16.h\"\n" );
3010     fprintf( outfile, "#include \"stackframe.h\"\n\n" );
3011
3012     /* Build the callback glue functions */
3013
3014     while (fgets( buffer, sizeof(buffer), infile ))
3015     {
3016         if (strstr( buffer, "### start build ###" )) break;
3017     }
3018     while (fgets( buffer, sizeof(buffer), infile ))
3019     {
3020         char *p; 
3021         if ( (p = strstr( buffer, "CallFrom16_" )) != NULL )
3022         {
3023             char *q, *profile = p + strlen( "CallFrom16_" );
3024             for (q = profile; (*q == '_') || isalpha(*q); q++ )
3025                 ;
3026             *q = '\0';
3027             for (q = p-1; q > buffer && ((*q == '_') || isalnum(*q)); q-- )
3028                 ;
3029             if ( ++q < p ) p[-1] = '\0'; else q = "";
3030             BuildCallFrom16Func( outfile, profile, q, FALSE );
3031         }
3032         if ( (p = strstr( buffer, "CallTo16_" )) != NULL )
3033         {
3034             char *q, *profile = p + strlen( "CallTo16_" );
3035             for (q = profile; (*q == '_') || isalpha(*q); q++ )
3036                 ;
3037             *q = '\0';
3038             for (q = p-1; q > buffer && ((*q == '_') || isalnum(*q)); q-- )
3039                 ;
3040             if ( ++q < p ) p[-1] = '\0'; else q = "";
3041             BuildCallTo16Func( outfile, profile, q );
3042         }
3043         if (strstr( buffer, "### stop build ###" )) break;
3044     }
3045
3046     fclose( infile );
3047 }
3048
3049 /*******************************************************************
3050  *         BuildCall16
3051  *
3052  * Build the 16-bit callbacks
3053  */
3054 static void BuildCall16( FILE *outfile )
3055 {
3056     /* File header */
3057
3058     fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
3059     fprintf( outfile, "\t.text\n" );
3060
3061 #ifdef __i386__
3062
3063 #ifdef USE_STABS
3064     if (output_file_name)
3065     {
3066         char buffer[1024];
3067         getcwd(buffer, sizeof(buffer));
3068         fprintf( outfile, "\t.file\t\"%s\"\n", output_file_name );
3069
3070         /*
3071          * The stabs help the internal debugger as they are an indication that it
3072          * is sensible to step into a thunk/trampoline.
3073          */
3074         fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
3075         fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", output_file_name );
3076         fprintf( outfile, "Code_Start:\n\n" );
3077     }
3078 #endif
3079     fprintf( outfile, PREFIX"Call16_Start:\n" );
3080     fprintf( outfile, "\t.globl "PREFIX"Call16_Start\n" );
3081     fprintf( outfile, "\t.byte 0\n\n" );
3082
3083
3084     /* Standard CallFrom16 routine (WORD return) */
3085     BuildCallFrom16Core( outfile, FALSE, FALSE, TRUE );
3086
3087     /* Standard CallFrom16 routine (DWORD return) */
3088     BuildCallFrom16Core( outfile, FALSE, FALSE, FALSE );
3089
3090     /* Register CallFrom16 routine */
3091     BuildCallFrom16Core( outfile, TRUE, FALSE, FALSE );
3092
3093     /* C16ThkSL CallFrom16 routine */
3094     BuildCallFrom16Core( outfile, FALSE, TRUE, FALSE );
3095
3096     /* Standard CallTo16 routine (WORD return) */
3097     BuildCallTo16Core( outfile, TRUE, FALSE );
3098
3099     /* Standard CallTo16 routine (DWORD return) */
3100     BuildCallTo16Core( outfile, FALSE, FALSE );
3101
3102     /* Register CallTo16 routine (16:16 retf) */
3103     BuildCallTo16Core( outfile, FALSE, 1 );
3104
3105     /* Register CallTo16 routine (16:32 retf) */
3106     BuildCallTo16Core( outfile, FALSE, 2 );
3107
3108     /* CBClientThunkSL routine */
3109     BuildCallTo32CBClient( outfile, FALSE );
3110
3111     /* CBClientThunkSLEx routine */
3112     BuildCallTo32CBClient( outfile, TRUE  );
3113
3114     fprintf( outfile, PREFIX"Call16_End:\n" );
3115     fprintf( outfile, "\t.globl "PREFIX"Call16_End\n" );
3116
3117 #ifdef USE_STABS
3118     fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
3119     fprintf( outfile, ".Letext:\n");
3120 #endif
3121
3122     /* The whole Call16_Ret segment must lie within the .data section */
3123     fprintf( outfile, "\n\t.data\n" );
3124     fprintf( outfile, "\t.globl " PREFIX "Call16_Ret_Start\n" );
3125     fprintf( outfile, PREFIX "Call16_Ret_Start:\n" );
3126
3127     /* Standard CallTo16 return stub */
3128     BuildRet16Func( outfile );
3129
3130     /* CBClientThunkSL return stub */
3131     BuildCallTo32CBClientRet( outfile, FALSE );
3132
3133     /* CBClientThunkSLEx return stub */
3134     BuildCallTo32CBClientRet( outfile, TRUE  );
3135
3136     /* End of Call16_Ret segment */
3137     fprintf( outfile, "\n\t.globl " PREFIX "Call16_Ret_End\n" );
3138     fprintf( outfile, PREFIX "Call16_Ret_End:\n" );
3139
3140 #else  /* __i386__ */
3141
3142     fprintf( outfile, PREFIX"Call16_Start:\n" );
3143     fprintf( outfile, "\t.globl "PREFIX"Call16_Start\n" );
3144     fprintf( outfile, "\t.byte 0\n\n" );
3145     fprintf( outfile, PREFIX"Call16_End:\n" );
3146     fprintf( outfile, "\t.globl "PREFIX"Call16_End\n" );
3147
3148     fprintf( outfile, "\t.globl " PREFIX "Call16_Ret_Start\n" );
3149     fprintf( outfile, PREFIX "Call16_Ret_Start:\n" );
3150     fprintf( outfile, "\t.byte 0\n\n" );
3151     fprintf( outfile, "\n\t.globl " PREFIX "Call16_Ret_End\n" );
3152     fprintf( outfile, PREFIX "Call16_Ret_End:\n" );
3153
3154 #endif  /* __i386__ */
3155 }
3156
3157 /*******************************************************************
3158  *         BuildCall32
3159  *
3160  * Build the 32-bit callbacks
3161  */
3162 static void BuildCall32( FILE *outfile )
3163 {
3164     /* File header */
3165
3166     fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
3167     fprintf( outfile, "\t.text\n" );
3168
3169 #ifdef __i386__
3170
3171 #ifdef USE_STABS
3172     if (output_file_name)
3173     {
3174         char buffer[1024];
3175         getcwd(buffer, sizeof(buffer));
3176         fprintf( outfile, "\t.file\t\"%s\"\n", output_file_name );
3177
3178         /*
3179          * The stabs help the internal debugger as they are an indication that it
3180          * is sensible to step into a thunk/trampoline.
3181          */
3182         fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
3183         fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", output_file_name );
3184         fprintf( outfile, "Code_Start:\n" );
3185     }
3186 #endif
3187
3188     /* Build the register callback function */
3189
3190     BuildCallFrom32Regs( outfile );
3191
3192 #ifdef USE_STABS
3193     fprintf( outfile, "\t.text\n");
3194     fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
3195     fprintf( outfile, ".Letext:\n");
3196 #endif
3197
3198 #else  /* __i386__ */
3199
3200     /* Just to avoid an empty file */
3201     fprintf( outfile, "\t.long 0\n" );
3202
3203 #endif  /* __i386__ */
3204 }
3205
3206
3207 /*******************************************************************
3208  *         usage
3209  */
3210 static void usage(void)
3211 {
3212     fprintf( stderr,
3213              "usage: build [-pic] [-o outfile] -spec SPEC_FILE\n"
3214              "       build [-pic] [-o outfile] -glue SOURCE_FILE\n"
3215              "       build [-pic] [-o outfile] -call16\n"
3216              "       build [-pic] [-o outfile] -call32\n" );
3217     if (output_file_name) unlink( output_file_name );
3218     exit(1);
3219 }
3220
3221
3222 /*******************************************************************
3223  *         open_input
3224  */
3225 static FILE *open_input( const char *name )
3226 {
3227     FILE *f;
3228
3229     if (!name)
3230     {
3231         input_file_name = "<stdin>";
3232         return stdin;
3233     }
3234     input_file_name = name;
3235     if (!(f = fopen( name, "r" )))
3236     {
3237         fprintf( stderr, "Cannot open input file '%s'\n", name );
3238         if (output_file_name) unlink( output_file_name );
3239         exit(1);
3240     }
3241     return f;
3242 }
3243
3244 /*******************************************************************
3245  *         main
3246  */
3247 int main(int argc, char **argv)
3248 {
3249     FILE *outfile = stdout;
3250
3251     if (argc < 2) usage();
3252
3253     if (!strcmp( argv[1], "-pic" ))
3254     {
3255         UsePIC = 1;
3256         argv += 1;
3257         argc -= 1;
3258         if (argc < 2) usage();
3259     }
3260
3261     if (!strcmp( argv[1], "-o" ))
3262     {
3263         output_file_name = argv[2];
3264         argv += 2;
3265         argc -= 2;
3266         if (argc < 2) usage();
3267         if (!(outfile = fopen( output_file_name, "w" )))
3268         {
3269             fprintf( stderr, "Unable to create output file '%s'\n", output_file_name );
3270             exit(1);
3271         }
3272     }
3273
3274     /* Retrieve the selector values; this assumes that we are building
3275      * the asm files on the platform that will also run them. Probably
3276      * a safe assumption to make.
3277      */
3278     Code_Selector = __get_cs();
3279     Data_Selector = __get_ds();
3280
3281     if (!strcmp( argv[1], "-spec" )) BuildSpecFile( outfile, open_input( argv[2] ) );
3282     else if (!strcmp( argv[1], "-glue" )) BuildGlue( outfile, open_input( argv[2] ) );
3283     else if (!strcmp( argv[1], "-call16" )) BuildCall16( outfile );
3284     else if (!strcmp( argv[1], "-call32" )) BuildCall32( outfile );
3285     else
3286     {
3287         fclose( outfile );
3288         usage();
3289     }
3290
3291     fclose( outfile );
3292     return 0;
3293 }