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