Added LDFLAGS to linking of wine-related binaries.
[wine] / tools / winebuild / spec16.c
1 /*
2  * 16-bit spec files
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Martin von Loewis
6  * Copyright 1995, 1996, 1997 Alexandre Julliard
7  * Copyright 1997 Eric Youngdale
8  * Copyright 1999 Ulrich Weigand
9  */
10
11 #include <assert.h>
12 #include <ctype.h>
13
14 #include "builtin16.h"
15 #include "module.h"
16 #include "neexe.h"
17 #include "stackframe.h"
18
19 #include "build.h"
20
21
22 /*******************************************************************
23  *         StoreVariableCode
24  *
25  * Store a list of ints into a byte array.
26  */
27 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
28 {
29     int i;
30
31     switch(size)
32     {
33     case 1:
34         for (i = 0; i < odp->u.var.n_values; i++)
35             buffer[i] = odp->u.var.values[i];
36         break;
37     case 2:
38         for (i = 0; i < odp->u.var.n_values; i++)
39             ((unsigned short *)buffer)[i] = odp->u.var.values[i];
40         break;
41     case 4:
42         for (i = 0; i < odp->u.var.n_values; i++)
43             ((unsigned int *)buffer)[i] = odp->u.var.values[i];
44         break;
45     }
46     return odp->u.var.n_values * size;
47 }
48
49
50 /*******************************************************************
51  *         BuildModule16
52  *
53  * Build the in-memory representation of a 16-bit NE module, and dump it
54  * as a byte stream into the assembly code.
55  */
56 static int BuildModule16( FILE *outfile, int max_code_offset,
57                           int max_data_offset )
58 {
59     int i;
60     char *buffer;
61     NE_MODULE *pModule;
62     SEGTABLEENTRY *pSegment;
63     OFSTRUCT *pFileInfo;
64     BYTE *pstr;
65     ET_BUNDLE *bundle = 0;
66     ET_ENTRY *entry = 0;
67
68     /*   Module layout:
69      * NE_MODULE       Module
70      * OFSTRUCT        File information
71      * SEGTABLEENTRY   Segment 1 (code)
72      * SEGTABLEENTRY   Segment 2 (data)
73      * WORD[2]         Resource table (empty)
74      * BYTE[2]         Imported names (empty)
75      * BYTE[n]         Resident names table
76      * BYTE[n]         Entry table
77      */
78
79     buffer = xmalloc( 0x10000 );
80
81     pModule = (NE_MODULE *)buffer;
82     memset( pModule, 0, sizeof(*pModule) );
83     pModule->magic = IMAGE_OS2_SIGNATURE;
84     pModule->count = 1;
85     pModule->next = 0;
86     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
87     pModule->dgroup = 2;
88     pModule->heap_size = DLLHeapSize;
89     pModule->stack_size = 0;
90     pModule->ip = 0;
91     pModule->cs = 0;
92     pModule->sp = 0;
93     pModule->ss = 0;
94     pModule->seg_count = 2;
95     pModule->modref_count = 0;
96     pModule->nrname_size = 0;
97     pModule->modref_table = 0;
98     pModule->nrname_fpos = 0;
99     pModule->moveable_entries = 0;
100     pModule->alignment = 0;
101     pModule->truetype = 0;
102     pModule->os_flags = NE_OSFLAGS_WINDOWS;
103     pModule->misc_flags = 0;
104     pModule->dlls_to_init  = 0;
105     pModule->nrname_handle = 0;
106     pModule->min_swap_area = 0;
107     pModule->expected_version = 0;
108     pModule->module32 = 0;
109     pModule->self = 0;
110     pModule->self_loading_sel = 0;
111
112       /* File information */
113
114     pFileInfo = (OFSTRUCT *)(pModule + 1);
115     pModule->fileinfo = (int)pFileInfo - (int)pModule;
116     memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
117     pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
118                         + strlen(DLLFileName);
119     strcpy( pFileInfo->szPathName, DLLFileName );
120     pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
121         
122 #ifdef __i386__  /* FIXME: Alignment problems! */
123
124       /* Segment table */
125
126     pSegment = (SEGTABLEENTRY *)pstr;
127     pModule->seg_table = (int)pSegment - (int)pModule;
128     pSegment->filepos = 0;
129     pSegment->size = max_code_offset;
130     pSegment->flags = 0;
131     pSegment->minsize = max_code_offset;
132     pSegment->hSeg = 0;
133     pSegment++;
134
135     pModule->dgroup_entry = (int)pSegment - (int)pModule;
136     pSegment->filepos = 0;
137     pSegment->size = max_data_offset;
138     pSegment->flags = NE_SEGFLAGS_DATA;
139     pSegment->minsize = max_data_offset;
140     pSegment->hSeg = 0;
141     pSegment++;
142
143       /* Resource table */
144
145     pstr = (char *)pSegment;
146     pModule->res_table = (int)pstr - (int)pModule;
147     pstr += output_res16_directory( pstr );
148
149       /* Imported names table */
150
151     pModule->import_table = (int)pstr - (int)pModule;
152     *pstr++ = 0;
153     *pstr++ = 0;
154
155       /* Resident names table */
156
157     pModule->name_table = (int)pstr - (int)pModule;
158     /* First entry is module name */
159     *pstr = strlen(DLLName );
160     strcpy( pstr + 1, DLLName );
161     pstr += *pstr + 1;
162     *(WORD *)pstr = 0;
163     pstr += sizeof(WORD);
164     /* Store all ordinals */
165     for (i = 1; i <= Limit; i++)
166     {
167         ORDDEF *odp = Ordinals[i];
168         if (!odp || !odp->name[0]) continue;
169         *pstr = strlen( odp->name );
170         strcpy( pstr + 1, odp->name );
171         strupper( pstr + 1 );
172         pstr += *pstr + 1;
173         *(WORD *)pstr = i;
174         pstr += sizeof(WORD);
175     }
176     *pstr++ = 0;
177
178       /* Entry table */
179
180     pModule->entry_table = (int)pstr - (int)pModule;
181     for (i = 1; i <= Limit; i++)
182     {
183         int selector = 0;
184         ORDDEF *odp = Ordinals[i];
185         if (!odp) continue;
186
187         switch (odp->type)
188         {
189         case TYPE_CDECL:
190         case TYPE_PASCAL:
191         case TYPE_PASCAL_16:
192         case TYPE_REGISTER:
193         case TYPE_INTERRUPT:
194         case TYPE_STUB:
195             selector = 1;  /* Code selector */
196             break;
197
198         case TYPE_BYTE:
199         case TYPE_WORD:
200         case TYPE_LONG:
201             selector = 2;  /* Data selector */
202             break;
203
204         case TYPE_ABS:
205             selector = 0xfe;  /* Constant selector */
206             break;
207
208         default:
209             selector = 0;  /* Invalid selector */
210             break;
211         }
212
213         if ( !selector )
214            continue;
215
216         if ( bundle && bundle->last+1 == i )
217             bundle->last++;
218         else
219         {
220             if ( bundle )
221                 bundle->next = (char *)pstr - (char *)pModule;
222
223             bundle = (ET_BUNDLE *)pstr;
224             bundle->first = i-1;
225             bundle->last = i;
226             bundle->next = 0;
227             pstr += sizeof(ET_BUNDLE);
228         }
229
230         /* FIXME: is this really correct ?? */
231         entry = (ET_ENTRY *)pstr;
232         entry->type = 0xff;  /* movable */
233         entry->flags = 3; /* exported & public data */
234         entry->segnum = selector;
235         entry->offs = odp->offset;
236         pstr += sizeof(ET_ENTRY);
237     }
238     *pstr++ = 0;
239 #endif
240
241       /* Dump the module content */
242
243     dump_bytes( outfile, (char *)pModule, (int)pstr - (int)pModule, "Module", 0 );
244     return (int)pstr - (int)pModule;
245 }
246
247
248 /*******************************************************************
249  *         BuildCallFrom16Func
250  *
251  * Build a 16-bit-to-Wine callback glue function. 
252  *
253  * The generated routines are intended to be used as argument conversion 
254  * routines to be called by the CallFrom16... core. Thus, the prototypes of
255  * the generated routines are (see also CallFrom16):
256  *
257  *  extern WORD WINAPI PREFIX_CallFrom16_C_word_xxx( FARPROC func, LPBYTE args );
258  *  extern LONG WINAPI PREFIX_CallFrom16_C_long_xxx( FARPROC func, LPBYTE args );
259  *  extern void WINAPI PREFIX_CallFrom16_C_regs_xxx( FARPROC func, LPBYTE args, 
260  *                                                   CONTEXT86 *context );
261  *  extern void WINAPI PREFIX_CallFrom16_C_intr_xxx( FARPROC func, LPBYTE args, 
262  *                                                   CONTEXT86 *context );
263  *
264  * where 'C' is the calling convention ('p' for pascal or 'c' for cdecl), 
265  * and each 'x' is an argument  ('w'=word, 's'=signed word, 'l'=long, 
266  * 'p'=linear pointer, 't'=linear pointer to null-terminated string,
267  * 'T'=segmented pointer to null-terminated string).
268  *
269  * The generated routines fetch the arguments from the 16-bit stack (pointed
270  * to by 'args'); the offsets of the single argument values are computed 
271  * according to the calling convention and the argument types.  Then, the
272  * 32-bit entry point is called with these arguments.
273  * 
274  * For register functions, the arguments (if present) are converted just
275  * the same as for normal functions, but in addition the CONTEXT86 pointer 
276  * filled with the current register values is passed to the 32-bit routine.
277  * (An 'intr' interrupt handler routine is treated exactly like a register 
278  * routine, except that upon return, the flags word pushed onto the stack 
279  * by the interrupt is removed by the 16-bit call stub.)
280  *
281  */
282 static void BuildCallFrom16Func( FILE *outfile, char *profile, char *prefix, int local )
283 {
284     int i, pos, argsize = 0;
285     int short_ret = 0;
286     int reg_func = 0;
287     int usecdecl = 0;
288     char *args = profile + 7;
289     char *ret_type;
290
291     /* Parse function type */
292
293     if (!strncmp( "c_", profile, 2 )) usecdecl = 1;
294     else if (strncmp( "p_", profile, 2 ))
295     {
296         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
297         return;
298     }
299
300     if (!strncmp( "word_", profile + 2, 5 )) short_ret = 1;
301     else if (!strncmp( "regs_", profile + 2, 5 )) reg_func = 1;
302     else if (!strncmp( "intr_", profile + 2, 5 )) reg_func = 2;
303     else if (strncmp( "long_", profile + 2, 5 ))
304     {
305         fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
306         return;
307     }
308
309     for ( i = 0; args[i]; i++ )
310         switch ( args[i] )
311         {
312         case 'w':  /* word */
313         case 's':  /* s_word */
314             argsize += 2;
315             break;
316         
317         case 'l':  /* long or segmented pointer */
318         case 'T':  /* segmented pointer to null-terminated string */
319         case 'p':  /* linear pointer */
320         case 't':  /* linear pointer to null-terminated string */
321             argsize += 4;
322             break;
323         }
324
325     ret_type = reg_func? "void" : short_ret? "WORD" : "LONG";
326
327     fprintf( outfile, "typedef %s WINAPI (*proc_%s_t)( ", 
328                       ret_type, profile );
329     args = profile + 7;
330     for ( i = 0; args[i]; i++ )
331     {
332         if ( i ) fprintf( outfile, ", " );
333         switch (args[i])
334         {
335         case 'w':           fprintf( outfile, "WORD" ); break;
336         case 's':           fprintf( outfile, "INT16" ); break;
337         case 'l': case 'T': fprintf( outfile, "LONG" ); break;
338         case 'p': case 't': fprintf( outfile, "LPVOID" ); break;
339         }
340     }
341     if ( reg_func )
342         fprintf( outfile, "%sstruct _CONTEXT86 *", i? ", " : "" );
343     else if ( !i )
344         fprintf( outfile, "void" );
345     fprintf( outfile, " );\n" );
346     
347     fprintf( outfile, "%s%s WINAPI %s_CallFrom16_%s( FARPROC proc, LPBYTE args%s )\n{\n",
348              local? "static " : "", ret_type, prefix, profile,
349              reg_func? ", struct _CONTEXT86 *context" : "" );
350
351     fprintf( outfile, "    %s((proc_%s_t) proc) (\n",
352              reg_func? "" : "return ", profile );
353     args = profile + 7;
354     pos = !usecdecl? argsize : 0;
355     for ( i = 0; args[i]; i++ )
356     {
357         if ( i ) fprintf( outfile, ",\n" );
358         fprintf( outfile, "        " );
359         switch (args[i])
360         {
361         case 'w':  /* word */
362             if ( !usecdecl ) pos -= 2;
363             fprintf( outfile, "*(WORD *)(args+%d)", pos );
364             if (  usecdecl ) pos += 2;
365             break;
366
367         case 's':  /* s_word */
368             if ( !usecdecl ) pos -= 2;
369             fprintf( outfile, "*(INT16 *)(args+%d)", pos );
370             if (  usecdecl ) pos += 2;
371             break;
372
373         case 'l':  /* long or segmented pointer */
374         case 'T':  /* segmented pointer to null-terminated string */
375             if ( !usecdecl ) pos -= 4;
376             fprintf( outfile, "*(LONG *)(args+%d)", pos );
377             if (  usecdecl ) pos += 4;
378             break;
379
380         case 'p':  /* linear pointer */
381         case 't':  /* linear pointer to null-terminated string */
382             if ( !usecdecl ) pos -= 4;
383             fprintf( outfile, "PTR_SEG_TO_LIN( *(SEGPTR *)(args+%d) )", pos );
384             if (  usecdecl ) pos += 4;
385             break;
386
387         default:
388             fprintf( stderr, "Unknown arg type '%c'\n", args[i] );
389         }
390     }
391     if ( reg_func )
392         fprintf( outfile, "%s        context", i? ",\n" : "" );
393     fprintf( outfile, " );\n}\n\n" );
394 }
395
396
397 /*******************************************************************
398  *         BuildCallTo16Func
399  *
400  * Build a Wine-to-16-bit callback glue function. 
401  *
402  * Prototypes for the CallTo16 functions:
403  *   extern WORD CALLBACK PREFIX_CallTo16_word_xxx( FARPROC16 func, args... );
404  *   extern LONG CALLBACK PREFIX_CallTo16_long_xxx( FARPROC16 func, args... );
405  * 
406  * These routines are provided solely for convenience; they simply
407  * write the arguments onto the 16-bit stack, and call the appropriate
408  * CallTo16... core routine.
409  *
410  * If you have more sophisticated argument conversion requirements than
411  * are provided by these routines, you might as well call the core 
412  * routines by yourself.
413  *
414  */
415 static void BuildCallTo16Func( FILE *outfile, char *profile, char *prefix )
416 {
417     char *args = profile + 5;
418     int i, argsize = 0, short_ret = 0;
419
420     if (!strncmp( "word_", profile, 5 )) short_ret = 1;
421     else if (strncmp( "long_", profile, 5 ))
422     {
423         fprintf( stderr, "Invalid function name '%s'.\n", profile );
424         exit(1);
425     }
426
427     fprintf( outfile, "%s %s_CallTo16_%s( FARPROC16 proc",
428              short_ret? "WORD" : "LONG", prefix, profile );
429     args = profile + 5;
430     for ( i = 0; args[i]; i++ )
431     {
432         fprintf( outfile, ", " );
433         switch (args[i])
434         {
435         case 'w': fprintf( outfile, "WORD" ); argsize += 2; break;
436         case 'l': fprintf( outfile, "LONG" ); argsize += 4; break;
437         }
438         fprintf( outfile, " arg%d", i+1 );
439     }
440     fprintf( outfile, " )\n{\n" );
441
442     if ( argsize > 0 )
443         fprintf( outfile, "    LPBYTE args = (LPBYTE)CURRENT_STACK16;\n" );
444
445     args = profile + 5;
446     for ( i = 0; args[i]; i++ )
447     {
448         switch (args[i])
449         {
450         case 'w': fprintf( outfile, "    args -= sizeof(WORD); *(WORD" ); break;
451         case 'l': fprintf( outfile, "    args -= sizeof(LONG); *(LONG" ); break;
452         default:  fprintf( stderr, "Unexpected case '%c' in BuildCallTo16Func\n",
453                                    args[i] );
454         }
455         fprintf( outfile, " *)args = arg%d;\n", i+1 );
456     }
457
458     fprintf( outfile, "    return CallTo16%s( proc, %d );\n}\n\n",
459              short_ret? "Word" : "Long", argsize );
460 }
461
462
463 /*******************************************************************
464  *         Spec16TypeCompare
465  */
466 static int Spec16TypeCompare( const void *e1, const void *e2 )
467 {
468     const ORDDEF *odp1 = *(const ORDDEF **)e1;
469     const ORDDEF *odp2 = *(const ORDDEF **)e2;
470
471     int type1 = (odp1->type == TYPE_CDECL) ? 0
472               : (odp1->type == TYPE_REGISTER) ? 3
473               : (odp1->type == TYPE_INTERRUPT) ? 4
474               : (odp1->type == TYPE_PASCAL_16) ? 1 : 2;
475
476     int type2 = (odp2->type == TYPE_CDECL) ? 0
477               : (odp2->type == TYPE_REGISTER) ? 3
478               : (odp2->type == TYPE_INTERRUPT) ? 4
479               : (odp2->type == TYPE_PASCAL_16) ? 1 : 2;
480
481     int retval = type1 - type2;
482     if ( !retval )
483         retval = strcmp( odp1->u.func.arg_types, odp2->u.func.arg_types );
484
485     return retval;
486 }
487
488
489 /*******************************************************************
490  *         BuildSpec16File
491  *
492  * Build a Win16 assembly file from a spec file.
493  */
494 void BuildSpec16File( FILE *outfile )
495 {
496     ORDDEF **type, **typelist;
497     int i, nFuncs, nTypes;
498     int code_offset, data_offset, module_size, res_size;
499     unsigned char *data;
500
501     /* File header */
502
503     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
504              input_file_name );
505     fprintf( outfile, "#define __FLATCS__ 0x%04x\n", code_selector );
506     fprintf( outfile, "#include \"builtin16.h\"\n\n" );
507
508     fprintf( outfile, "extern void RELAY_Unimplemented16(void);\n\n" );
509
510     data = (unsigned char *)xmalloc( 0x10000 );
511     memset( data, 0, 16 );
512     data_offset = 16;
513     strupper( DLLName );
514
515     /* Build sorted list of all argument types, without duplicates */
516
517     typelist = (ORDDEF **)calloc( Limit+1, sizeof(ORDDEF *) );
518
519     for (i = nFuncs = 0; i <= Limit; i++)
520     {
521         ORDDEF *odp = Ordinals[i];
522         if (!odp) continue;
523         switch (odp->type)
524         {
525           case TYPE_REGISTER:
526           case TYPE_INTERRUPT:
527           case TYPE_CDECL:
528           case TYPE_PASCAL:
529           case TYPE_PASCAL_16:
530           case TYPE_STUB:
531             typelist[nFuncs++] = odp;
532
533           default:
534             break;
535         }
536     }
537
538     qsort( typelist, nFuncs, sizeof(ORDDEF *), Spec16TypeCompare );
539
540     i = nTypes = 0;
541     while ( i < nFuncs )
542     {
543         typelist[nTypes++] = typelist[i++];
544         while ( i < nFuncs && Spec16TypeCompare( typelist + i, typelist + nTypes-1 ) == 0 )
545             i++;
546     }
547
548     /* Output CallFrom16 routines needed by this .spec file */
549
550     for ( i = 0; i < nTypes; i++ )
551     {
552         char profile[101];
553
554         sprintf( profile, "%s_%s_%s",
555                  (typelist[i]->type == TYPE_CDECL) ? "c" : "p",
556                  (typelist[i]->type == TYPE_REGISTER) ? "regs" :
557                  (typelist[i]->type == TYPE_INTERRUPT) ? "intr" :
558                  (typelist[i]->type == TYPE_PASCAL_16) ? "word" : "long",
559                  typelist[i]->u.func.arg_types );
560
561         BuildCallFrom16Func( outfile, profile, DLLName, TRUE );
562     }
563
564     /* Output the DLL functions prototypes */
565
566     for (i = 0; i <= Limit; i++)
567     {
568         ORDDEF *odp = Ordinals[i];
569         if (!odp) continue;
570         switch(odp->type)
571         {
572         case TYPE_REGISTER:
573         case TYPE_INTERRUPT:
574         case TYPE_CDECL:
575         case TYPE_PASCAL:
576         case TYPE_PASCAL_16:
577             fprintf( outfile, "extern void %s();\n", odp->u.func.link_name );
578             break;
579         default:
580             break;
581         }
582     }
583
584     /* Output code segment */
585
586     fprintf( outfile, "\nstatic struct\n{\n    CALLFROM16   call[%d];\n"
587                       "    ENTRYPOINT16 entry[%d];\n} Code_Segment = \n{\n  {\n",
588                       nTypes, nFuncs );
589     code_offset = 0;
590
591     for ( i = 0; i < nTypes; i++ )
592     {
593         char profile[101], *arg;
594         int argsize = 0;
595
596         sprintf( profile, "%s_%s_%s", 
597                           (typelist[i]->type == TYPE_CDECL) ? "c" : "p",
598                           (typelist[i]->type == TYPE_REGISTER) ? "regs" :
599                           (typelist[i]->type == TYPE_INTERRUPT) ? "intr" :
600                           (typelist[i]->type == TYPE_PASCAL_16) ? "word" : "long",
601                           typelist[i]->u.func.arg_types );
602
603         if ( typelist[i]->type != TYPE_CDECL )
604             for ( arg = typelist[i]->u.func.arg_types; *arg; arg++ )
605                 switch ( *arg )
606                 {
607                 case 'w':  /* word */
608                 case 's':  /* s_word */
609                     argsize += 2;
610                     break;
611         
612                 case 'l':  /* long or segmented pointer */
613                 case 'T':  /* segmented pointer to null-terminated string */
614                 case 'p':  /* linear pointer */
615                 case 't':  /* linear pointer to null-terminated string */
616                     argsize += 4;
617                     break;
618                 }
619
620         if ( typelist[i]->type == TYPE_INTERRUPT )
621             argsize += 2;
622
623         fprintf( outfile, "    { 0x68, %s_CallFrom16_%s, 0x9a, CallFrom16%s,\n",
624                  DLLName, profile, 
625                  (typelist[i]->type == TYPE_REGISTER 
626                   || typelist[i]->type == TYPE_INTERRUPT)? "Register":
627                  typelist[i]->type == TYPE_PASCAL_16? "Word" : "Long" );
628         if (argsize)
629             fprintf( outfile, "        0x%04x, 0x66, 0xca, %d, \"%s\" },\n",
630                      code_selector, argsize, profile );
631         else
632             fprintf( outfile, "        0x%04x, 0x66, 0xcb, 0x9090, \"%s\" },\n",
633                      code_selector, profile );
634
635         code_offset += sizeof(CALLFROM16);
636     }
637     fprintf( outfile, "  },\n  {\n" );
638
639     for (i = 0; i <= Limit; i++)
640     {
641         ORDDEF *odp = Ordinals[i];
642         if (!odp) continue;
643         switch (odp->type)
644         {
645           case TYPE_ABS:
646             odp->offset = LOWORD(odp->u.abs.value);
647             break;
648
649           case TYPE_BYTE:
650             odp->offset = data_offset;
651             data_offset += StoreVariableCode( data + data_offset, 1, odp);
652             break;
653
654           case TYPE_WORD:
655             odp->offset = data_offset;
656             data_offset += StoreVariableCode( data + data_offset, 2, odp);
657             break;
658
659           case TYPE_LONG:
660             odp->offset = data_offset;
661             data_offset += StoreVariableCode( data + data_offset, 4, odp);
662             break;
663
664           case TYPE_REGISTER:
665           case TYPE_INTERRUPT:
666           case TYPE_CDECL:
667           case TYPE_PASCAL:
668           case TYPE_PASCAL_16:
669           case TYPE_STUB:
670             type = bsearch( &odp, typelist, nTypes, sizeof(ORDDEF *), Spec16TypeCompare );
671             assert( type );
672
673             fprintf( outfile, "    /* %s.%d */ ", DLLName, i );
674             fprintf( outfile, "{ 0x5566, 0x68, %s, 0xe866, %d  /* %s_%s_%s */ },\n",
675                               odp->u.func.link_name,
676                               (type-typelist)*sizeof(CALLFROM16) - 
677                               (code_offset + sizeof(ENTRYPOINT16)),
678                               (odp->type == TYPE_CDECL) ? "c" : "p",
679                               (odp->type == TYPE_REGISTER) ? "regs" :
680                               (odp->type == TYPE_INTERRUPT) ? "intr" :
681                               (odp->type == TYPE_PASCAL_16) ? "word" : "long",
682                               odp->u.func.arg_types );
683                                  
684             odp->offset = code_offset;
685             code_offset += sizeof(ENTRYPOINT16);
686             break;
687                 
688           default:
689             fprintf(stderr,"build: function type %d not available for Win16\n",
690                     odp->type);
691             exit(1);
692         }
693     }
694
695     fprintf( outfile, "    }\n};\n" );
696
697     /* Output data segment */
698
699     dump_bytes( outfile, data, data_offset, "Data_Segment", 0 );
700
701     /* Build the module */
702
703     module_size = BuildModule16( outfile, code_offset, data_offset );
704     res_size = output_res16_data( outfile );
705
706     /* Output the DLL descriptor */
707
708     fprintf( outfile, "\nstatic const BUILTIN16_DESCRIPTOR descriptor = \n{\n" );
709     fprintf( outfile, "    \"%s\",\n", DLLName );
710     fprintf( outfile, "    Module,\n" );
711     fprintf( outfile, "    sizeof(Module),\n" );
712     fprintf( outfile, "    (BYTE *)&Code_Segment,\n" );
713     fprintf( outfile, "    (BYTE *)Data_Segment,\n" );
714     fprintf( outfile, "    \"%s\",\n", owner_name );
715     fprintf( outfile, "    %s\n", res_size ? "resource_data" : "0" );
716     fprintf( outfile, "};\n" );
717
718     /* Output the DLL constructor */
719
720     fprintf( outfile, "#ifdef __GNUC__\n" );
721     fprintf( outfile, "static void %s_init(void) __attribute__((constructor));\n", DLLName );
722     fprintf( outfile, "#else /* defined(__GNUC__) */\n" );
723     fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
724     fprintf( outfile, "asm(\"\\t.section\t.init ,\\\"ax\\\"\\n\"\n" );
725     fprintf( outfile, "    \"\\tcall %s_init\\n\"\n", DLLName );
726     fprintf( outfile, "    \"\\t.previous\\n\");\n" );
727     fprintf( outfile, "}\n" );
728     fprintf( outfile, "#endif /* defined(__GNUC__) */\n" );
729     fprintf( outfile, "static void %s_init(void) { BUILTIN_RegisterDLL( &descriptor ); }\n",
730              DLLName );
731 }
732
733
734 /*******************************************************************
735  *         BuildGlue
736  *
737  * Build the 16-bit-to-Wine/Wine-to-16-bit callback glue code
738  */
739 void BuildGlue( FILE *outfile, FILE *infile )
740 {
741     char buffer[1024];
742
743     /* File header */
744
745     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
746              input_file_name );
747     fprintf( outfile, "#include \"builtin16.h\"\n" );
748     fprintf( outfile, "#include \"stackframe.h\"\n\n" );
749
750     fprintf( outfile, "extern WORD CALLBACK CallTo16Word( FARPROC16 target, INT nArgs );\n" );
751     fprintf( outfile, "extern LONG CALLBACK CallTo16Long( FARPROC16 target, INT nArgs );\n" );
752
753     /* Build the callback glue functions */
754
755     while (fgets( buffer, sizeof(buffer), infile ))
756     {
757         if (strstr( buffer, "### start build ###" )) break;
758     }
759     while (fgets( buffer, sizeof(buffer), infile ))
760     {
761         char *p; 
762         if ( (p = strstr( buffer, "CallFrom16_" )) != NULL )
763         {
764             char *q, *profile = p + strlen( "CallFrom16_" );
765             for (q = profile; (*q == '_') || isalpha(*q); q++ )
766                 ;
767             *q = '\0';
768             for (q = p-1; q > buffer && ((*q == '_') || isalnum(*q)); q-- )
769                 ;
770             if ( ++q < p ) p[-1] = '\0'; else q = "";
771             BuildCallFrom16Func( outfile, profile, q, FALSE );
772         }
773         if ( (p = strstr( buffer, "CallTo16_" )) != NULL )
774         {
775             char *q, *profile = p + strlen( "CallTo16_" );
776             for (q = profile; (*q == '_') || isalpha(*q); q++ )
777                 ;
778             *q = '\0';
779             for (q = p-1; q > buffer && ((*q == '_') || isalnum(*q)); q-- )
780                 ;
781             if ( ++q < p ) p[-1] = '\0'; else q = "";
782             BuildCallTo16Func( outfile, profile, q );
783         }
784         if (strstr( buffer, "### stop build ###" )) break;
785     }
786
787     fclose( infile );
788 }