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