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