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