Release 950430
[wine] / tools / build.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include "wine.h"
11 #include "module.h"
12 #include "neexe.h"
13
14 /* ELF symbols do not have an underscore in front */
15 #ifdef __ELF__
16 #define PREFIX
17 #else
18 #define PREFIX "_"
19 #endif
20
21 #define TYPE_INVALID     0
22 #define TYPE_BYTE        1
23 #define TYPE_WORD        2
24 #define TYPE_LONG        3
25 #define TYPE_PASCAL_16   4
26 #define TYPE_PASCAL      5
27 #define TYPE_REGISTER    6
28 #define TYPE_ABS         7
29 #define TYPE_RETURN      8
30 #define TYPE_STUB        9
31
32 #define MAX_ORDINALS    1299
33
34   /* Callback function used for stub functions */
35 #define STUB_CALLBACK  "RELAY_Unimplemented"
36
37 typedef struct ordinal_definition_s
38 {
39     int type;
40     int offset;
41     char export_name[80];
42     void *additional_data;
43 } ORDDEF;
44
45 typedef struct ordinal_variable_definition_s
46 {
47     int n_values;
48     int *values;
49 } ORDVARDEF;
50
51 typedef struct ordinal_function_definition_s
52 {
53     int  n_args;
54     char arg_types[32];
55     char internal_name[80];
56 } ORDFUNCDEF;
57
58 typedef struct ordinal_return_definition_s
59 {
60     int arg_size;
61     int ret_value;
62 } ORDRETDEF;
63
64 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
65
66 char LowerDLLName[80];
67 char UpperDLLName[80];
68 int Limit = 0;
69 int DLLId;
70 FILE *SpecFp;
71
72 char *ParseBuffer = NULL;
73 char *ParseNext;
74 char ParseSaveChar;
75 int Line;
76
77 static int debugging = 1;
78
79   /* Offset of register relative to the end of the context struct */
80 #define CONTEXTOFFSET(reg) \
81    ((int)&(((struct sigcontext_struct *)1)->reg) - 1 \
82     - sizeof(struct sigcontext_struct))
83
84 static int IsNumberString(char *s)
85 {
86     while (*s != '\0')
87         if (!isdigit(*s++))
88             return 0;
89
90     return 1;
91 }
92
93 static char *strlower(char *s)
94 {
95     char *p;
96     
97     for(p = s; *p != '\0'; p++)
98         *p = tolower(*p);
99
100     return s;
101 }
102
103 static char *strupper(char *s)
104 {
105     char *p;
106     
107     for(p = s; *p != '\0'; p++)
108         *p = toupper(*p);
109
110     return s;
111 }
112
113 static char * GetTokenInLine(void)
114 {
115     char *p;
116     char *token;
117
118     if (ParseNext != ParseBuffer)
119     {
120         if (ParseSaveChar == '\0')
121             return NULL;
122         *ParseNext = ParseSaveChar;
123     }
124     
125     /*
126      * Remove initial white space.
127      */
128     for (p = ParseNext; isspace(*p); p++)
129         ;
130     
131     if ((*p == '\0') || (*p == '#'))
132         return NULL;
133     
134     /*
135      * Find end of token.
136      */
137     token = p++;
138     if (*token != '(' && *token != ')')
139         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
140             p++;
141     
142     ParseSaveChar = *p;
143     ParseNext = p;
144     *p = '\0';
145
146     return token;
147 }
148
149 static char * GetToken(void)
150 {
151     char *token;
152
153     if (ParseBuffer == NULL)
154     {
155         ParseBuffer = malloc(512);
156         ParseNext = ParseBuffer;
157         Line++;
158         while (1)
159         {
160             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
161                 return NULL;
162             if (ParseBuffer[0] != '#')
163                 break;
164         }
165     }
166
167     while ((token = GetTokenInLine()) == NULL)
168     {
169         ParseNext = ParseBuffer;
170         Line++;
171         while (1)
172         {
173             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
174                 return NULL;
175             if (ParseBuffer[0] != '#')
176                 break;
177         }
178     }
179
180     return token;
181 }
182
183 static int ParseVariable(int ordinal, int type)
184 {
185     ORDDEF *odp;
186     ORDVARDEF *vdp;
187     char export_name[80];
188     char *token;
189     char *endptr;
190     int *value_array;
191     int n_values;
192     int value_array_size;
193     
194     strcpy(export_name, GetToken());
195
196     token = GetToken();
197     if (*token != '(')
198     {
199         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
200         exit(1);
201     }
202
203     n_values = 0;
204     value_array_size = 25;
205     value_array = malloc(sizeof(*value_array) * value_array_size);
206     
207     while ((token = GetToken()) != NULL)
208     {
209         if (*token == ')')
210             break;
211
212         value_array[n_values++] = strtol(token, &endptr, 0);
213         if (n_values == value_array_size)
214         {
215             value_array_size += 25;
216             value_array = realloc(value_array, 
217                                   sizeof(*value_array) * value_array_size);
218         }
219         
220         if (endptr == NULL || *endptr != '\0')
221         {
222             fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
223                     token);
224             exit(1);
225         }
226     }
227     
228     if (token == NULL)
229     {
230         fprintf(stderr, "%d: End of file in variable declaration\n", Line);
231         exit(1);
232     }
233
234     if (ordinal >= MAX_ORDINALS)
235     {
236         fprintf(stderr, "%d: Ordinal number too large\n", Line);
237         exit(1);
238     }
239     
240     odp = &OrdinalDefinitions[ordinal];
241     odp->type = type;
242     strcpy(odp->export_name, export_name);
243
244     vdp = malloc(sizeof(*vdp));
245     odp->additional_data = vdp;
246     
247     vdp->n_values = n_values;
248     vdp->values = realloc(value_array, sizeof(*value_array) * n_values);
249
250     return 0;
251 }
252
253 static int ParseExportFunction(int ordinal, int type)
254 {
255     char *token;
256     ORDDEF *odp;
257     ORDFUNCDEF *fdp;
258     int i;
259     
260     odp = &OrdinalDefinitions[ordinal];
261     strcpy(odp->export_name, GetToken());
262     odp->type = type;
263     fdp = malloc(sizeof(*fdp));
264     odp->additional_data = fdp;
265
266     token = GetToken();
267     if (*token != '(')
268     {
269         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
270         exit(1);
271     }
272
273     for (i = 0; i < 16; i++)
274     {
275         token = GetToken();
276         if (*token == ')')
277             break;
278
279         if (!strcmp(token, "byte") || !strcmp(token, "word"))
280             fdp->arg_types[i] = 'w';
281         else if (!strcmp(token, "s_byte") || !strcmp(token, "s_word"))
282             fdp->arg_types[i] = 's';
283         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
284             fdp->arg_types[i] = 'l';
285         else if (!strcmp(token, "ptr"))
286             fdp->arg_types[i] = 'p';
287         else
288         {
289             fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
290             exit(1);
291         }
292     }
293     fdp->arg_types[i] = '\0';
294
295     if ((type == TYPE_REGISTER) && (i > 0))
296     {
297         fprintf( stderr, "%d: Register function can't have arguments\n", Line);
298         exit(1);
299     }
300
301     strcpy(fdp->internal_name, GetToken());
302     return 0;
303 }
304
305 static int ParseEquate(int ordinal)
306 {
307     ORDDEF *odp;
308     char *token;
309     char *endptr;
310     int value;
311     
312     odp = &OrdinalDefinitions[ordinal];
313     strcpy(odp->export_name, GetToken());
314
315     token = GetToken();
316     value = strtol(token, &endptr, 0);
317     if (endptr == NULL || *endptr != '\0')
318     {
319         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
320                 token);
321         exit(1);
322     }
323
324     odp->type = TYPE_ABS;
325     odp->additional_data = (void *) value;
326
327     return 0;
328 }
329
330 static int ParseReturn(int ordinal)
331 {
332     ORDDEF *odp;
333     ORDRETDEF *rdp;
334     char *token;
335     char *endptr;
336     
337     rdp = malloc(sizeof(*rdp));
338     
339     odp = &OrdinalDefinitions[ordinal];
340     strcpy(odp->export_name, GetToken());
341     odp->type = TYPE_RETURN;
342     odp->additional_data = rdp;
343
344     token = GetToken();
345     rdp->arg_size = strtol(token, &endptr, 0);
346     if (endptr == NULL || *endptr != '\0')
347     {
348         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
349                 token);
350         exit(1);
351     }
352
353     token = GetToken();
354     rdp->ret_value = strtol(token, &endptr, 0);
355     if (endptr == NULL || *endptr != '\0')
356     {
357         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
358                 token);
359         exit(1);
360     }
361
362     return 0;
363 }
364
365
366 static int ParseStub( int ordinal )
367 {
368     ORDDEF *odp;
369     ORDFUNCDEF *fdp;
370     
371     odp = &OrdinalDefinitions[ordinal];
372     strcpy( odp->export_name, GetToken() );
373     odp->type = TYPE_STUB;
374     fdp = malloc(sizeof(*fdp));
375     odp->additional_data = fdp;
376     fdp->arg_types[0] = '\0';
377     strcpy( fdp->internal_name, STUB_CALLBACK );
378     return 0;
379 }
380
381
382 static int ParseOrdinal(int ordinal)
383 {
384     char *token;
385     
386     if (ordinal >= MAX_ORDINALS)
387     {
388         fprintf(stderr, "%d: Ordinal number too large\n", Line);
389         exit(1);
390     }
391     if (ordinal > Limit) Limit = ordinal;
392
393     token = GetToken();
394     if (token == NULL)
395     {
396         fprintf(stderr, "%d: Expected type after ordinal\n", Line);
397         exit(1);
398     }
399
400     if (strcmp(token, "byte") == 0)
401         return ParseVariable(ordinal, TYPE_BYTE);
402     else if (strcmp(token, "word") == 0)
403         return ParseVariable(ordinal, TYPE_WORD);
404     else if (strcmp(token, "long") == 0)
405         return ParseVariable(ordinal, TYPE_LONG);
406     else if (strcmp(token, "p") == 0)
407         return ParseExportFunction(ordinal, TYPE_PASCAL);
408     else if (strcmp(token, "pascal") == 0)
409         return ParseExportFunction(ordinal, TYPE_PASCAL);
410     else if (strcmp(token, "pascal16") == 0)
411         return ParseExportFunction(ordinal, TYPE_PASCAL_16);
412     else if (strcmp(token, "register") == 0)
413         return ParseExportFunction(ordinal, TYPE_REGISTER);
414     else if (strcmp(token, "equate") == 0)
415         return ParseEquate(ordinal);
416     else if (strcmp(token, "return") == 0)
417         return ParseReturn(ordinal);
418     else if (strcmp(token, "stub") == 0)
419         return ParseStub(ordinal);
420     else
421     {
422         fprintf(stderr, 
423                 "%d: Expected type after ordinal, found '%s' instead\n",
424                 Line, token);
425         exit(1);
426     }
427 }
428
429 static int ParseTopLevel(void)
430 {
431     char *token;
432     
433     while ((token = GetToken()) != NULL)
434     {
435         if (strcmp(token, "name") == 0)
436         {
437             strcpy(LowerDLLName, GetToken());
438             strlower(LowerDLLName);
439
440             strcpy(UpperDLLName, LowerDLLName);
441             strupper(UpperDLLName);
442         }
443         else if (strcmp(token, "id") == 0)
444         {
445             token = GetToken();
446             if (!IsNumberString(token))
447             {
448                 fprintf(stderr, "%d: Expected number after id\n", Line);
449                 exit(1);
450             }
451             
452             DLLId = atoi(token);
453         }
454         else if (IsNumberString(token))
455         {
456             int ordinal;
457             int rv;
458             
459             ordinal = atoi(token);
460             if ((rv = ParseOrdinal(ordinal)) < 0)
461                 return rv;
462         }
463         else
464         {
465             fprintf(stderr, 
466                     "%d: Expected name, id, length or ordinal\n", Line);
467             exit(1);
468         }
469     }
470
471     return 0;
472 }
473
474
475 static int OutputVariableCode(FILE *fp, char *storage, ORDDEF *odp)
476 {
477     ORDVARDEF *vdp;
478     int i;
479
480     vdp = odp->additional_data;
481     fprintf( fp, "\t.data\n" );
482     for (i = 0; i < vdp->n_values; i++)
483     {
484         if ((i & 7) == 0)
485             fprintf(fp, "\t%s\t", storage);
486             
487         fprintf(fp, "%d", vdp->values[i]);
488         
489         if ((i & 7) == 7 || i == vdp->n_values - 1)
490             fprintf(fp, "\n");
491         else
492             fprintf(fp, ", ");
493     }
494     fprintf(fp, "\n");
495     fprintf( fp, "\t.text\n" );
496     return vdp->n_values;
497 }
498
499
500 /*******************************************************************
501  *         BuildModule
502  *
503  * Build the in-memory representation of the module, and dump it
504  * as a byte stream into the assembly code.
505  */
506 static void BuildModule( FILE *fp, int max_code_offset, int max_data_offset )
507 {
508     ORDDEF *odp;
509     int i, size;
510     char *buffer;
511     NE_MODULE *pModule;
512     SEGTABLEENTRY *pSegment;
513     LOADEDFILEINFO *pFileInfo;
514     BYTE *pstr, *bundle;
515     WORD *pword;
516
517     /*   Module layout:
518      * NE_MODULE       Module
519      * LOADEDFILEINFO  File information
520      * SEGTABLEENTRY   Segment 1 (code)
521      * SEGTABLEENTRY   Segment 2 (data)
522      * WORD[2]         Resource table (empty)
523      * BYTE[2]         Imported names (empty)
524      * BYTE[n]         Resident names table
525      * BYTE[n]         Entry table
526      */
527
528     buffer = malloc( 0x10000 );
529
530     pModule = (NE_MODULE *)buffer;
531     pModule->magic = NE_SIGNATURE;
532     pModule->count = 1;
533     pModule->next = 0;
534     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_LIBMODULE;
535     pModule->dgroup = 2;
536     pModule->heap_size = 0xffff;
537     pModule->stack_size = 0;
538     pModule->ip = 0;
539     pModule->cs = 0;
540     pModule->sp = 0;
541     pModule->ss = 0;
542     pModule->seg_count = 2;
543     pModule->modref_count = 0;
544     pModule->nrname_size = 0;
545     pModule->modref_table = 0;
546     pModule->nrname_fpos = 0;
547     pModule->moveable_entries = 0;
548     pModule->alignment = 0;
549     pModule->truetype = 0;
550     pModule->os_flags = NE_OSFLAGS_WINDOWS;
551     pModule->misc_flags = 0;
552     pModule->reserved = 0;
553     pModule->nrname_handle = 0;
554     pModule->min_swap_area = 0;
555     pModule->expected_version = 0x030a;
556
557       /* File information */
558
559     pFileInfo = (LOADEDFILEINFO *)(pModule + 1);
560     pModule->fileinfo = (int)pFileInfo - (int)pModule;
561     pFileInfo->length = sizeof(LOADEDFILEINFO) + strlen(UpperDLLName) + 3;
562     pFileInfo->fixed_media = 0;
563     pFileInfo->error = 0;
564     pFileInfo->date = 0;
565     pFileInfo->time = 0;
566     sprintf( pFileInfo->filename, "%s.DLL", UpperDLLName );
567     pstr = (char *)pFileInfo + pFileInfo->length + 1;
568         
569       /* Segment table */
570
571     pSegment = (SEGTABLEENTRY *)pstr;
572     pModule->seg_table = (int)pSegment - (int)pModule;
573     pSegment->filepos = 0;
574     pSegment->size = max_code_offset;
575     pSegment->flags = 0;
576     pSegment->minsize = max_code_offset;
577     pSegment->selector = 0;
578     pSegment++;
579
580     pModule->dgroup_entry = (int)pSegment - (int)pModule;
581     pSegment->filepos = 0;
582     pSegment->size = max_data_offset;
583     pSegment->flags = NE_SEGFLAGS_DATA;
584     pSegment->minsize = max_data_offset;
585     pSegment->selector = 0;
586     pSegment++;
587
588       /* Resource table */
589
590     pword = (WORD *)pSegment;
591     pModule->res_table = (int)pword - (int)pModule;
592     *pword++ = 0;
593     *pword++ = 0;
594
595       /* Imported names table */
596
597     pstr = (char *)pword;
598     pModule->import_table = (int)pstr - (int)pModule;
599     *pstr++ = 0;
600     *pstr++ = 0;
601
602       /* Resident names table */
603
604     pModule->name_table = (int)pstr - (int)pModule;
605     /* First entry is module name */
606     *pstr = strlen(UpperDLLName );
607     strcpy( pstr + 1, UpperDLLName );
608     pstr += *pstr + 1;
609     *(WORD *)pstr = 0;
610     pstr += sizeof(WORD);
611     /* Store all ordinals */
612     odp = OrdinalDefinitions + 1;
613     for (i = 1; i <= Limit; i++, odp++)
614     {
615         if (!odp->export_name[0]) continue;
616         *pstr = strlen( odp->export_name );
617         strcpy( pstr + 1, odp->export_name );
618         strupper( pstr + 1 );
619         pstr += *pstr + 1;
620         *(WORD *)pstr = i;
621         pstr += sizeof(WORD);
622     }
623     *pstr++ = 0;
624
625       /* Entry table */
626
627     pModule->entry_table = (int)pstr - (int)pModule;
628     bundle = NULL;
629     odp = OrdinalDefinitions + 1;
630     for (i = 1; i <= Limit; i++, odp++)
631     {
632         int selector = 0;
633
634         switch (odp->type)
635         {
636         case TYPE_INVALID:
637             selector = 0;  /* Invalid selector */
638             break;
639
640         case TYPE_PASCAL:
641         case TYPE_PASCAL_16:
642         case TYPE_REGISTER:
643         case TYPE_RETURN:
644         case TYPE_STUB:
645             selector = 1;  /* Code selector */
646             break;
647
648         case TYPE_BYTE:
649         case TYPE_WORD:
650         case TYPE_LONG:
651             selector = 2;  /* Data selector */
652             break;
653
654         case TYPE_ABS:
655             selector = 0xfe;  /* Constant selector */
656             break;
657         }
658
659           /* create a new bundle if necessary */
660         if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
661         {
662             bundle = pstr;
663             bundle[0] = 0;
664             bundle[1] = selector;
665             pstr += 2;
666         }
667
668         (*bundle)++;
669         if (selector != 0)
670         {
671             *pstr++ = 1;
672             *(WORD *)pstr = odp->offset;
673             pstr += sizeof(WORD);
674         }
675     }
676     *pstr++ = 0;
677
678       /* Dump the module content */
679
680     fprintf( fp, "\t.data\n" );
681     fprintf( fp, "\t.globl " PREFIX "%s_Module_Start\n", UpperDLLName );
682     fprintf( fp, PREFIX "%s_Module_Start:\n", UpperDLLName );
683     size = (int)pstr - (int)pModule;
684     for (i = 0, pstr = buffer; i < size; i++, pstr++)
685     {
686         if (!(i & 7)) fprintf( fp, "\t.byte " );
687         fprintf( fp, "%d%c", *pstr, ((i & 7) != 7) ? ',' : '\n' );
688     }
689     if (i & 7) fprintf( fp, "0\n" );
690     fprintf( fp, "\t.globl " PREFIX "%s_Module_End\n", UpperDLLName );
691     fprintf( fp, PREFIX "%s_Module_End:\n", UpperDLLName );
692 }
693
694
695 static void BuildSpecFiles( char *specname)
696 {
697     ORDDEF *odp;
698     ORDFUNCDEF *fdp;
699     ORDRETDEF *rdp;
700     FILE *fp;
701     char filename[80];
702     int i;
703     int code_offset, data_offset;
704
705     SpecFp = fopen( specname, "r");
706     if (SpecFp == NULL)
707     {
708         fprintf(stderr, "Could not open specification file, '%s'\n", specname);
709         exit(1);
710     }
711
712     ParseTopLevel();
713
714     sprintf(filename, "dll_%s.S", LowerDLLName);
715     fp = fopen(filename, "w");
716     fprintf( fp, "/* File generated automatically; do not edit! */\n" );
717     fprintf( fp, "\t.data\n" );
718     fprintf( fp, "\t.globl " PREFIX "%s_Data_Start\n", UpperDLLName );
719     fprintf( fp, PREFIX "%s_Data_Start:\n", UpperDLLName );
720     fprintf( fp, "\t.word 0,0,0,0,0,0,0,0\n" );
721     data_offset = 16;
722     fprintf( fp, "\t.text\n" );
723     fprintf( fp, "\t.globl " PREFIX "%s_Code_Start\n", UpperDLLName );
724     fprintf( fp, PREFIX "%s_Code_Start:\n", UpperDLLName );
725     code_offset = 0;
726
727     odp = OrdinalDefinitions;
728     for (i = 0; i <= Limit; i++, odp++)
729     {
730         fdp = odp->additional_data;
731         rdp = odp->additional_data;
732             
733         switch (odp->type)
734         {
735           case TYPE_INVALID:
736             odp->offset = 0xffff;
737             break;
738
739           case TYPE_ABS:
740             odp->offset = (int)odp->additional_data & 0xffff;
741             break;
742
743           case TYPE_BYTE:
744             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
745             odp->offset = data_offset;
746             data_offset += OutputVariableCode(fp, ".byte", odp);
747             break;
748
749           case TYPE_WORD:
750             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
751             odp->offset = data_offset;
752             data_offset += 2 * OutputVariableCode(fp, ".word", odp);
753             break;
754
755           case TYPE_LONG:
756             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
757             odp->offset = data_offset;
758             data_offset += 4 * OutputVariableCode(fp, ".long", odp);
759             break;
760
761           case TYPE_RETURN:
762             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
763             fprintf( fp, "\tmovw $%d,%%ax\n", rdp->ret_value & 0xffff );
764             fprintf( fp, "\tmovw $%d,%%dx\n", (rdp->ret_value >> 16) & 0xffff);
765             fprintf(fp, "\t.byte 0x66\n");
766             if (rdp->arg_size != 0)
767                 fprintf(fp, "\tlret $%d\n", rdp->arg_size);
768             else
769                 fprintf(fp, "\tlret\n");
770             odp->offset = code_offset;
771             code_offset += 10;  /* Assembly code is 10 bytes long */
772             if (rdp->arg_size != 0) code_offset += 2;
773             break;
774
775           case TYPE_REGISTER:
776           case TYPE_PASCAL:
777           case TYPE_PASCAL_16:
778           case TYPE_STUB:
779             fprintf( fp, "/* %s.%d */\n", UpperDLLName, i);
780             fprintf(fp, "\tpushw %%bp\n" );
781             fprintf(fp, "\tpushl $0x%08x\n", (DLLId << 16) | i);
782             fprintf(fp, "\tpushl $" PREFIX "%s\n", fdp->internal_name );
783             fprintf(fp, "\tljmp $0x%04x, $" PREFIX "CallTo32_%s_%s\n\n",
784                         WINE_CODE_SELECTOR,
785                         (odp->type == TYPE_REGISTER) ? "regs" :
786                         (odp->type == TYPE_PASCAL) ? "long" : "word",
787                         fdp->arg_types );
788             odp->offset = code_offset;
789             code_offset += 19;  /* Assembly code is 19 bytes long */
790             break;
791                 
792           default:
793             fprintf( stderr, "build: Unknown function type; please report.\n");
794             break;
795         }
796     }
797
798     if (!code_offset)  /* Make sure the code segment is not empty */
799     {
800         fprintf( fp, "\t.byte 0\n" );
801         code_offset++;
802     }
803
804     BuildModule( fp, code_offset, data_offset );
805
806     fclose(fp);
807
808     sprintf(filename, "tab_%s.c", LowerDLLName);
809     fp = fopen(filename, "w");
810
811     fprintf( fp, "/* File generated automatically; do not edit! */\n\n" );
812     fprintf( fp, "#include \"dlls.h\"\n\n" );
813     fprintf( fp, "static struct dll_table_entry_s %s_table_entries[%d] =\n{\n",
814                  UpperDLLName, Limit + 1);
815     odp = OrdinalDefinitions;
816     for (i = 0; i <= Limit; i++, odp++)
817     {
818         int selector = 0;
819
820         switch (odp->type)
821         {
822         case TYPE_INVALID:
823             selector = 0;  /* Invalid selector */
824             break;
825
826         case TYPE_PASCAL:
827         case TYPE_PASCAL_16:
828         case TYPE_REGISTER:
829         case TYPE_RETURN:
830         case TYPE_STUB:
831             selector = 1;  /* Code selector */
832             break;
833
834         case TYPE_BYTE:
835         case TYPE_WORD:
836         case TYPE_LONG:
837             selector = 2;  /* Data selector */
838             break;
839
840         case TYPE_ABS:
841             selector = 0xff;  /* Constant selector */
842             break;
843         }
844
845 /*         fprintf(fp, "    { %d, %d, ", selector, odp->offset ); */
846         fprintf( fp, "    { " );
847         fprintf(fp, "\"%s\" ", odp->export_name);
848 #ifdef WINESTAT
849         fprintf(fp, ",0 ");
850 #endif      
851         fprintf(fp, "}, \n");
852     }
853
854     fprintf(fp, "};\n\n");
855
856     fprintf( fp, "extern BYTE %s_Code_Start[];\n", UpperDLLName );
857     fprintf( fp, "extern BYTE %s_Data_Start[];\n", UpperDLLName );
858     fprintf( fp, "extern BYTE %s_Module_Start[];\n", UpperDLLName );
859     fprintf( fp, "extern BYTE %s_Module_End[];\n\n", UpperDLLName );
860     fprintf( fp, "struct dll_table_s %s_table =\n{\n", UpperDLLName );
861     fprintf( fp, "  %s_table_entries, %d, %d,\n",
862              UpperDLLName, Limit + 1, DLLId );
863     fprintf( fp, "  %s_Code_Start, %s_Data_Start,\n",
864              UpperDLLName, UpperDLLName );
865     fprintf( fp, "  %s_Module_Start, %s_Module_End\n};\n",
866              UpperDLLName, UpperDLLName );
867     fclose(fp);
868 }
869
870
871 /*******************************************************************
872  *         TransferArgs16To32
873  *
874  * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
875  * The 16-bit stack layout is:
876  *   ...     ...
877  *  (bp+8)    arg2
878  *  (bp+6)    arg1
879  *  (bp+4)    cs
880  *  (bp+2)    ip
881  *  (bp)      bp
882  */
883 static int TransferArgs16To32( char *args )
884 {
885     int i, pos16, pos32;
886
887     /* Save ebx first */
888
889     printf( "\tpushl %%ebx\n" );
890
891     /* Get the 32-bit stack pointer */
892
893     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
894
895     /* Copy the arguments */
896
897     pos16 = 6;  /* skip bp and return address */
898     pos32 = 0;
899
900     for (i = strlen(args); i > 0; i--)
901     {
902         pos32 -= 4;
903         switch(args[i-1])
904         {
905         case 'w':  /* word */
906             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
907             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
908             pos16 += 2;
909             break;
910
911         case 's':  /* s_word */
912             printf( "\tmovswl %d(%%ebp),%%eax\n", pos16 );
913             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
914             pos16 += 2;
915             break;
916
917         case 'l':  /* long */
918             printf( "\tmovl %d(%%ebp),%%eax\n", pos16 );
919             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
920             pos16 += 4;
921             break;
922
923         case 'p':  /* ptr */
924             /* Get the selector */
925             printf( "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
926             /* Get the selector base */
927             printf( "\tandl $0xfff8,%%eax\n" );
928             printf( "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
929             printf( "\tmovl %%eax,%d(%%ebx)\n", pos32 );
930             /* Add the offset */
931             printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
932             printf( "\taddl %%eax,%d(%%ebx)\n", pos32 );
933             pos16 += 4;
934             break;
935
936         default:
937             fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
938         }
939     }
940
941     /* Restore ebx */
942     
943     printf( "\tpopl %%ebx\n" );
944
945     return pos16 - 6;  /* Return the size of the 16-bit args */
946 }
947
948
949 /*******************************************************************
950  *         BuildContext
951  *
952  * Build the context structure on the 32-bit stack.
953  * The only valid registers in the context structure are:
954  *   eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
955  */
956 static void BuildContext(void)
957 {
958     /* Save ebx first */
959
960     printf( "\tpushl %%ebx\n" );
961
962     /* Get the 32-bit stack pointer */
963
964     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
965
966     /* Store the registers */
967
968     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_ebx) ); /* Get ebx from stack */
969     printf( "\tmovl %%eax,%d(%%ebx)\n", CONTEXTOFFSET(sc_eax) );
970     printf( "\tmovl %%ecx,%d(%%ebx)\n", CONTEXTOFFSET(sc_ecx) );
971     printf( "\tmovl %%edx,%d(%%ebx)\n", CONTEXTOFFSET(sc_edx) );
972     printf( "\tmovl %%esi,%d(%%ebx)\n", CONTEXTOFFSET(sc_esi) );
973     printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(sc_edi) );
974     printf( "\tpushw %%es\n" );
975     printf( "\tpopw %d(%%ebx)\n", CONTEXTOFFSET(sc_es) );
976     printf( "\tmovw -10(%%ebp),%%ax\n" );  /* Get saved ds from stack */
977     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(sc_ds) );
978     printf( "\tpushfl\n" );
979 #ifndef __FreeBSD__
980     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
981 #else    
982     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
983 #endif
984 }
985
986
987 /*******************************************************************
988  *         RestoreContext
989  *
990  * Restore the registers from the context structure
991  */
992 static void RestoreContext(void)
993 {
994     /* Get the 32-bit stack pointer */
995
996     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
997
998     /* Restore the registers */
999
1000     printf( "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(sc_ecx) );
1001     printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(sc_edx) );
1002     printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(sc_esi) );
1003     printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(sc_edi) );
1004     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_es) );
1005     printf( "\tpopw %%es\n" );
1006     printf( "\tpopw %%ax\n" );  /* Remove old ds from the stack */
1007     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(sc_ds) ); /* Push new ds */
1008 #ifndef __FreeBSD__
1009     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_eflags) );
1010 #else    
1011     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(sc_efl) );
1012 #endif
1013     printf( "\tpopfl\n" );
1014     printf( "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(sc_eax) );
1015     printf( "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(sc_ebx) );
1016 }
1017
1018
1019 /*******************************************************************
1020  *         BuildCall32Func
1021  *
1022  * Build a 32-bit callback function. The syntax of the function
1023  * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1024  * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1025  * 'l'=long, 'p'=pointer).
1026  *
1027  * Stack layout upon entry to the callback function:
1028  *  ...      ...
1029  * (sp+14)  first 16-bit arg
1030  * (sp+12)  cs (word)
1031  * (sp+10)  ip (word)
1032  * (sp+8)   bp (word)
1033  * (sp+4)   dll_id+ordinal (long)
1034  * (sp)     entrypoint (long)
1035  *
1036  */
1037 static void BuildCall32Func( char *profile )
1038 {
1039     int argsize = 0;
1040     int short_ret = 0;
1041     int reg_func = 0;
1042     char *args = profile + 5;
1043
1044     /* Parse function type */
1045
1046     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1047     else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1048     else if (strncmp( "long_", profile, 5 ))
1049     {
1050         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1051         return;
1052     }
1053
1054     /* Function header */
1055
1056     printf( "/**********\n" );
1057     printf( " * " PREFIX "CallTo32_%s\n", profile );
1058     printf( " **********/\n" );
1059     printf( "\t.align 4\n" );
1060     printf( "\t.globl " PREFIX "CallTo32_%s\n\n", profile );
1061     printf( PREFIX "CallTo32_%s:\n", profile );
1062
1063     /* Setup bp to point to its copy on the stack */
1064
1065     printf( "\tmovzwl %%sp,%%ebp\n" );
1066     printf( "\taddw $8,%%bp\n" );
1067
1068     /* Save 16-bit ds */
1069
1070     printf( "\tpushw %%ds\n" );
1071
1072     /* Restore 32-bit ds */
1073
1074     printf( "\tpushw $0x%04x\n", WINE_DATA_SELECTOR );
1075     printf( "\tpopw %%ds\n" );
1076
1077     /* Save the 16-bit stack */
1078
1079     printf( "\tpushw " PREFIX "IF1632_Saved16_sp\n" );
1080     printf( "\tpushw " PREFIX "IF1632_Saved16_ss\n" );
1081     printf( "\tmovw %%ss," PREFIX "IF1632_Saved16_ss\n" );
1082     printf( "\tmovw %%sp," PREFIX "IF1632_Saved16_sp\n" );
1083
1084     /* Transfer the arguments */
1085
1086     if (reg_func) BuildContext();
1087     else if (*args) argsize = TransferArgs16To32( args );
1088
1089     /* Get the address of the API function */
1090
1091     printf( "\tmovl -8(%%ebp),%%eax\n" );
1092
1093     /* Setup es */
1094
1095     printf( "\tpushw %%ds\n" );
1096     printf( "\tpopw %%es\n" );
1097
1098     /* Switch to the 32-bit stack */
1099
1100     printf( "\tpushw %%ds\n" );
1101     printf( "\tpopw %%ss\n" );
1102     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1103
1104     /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1105
1106     printf( "\tmovl %%esp,%%ebp\n" );
1107     printf( "\taddl $24,%%ebp\n" );
1108
1109     if (reg_func)
1110         printf( "\tsubl $%d,%%esp\n", sizeof(struct sigcontext_struct) );
1111     else if (*args)
1112         printf( "\tsubl $%d,%%esp\n", 4 * strlen(args) );
1113
1114     /* Call the entry point */
1115
1116     if (debugging)
1117     {
1118         printf( "\tpushl %%eax\n" );
1119         printf( "\tpushl $CALL32_Str_%s\n", profile );
1120         printf( "\tcall " PREFIX "RELAY_DebugCall32\n" );
1121         printf( "\tpopl %%eax\n" );
1122         printf( "\tpopl %%eax\n" );
1123     }
1124
1125     printf( "\tcall %%eax\n" );
1126
1127     if (debugging)
1128     {
1129         printf( "\tpushl %%eax\n" );
1130         printf( "\tpushl $%d\n", short_ret );
1131         printf( "\tcall " PREFIX "RELAY_DebugReturn\n" );
1132         printf( "\tpopl %%eax\n" );
1133         printf( "\tpopl %%eax\n" );
1134     }
1135
1136     if (reg_func)
1137         printf( "\taddl $%d,%%esp\n", sizeof(struct sigcontext_struct) );
1138     else if (*args)
1139         printf( "\taddl $%d,%%esp\n", 4 * strlen(args) );
1140
1141     /* Restore the 16-bit stack */
1142
1143     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1144     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1145     printf( "\tpopw " PREFIX "IF1632_Saved16_ss\n" );
1146     printf( "\tpopw " PREFIX "IF1632_Saved16_sp\n" );
1147
1148     if (reg_func)
1149     {
1150         /* Restore registers from the context structure */
1151         RestoreContext();
1152     }
1153     else  /* Store the return value in dx:ax if needed */
1154     {
1155         if (!short_ret)
1156         {
1157             printf( "\tpushl %%eax\n" );
1158             printf( "\tpopw %%dx\n" );
1159             printf( "\tpopw %%dx\n" );
1160         }
1161     }
1162
1163     /* Restore ds and bp */
1164
1165     printf( "\tpopw %%ds\n" );
1166     printf( "\tpopl %%ebp\n" );  /* Remove entry point address */
1167     printf( "\tpopl %%ebp\n" );  /* Remove DLL id and ordinal */
1168     printf( "\tpopw %%bp\n" );
1169
1170     /* Remove the arguments and return */
1171
1172     if (argsize)
1173     {
1174         printf( "\t.byte 0x66\n" );
1175         printf( "\tlret $%d\n", argsize );
1176     }
1177     else
1178     {
1179         printf( "\t.byte 0x66\n" );
1180         printf( "\tlret\n" );
1181     }
1182 }
1183
1184
1185 /*******************************************************************
1186  *         BuildCall16Func
1187  *
1188  * Build a 16-bit callback function.
1189  *
1190  * Stack frame of the callback function:
1191  *  ...      ...
1192  * (ebp+24) arg2
1193  * (ebp+20) arg1
1194  * (ebp+16) 16-bit ds
1195  * (ebp+12) func to call
1196  * (ebp+8)  code selector
1197  * (ebp+4)  return address
1198  * (ebp)    previous ebp
1199  *
1200  * Prototypes for the CallTo16 functions:
1201  *   extern WORD CallTo16_word_xxx( FARPROC func, WORD ds, args... );
1202  *   extern LONG CallTo16_long_xxx( FARPROC func, WORD ds, args... );
1203  *   extern void CallTo16_regs_( FARPROC func, WORD ds, WORD es, WORD bp,
1204  *                               WORD ax, WORD bx, WORD cx, WORD dx,
1205  *                               WORD si, WORD di );
1206  */
1207 static void BuildCall16Func( char *profile )
1208 {
1209     int short_ret = 0;
1210     int reg_func = 0;
1211     char *args = profile + 5;
1212
1213     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1214     else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1215     else if (strncmp( "long_", profile, 5 ))
1216     {
1217         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1218         return;
1219     }
1220
1221     /* Function header */
1222
1223     printf( "/**********\n" );
1224     printf( " * " PREFIX "CallTo16_%s\n", profile );
1225     printf( " **********/\n" );
1226     printf( "\t.align 4\n" );
1227     printf( "\t.globl " PREFIX "CallTo16_%s\n\n", profile );
1228     printf( PREFIX "CallTo16_%s:\n", profile );
1229
1230     /* Push code selector before return address to simulate a lcall */
1231
1232     printf( "\tpopl %%eax\n" );
1233     printf( "\tpushl $0x%04x\n", WINE_CODE_SELECTOR );
1234     printf( "\tpushl %%eax\n" );
1235
1236     /* Entry code */
1237
1238     printf( "\tpushl %%ebp\n" );
1239     printf( "\tmovl %%esp,%%ebp\n" );
1240
1241     /* Save the 32-bit registers */
1242
1243     printf( "\tpushl %%ebx\n" );
1244     printf( "\tpushl %%ecx\n" );
1245     printf( "\tpushl %%edx\n" );
1246     printf( "\tpushl %%esi\n" );
1247     printf( "\tpushl %%edi\n" );
1248
1249     /* Save the 32-bit stack */
1250
1251     printf( "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1252     printf( "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1253     printf( "\tmovl %%ebp,%%ebx\n" );
1254
1255     /* Print debugging info */
1256
1257     if (debugging)
1258     {
1259         /* Push the address of the first argument */
1260         printf( "\tmovl %%ebx,%%eax\n" );
1261         printf( "\taddl $12,%%eax\n" );
1262         printf( "\tpushl $%d\n", reg_func ? 7 : strlen(args) );
1263         printf( "\tpushl %%eax\n" );
1264         printf( "\tcall " PREFIX "RELAY_DebugCall16\n" );
1265         printf( "\tpopl %%eax\n" );
1266         printf( "\tpopl %%eax\n" );
1267     }
1268
1269     /* Switch to the 16-bit stack */
1270
1271     printf( "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1272     printf( "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1273
1274     /* Transfer the arguments */
1275
1276     if (reg_func)
1277     {
1278         /* Get the registers. ebx is handled later on. */
1279         printf( "\tpushw 20(%%ebx)\n" );
1280         printf( "\tpopw %%es\n" );
1281         printf( "\tmovl 24(%%ebx),%%ebp\n" );
1282         printf( "\tmovl 28(%%ebx),%%eax\n" );
1283         printf( "\tmovl 36(%%ebx),%%ecx\n" );
1284         printf( "\tmovl 40(%%ebx),%%edx\n" );
1285         printf( "\tmovl 44(%%ebx),%%esi\n" );
1286         printf( "\tmovl 48(%%ebx),%%edi\n" );
1287     }
1288     else  /* not a register function */
1289     {
1290         int pos = 20;  /* first argument position */
1291
1292         /* Make %bp point to the previous stackframe (built by CallTo32) */
1293         printf( "\tmovw %%sp,%%bp\n" );
1294         printf( "\taddw $16,%%bp\n" );
1295
1296         while (*args)
1297         {
1298             switch(*args++)
1299             {
1300             case 'w': /* word */
1301                 printf( "\tpushw %d(%%ebx)\n", pos );
1302                 break;
1303             case 'l': /* long */
1304                 printf( "\tpushl %d(%%ebx)\n", pos );
1305                 break;
1306             }
1307             pos += 4;
1308         }
1309     }
1310
1311     /* Push the return address */
1312
1313     printf( "\tpushl " PREFIX "CALL16_RetAddr_%s\n",
1314             short_ret ? "word" : "long" );
1315
1316     /* Push the called routine address */
1317
1318     printf( "\tpushl 12(%%ebx)\n" );
1319
1320     /* Get the 16-bit ds */
1321     /* FIXME: this shouldn't be necessary if function prologs fixup worked. */
1322
1323     printf( "\tpushw 16(%%ebx)\n" );
1324     printf( "\tpopw %%ds\n" );
1325
1326     if (reg_func)
1327     {
1328         /* Retrieve ebx from the 32-bit stack */
1329         printf( "\tmovl %%fs:28(%%ebx),%%ebx\n" );
1330     }
1331     else
1332     {
1333         /* Set ax equal to ds for window procedures */
1334         printf( "\tmovw %%ds,%%ax\n" );
1335     }
1336
1337     /* Jump to the called routine */
1338
1339     printf( "\t.byte 0x66\n" );
1340     printf( "\tlret\n" );
1341 }
1342
1343
1344 /*******************************************************************
1345  *         BuildRet16Func
1346  *
1347  * Build the return code for 16-bit callbacks
1348  */
1349 static void BuildRet16Func()
1350 {
1351     printf( "\t.globl " PREFIX "CALL16_Ret_word\n" );
1352     printf( "\t.globl " PREFIX "CALL16_Ret_long\n" );
1353
1354     /* Put return value into eax */
1355
1356     printf( PREFIX "CALL16_Ret_long:\n" );
1357     printf( "\tpushw %%dx\n" );
1358     printf( "\tpushw %%ax\n" );
1359     printf( "\tpopl %%eax\n" );
1360     printf( PREFIX "CALL16_Ret_word:\n" );
1361
1362     /* Restore 32-bit segment registers */
1363
1364     printf( "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1365     printf( "\tmovw %%bx,%%ds\n" );
1366     printf( "\tmovw %%bx,%%es\n" );
1367     printf( "\tmovw %%bx,%%ss\n" );
1368
1369     /* Restore the 32-bit stack */
1370
1371     printf( "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1372     printf( "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
1373
1374     /* Restore the 32-bit registers */
1375
1376     printf( "\tpopl %%edi\n" );
1377     printf( "\tpopl %%esi\n" );
1378     printf( "\tpopl %%edx\n" );
1379     printf( "\tpopl %%ecx\n" );
1380     printf( "\tpopl %%ebx\n" );
1381
1382     /* Return to caller */
1383
1384     printf( "\tpopl %%ebp\n" );
1385     printf( "\tlret\n" );
1386
1387     /* Declare the return address variables */
1388
1389     printf( "\t.data\n" );
1390     printf( "\t.globl " PREFIX "CALL16_RetAddr_word\n" );
1391     printf( "\t.globl " PREFIX "CALL16_RetAddr_long\n" );
1392     printf( PREFIX "CALL16_RetAddr_word:\t.long 0\n" );
1393     printf( PREFIX "CALL16_RetAddr_long:\t.long 0\n" );
1394     printf( "\t.text\n" );
1395 }
1396
1397
1398 static void usage(void)
1399 {
1400     fprintf(stderr, "usage: build -spec SPECNAMES\n"
1401                     "       build -call32 FUNCTION_PROFILES\n"
1402                     "       build -call16 FUNCTION_PROFILES\n" );
1403     exit(1);
1404 }
1405
1406
1407 int main(int argc, char **argv)
1408 {
1409     int i;
1410
1411     if (argc <= 2) usage();
1412
1413     if (!strcmp( argv[1], "-spec" ))
1414     {
1415         for (i = 2; i < argc; i++) BuildSpecFiles( argv[i] );
1416     }
1417     else if (!strcmp( argv[1], "-call32" ))  /* 32-bit callbacks */
1418     {
1419         /* File header */
1420
1421         printf( "/* File generated automatically. Do no edit! */\n\n" );
1422         printf( "\t.text\n" );
1423
1424         /* Build the callback functions */
1425
1426         for (i = 2; i < argc; i++) BuildCall32Func( argv[i] );
1427
1428         /* Output the argument debugging strings */
1429
1430         if (debugging)
1431         {
1432             printf( "/* Argument strings */\n" );
1433             for (i = 2; i < argc; i++)
1434             {
1435                 printf( "CALL32_Str_%s:\n", argv[i] );
1436                 printf( "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
1437             }
1438         }
1439     }
1440     else if (!strcmp( argv[1], "-call16" ))  /* 16-bit callbacks */
1441     {
1442         /* File header */
1443
1444         printf( "/* File generated automatically. Do no edit! */\n\n" );
1445         printf( "\t.text\n" );
1446         printf( "\t.globl " PREFIX "CALL16_Start\n" );
1447         printf( PREFIX "CALL16_Start:\n" );
1448
1449         /* Build the callback functions */
1450
1451         for (i = 2; i < argc; i++) BuildCall16Func( argv[i] );
1452
1453         /* Output the 16-bit return code */
1454
1455         BuildRet16Func();
1456
1457         printf( "\t.globl " PREFIX "CALL16_End\n" );
1458         printf( PREFIX "CALL16_End:\n" );
1459     }
1460     else usage();
1461
1462     return 0;
1463 }