Release 971012
[wine] / tools / build.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Martin von Loewis
4  * Copyright 1995, 1996 Alexandre Julliard
5  * Copyright 1997 Eric Youngdale
6  */
7
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <unistd.h>
14
15 #include "windows.h"
16 #include "winnt.h"
17 #include "module.h"
18 #include "neexe.h"
19 #include "selectors.h"
20 #include "stackframe.h"
21
22 #ifdef NEED_UNDERSCORE_PREFIX
23 # define PREFIX "_"
24 #else
25 # define PREFIX
26 #endif
27
28 #if defined(__GNUC__) && !defined(__svr4__)
29 # define USE_STABS
30 #else
31 # undef USE_STABS
32 #endif
33
34 typedef enum
35 {
36     TYPE_INVALID,
37     TYPE_BYTE,         /* byte variable (Win16) */
38     TYPE_WORD,         /* word variable (Win16) */
39     TYPE_LONG,         /* long variable (Win16) */
40     TYPE_PASCAL_16,    /* pascal function with 16-bit return (Win16) */
41     TYPE_PASCAL,       /* pascal function with 32-bit return (Win16) */
42     TYPE_ABS,          /* absolute value (Win16) */
43     TYPE_RETURN,       /* simple return value function (Win16) */
44     TYPE_REGISTER,     /* register function */
45     TYPE_STUB,         /* unimplemented stub */
46     TYPE_STDCALL,      /* stdcall function (Win32) */
47     TYPE_CDECL,        /* cdecl function (Win32) */
48     TYPE_VARARGS,      /* varargs function (Win32) */
49     TYPE_EXTERN,       /* external symbol (Win32) */
50     TYPE_NBTYPES
51 } ORD_TYPE;
52
53 static const char * const TypeNames[TYPE_NBTYPES] =
54 {
55     NULL,
56     "byte",         /* TYPE_BYTE */
57     "word",         /* TYPE_WORD */
58     "long",         /* TYPE_LONG */
59     "pascal16",     /* TYPE_PASCAL_16 */
60     "pascal",       /* TYPE_PASCAL */
61     "equate",       /* TYPE_ABS */
62     "return",       /* TYPE_RETURN */
63     "register",     /* TYPE_REGISTER */
64     "stub",         /* TYPE_STUB */
65     "stdcall",      /* TYPE_STDCALL */
66     "cdecl",        /* TYPE_CDECL */
67     "varargs",      /* TYPE_VARARGS */
68     "extern"        /* TYPE_EXTERN */
69 };
70
71 #define MAX_ORDINALS    1299
72
73   /* Callback function used for stub functions */
74 #define STUB_CALLBACK \
75   ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
76
77 typedef enum
78 {
79     SPEC_INVALID,
80     SPEC_WIN16,
81     SPEC_WIN32
82 } SPEC_TYPE;
83
84 typedef struct
85 {
86     int n_values;
87     int *values;
88 } ORD_VARIABLE;
89
90 typedef struct
91 {
92     int  n_args;
93     char arg_types[32];
94     char link_name[80];
95 } ORD_FUNCTION;
96
97 typedef struct
98 {
99     int arg_size;
100     int ret_value;
101 } ORD_RETURN;
102
103 typedef struct
104 {
105     int value;
106 } ORD_ABS;
107
108 typedef struct
109 {
110     char link_name[80];
111 } ORD_VARARGS;
112
113 typedef struct
114 {
115     char link_name[80];
116 } ORD_EXTERN;
117
118 typedef struct
119 {
120     ORD_TYPE    type;
121     int         offset;
122     int         lineno;
123     char        name[80];
124     union
125     {
126         ORD_VARIABLE   var;
127         ORD_FUNCTION   func;
128         ORD_RETURN     ret;
129         ORD_ABS        abs;
130         ORD_VARARGS    vargs;
131         ORD_EXTERN     ext;
132     } u;
133 } ORDDEF;
134
135 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
136
137 static SPEC_TYPE SpecType = SPEC_INVALID;
138 static char DLLName[80];
139 static char DLLFileName[80];
140 int Limit = 0;
141 int Base = MAX_ORDINALS;
142 int DLLHeapSize = 0;
143 char *SpecName;
144 FILE *SpecFp;
145
146 char *ParseBuffer = NULL;
147 char *ParseNext;
148 char ParseSaveChar;
149 int Line;
150
151 static int debugging = 1;
152
153   /* Offset of a structure field relative to the start of the struct */
154 #define STRUCTOFFSET(type,field) ((int)&((type *)0)->field)
155
156   /* Offset of register relative to the start of the CONTEXT struct */
157 #define CONTEXTOFFSET(reg)  STRUCTOFFSET(CONTEXT,reg)
158
159 static void *xmalloc (size_t size)
160 {
161     void *res;
162
163     res = malloc (size ? size : 1);
164     if (res == NULL)
165     {
166         fprintf (stderr, "Virtual memory exhausted.\n");
167         exit (1);
168     }
169     return res;
170 }
171
172
173 static void *xrealloc (void *ptr, size_t size)
174 {
175     void *res = realloc (ptr, size);
176     if (res == NULL)
177     {
178         fprintf (stderr, "Virtual memory exhausted.\n");
179         exit (1);
180     }
181     return res;
182 }
183
184
185 static int IsNumberString(char *s)
186 {
187     while (*s != '\0')
188         if (!isdigit(*s++))
189             return 0;
190
191     return 1;
192 }
193
194 static char *strupper(char *s)
195 {
196     char *p;
197     
198     for(p = s; *p != '\0'; p++)
199         *p = toupper(*p);
200
201     return s;
202 }
203
204 static char * GetTokenInLine(void)
205 {
206     char *p;
207     char *token;
208
209     if (ParseNext != ParseBuffer)
210     {
211         if (ParseSaveChar == '\0')
212             return NULL;
213         *ParseNext = ParseSaveChar;
214     }
215     
216     /*
217      * Remove initial white space.
218      */
219     for (p = ParseNext; isspace(*p); p++)
220         ;
221     
222     if ((*p == '\0') || (*p == '#'))
223         return NULL;
224     
225     /*
226      * Find end of token.
227      */
228     token = p++;
229     if (*token != '(' && *token != ')')
230         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
231             p++;
232     
233     ParseSaveChar = *p;
234     ParseNext = p;
235     *p = '\0';
236
237     return token;
238 }
239
240 static char * GetToken(void)
241 {
242     char *token;
243
244     if (ParseBuffer == NULL)
245     {
246         ParseBuffer = xmalloc(512);
247         ParseNext = ParseBuffer;
248         while (1)
249         {
250             Line++;
251             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
252                 return NULL;
253             if (ParseBuffer[0] != '#')
254                 break;
255         }
256     }
257
258     while ((token = GetTokenInLine()) == NULL)
259     {
260         ParseNext = ParseBuffer;
261         while (1)
262         {
263             Line++;
264             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
265                 return NULL;
266             if (ParseBuffer[0] != '#')
267                 break;
268         }
269     }
270
271     return token;
272 }
273
274
275 /*******************************************************************
276  *         ParseVariable
277  *
278  * Parse a variable definition.
279  */
280 static int ParseVariable( ORDDEF *odp )
281 {
282     char *endptr;
283     int *value_array;
284     int n_values;
285     int value_array_size;
286     
287     char *token = GetToken();
288     if (*token != '(')
289     {
290         fprintf(stderr, "%s:%d: Expected '(' got '%s'\n",
291                 SpecName, Line, token);
292         return -1;
293     }
294
295     n_values = 0;
296     value_array_size = 25;
297     value_array = xmalloc(sizeof(*value_array) * value_array_size);
298     
299     while ((token = GetToken()) != NULL)
300     {
301         if (*token == ')')
302             break;
303
304         value_array[n_values++] = strtol(token, &endptr, 0);
305         if (n_values == value_array_size)
306         {
307             value_array_size += 25;
308             value_array = xrealloc(value_array, 
309                                    sizeof(*value_array) * value_array_size);
310         }
311         
312         if (endptr == NULL || *endptr != '\0')
313         {
314             fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
315                     SpecName, Line, token);
316             return -1;
317         }
318     }
319     
320     if (token == NULL)
321     {
322         fprintf(stderr, "%s:%d: End of file in variable declaration\n",
323                 SpecName, Line);
324         return -1;
325     }
326
327     odp->u.var.n_values = n_values;
328     odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
329
330     return 0;
331 }
332
333
334 /*******************************************************************
335  *         ParseExportFunction
336  *
337  * Parse a function definition.
338  */
339 static int ParseExportFunction( ORDDEF *odp )
340 {
341     char *token;
342     int i;
343
344     switch(SpecType)
345     {
346     case SPEC_WIN16:
347         if (odp->type == TYPE_STDCALL)
348         {
349             fprintf( stderr, "%s:%d: 'stdcall' not supported for Win16\n",
350                      SpecName, Line );
351             return -1;
352         }
353         if (odp->type == TYPE_CDECL)
354         {
355             fprintf( stderr, "%s:%d: 'cdecl' not supported for Win16\n",
356                      SpecName, Line );
357             return -1;
358         }
359         break;
360     case SPEC_WIN32:
361         if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
362         {
363             fprintf( stderr, "%s:%d: 'pascal' not supported for Win32\n",
364                      SpecName, Line );
365             return -1;
366         }
367         break;
368     default:
369         break;
370     }
371
372     token = GetToken();
373     if (*token != '(')
374     {
375         fprintf(stderr, "%s:%d: Expected '(' got '%s'\n",
376                 SpecName, Line, token);
377         return -1;
378     }
379
380     for (i = 0; i < sizeof(odp->u.func.arg_types)-1; i++)
381     {
382         token = GetToken();
383         if (*token == ')')
384             break;
385
386         if (!strcmp(token, "word"))
387             odp->u.func.arg_types[i] = 'w';
388         else if (!strcmp(token, "s_word"))
389             odp->u.func.arg_types[i] = 's';
390         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
391             odp->u.func.arg_types[i] = 'l';
392         else if (!strcmp(token, "ptr"))
393             odp->u.func.arg_types[i] = 'p';
394         else if (!strcmp(token, "str"))
395             odp->u.func.arg_types[i] = 't';
396         else if (!strcmp(token, "segstr"))
397             odp->u.func.arg_types[i] = 'T';
398         else if (!strcmp(token, "double"))
399         {
400             odp->u.func.arg_types[i++] = 'l';
401             odp->u.func.arg_types[i] = 'l';
402         }
403         else
404         {
405             fprintf(stderr, "%s:%d: Unknown variable type '%s'\n",
406                     SpecName, Line, token);
407             return -1;
408         }
409         if (SpecType == SPEC_WIN32)
410         {
411             if (strcmp(token, "long") &&
412                 strcmp(token, "ptr") &&
413                 strcmp(token, "double"))
414             {
415                 fprintf( stderr, "%s:%d: Type '%s' not supported for Win32\n",
416                          SpecName, Line, token );
417                 return -1;
418             }
419         }
420     }
421     if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
422     {
423         fprintf( stderr, "%s:%d: Too many arguments\n", SpecName, Line );
424         return -1;
425     }
426     odp->u.func.arg_types[i] = '\0';
427     if ((odp->type == TYPE_STDCALL) && !i)
428         odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
429     if ((odp->type == TYPE_REGISTER) && (SpecType == SPEC_WIN32) && i)
430     {
431         fprintf( stderr, "%s:%d: register functions cannot have arguments in Win32\n",
432                  SpecName, Line );
433         return -1;
434     }
435     strcpy(odp->u.func.link_name, GetToken());
436     return 0;
437 }
438
439
440 /*******************************************************************
441  *         ParseEquate
442  *
443  * Parse an 'equate' definition.
444  */
445 static int ParseEquate( ORDDEF *odp )
446 {
447     char *endptr;
448     
449     char *token = GetToken();
450     int value = strtol(token, &endptr, 0);
451     if (endptr == NULL || *endptr != '\0')
452     {
453         fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
454                 SpecName, Line, token);
455         return -1;
456     }
457
458     if (SpecType == SPEC_WIN32)
459     {
460         fprintf( stderr, "%s:%d: 'equate' not supported for Win32\n",
461                  SpecName, Line );
462         return -1;
463     }
464
465     odp->u.abs.value = value;
466     return 0;
467 }
468
469
470 /*******************************************************************
471  *         ParseReturn
472  *
473  * Parse a 'return' definition.
474  */
475 static int ParseReturn( ORDDEF *odp )
476 {
477     char *token;
478     char *endptr;
479     
480     token = GetToken();
481     odp->u.ret.arg_size = strtol(token, &endptr, 0);
482     if (endptr == NULL || *endptr != '\0')
483     {
484         fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
485                 SpecName, Line, token);
486         return -1;
487     }
488
489     token = GetToken();
490     odp->u.ret.ret_value = strtol(token, &endptr, 0);
491     if (endptr == NULL || *endptr != '\0')
492     {
493         fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
494                 SpecName, Line, token);
495         return -1;
496     }
497
498     if (SpecType == SPEC_WIN32)
499     {
500         fprintf( stderr, "%s:%d: 'return' not supported for Win32\n",
501                  SpecName, Line );
502         return -1;
503     }
504
505     return 0;
506 }
507
508
509 /*******************************************************************
510  *         ParseStub
511  *
512  * Parse a 'stub' definition.
513  */
514 static int ParseStub( ORDDEF *odp )
515 {
516     odp->u.func.arg_types[0] = '\0';
517     strcpy( odp->u.func.link_name, STUB_CALLBACK );
518     return 0;
519 }
520
521
522 /*******************************************************************
523  *         ParseVarargs
524  *
525  * Parse an 'varargs' definition.
526  */
527 static int ParseVarargs( ORDDEF *odp )
528 {
529     char *token;
530
531     if (SpecType == SPEC_WIN16)
532     {
533         fprintf( stderr, "%s:%d: 'varargs' not supported for Win16\n",
534                  SpecName, Line );
535         return -1;
536     }
537
538     token = GetToken();
539     if (*token != '(')
540     {
541         fprintf(stderr, "%s:%d: Expected '(' got '%s'\n",
542                 SpecName, Line, token);
543         return -1;
544     }
545     token = GetToken();
546     if (*token != ')')
547     {
548         fprintf(stderr, "%s:%d: Expected ')' got '%s'\n",
549                 SpecName, Line, token);
550         return -1;
551     }
552
553     strcpy( odp->u.vargs.link_name, GetToken() );
554     return 0;
555 }
556
557
558 /*******************************************************************
559  *         ParseExtern
560  *
561  * Parse an 'extern' definition.
562  */
563 static int ParseExtern( ORDDEF *odp )
564 {
565     if (SpecType == SPEC_WIN16)
566     {
567         fprintf( stderr, "%s:%d: 'extern' not supported for Win16\n",
568                  SpecName, Line );
569         return -1;
570     }
571     strcpy( odp->u.ext.link_name, GetToken() );
572     return 0;
573 }
574
575
576 /*******************************************************************
577  *         ParseOrdinal
578  *
579  * Parse an ordinal definition.
580  */
581 static int ParseOrdinal(int ordinal)
582 {
583     ORDDEF *odp;
584     char *token;
585
586     if (ordinal >= MAX_ORDINALS)
587     {
588         fprintf(stderr, "%s:%d: Ordinal number too large\n", SpecName, Line );
589         return -1;
590     }
591     if (ordinal > Limit) Limit = ordinal;
592     if (ordinal < Base) Base = ordinal;
593
594     odp = &OrdinalDefinitions[ordinal];
595     if (!(token = GetToken()))
596     {
597         fprintf(stderr, "%s:%d: Expected type after ordinal\n", SpecName, Line);
598         return -1;
599     }
600
601     for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
602         if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
603             break;
604
605     if (odp->type >= TYPE_NBTYPES)
606     {
607         fprintf( stderr,
608                  "%s:%d: Expected type after ordinal, found '%s' instead\n",
609                  SpecName, Line, token );
610         return -1;
611     }
612
613     if (!(token = GetToken()))
614     {
615         fprintf( stderr, "%s:%d: Expected name after type\n", SpecName, Line );
616         return -1;
617     }
618     strcpy( odp->name, token );
619     odp->lineno = Line;
620
621     switch(odp->type)
622     {
623     case TYPE_BYTE:
624     case TYPE_WORD:
625     case TYPE_LONG:
626         return ParseVariable( odp );
627     case TYPE_PASCAL_16:
628     case TYPE_PASCAL:
629     case TYPE_REGISTER:
630     case TYPE_STDCALL:
631     case TYPE_CDECL:
632         return ParseExportFunction( odp );
633     case TYPE_ABS:
634         return ParseEquate( odp );
635     case TYPE_RETURN:
636         return ParseReturn( odp );
637     case TYPE_STUB:
638         return ParseStub( odp );
639     case TYPE_VARARGS:
640         return ParseVarargs( odp );
641     case TYPE_EXTERN:
642         return ParseExtern( odp );
643     default:
644         fprintf( stderr, "Should not happen\n" );
645         return -1;
646     }
647 }
648
649
650 /*******************************************************************
651  *         ParseTopLevel
652  *
653  * Parse a spec file.
654  */
655 static int ParseTopLevel(void)
656 {
657     char *token;
658     
659     while ((token = GetToken()) != NULL)
660     {
661         if (strcmp(token, "name") == 0)
662         {
663             strcpy(DLLName, GetToken());
664             strupper(DLLName);
665             if (!DLLFileName[0]) sprintf( DLLFileName, "%s.DLL", DLLName );
666         }
667         else if (strcmp(token, "file") == 0)
668         {
669             strcpy(DLLFileName, GetToken());
670             strupper(DLLFileName);
671         }
672         else if (strcmp(token, "type") == 0)
673         {
674             token = GetToken();
675             if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
676             else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
677             else
678             {
679                 fprintf(stderr, "%s:%d: Type must be 'win16' or 'win32'\n",
680                         SpecName, Line);
681                 return -1;
682             }
683         }
684         else if (strcmp(token, "heap") == 0)
685         {
686             token = GetToken();
687             if (!IsNumberString(token))
688             {
689                 fprintf(stderr, "%s:%d: Expected number after heap\n",
690                         SpecName, Line);
691                 return -1;
692             }
693             DLLHeapSize = atoi(token);
694         }
695         else if (IsNumberString(token))
696         {
697             int ordinal;
698             int rv;
699             
700             ordinal = atoi(token);
701             if ((rv = ParseOrdinal(ordinal)) < 0)
702                 return rv;
703         }
704         else
705         {
706             fprintf(stderr, 
707                     "%s:%d: Expected name, id, length or ordinal\n",
708                     SpecName, Line);
709             return -1;
710         }
711     }
712
713     return 0;
714 }
715
716
717 /*******************************************************************
718  *         StoreVariableCode
719  *
720  * Store a list of ints into a byte array.
721  */
722 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
723 {
724     int i;
725
726     switch(size)
727     {
728     case 1:
729         for (i = 0; i < odp->u.var.n_values; i++)
730             buffer[i] = odp->u.var.values[i];
731         break;
732     case 2:
733         for (i = 0; i < odp->u.var.n_values; i++)
734             ((unsigned short *)buffer)[i] = odp->u.var.values[i];
735         break;
736     case 4:
737         for (i = 0; i < odp->u.var.n_values; i++)
738             ((unsigned int *)buffer)[i] = odp->u.var.values[i];
739         break;
740     }
741     return odp->u.var.n_values * size;
742 }
743
744
745 /*******************************************************************
746  *         DumpBytes
747  *
748  * Dump a byte stream into the assembly code.
749  */
750 static void DumpBytes( FILE *outfile, const unsigned char *data, int len,
751                        const char *section, const char *label_start )
752 {
753     int i;
754     if (section) fprintf( outfile, "\t%s\n", section );
755     if (label_start) fprintf( outfile, "%s:\n", label_start );
756     for (i = 0; i < len; i++)
757     {
758         if (!(i & 0x0f)) fprintf( outfile, "\t.byte " );
759         fprintf( outfile, "%d", *data++ );
760         if (i < len - 1)
761             fprintf( outfile, "%c", ((i & 0x0f) != 0x0f) ? ',' : '\n' );
762     }
763     fprintf( outfile, "\n" );
764 }
765
766
767 /*******************************************************************
768  *         BuildModule16
769  *
770  * Build the in-memory representation of a 16-bit NE module, and dump it
771  * as a byte stream into the assembly code.
772  */
773 static int BuildModule16( FILE *outfile, int max_code_offset,
774                           int max_data_offset )
775 {
776     ORDDEF *odp;
777     int i;
778     char *buffer;
779     NE_MODULE *pModule;
780     SEGTABLEENTRY *pSegment;
781     OFSTRUCT *pFileInfo;
782     BYTE *pstr, *bundle;
783     WORD *pword;
784
785     /*   Module layout:
786      * NE_MODULE       Module
787      * OFSTRUCT        File information
788      * SEGTABLEENTRY   Segment 1 (code)
789      * SEGTABLEENTRY   Segment 2 (data)
790      * WORD[2]         Resource table (empty)
791      * BYTE[2]         Imported names (empty)
792      * BYTE[n]         Resident names table
793      * BYTE[n]         Entry table
794      */
795
796     buffer = xmalloc( 0x10000 );
797
798     pModule = (NE_MODULE *)buffer;
799     pModule->magic = IMAGE_OS2_SIGNATURE;
800     pModule->count = 1;
801     pModule->next = 0;
802     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
803     pModule->dgroup = 2;
804     pModule->heap_size = DLLHeapSize;
805     pModule->stack_size = 0;
806     pModule->ip = 0;
807     pModule->cs = 0;
808     pModule->sp = 0;
809     pModule->ss = 0;
810     pModule->seg_count = 2;
811     pModule->modref_count = 0;
812     pModule->nrname_size = 0;
813     pModule->modref_table = 0;
814     pModule->nrname_fpos = 0;
815     pModule->moveable_entries = 0;
816     pModule->alignment = 0;
817     pModule->truetype = 0;
818     pModule->os_flags = NE_OSFLAGS_WINDOWS;
819     pModule->misc_flags = 0;
820     pModule->dlls_to_init  = 0;
821     pModule->nrname_handle = 0;
822     pModule->min_swap_area = 0;
823     pModule->expected_version = 0x030a;
824     pModule->pe_module = NULL;
825     pModule->self = 0;
826     pModule->self_loading_sel = 0;
827
828       /* File information */
829
830     pFileInfo = (OFSTRUCT *)(pModule + 1);
831     pModule->fileinfo = (int)pFileInfo - (int)pModule;
832     memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
833     pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
834                         + strlen(DLLFileName);
835     strcpy( pFileInfo->szPathName, DLLFileName );
836     pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
837         
838       /* Segment table */
839
840     pSegment = (SEGTABLEENTRY *)pstr;
841     pModule->seg_table = (int)pSegment - (int)pModule;
842     pSegment->filepos = 0;
843     pSegment->size = max_code_offset;
844     pSegment->flags = 0;
845     pSegment->minsize = max_code_offset;
846     pSegment->selector = 0;
847     pSegment++;
848
849     pModule->dgroup_entry = (int)pSegment - (int)pModule;
850     pSegment->filepos = 0;
851     pSegment->size = max_data_offset;
852     pSegment->flags = NE_SEGFLAGS_DATA;
853     pSegment->minsize = max_data_offset;
854     pSegment->selector = 0;
855     pSegment++;
856
857       /* Resource table */
858
859     pword = (WORD *)pSegment;
860     pModule->res_table = (int)pword - (int)pModule;
861     *pword++ = 0;
862     *pword++ = 0;
863
864       /* Imported names table */
865
866     pstr = (char *)pword;
867     pModule->import_table = (int)pstr - (int)pModule;
868     *pstr++ = 0;
869     *pstr++ = 0;
870
871       /* Resident names table */
872
873     pModule->name_table = (int)pstr - (int)pModule;
874     /* First entry is module name */
875     *pstr = strlen(DLLName );
876     strcpy( pstr + 1, DLLName );
877     pstr += *pstr + 1;
878     *(WORD *)pstr = 0;
879     pstr += sizeof(WORD);
880     /* Store all ordinals */
881     odp = OrdinalDefinitions + 1;
882     for (i = 1; i <= Limit; i++, odp++)
883     {
884         if (!odp->name[0]) continue;
885         *pstr = strlen( odp->name );
886         strcpy( pstr + 1, odp->name );
887         strupper( pstr + 1 );
888         pstr += *pstr + 1;
889         *(WORD *)pstr = i;
890         pstr += sizeof(WORD);
891     }
892     *pstr++ = 0;
893
894       /* Entry table */
895
896     pModule->entry_table = (int)pstr - (int)pModule;
897     bundle = NULL;
898     odp = OrdinalDefinitions + 1;
899     for (i = 1; i <= Limit; i++, odp++)
900     {
901         int selector = 0;
902
903         switch (odp->type)
904         {
905         case TYPE_PASCAL:
906         case TYPE_PASCAL_16:
907         case TYPE_REGISTER:
908         case TYPE_RETURN:
909         case TYPE_STUB:
910             selector = 1;  /* Code selector */
911             break;
912
913         case TYPE_BYTE:
914         case TYPE_WORD:
915         case TYPE_LONG:
916             selector = 2;  /* Data selector */
917             break;
918
919         case TYPE_ABS:
920             selector = 0xfe;  /* Constant selector */
921             break;
922
923         default:
924             selector = 0;  /* Invalid selector */
925             break;
926         }
927
928           /* create a new bundle if necessary */
929         if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
930         {
931             bundle = pstr;
932             bundle[0] = 0;
933             bundle[1] = selector;
934             pstr += 2;
935         }
936
937         (*bundle)++;
938         if (selector != 0)
939         {
940             *pstr++ = 1;
941             *(WORD *)pstr = odp->offset;
942             pstr += sizeof(WORD);
943         }
944     }
945     *pstr++ = 0;
946
947       /* Dump the module content */
948
949     DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
950                ".data", "Module_Start" );
951     return (int)pstr - (int)pModule;
952 }
953
954
955 /*******************************************************************
956  *         BuildSpec32File
957  *
958  * Build a Win32 assembly file from a spec file.
959  */
960 static int BuildSpec32File( char * specfile, FILE *outfile )
961 {
962     ORDDEF *odp;
963     int i, nb_names, nb_stubs;
964     char buffer[1024];
965     unsigned char *args, *p;
966
967     fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
968     fprintf( outfile, "\t.file\t\"%s\"\n", specfile );
969 #ifdef USE_STABS
970     getcwd(buffer, sizeof(buffer));
971
972     /*
973      * The stabs help the internal debugger as they are an indication that it
974      * is sensible to step into a thunk/trampoline.
975      */
976     fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
977     fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", specfile);
978 #endif
979
980     fprintf( outfile, "\t.text\n" );
981     fprintf( outfile, "\t.align 4\n" );
982     fprintf( outfile, "Code_Start:\n" );
983
984     /* Output code for all register functions */
985
986     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
987     {
988         if (odp->type != TYPE_REGISTER) continue;
989         fprintf( outfile, "\n/* %s.%d (%s) */\n", DLLName, i, odp->name);
990         fprintf( outfile, "\t.align 4\n" );
991 #ifdef USE_STABS
992         fprintf( outfile, ".stabs \"%s_%d:F1\",36,0,%d,%s_%d\n", 
993                  DLLName, i, odp->lineno, DLLName, i);
994 #endif
995         fprintf( outfile, "%s_%d:\n", DLLName, i );
996 #ifdef USE_STABS
997         fprintf( outfile, ".stabn 68,0,%d,0\n", odp->lineno);
998 #endif
999         fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1000         fprintf( outfile, "\tjmp " PREFIX "CALL32_Regs\n" );
1001     }
1002
1003     /* Output code for all stubs functions */
1004
1005     nb_stubs = 0;
1006     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1007     {
1008         if (odp->type != TYPE_STUB) continue;
1009         fprintf( outfile, "\n/* %s.%d (%s) */\n", DLLName, i, odp->name);
1010 #ifdef USE_STABS
1011         fprintf( outfile, ".stabs \"%s_%d:F1\",36,0,%d,%s_%d\n", 
1012                  DLLName, i, odp->lineno, DLLName, i);
1013 #endif
1014         fprintf( outfile, "%s_%d:\n", DLLName, i );
1015 #ifdef USE_STABS
1016         fprintf( outfile, ".stabn 68,0,%d,0\n", odp->lineno);
1017 #endif
1018         fprintf( outfile, "\tpushl $Name_%d\n", i );
1019         fprintf( outfile, "\tpushl $%d\n", i );
1020         if (++nb_stubs == 1)
1021         {
1022             fprintf( outfile, "DoStub:\n" );
1023             fprintf( outfile, "\tpushl $DLLName\n" );
1024             fprintf( outfile, "\tcall " PREFIX "RELAY_Unimplemented32\n" );
1025         }
1026         else fprintf( outfile, "\tjmp DoStub\n" );
1027     }
1028
1029     /* Output the DLL functions table */
1030
1031     fprintf( outfile, "\t.text\n" );
1032     fprintf( outfile, "\t.align 4\n" );
1033     fprintf( outfile, "Functions:\n" );
1034     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1035     {
1036         switch(odp->type)
1037         {
1038         case TYPE_INVALID:
1039             fprintf( outfile, "\t.long 0\n" );
1040             break;
1041         case TYPE_VARARGS:
1042             fprintf( outfile, "\t.long " PREFIX "%s\n",odp->u.vargs.link_name);
1043             break;
1044         case TYPE_EXTERN:
1045             fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.ext.link_name );
1046             break;
1047         case TYPE_STDCALL:
1048         case TYPE_CDECL:
1049             fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.func.link_name);
1050             break;
1051         case TYPE_REGISTER:
1052         case TYPE_STUB:
1053             fprintf( outfile, "\t.long %s_%d\n", DLLName, i );
1054             break;
1055         default:
1056             fprintf(stderr,"build: function type %d not available for Win32\n",
1057                     odp->type);
1058             return -1;
1059         }
1060     }
1061
1062     /* Output the DLL names table */
1063
1064     fprintf( outfile, "FuncNames:\n" );
1065     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1066     {
1067         if (odp->type != TYPE_INVALID)
1068             fprintf( outfile, "\t.long Name_%d\n", i );
1069     }
1070
1071     /* Output the DLL ordinals table */
1072
1073     fprintf( outfile, "FuncOrdinals:\n" );
1074     nb_names = 0;
1075     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1076     {
1077         if (odp->type == TYPE_INVALID) continue;
1078         nb_names++;
1079         /* Some assemblers do not have .word */
1080         fprintf( outfile, "\t.byte %d,%d\n", LOBYTE(i), HIBYTE(i) );
1081     }
1082
1083     /* Output the DLL names */
1084
1085     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1086     {
1087         if (odp->type != TYPE_INVALID)
1088             fprintf( outfile, "Name_%d:\t.ascii \"%s\\0\"\n", i, odp->name );
1089     }
1090
1091     /* Output the DLL functions arguments */
1092
1093     args = p = (unsigned char *)xmalloc( Limit - Base + 1 );
1094     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1095     {
1096         switch(odp->type)
1097         {
1098         case TYPE_STDCALL:
1099             *p++ = (unsigned char)strlen(odp->u.func.arg_types);
1100             break;
1101         case TYPE_CDECL:
1102             *p++ = 0x80 | (unsigned char)strlen(odp->u.func.arg_types);
1103             break;
1104         case TYPE_REGISTER:
1105             *p++ = 0xfe;
1106             break;
1107         default:
1108             *p++ = 0xff;
1109             break;
1110         }
1111     }
1112     DumpBytes( outfile, args, Limit - Base + 1, NULL, "FuncArgs" );
1113
1114     /* Output the DLL descriptor */
1115
1116     fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1117     fprintf( outfile, "\t.align 4\n" );
1118     fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1119     fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1120     fprintf( outfile, "\t.long DLLName\n" );          /* Name */
1121     fprintf( outfile, "\t.long %d\n", Base );         /* Base */
1122     fprintf( outfile, "\t.long %d\n", Limit+1-Base ); /* Number of functions */
1123     fprintf( outfile, "\t.long %d\n", nb_names );     /* Number of names */
1124     fprintf( outfile, "\t.long Functions\n" );        /* Functions */
1125     fprintf( outfile, "\t.long FuncNames\n" );        /* Function names */
1126     fprintf( outfile, "\t.long FuncOrdinals\n" );     /* Function ordinals */
1127     fprintf( outfile, "\t.long FuncArgs\n" );         /* Function arguments */
1128 #ifdef USE_STABS
1129     fprintf( outfile, "\t.text\n");
1130     fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
1131     fprintf( outfile, ".Letext:\n");
1132 #endif
1133     return 0;
1134 }
1135
1136
1137 /*******************************************************************
1138  *         BuildSpec16File
1139  *
1140  * Build a Win16 assembly file from a spec file.
1141  */
1142 static int BuildSpec16File( char * specfile, FILE *outfile )
1143 {
1144     ORDDEF *odp;
1145     int i;
1146     int code_offset, data_offset, module_size;
1147     unsigned char *data;
1148
1149     data = (unsigned char *)xmalloc( 0x10000 );
1150     memset( data, 0, 16 );
1151     data_offset = 16;
1152
1153     fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
1154     fprintf( outfile, "\t.text\n" );
1155     fprintf( outfile, "Code_Start:\n" );
1156     code_offset = 0;
1157
1158     odp = OrdinalDefinitions;
1159     for (i = 0; i <= Limit; i++, odp++)
1160     {
1161         switch (odp->type)
1162         {
1163           case TYPE_INVALID:
1164             odp->offset = 0xffff;
1165             break;
1166
1167           case TYPE_ABS:
1168             odp->offset = LOWORD(odp->u.abs.value);
1169             break;
1170
1171           case TYPE_BYTE:
1172             odp->offset = data_offset;
1173             data_offset += StoreVariableCode( data + data_offset, 1, odp);
1174             break;
1175
1176           case TYPE_WORD:
1177             odp->offset = data_offset;
1178             data_offset += StoreVariableCode( data + data_offset, 2, odp);
1179             break;
1180
1181           case TYPE_LONG:
1182             odp->offset = data_offset;
1183             data_offset += StoreVariableCode( data + data_offset, 4, odp);
1184             break;
1185
1186           case TYPE_RETURN:
1187             fprintf( outfile,"/* %s.%d */\n", DLLName, i);
1188             fprintf( outfile,"\tmovw $%d,%%ax\n",LOWORD(odp->u.ret.ret_value));
1189             fprintf( outfile,"\tmovw $%d,%%dx\n",HIWORD(odp->u.ret.ret_value));
1190             fprintf( outfile,"\t.byte 0x66\n");
1191             if (odp->u.ret.arg_size != 0)
1192                 fprintf( outfile, "\tlret $%d\n\n", odp->u.ret.arg_size);
1193             else
1194             {
1195                 fprintf( outfile, "\tlret\n");
1196                 fprintf( outfile, "\tnop\n");
1197                 fprintf( outfile, "\tnop\n\n");
1198             }
1199             odp->offset = code_offset;
1200             code_offset += 12;  /* Assembly code is 12 bytes long */
1201             break;
1202
1203           case TYPE_REGISTER:
1204           case TYPE_PASCAL:
1205           case TYPE_PASCAL_16:
1206           case TYPE_STUB:
1207             fprintf( outfile, "/* %s.%d */\n", DLLName, i);
1208             fprintf( outfile, "\tpushw %%bp\n" );
1209             fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1210             /* FreeBSD does not understand lcall, so do it the hard way */
1211             fprintf( outfile, "\t.byte 0x9a\n" );
1212             fprintf( outfile, "\t.long " PREFIX "CallFrom16_%s_%s\n",
1213                      (odp->type == TYPE_REGISTER) ? "regs" :
1214                      (odp->type == TYPE_PASCAL) ? "long" : "word",
1215                      odp->u.func.arg_types );
1216             fprintf( outfile,"\t.byte 0x%02x,0x%02x\n", /* Some asms don't have .word */
1217                      LOBYTE(WINE_CODE_SELECTOR), HIBYTE(WINE_CODE_SELECTOR) );
1218             fprintf( outfile, "\tnop\n" );
1219             fprintf( outfile, "\tnop\n\n" );
1220             odp->offset = code_offset;
1221             code_offset += 16;  /* Assembly code is 16 bytes long */
1222             break;
1223                 
1224           default:
1225             fprintf(stderr,"build: function type %d not available for Win16\n",
1226                     odp->type);
1227             return -1;
1228         }
1229     }
1230
1231     if (!code_offset)  /* Make sure the code segment is not empty */
1232     {
1233         fprintf( outfile, "\t.byte 0\n" );
1234         code_offset++;
1235     }
1236
1237     /* Output data segment */
1238
1239     DumpBytes( outfile, data, data_offset, NULL, "Data_Start" );
1240
1241     /* Build the module */
1242
1243     module_size = BuildModule16( outfile, code_offset, data_offset );
1244
1245     /* Output the DLL descriptor */
1246
1247     fprintf( outfile, "\t.text\n" );
1248     fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1249     fprintf( outfile, "\t.align 4\n" );
1250     fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1251     fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1252     fprintf( outfile, "\t.long DLLName\n" );          /* Name */
1253     fprintf( outfile, "\t.long Module_Start\n" );     /* Module start */
1254     fprintf( outfile, "\t.long %d\n", module_size );  /* Module size */
1255     fprintf( outfile, "\t.long Code_Start\n" );       /* Code start */
1256     fprintf( outfile, "\t.long Data_Start\n" );       /* Data start */
1257     return 0;
1258 }
1259
1260
1261 /*******************************************************************
1262  *         BuildSpecFile
1263  *
1264  * Build an assembly file from a spec file.
1265  */
1266 static int BuildSpecFile( FILE *outfile, char *specname )
1267 {
1268     SpecName = specname;
1269     SpecFp = fopen( specname, "r");
1270     if (SpecFp == NULL)
1271     {
1272         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
1273         return -1;
1274     }
1275
1276     if (ParseTopLevel() < 0) return -1;
1277
1278     switch(SpecType)
1279     {
1280     case SPEC_WIN16:
1281         return BuildSpec16File( specname, outfile );
1282     case SPEC_WIN32:
1283         return BuildSpec32File( specname, outfile );
1284     default:
1285         fprintf( stderr, "%s: Missing 'type' declaration\n", specname );
1286         return -1;
1287     }
1288 }
1289
1290
1291 /*******************************************************************
1292  *         TransferArgs16To32
1293  *
1294  * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1295  * The 16-bit stack layout is:
1296  *   ...     ...
1297  *  (bp+8)    arg2
1298  *  (bp+6)    arg1
1299  *  (bp+4)    cs
1300  *  (bp+2)    ip
1301  *  (bp)      bp
1302  */
1303 static int TransferArgs16To32( FILE *outfile, char *args )
1304 {
1305     int i, pos16, pos32;
1306
1307     /* Save ebx first */
1308
1309     fprintf( outfile, "\tpushl %%ebx\n" );
1310
1311     /* Get the 32-bit stack pointer */
1312
1313     fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
1314
1315     /* Copy the arguments */
1316
1317     pos16 = 6;  /* skip bp and return address */
1318     pos32 = 0;
1319
1320     for (i = strlen(args); i > 0; i--)
1321     {
1322         pos32 -= 4;
1323         switch(args[i-1])
1324         {
1325         case 'w':  /* word */
1326             fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1327             fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1328             pos16 += 2;
1329             break;
1330
1331         case 's':  /* s_word */
1332             fprintf( outfile, "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1333             fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1334             pos16 += 2;
1335             break;
1336
1337         case 'l':  /* long or segmented pointer */
1338         case 'T':  /* segmented pointer to null-terminated string */
1339             fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", pos16 );
1340             fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1341             pos16 += 4;
1342             break;
1343
1344         case 'p':  /* linear pointer */
1345         case 't':  /* linear pointer to null-terminated string */
1346             /* Get the selector */
1347             fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1348             /* Get the selector base */
1349             fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
1350             fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1351             fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1352             /* Add the offset */
1353             fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1354             fprintf( outfile, "\taddl %%eax,%d(%%ebx)\n", pos32 );
1355             pos16 += 4;
1356             break;
1357
1358         default:
1359             fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1360         }
1361     }
1362
1363     /* Restore ebx */
1364     
1365     fprintf( outfile, "\tpopl %%ebx\n" );
1366
1367     return pos16 - 6;  /* Return the size of the 16-bit args */
1368 }
1369
1370
1371 /*******************************************************************
1372  *         BuildContext16
1373  *
1374  * Build the context structure on the 32-bit stack.
1375  */
1376 static void BuildContext16( FILE *outfile )
1377 {
1378     /* Save ebx first */
1379
1380     fprintf( outfile, "\tpushl %%ebx\n" );
1381
1382     /* Get the 32-bit stack pointer */
1383
1384     fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
1385
1386     /* Store the registers */
1387
1388     fprintf( outfile, "\tpopl %d(%%ebx)\n", /* Get ebx from stack*/
1389              CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
1390     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1391              CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
1392     fprintf( outfile, "\tmovl %%ecx,%d(%%ebx)\n",
1393              CONTEXTOFFSET(Ecx) - sizeof(CONTEXT) );
1394     fprintf( outfile, "\tmovl %%edx,%d(%%ebx)\n",
1395              CONTEXTOFFSET(Edx) - sizeof(CONTEXT) );
1396     fprintf( outfile, "\tmovl %%esi,%d(%%ebx)\n",
1397              CONTEXTOFFSET(Esi) - sizeof(CONTEXT) );
1398     fprintf( outfile, "\tmovl %%edi,%d(%%ebx)\n",
1399              CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
1400
1401     fprintf( outfile, "\tmovzwl -10(%%ebp),%%eax\n" ); /* Get %ds from stack*/
1402     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1403              CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
1404     fprintf( outfile, "\tmovzwl -6(%%ebp),%%eax\n" ); /* Get %es from stack*/
1405     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1406              CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
1407     fprintf( outfile, "\tpushfl\n" );
1408     fprintf( outfile, "\tpopl %d(%%ebx)\n",
1409              CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
1410     fprintf( outfile, "\tmovl -16(%%ebp),%%eax\n" ); /* Get %ebp from stack */
1411     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1412              CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
1413     fprintf( outfile, "\tmovzwl 2(%%ebp),%%eax\n" ); /* Get %ip from stack */
1414     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1415              CONTEXTOFFSET(Eip) - sizeof(CONTEXT) );
1416     fprintf( outfile, "\tmovzwl 4(%%ebp),%%eax\n" ); /* Get %cs from stack */
1417     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1418              CONTEXTOFFSET(SegCs) - sizeof(CONTEXT) );
1419     fprintf( outfile, "\tmovw %%fs,%%ax\n" );
1420     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1421              CONTEXTOFFSET(SegFs) - sizeof(CONTEXT) );
1422     fprintf( outfile, "\tmovw %%gs,%%ax\n" );
1423     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1424              CONTEXTOFFSET(SegGs) - sizeof(CONTEXT) );
1425     fprintf( outfile, "\tmovw %%ss,%%ax\n" );
1426     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1427              CONTEXTOFFSET(SegSs) - sizeof(CONTEXT) );
1428 #if 0
1429     fprintf( outfile, "\tfsave %d(%%ebx)\n",
1430              CONTEXTOFFSET(FloatSave) - sizeof(CONTEXT) );
1431 #endif
1432 }
1433
1434
1435 /*******************************************************************
1436  *         RestoreContext16
1437  *
1438  * Restore the registers from the context structure.
1439  * %edx must point to the 32-bit stack top.
1440  */
1441 static void RestoreContext16( FILE *outfile )
1442 {
1443     /* Get the 32-bit stack pointer */
1444
1445     fprintf( outfile, "\tmovl %%edx,%%ebx\n" );
1446
1447     /* Remove everything up to the return address from the 16-bit stack */
1448
1449     fprintf( outfile, "\taddl $22,%%esp\n" );
1450
1451     /* Restore the registers */
1452
1453     fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n",
1454              CONTEXTOFFSET(Ecx) - sizeof(CONTEXT) );
1455     fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n",
1456              CONTEXTOFFSET(Edx) - sizeof(CONTEXT) );
1457     fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n",
1458              CONTEXTOFFSET(Esi) - sizeof(CONTEXT) );
1459     fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n",
1460              CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
1461     fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n",
1462              CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
1463     fprintf( outfile, "\tpushw %d(%%ebx)\n",  /* Push new cs */
1464              CONTEXTOFFSET(SegCs) - sizeof(CONTEXT) );
1465     fprintf( outfile, "\tpushw %d(%%ebx)\n",  /* Push new ip */
1466              CONTEXTOFFSET(Eip) - sizeof(CONTEXT) );
1467     fprintf( outfile, "\tpushw %d(%%ebx)\n",  /* Push new ds */
1468              CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
1469     fprintf( outfile, "\tpushw %d(%%ebx)\n",  /* Push new es */
1470              CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
1471     fprintf( outfile, "\tpushl %d(%%ebx)\n",
1472              CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
1473     fprintf( outfile, "\tpopfl\n" );
1474     fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n",
1475              CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
1476     fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n",
1477              CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
1478     fprintf( outfile, "\tpopw %%es\n" );  /* Set es */
1479     fprintf( outfile, "\tpopw %%ds\n" );  /* Set ds */
1480 }
1481
1482
1483 /*******************************************************************
1484  *         BuildCallFrom16Func
1485  *
1486  * Build a 16-bit-to-Wine callback function. The syntax of the function
1487  * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1488  * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1489  * 'l'=long, 'p'=linear pointer, 't'=linear pointer to null-terminated string,
1490  * 'T'=segmented pointer to null-terminated string).
1491  * For register functions, the arguments are ignored, but they are still
1492  * removed from the stack upon return.
1493  *
1494  * Stack layout upon entry to the callback function:
1495  *  ...           ...
1496  * (sp+18) word   first 16-bit arg
1497  * (sp+16) word   cs
1498  * (sp+14) word   ip
1499  * (sp+12) word   bp
1500  * (sp+8)  long   32-bit entry point (used to store edx)
1501  * (sp+6)  word   high word of cs (always 0, used to store es)
1502  * (sp+4)  word   low word of cs of 16-bit entry point
1503  * (sp+2)  word   high word of ip (always 0, used to store ds)
1504  * (sp)    word   low word of ip of 16-bit entry point
1505  *
1506  * Added on the stack:
1507  * (sp-4)  long   ebp
1508  * (sp-6)  word   saved previous sp
1509  * (sp-8)  word   saved previous ss
1510  */
1511 static void BuildCallFrom16Func( FILE *outfile, char *profile )
1512 {
1513     int argsize = 0;
1514     int short_ret = 0;
1515     int reg_func = 0;
1516     char *args = profile + 5;
1517
1518     /* Parse function type */
1519
1520     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1521     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1522     else if (strncmp( "long_", profile, 5 ))
1523     {
1524         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1525         return;
1526     }
1527
1528     /* Function header */
1529
1530     fprintf( outfile, "\n\t.align 4\n" );
1531 #ifdef USE_STABS
1532     fprintf( outfile, ".stabs \"CallFrom16_%s:F1\",36,0,0," PREFIX "CallFrom16_%s\n", 
1533              profile, profile);
1534 #endif
1535     fprintf( outfile, "\t.globl " PREFIX "CallFrom16_%s\n", profile );
1536     fprintf( outfile, PREFIX "CallFrom16_%s:\n", profile );
1537
1538     /* Setup bp to point to its copy on the stack */
1539
1540     fprintf( outfile, "\tpushl %%ebp\n" );  /* Save the full 32-bit ebp */
1541     fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1542     fprintf( outfile, "\taddw $16,%%bp\n" );
1543
1544     /* Save 16-bit ds and es */
1545
1546     /* Stupid FreeBSD assembler doesn't know these either */
1547     /* fprintf( outfile, "\tmovw %%ds,-10(%%ebp)\n" ); */
1548     fprintf( outfile, "\t.byte 0x66,0x8c,0x5d,0xf6\n" );
1549     /* fprintf( outfile, "\tmovw %%es,-6(%%ebp)\n" ); */
1550     fprintf( outfile, "\t.byte 0x66,0x8c,0x45,0xfa\n" );
1551
1552     /* Restore 32-bit ds and es */
1553
1554     fprintf( outfile, "\tpushl $0x%04x%04x\n",
1555              WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1556     fprintf( outfile, "\tpopw %%ds\n" );
1557     fprintf( outfile, "\tpopw %%es\n" );
1558
1559
1560     /* Save the 16-bit stack */
1561
1562     fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved16_ss_sp\n" );
1563 #ifdef __svr4__
1564     fprintf( outfile,"\tdata16\n");
1565 #endif
1566     fprintf( outfile, "\tmovw %%ss," PREFIX "IF1632_Saved16_ss_sp+2\n" );
1567     fprintf( outfile, "\tmovw %%sp," PREFIX "IF1632_Saved16_ss_sp\n" );
1568
1569     /* Transfer the arguments */
1570
1571     if (reg_func) BuildContext16( outfile );
1572     else if (*args) argsize = TransferArgs16To32( outfile, args );
1573
1574     /* Get the address of the API function */
1575
1576     fprintf( outfile, "\tmovl -4(%%ebp),%%eax\n" );
1577
1578     /* If necessary, save %edx over the API function address */
1579
1580     if (!reg_func && short_ret)
1581         fprintf( outfile, "\tmovl %%edx,-4(%%ebp)\n" );
1582
1583     /* Switch to the 32-bit stack */
1584
1585     fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebp\n" );
1586     fprintf( outfile, "\tpushw %%ds\n" );
1587     fprintf( outfile, "\tpopw %%ss\n" );
1588     fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1589              reg_func ? sizeof(CONTEXT) : 4 * strlen(args) );
1590     if (reg_func)  /* Push the address of the context struct */
1591         fprintf( outfile, "\tpushl %%esp\n" );
1592
1593     /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1594
1595     fprintf( outfile, "\taddl $%d,%%ebp\n", STRUCTOFFSET(STACK32FRAME,ebp) );
1596
1597     /* Print the debug information before the call */
1598
1599     if (debugging)
1600     {
1601         fprintf( outfile, "\tpushl %%eax\n" );
1602         fprintf( outfile, "\tpushl $Profile_%s\n", profile );
1603         fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1604         fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16\n" );
1605         fprintf( outfile, "\tpopl %%eax\n" );
1606         fprintf( outfile, "\tpopl %%eax\n" );
1607         fprintf( outfile, "\tpopl %%eax\n" );
1608     }
1609
1610     /* Call the entry point */
1611
1612     fprintf( outfile, "\tcall %%eax\n" );
1613
1614     /* Print the debug information after the call */
1615
1616     if (debugging)
1617     {
1618         if (reg_func)
1619         {
1620             /* Push again the address of the context struct in case */
1621             /* it has been removed by an stdcall function */
1622             fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1623                      sizeof(CONTEXT) + 32 );
1624             fprintf( outfile, "\tpushl %%esp\n" );
1625         }
1626         fprintf( outfile, "\tpushl %%eax\n" );
1627         fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1628         fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16Ret\n" );
1629         fprintf( outfile, "\tpopl %%eax\n" );
1630         fprintf( outfile, "\tpopl %%eax\n" );
1631     }
1632
1633     /* Restore the value of the saved 32-bit stack pointer */
1634
1635     fprintf( outfile, "\tleal -%d(%%ebp),%%edx\n",
1636              STRUCTOFFSET(STACK32FRAME,ebp) );
1637     fprintf( outfile, "movl %%edx," PREFIX "CALLTO16_Saved32_esp\n" );
1638
1639     /* Restore the 16-bit stack */
1640
1641 #ifdef __svr4__
1642     fprintf( outfile, "\tdata16\n");
1643 #endif
1644     fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
1645     fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
1646     fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved16_ss_sp\n" );
1647
1648     if (reg_func)
1649     {
1650         /* Calc the arguments size */
1651         while (*args)
1652         {
1653             switch(*args)
1654             {
1655             case 'w':
1656             case 's':
1657                 argsize += 2;
1658                 break;
1659             case 'p':
1660             case 't':
1661             case 'l':
1662             case 'T':
1663                 argsize += 4;
1664                 break;
1665             default:
1666                 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1667             }
1668             args++;
1669         }
1670
1671         /* Restore registers from the context structure */
1672         RestoreContext16( outfile );
1673     }
1674     else
1675     {
1676         /* Restore high 16 bits of ebp */
1677         fprintf( outfile, "\tpopl %%ebp\n" );
1678
1679         /* Restore ds and es */
1680         fprintf( outfile, "\tincl %%esp\n" );      /* Remove ip */
1681         fprintf( outfile, "\tincl %%esp\n" );
1682         fprintf( outfile, "\tpopl %%edx\n" );      /* Remove cs and ds */
1683         fprintf( outfile, "\tmovw %%dx,%%ds\n" );  /* and restore ds */
1684         fprintf( outfile, "\tpopw %%es\n" );       /* Restore es */
1685
1686         if (short_ret) fprintf( outfile, "\tpopl %%edx\n" );  /* Restore edx */
1687         else
1688         {
1689             /* Get the return value into dx:ax */
1690             fprintf( outfile, "\tmovl %%eax,%%edx\n" );
1691             fprintf( outfile, "\tshrl $16,%%edx\n" );
1692             /* Remove API entry point */
1693             fprintf( outfile, "\taddl $4,%%esp\n" );
1694         }
1695
1696         /* Restore low 16 bits of ebp */
1697         fprintf( outfile, "\tpopw %%bp\n" );
1698     }
1699
1700     /* Remove the arguments and return */
1701
1702     if (argsize)
1703     {
1704         fprintf( outfile, "\t.byte 0x66\n" );
1705         fprintf( outfile, "\tlret $%d\n", argsize );
1706     }
1707     else
1708     {
1709         fprintf( outfile, "\t.byte 0x66\n" );
1710         fprintf( outfile, "\tlret\n" );
1711     }
1712 }
1713
1714
1715 /*******************************************************************
1716  *         BuildCallTo16Func
1717  *
1718  * Build a Wine-to-16-bit callback function.
1719  *
1720  * Stack frame of the callback function:
1721  *  ...      ...
1722  * (ebp+16) arg2
1723  * (ebp+12) arg1
1724  * (ebp+8)  func to call
1725  * (ebp+4)  return address
1726  * (ebp)    previous ebp
1727  *
1728  * Prototypes for the CallTo16 functions:
1729  *   extern WINAPI WORD CallTo16_word_xxx( FARPROC16 func, args... );
1730  *   extern WINAPI LONG CallTo16_long_xxx( FARPROC16 func, args... );
1731  *   extern WINAPI void CallTo16_regs_( const CONTEXT *context );
1732  */
1733 static void BuildCallTo16Func( FILE *outfile, char *profile )
1734 {
1735     int short_ret = 0;
1736     int reg_func = 0;
1737     char *args = profile + 5;
1738
1739     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1740     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1741     else if (strncmp( "long_", profile, 5 ))
1742     {
1743         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1744         return;
1745     }
1746
1747     /* Function header */
1748
1749     fprintf( outfile, "\n\t.align 4\n" );
1750 #ifdef USE_STABS
1751     fprintf( outfile, ".stabs \"CallTo16_%s:F1\",36,0,0," PREFIX "CallTo16_%s\n", 
1752              profile, profile);
1753 #endif
1754     fprintf( outfile, "\t.globl " PREFIX "CallTo16_%s\n", profile );
1755     fprintf( outfile, PREFIX "CallTo16_%s:\n", profile );
1756
1757     /* Entry code */
1758
1759     fprintf( outfile, "\tpushl %%ebp\n" );
1760     fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1761
1762     /* Call the actual CallTo16 routine (simulate a lcall) */
1763
1764     fprintf( outfile, "\tpushw $0\n" );
1765     fprintf( outfile, "\tpushw %%cs\n" );
1766     fprintf( outfile, "\tcall do_callto16_%s\n", profile );
1767
1768     /* Exit code */
1769
1770     /* FIXME: this is a hack because of task.c */
1771     if (!strcmp( profile, "word_" ))
1772     {
1773         fprintf( outfile, ".globl " PREFIX "CALLTO16_Restore\n" );
1774         fprintf( outfile, PREFIX "CALLTO16_Restore:\n" );
1775     }
1776     fprintf( outfile, "\tpopl %%ebp\n" );
1777     fprintf( outfile, "\tret $%d\n", strlen(args) + 1 );
1778
1779     /* Start of the actual CallTo16 routine */
1780
1781     /* Save the 32-bit registers */
1782
1783     fprintf( outfile, "do_callto16_%s:\n", profile );
1784     fprintf( outfile, "\tpushl %%ebx\n" );
1785     fprintf( outfile, "\tpushl %%ecx\n" );
1786     fprintf( outfile, "\tpushl %%edx\n" );
1787     fprintf( outfile, "\tpushl %%esi\n" );
1788     fprintf( outfile, "\tpushl %%edi\n" );
1789
1790     /* Save the 32-bit stack */
1791
1792     fprintf( outfile, "\tmovl %%esp," PREFIX "CALLTO16_Saved32_esp\n" );
1793     fprintf( outfile, "\tmovl %%ebp,%%ebx\n" );
1794
1795     /* Print debugging info */
1796
1797     if (debugging)
1798     {
1799         /* Push the address of the first argument */
1800         fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" );
1801         fprintf( outfile, "\tpushl $%d\n", reg_func ? -1 : strlen(args) );
1802         fprintf( outfile, "\tpushl %%eax\n" );
1803         fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16\n" );
1804         fprintf( outfile, "\tpopl %%eax\n" );
1805         fprintf( outfile, "\tpopl %%eax\n" );
1806     }
1807
1808     if (reg_func)
1809     {
1810         /* Switch to the 16-bit stack, saving the current %%esp, */
1811         /* and adding the specified offset to the new sp */
1812         fprintf( outfile, "\tmovzwl " PREFIX "IF1632_Saved16_ss_sp,%%edx\n" );
1813         fprintf( outfile, "\tleal -4(%%edx),%%edx\n" );
1814         fprintf( outfile, "\tmovl 12(%%ebx),%%eax\n" ); /* Get the offset */
1815         fprintf( outfile, "\taddl %%edx,%%eax\n" );
1816 #ifdef __svr4__
1817         fprintf( outfile,"\tdata16\n");
1818 #endif
1819         fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
1820         fprintf( outfile, "\txchgl %%esp,%%eax\n" );
1821         fprintf( outfile, "\t.byte 0x36\n" /* %ss: */ );
1822         fprintf( outfile, "\tmovl %%eax,0(%%edx)\n" );
1823
1824         /* Get the registers. ebx is handled later on. */
1825
1826         fprintf( outfile, "\tmovl 8(%%ebx),%%ebx\n" );
1827         fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(SegEs) );
1828         fprintf( outfile, "\tmovw %%ax,%%es\n" );
1829         fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n", CONTEXTOFFSET(Ebp) );
1830         fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(Eax) );
1831         fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(Ecx) );
1832         fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(Edx) );
1833         fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(Esi) );
1834         fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(Edi) );
1835
1836         /* Push the return address */
1837
1838         fprintf( outfile, "\tpushl " PREFIX "CALLTO16_RetAddr_regs\n" );
1839
1840         /* Push the called routine address */
1841
1842         fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegCs) );
1843         fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(Eip) );
1844
1845         /* Get the 16-bit ds */
1846
1847         fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegDs) );
1848         /* Get ebx from the 32-bit stack */
1849         fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(Ebx) );
1850         fprintf( outfile, "\tpopw %%ds\n" );
1851     }
1852     else  /* not a register function */
1853     {
1854         int pos = 12;  /* first argument position */
1855
1856         /* Switch to the 16-bit stack, saving the current %%esp */
1857         fprintf( outfile, "\tmovl %%esp,%%eax\n" );
1858 #ifdef __svr4__
1859         fprintf( outfile,"\tdata16\n");
1860 #endif
1861         fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
1862         fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
1863         fprintf( outfile, "\tpushl %%eax\n" );
1864
1865         /* Make %bp point to the previous stackframe (built by CallFrom16) */
1866         fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1867         fprintf( outfile, "\tleal %d(%%ebp),%%ebp\n",
1868                  STRUCTOFFSET(STACK16FRAME,bp) + 4 /* for saved %%esp */ );
1869
1870         /* Transfer the arguments */
1871
1872         while (*args)
1873         {
1874             switch(*args++)
1875             {
1876             case 'w': /* word */
1877                 fprintf( outfile, "\tpushw %d(%%ebx)\n", pos );
1878                 break;
1879             case 'l': /* long */
1880                 fprintf( outfile, "\tpushl %d(%%ebx)\n", pos );
1881                 break;
1882             default:
1883                 fprintf( stderr, "Unexpected case '%c' in BuildCallTo16Func\n",
1884                         args[-1] );
1885             }
1886             pos += 4;
1887         }
1888
1889         /* Push the return address */
1890
1891         fprintf( outfile, "\tpushl " PREFIX "CALLTO16_RetAddr_%s\n",
1892                  short_ret ? "word" : "long" );
1893
1894         /* Push the called routine address */
1895
1896         fprintf( outfile, "\tpushl 8(%%ebx)\n" );
1897
1898         /* Set %ds and %es (and %ax just in case) equal to %ss */
1899
1900         fprintf( outfile, "\tmovw %%ss,%%ax\n" );
1901         fprintf( outfile, "\tmovw %%ax,%%ds\n" );
1902         fprintf( outfile, "\tmovw %%ax,%%es\n" );
1903     }
1904
1905     /* Jump to the called routine */
1906
1907     fprintf( outfile, "\t.byte 0x66\n" );
1908     fprintf( outfile, "\tlret\n" );
1909 }
1910
1911
1912 /*******************************************************************
1913  *         BuildRet16Func
1914  *
1915  * Build the return code for 16-bit callbacks
1916  */
1917 static void BuildRet16Func( FILE *outfile )
1918 {
1919     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_word\n" );
1920     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_long\n" );
1921     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_regs\n" );
1922
1923     fprintf( outfile, PREFIX "CALLTO16_Ret_word:\n" );
1924     fprintf( outfile, "\txorl %%edx,%%edx\n" );
1925
1926     /* Remove the arguments just in case */
1927
1928     fprintf( outfile, PREFIX "CALLTO16_Ret_long:\n" );
1929     fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1930                  STRUCTOFFSET(STACK16FRAME,bp) + 4 /* for saved %%esp */ );
1931
1932     /* Put return value into %eax */
1933
1934     fprintf( outfile, PREFIX "CALLTO16_Ret_regs:\n" );
1935     fprintf( outfile, "\tshll $16,%%edx\n" );
1936     fprintf( outfile, "\tmovw %%ax,%%dx\n" );
1937     fprintf( outfile, "\tmovl %%edx,%%eax\n" );
1938
1939     /* Restore 32-bit segment registers and stack*/
1940
1941     fprintf( outfile, "\tpopl %%ecx\n" );  /* Get the saved %%esp */
1942     fprintf( outfile, "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1943 #ifdef __svr4__
1944     fprintf( outfile, "\tdata16\n");
1945 #endif
1946     fprintf( outfile, "\tmovw %%bx,%%ds\n" );
1947 #ifdef __svr4__
1948     fprintf( outfile, "\tdata16\n");
1949 #endif
1950     fprintf( outfile, "\tmovw %%bx,%%es\n" );
1951
1952     /* Restore the 32-bit stack */
1953
1954 #ifdef __svr4__
1955     fprintf( outfile, "\tdata16\n");
1956 #endif
1957     fprintf( outfile, "\tmovw %%bx,%%ss\n" );
1958     fprintf( outfile, "\tmovl %%ecx,%%esp\n" );
1959
1960     /* Restore the 32-bit registers */
1961
1962     fprintf( outfile, "\tpopl %%edi\n" );
1963     fprintf( outfile, "\tpopl %%esi\n" );
1964     fprintf( outfile, "\tpopl %%edx\n" );
1965     fprintf( outfile, "\tpopl %%ecx\n" );
1966     fprintf( outfile, "\tpopl %%ebx\n" );
1967
1968     /* Return to caller */
1969
1970     fprintf( outfile, "\tlret\n" );
1971
1972     /* Declare the return address variables */
1973
1974     fprintf( outfile, "\t.data\n" );
1975     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_word\n" );
1976     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_long\n" );
1977     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_regs\n" );
1978     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Saved32_esp\n" );
1979     fprintf( outfile, PREFIX "CALLTO16_RetAddr_word:\t.long 0\n" );
1980     fprintf( outfile, PREFIX "CALLTO16_RetAddr_long:\t.long 0\n" );
1981     fprintf( outfile, PREFIX "CALLTO16_RetAddr_regs:\t.long 0\n" );
1982     fprintf( outfile, PREFIX "CALLTO16_Saved32_esp:\t.long 0\n" );
1983     fprintf( outfile, "\t.text\n" );
1984 }
1985
1986
1987 /*******************************************************************
1988  *         BuildCallTo32LargeStack
1989  *
1990  * Build the function used to switch to the original 32-bit stack
1991  * before calling a 32-bit function from 32-bit code. This is used for
1992  * functions that need a large stack, like X bitmaps functions.
1993  *
1994  * The generated function has the following prototype:
1995  *   int xxx( int (*func)(), void *arg );
1996  *
1997  * The pointer to the function can be retrieved by calling CALL32_Init,
1998  * which also takes care of saving the current 32-bit stack pointer.
1999  *
2000  * Stack layout:
2001  *   ...     ...
2002  * (ebp+12)  arg
2003  * (ebp+8)   func
2004  * (ebp+4)   ret addr
2005  * (ebp)     ebp
2006  */
2007 static void BuildCallTo32LargeStack( FILE *outfile )
2008 {
2009     /* Initialization function */
2010
2011     fprintf( outfile, "\n\t.align 4\n" );
2012 #ifdef USE_STABS
2013     fprintf( outfile, ".stabs \"CALL32_Init:F1\",36,0,0," PREFIX "CALL32_Init\n");
2014 #endif
2015     fprintf( outfile, "\t.globl " PREFIX "CALL32_Init\n" );
2016     fprintf( outfile, PREFIX "CALL32_Init:\n" );
2017     fprintf( outfile, "\tleal -256(%%esp),%%eax\n" );
2018     fprintf( outfile, "\tmovl %%eax,CALL32_Original32_esp\n" );
2019     fprintf( outfile, "\tmovl $CALL32_LargeStack,%%eax\n" );
2020     fprintf( outfile, "\tret\n" );
2021
2022     /* Function header */
2023
2024     fprintf( outfile, "\n\t.align 4\n" );
2025 #ifdef USE_STABS
2026     fprintf( outfile, ".stabs \"CALL32_LargeStack:F1\",36,0,0,CALL32_LargeStack\n");
2027 #endif
2028     fprintf( outfile, "CALL32_LargeStack:\n" );
2029     
2030     /* Entry code */
2031
2032     fprintf( outfile, "\tpushl %%ebp\n" );
2033     fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
2034
2035     /* Switch to the original 32-bit stack pointer */
2036
2037     fprintf( outfile, "\tmovl CALL32_Original32_esp, %%esp\n" );
2038
2039     /* Transfer the argument and call the function */
2040
2041     fprintf( outfile, "\tpushl 12(%%ebp)\n" );
2042     fprintf( outfile, "\tcall 8(%%ebp)\n" );
2043
2044     /* Restore registers and return */
2045
2046     fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
2047     fprintf( outfile, "\tpopl %%ebp\n" );
2048     fprintf( outfile, "\tret\n" );
2049
2050     /* Data */
2051
2052     fprintf( outfile, "\t.data\n" );
2053     fprintf( outfile, "CALL32_Original32_esp:\t.long 0\n" );
2054     fprintf( outfile, "\t.text\n" );
2055 }
2056
2057
2058 /*******************************************************************
2059  *         BuildCallFrom32Regs
2060  *
2061  * Build a 32-bit-to-Wine call-back function for a 'register' function.
2062  * 'args' is the number of dword arguments.
2063  *
2064  * Stack layout:
2065  *   ...     ...
2066  * (esp+208) ret addr (or relay addr when debugging_relay is on)
2067  * (esp+204) entry point
2068  * (esp+0)   CONTEXT struct
2069  */
2070 static void BuildCallFrom32Regs( FILE *outfile )
2071 {
2072     /* Function header */
2073
2074     fprintf( outfile, "\n\t.align 4\n" );
2075 #ifdef USE_STABS
2076     fprintf( outfile, ".stabs \"CALL32_Regs:F1\",36,0,0," PREFIX "CALL32_Regs\n" );
2077 #endif
2078     fprintf( outfile, "\t.globl " PREFIX "CALL32_Regs\n" );
2079     fprintf( outfile, PREFIX "CALL32_Regs:\n" );
2080
2081     /* Build the context structure */
2082
2083     fprintf( outfile, "\tpushw $0\n" );
2084     fprintf( outfile, "\tpushw %%ss\n" );
2085     fprintf( outfile, "\tpushl %%eax\n" );  /* %esp place holder */
2086     fprintf( outfile, "\tpushfl\n" );
2087     fprintf( outfile, "\tpushw $0\n" );
2088     fprintf( outfile, "\tpushw %%cs\n" );
2089     fprintf( outfile, "\tpushl 20(%%esp)\n" );  /* %eip at time of call */
2090     fprintf( outfile, "\tpushl %%ebp\n" );
2091
2092     fprintf( outfile, "\tpushl %%eax\n" );
2093     fprintf( outfile, "\tpushl %%ecx\n" );
2094     fprintf( outfile, "\tpushl %%edx\n" );
2095     fprintf( outfile, "\tpushl %%ebx\n" );
2096     fprintf( outfile, "\tpushl %%esi\n" );
2097     fprintf( outfile, "\tpushl %%edi\n" );
2098
2099     fprintf( outfile, "\txorl %%eax,%%eax\n" );
2100     fprintf( outfile, "\tmovw %%ds,%%ax\n" );
2101     fprintf( outfile, "\tpushl %%eax\n" );
2102     fprintf( outfile, "\tmovw %%es,%%ax\n" );
2103     fprintf( outfile, "\tpushl %%eax\n" );
2104     fprintf( outfile, "\tmovw %%fs,%%ax\n" );
2105     fprintf( outfile, "\tpushl %%eax\n" );
2106     fprintf( outfile, "\tmovw %%gs,%%ax\n" );
2107     fprintf( outfile, "\tpushl %%eax\n" );
2108
2109     fprintf( outfile, "\tleal -%d(%%esp),%%esp\n",
2110              sizeof(FLOATING_SAVE_AREA) + 6 * sizeof(DWORD) /* DR regs */ );
2111     fprintf( outfile, "\tpushl $0x0001001f\n" );  /* ContextFlags */
2112
2113     fprintf( outfile, "\tfsave %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2114
2115     fprintf( outfile, "\tleal %d(%%esp),%%eax\n",
2116              sizeof(CONTEXT) + 4 ); /* %esp at time of call */
2117     fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Esp) );
2118
2119     fprintf( outfile, "\tcall " PREFIX "RELAY_CallFrom32Regs\n" );
2120
2121     /* Restore the context structure */
2122
2123     fprintf( outfile, "\tfrstor %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2124
2125     /* Store %eip value onto the new stack */
2126
2127     fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Eip) );
2128     fprintf( outfile, "\tmovl %d(%%esp),%%ebx\n", CONTEXTOFFSET(Esp) );
2129     fprintf( outfile, "\tmovl %%eax,0(%%ebx)\n" );
2130
2131     /* Restore all registers */
2132
2133     fprintf( outfile, "\tleal %d(%%esp),%%esp\n",
2134              sizeof(FLOATING_SAVE_AREA) + 7 * sizeof(DWORD) );
2135     fprintf( outfile, "\tpopl %%eax\n" );
2136     fprintf( outfile, "\tmovw %%ax,%%gs\n" );
2137     fprintf( outfile, "\tpopl %%eax\n" );
2138     fprintf( outfile, "\tmovw %%ax,%%fs\n" );
2139     fprintf( outfile, "\tpopl %%eax\n" );
2140     fprintf( outfile, "\tmovw %%ax,%%es\n" );
2141     fprintf( outfile, "\tpopl %%eax\n" );
2142     fprintf( outfile, "\tmovw %%ax,%%ds\n" );
2143
2144     fprintf( outfile, "\tpopl %%edi\n" );
2145     fprintf( outfile, "\tpopl %%esi\n" );
2146     fprintf( outfile, "\tpopl %%ebx\n" );
2147     fprintf( outfile, "\tpopl %%edx\n" );
2148     fprintf( outfile, "\tpopl %%ecx\n" );
2149     fprintf( outfile, "\tpopl %%eax\n" );
2150     fprintf( outfile, "\tpopl %%ebp\n" );
2151     fprintf( outfile, "\tleal 8(%%esp),%%esp\n" );  /* skip %eip and %cs */
2152     fprintf( outfile, "\tpopfl\n" );
2153     fprintf( outfile, "\tpopl %%esp\n" );
2154     fprintf( outfile, "\tret\n" );
2155 }
2156
2157
2158 /*******************************************************************
2159  *         BuildSpec
2160  *
2161  * Build the spec files
2162  */
2163 static int BuildSpec( FILE *outfile, int argc, char *argv[] )
2164 {
2165     int i;
2166     for (i = 2; i < argc; i++)
2167         if (BuildSpecFile( outfile, argv[i] ) < 0) return -1;
2168     return 0;
2169 }
2170
2171
2172 /*******************************************************************
2173  *         BuildCallFrom16
2174  *
2175  * Build the 16-bit-to-Wine callbacks
2176  */
2177 static int BuildCallFrom16( FILE *outfile, char * outname, int argc, char *argv[] )
2178 {
2179     int i;
2180     char buffer[1024];
2181
2182     /* File header */
2183
2184     fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2185     fprintf( outfile, "\t.text\n" );
2186
2187 #ifdef USE_STABS
2188     fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2189     getcwd(buffer, sizeof(buffer));
2190
2191     /*
2192      * The stabs help the internal debugger as they are an indication that it
2193      * is sensible to step into a thunk/trampoline.
2194      */
2195     fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2196     fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2197     fprintf( outfile, "\t.text\n" );
2198     fprintf( outfile, "\t.align 4\n" );
2199     fprintf( outfile, "Code_Start:\n\n" );
2200 #endif
2201
2202     /* Build the callback functions */
2203
2204     for (i = 2; i < argc; i++) BuildCallFrom16Func( outfile, argv[i] );
2205
2206     /* Output the argument debugging strings */
2207
2208     if (debugging)
2209     {
2210         fprintf( outfile, "/* Argument strings */\n" );
2211         for (i = 2; i < argc; i++)
2212         {
2213             fprintf( outfile, "Profile_%s:\n", argv[i] );
2214             fprintf( outfile, "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
2215         }
2216     }
2217
2218 #ifdef USE_STABS
2219     fprintf( outfile, "\t.text\n");
2220     fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2221     fprintf( outfile, ".Letext:\n");
2222 #endif
2223
2224     return 0;
2225 }
2226
2227
2228 /*******************************************************************
2229  *         BuildCallTo16
2230  *
2231  * Build the Wine-to-16-bit callbacks
2232  */
2233 static int BuildCallTo16( FILE *outfile, char * outname, int argc, char *argv[] )
2234 {
2235     char buffer[1024];
2236     int i;
2237
2238     /* File header */
2239
2240     fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2241     fprintf( outfile, "\t.text\n" );
2242
2243 #ifdef USE_STABS
2244     fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2245     getcwd(buffer, sizeof(buffer));
2246
2247     /*
2248      * The stabs help the internal debugger as they are an indication that it
2249      * is sensible to step into a thunk/trampoline.
2250      */
2251     fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2252     fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2253     fprintf( outfile, "\t.text\n" );
2254     fprintf( outfile, "\t.align 4\n" );
2255     fprintf( outfile, "Code_Start:\n\n" );
2256 #endif
2257
2258     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Start\n" );
2259     fprintf( outfile, PREFIX "CALLTO16_Start:\n" );
2260
2261     /* Build the callback functions */
2262
2263     for (i = 2; i < argc; i++) BuildCallTo16Func( outfile, argv[i] );
2264
2265     /* Output the 16-bit return code */
2266
2267     BuildRet16Func( outfile );
2268
2269     fprintf( outfile, "\t.globl " PREFIX "CALLTO16_End\n" );
2270     fprintf( outfile, PREFIX "CALLTO16_End:\n" );
2271
2272 #ifdef USE_STABS
2273     fprintf( outfile, "\t.text\n");
2274     fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2275     fprintf( outfile, ".Letext:\n");
2276 #endif
2277
2278     return 0;
2279 }
2280
2281
2282 /*******************************************************************
2283  *         BuildCall32
2284  *
2285  * Build the 32-bit callbacks
2286  */
2287 static int BuildCall32( FILE *outfile, char * outname )
2288 {
2289     char buffer[1024];
2290
2291     /* File header */
2292
2293     fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2294     fprintf( outfile, "\t.text\n" );
2295
2296 #ifdef USE_STABS
2297     fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2298     getcwd(buffer, sizeof(buffer));
2299
2300     /*
2301      * The stabs help the internal debugger as they are an indication that it
2302      * is sensible to step into a thunk/trampoline.
2303      */
2304     fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2305     fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2306     fprintf( outfile, "\t.text\n" );
2307     fprintf( outfile, "\t.align 4\n" );
2308     fprintf( outfile, "Code_Start:\n" );
2309 #endif
2310
2311     /* Build the 32-bit large stack callback */
2312
2313     BuildCallTo32LargeStack( outfile );
2314
2315     /* Build the register callback function */
2316
2317     BuildCallFrom32Regs( outfile );
2318
2319 #ifdef USE_STABS
2320     fprintf( outfile, "\t.text\n");
2321     fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2322     fprintf( outfile, ".Letext:\n");
2323 #endif
2324
2325     return 0;
2326 }
2327
2328
2329 /*******************************************************************
2330  *         usage
2331  */
2332 static void usage(void)
2333 {
2334     fprintf( stderr,
2335              "usage: build [-o outfile] -spec SPECNAMES\n"
2336              "       build [-o outfile] -callfrom16 FUNCTION_PROFILES\n"
2337              "       build [-o outfile] -callto16 FUNCTION_PROFILES\n"
2338              "       build [-o outfile] -call32\n" );
2339     exit(1);
2340 }
2341
2342
2343 /*******************************************************************
2344  *         main
2345  */
2346 int main(int argc, char **argv)
2347 {
2348     char *outname = NULL;
2349     FILE *outfile = stdout;
2350     int res = -1;
2351
2352     if (argc < 2) usage();
2353
2354     if (!strcmp( argv[1], "-o" ))
2355     {
2356         outname = argv[2];
2357         argv += 2;
2358         argc -= 2;
2359         if (argc < 2) usage();
2360         if (!(outfile = fopen( outname, "w" )))
2361         {
2362             fprintf( stderr, "Unable to create output file '%s'\n", outname );
2363             exit(1);
2364         }
2365     }
2366
2367     if (!strcmp( argv[1], "-spec" ))
2368         res = BuildSpec( outfile, argc, argv );
2369     else if (!strcmp( argv[1], "-callfrom16" ))
2370         res = BuildCallFrom16( outfile, outname, argc, argv );
2371     else if (!strcmp( argv[1], "-callto16" ))
2372         res = BuildCallTo16( outfile, outname, argc, argv );
2373     else if (!strcmp( argv[1], "-call32" ))
2374         res = BuildCall32( outfile, outname );
2375     else
2376     {
2377         fclose( outfile );
2378         unlink( outname );
2379         usage();
2380     }
2381
2382     fclose( outfile );
2383     if (res < 0)
2384     {
2385         unlink( outname );
2386         return 1;
2387     }
2388     return 0;
2389 }