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