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