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