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