jscript: Use single string instance for strings representing NULL BSTR instead of...
[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  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <ctype.h>
30
31 #include "build.h"
32
33 #define NE_FFLAGS_SINGLEDATA 0x0001
34 #define NE_FFLAGS_LIBMODULE  0x8000
35
36 /* argument type flags for relay debugging */
37 enum arg_types
38 {
39     ARG16_NONE = 0, /* indicates end of arg list */
40     ARG16_WORD,     /* unsigned word */
41     ARG16_SWORD,    /* signed word */
42     ARG16_LONG,     /* long or segmented pointer */
43     ARG16_PTR,      /* linear pointer */
44     ARG16_STR,      /* linear pointer to null-terminated string */
45     ARG16_SEGSTR,   /* segmented pointer to null-terminated string */
46     ARG16_VARARG    /* start of varargs */
47 };
48
49 /* sequences of nops to fill a certain number of words */
50 static const char * const nop_sequence[4] =
51 {
52     ".byte 0x89,0xf6",  /* mov %esi,%esi */
53     ".byte 0x8d,0x74,0x26,0x00",  /* lea 0x00(%esi),%esi */
54     ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00",  /* lea 0x00000000(%esi),%esi */
55     ".byte 0x8d,0x74,0x26,0x00,0x8d,0x74,0x26,0x00" /* lea 0x00(%esi),%esi; lea 0x00(%esi),%esi */
56 };
57
58 static inline int is_function( const ORDDEF *odp )
59 {
60     if (odp->flags & FLAG_EXPORT32) return 0;
61     return (odp->type == TYPE_CDECL ||
62             odp->type == TYPE_PASCAL ||
63             odp->type == TYPE_VARARGS ||
64             odp->type == TYPE_STUB);
65 }
66
67 static const char *get_args_str( const ORDDEF *odp )
68 {
69     static char buffer[MAX_ARGUMENTS*2+1];
70     int i;
71
72     buffer[0] = 0;
73     for (i = 0; i < odp->u.func.nb_args; i++)
74     {
75         switch (odp->u.func.args[i])
76         {
77         case ARG_WORD:   strcat( buffer, "w" ); break;
78         case ARG_SWORD:  strcat( buffer, "s" ); break;
79         case ARG_SEGSTR: strcat( buffer, "T" ); break;
80         case ARG_STR:    strcat( buffer, "t" ); break;
81         case ARG_LONG:
82         case ARG_FLOAT:
83         case ARG_SEGPTR: strcat( buffer, "l" ); break;
84         case ARG_PTR:
85         case ARG_WSTR:
86         case ARG_INT128: strcat( buffer, "p" ); break;
87         case ARG_INT64:
88         case ARG_DOUBLE: strcat( buffer, "ll" ); break;
89         }
90     }
91     return buffer;
92 }
93
94 /*******************************************************************
95  *         output_entries
96  *
97  * Output entries for individual symbols in the entry table.
98  */
99 static void output_entries( DLLSPEC *spec, int first, int count )
100 {
101     int i;
102
103     for (i = 0; i < count; i++)
104     {
105         ORDDEF *odp = spec->ordinals[first + i];
106         output( "\t.byte 0x03\n" );  /* flags: exported & public data */
107         switch (odp->type)
108         {
109         case TYPE_CDECL:
110         case TYPE_PASCAL:
111         case TYPE_VARARGS:
112         case TYPE_STUB:
113             output( "\t.short .L__wine_%s_%u-.L__wine_spec_code_segment\n",
114                      make_c_identifier(spec->dll_name), first + i );
115             break;
116         case TYPE_VARIABLE:
117             output( "\t.short .L__wine_%s_%u-.L__wine_spec_data_segment\n",
118                      make_c_identifier(spec->dll_name), first + i );
119             break;
120         case TYPE_ABS:
121             output( "\t.short 0x%04x  /* %s */\n",
122                      odp->u.abs.value, odp->name );
123             break;
124         default:
125             assert(0);
126         }
127     }
128 }
129
130
131 /*******************************************************************
132  *         output_entry_table
133  */
134 static void output_entry_table( DLLSPEC *spec )
135 {
136     int i, prev = 0, prev_sel = -1, bundle_count = 0;
137
138     for (i = 1; i <= spec->limit; i++)
139     {
140         int selector = 0;
141         ORDDEF *odp = spec->ordinals[i];
142         if (!odp) continue;
143         if (odp->flags & FLAG_EXPORT32) continue;
144
145         switch (odp->type)
146         {
147         case TYPE_CDECL:
148         case TYPE_PASCAL:
149         case TYPE_VARARGS:
150         case TYPE_STUB:
151             selector = 1;  /* Code selector */
152             break;
153         case TYPE_VARIABLE:
154             selector = 2;  /* Data selector */
155             break;
156         case TYPE_ABS:
157             selector = 0xfe;  /* Constant selector */
158             break;
159         default:
160             continue;
161         }
162
163         if (prev + 1 != i || prev_sel != selector || bundle_count == 255)
164         {
165             /* need to start a new bundle */
166
167             /* flush previous bundle */
168             if (bundle_count)
169             {
170                 output( "\t/* %s.%d - %s.%d */\n",
171                          spec->dll_name, prev - bundle_count + 1, spec->dll_name, prev );
172                 output( "\t.byte 0x%02x,0x%02x\n", bundle_count, prev_sel );
173                 output_entries( spec, prev - bundle_count + 1, bundle_count );
174             }
175
176             if (prev + 1 != i)
177             {
178                 int skip = i - (prev + 1);
179                 while (skip > 255)
180                 {
181                     output( "\t.byte 0xff,0x00\n" );
182                     skip -= 255;
183                 }
184                 output( "\t.byte 0x%02x,0x00\n", skip );
185             }
186
187             bundle_count = 0;
188             prev_sel = selector;
189         }
190         bundle_count++;
191         prev = i;
192     }
193
194     /* flush last bundle */
195     if (bundle_count)
196     {
197         output( "\t.byte 0x%02x,0x%02x\n", bundle_count, prev_sel );
198         output_entries( spec, prev - bundle_count + 1, bundle_count );
199     }
200     output( "\t.byte 0x00\n" );
201 }
202
203
204 /*******************************************************************
205  *         output_resident_name
206  */
207 static void output_resident_name( const char *string, int ordinal )
208 {
209     unsigned int i, len = strlen(string);
210
211     output( "\t.byte 0x%02x", len );
212     for (i = 0; i < len; i++) output( ",0x%02x", (unsigned char)toupper(string[i]) );
213     output( " /* %s */\n", string );
214     output( "\t.short %u\n", ordinal );
215 }
216
217
218 /*******************************************************************
219  *         get_callfrom16_name
220  */
221 static const char *get_callfrom16_name( const ORDDEF *odp )
222 {
223     static char *buffer;
224
225     free( buffer );
226     buffer = strmake( "%s_%s_%s",
227                       (odp->type == TYPE_PASCAL) ? "p" :
228                       (odp->type == TYPE_VARARGS) ? "v" : "c",
229                       (odp->flags & FLAG_REGISTER) ? "regs" :
230                       (odp->flags & FLAG_RET16) ? "word" : "long",
231                       get_args_str(odp) );
232     return buffer;
233 }
234
235
236 /*******************************************************************
237  *         get_relay_name
238  */
239 static const char *get_relay_name( const ORDDEF *odp )
240 {
241     static char buffer[80];
242     char *p;
243
244     switch(odp->type)
245     {
246     case TYPE_PASCAL:
247         strcpy( buffer, "p_" );
248         break;
249     case TYPE_VARARGS:
250         strcpy( buffer, "v_" );
251         break;
252     case TYPE_CDECL:
253     case TYPE_STUB:
254         strcpy( buffer, "c_" );
255         break;
256     default:
257         assert(0);
258     }
259     strcat( buffer, get_args_str(odp) );
260     for (p = buffer + 2; *p; p++)
261     {
262         /* map string types to the corresponding plain pointer type */
263         if (*p == 't') *p = 'p';
264         else if (*p == 'T') *p = 'l';
265     }
266     if (odp->flags & FLAG_REGISTER) strcat( buffer, "_regs" );
267     return buffer;
268 }
269
270
271 /*******************************************************************
272  *         get_function_argsize
273  */
274 static int get_function_argsize( const ORDDEF *odp )
275 {
276     int i, argsize = 0;
277
278     for (i = 0; i < odp->u.func.nb_args; i++)
279     {
280         switch (odp->u.func.args[i])
281         {
282         case ARG_WORD:
283         case ARG_SWORD:
284             argsize += 2;
285             break;
286         case ARG_SEGPTR:
287         case ARG_SEGSTR:
288         case ARG_LONG:
289         case ARG_PTR:
290         case ARG_STR:
291         case ARG_WSTR:
292         case ARG_FLOAT:
293         case ARG_INT128:
294             argsize += 4;
295             break;
296         case ARG_INT64:
297         case ARG_DOUBLE:
298             argsize += 8;
299             break;
300         }
301     }
302     return argsize;
303 }
304
305
306 /*******************************************************************
307  *         output_call16_function
308  *
309  * Build a 16-bit-to-Wine callback glue function.
310  *
311  * The generated routines are intended to be used as argument conversion
312  * routines to be called by the CallFrom16... core. Thus, the prototypes of
313  * the generated routines are (see also CallFrom16):
314  *
315  *  extern WORD WINAPI __wine_spec_call16_C_xxx( FARPROC func, LPBYTE args );
316  *  extern LONG WINAPI __wine_spec_call16_C_xxx( FARPROC func, LPBYTE args );
317  *  extern void WINAPI __wine_spec_call16_C_xxx_regs( FARPROC func, LPBYTE args, CONTEXT86 *context );
318  *
319  * where 'C' is the calling convention ('p' for pascal or 'c' for cdecl),
320  * and each 'x' is an argument  ('w'=word, 's'=signed word, 'l'=long,
321  * 'p'=linear pointer, 't'=linear pointer to null-terminated string,
322  * 'T'=segmented pointer to null-terminated string).
323  *
324  * The generated routines fetch the arguments from the 16-bit stack (pointed
325  * to by 'args'); the offsets of the single argument values are computed
326  * according to the calling convention and the argument types.  Then, the
327  * 32-bit entry point is called with these arguments.
328  *
329  * For register functions, the arguments (if present) are converted just
330  * the same as for normal functions, but in addition the CONTEXT86 pointer
331  * filled with the current register values is passed to the 32-bit routine.
332  */
333 static void output_call16_function( ORDDEF *odp )
334 {
335     char *name;
336     int i, pos, stack_words;
337     int argsize = get_function_argsize( odp );
338     int needs_ldt = (strpbrk( get_args_str( odp ), "pt" ) != NULL);
339
340     name = strmake( ".L__wine_spec_call16_%s", get_relay_name(odp) );
341
342     output( "\t.align %d\n", get_alignment(4) );
343     output( "\t%s\n", func_declaration(name) );
344     output( "%s:\n", name );
345     output_cfi( ".cfi_startproc" );
346     output( "\tpushl %%ebp\n" );
347     output_cfi( ".cfi_adjust_cfa_offset 4" );
348     output_cfi( ".cfi_rel_offset %%ebp,0" );
349     output( "\tmovl %%esp,%%ebp\n" );
350     output_cfi( ".cfi_def_cfa_register %%ebp" );
351     stack_words = 2;
352     if (needs_ldt)
353     {
354         output( "\tpushl %%esi\n" );
355         output_cfi( ".cfi_rel_offset %%esi,-4" );
356         stack_words++;
357         if (UsePIC)
358         {
359             output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
360             output( "1:\tmovl wine_ldt_copy_ptr-1b(%%eax),%%esi\n" );
361         }
362         else
363             output( "\tmovl $%s,%%esi\n", asm_name("wine_ldt_copy") );
364     }
365
366     /* preserve 16-byte stack alignment */
367     stack_words += odp->u.func.nb_args;
368     for (i = 0; i < odp->u.func.nb_args; i++)
369         if (odp->u.func.args[i] == ARG_DOUBLE || odp->u.func.args[i] == ARG_INT64) stack_words++;
370     if ((odp->flags & FLAG_REGISTER) || (odp->type == TYPE_VARARGS)) stack_words++;
371     if (stack_words % 4) output( "\tsubl $%d,%%esp\n", 16 - 4 * (stack_words % 4) );
372
373     if (odp->u.func.nb_args || odp->type == TYPE_VARARGS)
374         output( "\tmovl 12(%%ebp),%%ecx\n" );  /* args */
375
376     if (odp->flags & FLAG_REGISTER)
377     {
378         output( "\tpushl 16(%%ebp)\n" );  /* context */
379     }
380     else if (odp->type == TYPE_VARARGS)
381     {
382         output( "\tleal %d(%%ecx),%%eax\n", argsize );
383         output( "\tpushl %%eax\n" );  /* va_list16 */
384     }
385
386     pos = (odp->type == TYPE_PASCAL) ? 0 : argsize;
387     for (i = odp->u.func.nb_args - 1; i >= 0; i--)
388     {
389         switch (odp->u.func.args[i])
390         {
391         case ARG_WORD:
392             if (odp->type != TYPE_PASCAL) pos -= 2;
393             output( "\tmovzwl %d(%%ecx),%%eax\n", pos );
394             output( "\tpushl %%eax\n" );
395             if (odp->type == TYPE_PASCAL) pos += 2;
396             break;
397
398         case ARG_SWORD:
399             if (odp->type != TYPE_PASCAL) pos -= 2;
400             output( "\tmovswl %d(%%ecx),%%eax\n", pos );
401             output( "\tpushl %%eax\n" );
402             if (odp->type == TYPE_PASCAL) pos += 2;
403             break;
404
405         case ARG_INT64:
406         case ARG_DOUBLE:
407             if (odp->type != TYPE_PASCAL) pos -= 4;
408             output( "\tpushl %d(%%ecx)\n", pos );
409             if (odp->type == TYPE_PASCAL) pos += 4;
410             /* fall through */
411         case ARG_LONG:
412         case ARG_FLOAT:
413         case ARG_SEGPTR:
414         case ARG_SEGSTR:
415             if (odp->type != TYPE_PASCAL) pos -= 4;
416             output( "\tpushl %d(%%ecx)\n", pos );
417             if (odp->type == TYPE_PASCAL) pos += 4;
418             break;
419
420         case ARG_PTR:
421         case ARG_STR:
422         case ARG_WSTR:
423         case ARG_INT128:
424             if (odp->type != TYPE_PASCAL) pos -= 4;
425             output( "\tmovzwl %d(%%ecx),%%edx\n", pos + 2 ); /* sel */
426             output( "\tshr $3,%%edx\n" );
427             output( "\tmovzwl %d(%%ecx),%%eax\n", pos ); /* offset */
428             output( "\taddl (%%esi,%%edx,4),%%eax\n" );
429             output( "\tpushl %%eax\n" );
430             if (odp->type == TYPE_PASCAL) pos += 4;
431             break;
432         }
433     }
434
435     output( "\tcall *8(%%ebp)\n" );
436
437     if (needs_ldt)
438     {
439         output( "\tmovl -4(%%ebp),%%esi\n" );
440         output_cfi( ".cfi_same_value %%esi" );
441     }
442     output( "\tleave\n" );
443     output_cfi( ".cfi_def_cfa %%esp,4" );
444     output_cfi( ".cfi_same_value %%ebp" );
445     output( "\tret\n" );
446     output_cfi( ".cfi_endproc" );
447     output_function_size( name );
448     free( name );
449 }
450
451
452 /*******************************************************************
453  *         callfrom16_type_compare
454  *
455  * Compare two callfrom16 sequences.
456  */
457 static int callfrom16_type_compare( const void *e1, const void *e2 )
458 {
459     const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
460     const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
461     int retval;
462     int type1 = odp1->type;
463     int type2 = odp2->type;
464     char args1[80];
465
466     if (type1 == TYPE_STUB) type1 = TYPE_CDECL;
467     if (type2 == TYPE_STUB) type2 = TYPE_CDECL;
468
469     if ((retval = type1 - type2) != 0) return retval;
470
471     type1 = odp1->flags & (FLAG_RET16|FLAG_REGISTER);
472     type2 = odp2->flags & (FLAG_RET16|FLAG_REGISTER);
473
474     if ((retval = type1 - type2) != 0) return retval;
475
476     strcpy( args1, get_args_str( odp1 ));
477     return strcmp( args1, get_args_str( odp2 ));
478 }
479
480
481 /*******************************************************************
482  *         relay_type_compare
483  *
484  * Same as callfrom16_type_compare but ignores differences that don't affect the resulting relay function.
485  */
486 static int relay_type_compare( const void *e1, const void *e2 )
487 {
488     const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
489     const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
490     char name1[80];
491
492     strcpy( name1, get_relay_name(odp1) );
493     return strcmp( name1, get_relay_name(odp2) );
494 }
495
496
497 /*******************************************************************
498  *         sort_func_list
499  *
500  * Sort a list of functions, removing duplicates.
501  */
502 static int sort_func_list( ORDDEF **list, int count,
503                            int (*compare)(const void *, const void *) )
504 {
505     int i, j;
506
507     if (!count) return 0;
508     qsort( list, count, sizeof(*list), compare );
509
510     for (i = j = 0; i < count; i++)
511     {
512         if (compare( &list[j], &list[i] )) list[++j] = list[i];
513     }
514     return j + 1;
515 }
516
517
518 /*******************************************************************
519  *         output_module16
520  *
521  * Output code for a 16-bit module.
522  */
523 static void output_module16( DLLSPEC *spec )
524 {
525     ORDDEF **typelist;
526     ORDDEF *entry_point = NULL;
527     int i, j, nb_funcs;
528
529     /* store the main entry point as ordinal 0 */
530
531     if (!spec->ordinals)
532     {
533         assert(spec->limit == 0);
534         spec->ordinals = xmalloc( sizeof(spec->ordinals[0]) );
535         spec->ordinals[0] = NULL;
536     }
537     if (spec->init_func && !(spec->characteristics & IMAGE_FILE_DLL))
538     {
539         entry_point = xmalloc( sizeof(*entry_point) );
540         entry_point->type = TYPE_PASCAL;
541         entry_point->ordinal = 0;
542         entry_point->lineno = 0;
543         entry_point->flags = FLAG_REGISTER;
544         entry_point->name = NULL;
545         entry_point->link_name = xstrdup( spec->init_func );
546         entry_point->export_name = NULL;
547         entry_point->u.func.nb_args = 0;
548         assert( !spec->ordinals[0] );
549         spec->ordinals[0] = entry_point;
550     }
551
552     /* Build sorted list of all argument types, without duplicates */
553
554     typelist = xmalloc( (spec->limit + 1) * sizeof(*typelist) );
555
556     for (i = nb_funcs = 0; i <= spec->limit; i++)
557     {
558         ORDDEF *odp = spec->ordinals[i];
559         if (!odp) continue;
560         if (is_function( odp )) typelist[nb_funcs++] = odp;
561     }
562
563     nb_funcs = sort_func_list( typelist, nb_funcs, callfrom16_type_compare );
564
565     /* Output the module structure */
566
567     output( "\n/* module data */\n\n" );
568     output( "\t.data\n" );
569     output( "\t.align %d\n", get_alignment(4) );
570     output( ".L__wine_spec_dos_header:\n" );
571     output( "\t.short 0x5a4d\n" );                                         /* e_magic */
572     output( "\t.short 0\n" );                                              /* e_cblp */
573     output( "\t.short 0\n" );                                              /* e_cp */
574     output( "\t.short 0\n" );                                              /* e_crlc */
575     output( "\t.short 0\n" );                                              /* e_cparhdr */
576     output( "\t.short 0\n" );                                              /* e_minalloc */
577     output( "\t.short 0\n" );                                              /* e_maxalloc */
578     output( "\t.short 0\n" );                                              /* e_ss */
579     output( "\t.short 0\n" );                                              /* e_sp */
580     output( "\t.short 0\n" );                                              /* e_csum */
581     output( "\t.short 0\n" );                                              /* e_ip */
582     output( "\t.short 0\n" );                                              /* e_cs */
583     output( "\t.short 0\n" );                                              /* e_lfarlc */
584     output( "\t.short 0\n" );                                              /* e_ovno */
585     output( "\t.short 0,0,0,0\n" );                                        /* e_res */
586     output( "\t.short 0\n" );                                              /* e_oemid */
587     output( "\t.short 0\n" );                                              /* e_oeminfo */
588     output( "\t.short 0,0,0,0,0,0,0,0,0,0\n" );                            /* e_res2 */
589     output( "\t.long .L__wine_spec_ne_header-.L__wine_spec_dos_header\n" );/* e_lfanew */
590
591     output( ".L__wine_spec_ne_header:\n" );
592     output( "\t.short 0x454e\n" );                                         /* ne_magic */
593     output( "\t.byte 0\n" );                                               /* ne_ver */
594     output( "\t.byte 0\n" );                                               /* ne_rev */
595     output( "\t.short .L__wine_spec_ne_enttab-.L__wine_spec_ne_header\n" );/* ne_enttab */
596     output( "\t.short .L__wine_spec_ne_enttab_end-.L__wine_spec_ne_enttab\n" );/* ne_cbenttab */
597     output( "\t.long 0\n" );                                               /* ne_crc */
598     output( "\t.short 0x%04x\n", NE_FFLAGS_SINGLEDATA |                    /* ne_flags */
599              ((spec->characteristics & IMAGE_FILE_DLL) ? NE_FFLAGS_LIBMODULE : 0) );
600     output( "\t.short 2\n" );                                              /* ne_autodata */
601     output( "\t.short %u\n", spec->heap_size );                            /* ne_heap */
602     output( "\t.short 0\n" );                                              /* ne_stack */
603     if (!entry_point) output( "\t.long 0\n" );                             /* ne_csip */
604     else output( "\t.short .L__wine_%s_0-.L__wine_spec_code_segment,1\n",
605                  make_c_identifier(spec->dll_name) );
606     output( "\t.short 0,2\n" );                                            /* ne_sssp */
607     output( "\t.short 2\n" );                                              /* ne_cseg */
608     output( "\t.short 0\n" );                                              /* ne_cmod */
609     output( "\t.short 0\n" );                                              /* ne_cbnrestab */
610     output( "\t.short .L__wine_spec_ne_segtab-.L__wine_spec_ne_header\n" );/* ne_segtab */
611     output( "\t.short .L__wine_spec_ne_rsrctab-.L__wine_spec_ne_header\n" );   /* ne_rsrctab */
612     output( "\t.short .L__wine_spec_ne_restab-.L__wine_spec_ne_header\n" );    /* ne_restab */
613     output( "\t.short .L__wine_spec_ne_modtab-.L__wine_spec_ne_header\n" );    /* ne_modtab */
614     output( "\t.short .L__wine_spec_ne_imptab-.L__wine_spec_ne_header\n" );    /* ne_imptab */
615     output( "\t.long 0\n" );                                   /* ne_nrestab */
616     output( "\t.short 0\n" );                                  /* ne_cmovent */
617     output( "\t.short 0\n" );                                  /* ne_align */
618     output( "\t.short 0\n" );                                  /* ne_cres */
619     output( "\t.byte 0x02\n" );                                /* ne_exetyp = NE_OSFLAGS_WINDOWS */
620     output( "\t.byte 0x08\n" );                                /* ne_flagsothers = NE_AFLAGS_FASTLOAD */
621     output( "\t.short 0\n" );                                  /* ne_pretthunks */
622     output( "\t.short 0\n" );                                  /* ne_psegrefbytes */
623     output( "\t.short 0\n" );                                  /* ne_swaparea */
624     output( "\t.short 0\n" );                                  /* ne_expver */
625
626     /* segment table */
627
628     output( "\n.L__wine_spec_ne_segtab:\n" );
629
630     /* code segment entry */
631
632     output( "\t.short .L__wine_spec_code_segment-.L__wine_spec_dos_header\n" );         /* filepos */
633     output( "\t.short .L__wine_spec_code_segment_end-.L__wine_spec_code_segment\n" );   /* size */
634     output( "\t.short 0x2000\n" );                                                      /* flags = NE_SEGFLAGS_32BIT */
635     output( "\t.short .L__wine_spec_code_segment_end-.L__wine_spec_code_segment\n" );   /* minsize */
636
637     /* data segment entry */
638
639     output( "\t.short .L__wine_spec_data_segment-.L__wine_spec_dos_header\n" );         /* filepos */
640     output( "\t.short .L__wine_spec_data_segment_end-.L__wine_spec_data_segment\n" );   /* size */
641     output( "\t.short 0x0001\n" );                                                      /* flags = NE_SEGFLAGS_DATA */
642     output( "\t.short .L__wine_spec_data_segment_end-.L__wine_spec_data_segment\n" );   /* minsize */
643
644     /* resource directory */
645
646     output_res16_directory( spec );
647
648     /* resident names table */
649
650     output( "\n\t.align %d\n", get_alignment(2) );
651     output( ".L__wine_spec_ne_restab:\n" );
652     output_resident_name( spec->dll_name, 0 );
653     for (i = 1; i <= spec->limit; i++)
654     {
655         ORDDEF *odp = spec->ordinals[i];
656         if (!odp || !odp->name[0]) continue;
657         if (odp->flags & FLAG_EXPORT32) continue;
658         output_resident_name( odp->name, i );
659     }
660     output( "\t.byte 0\n" );
661
662     /* imported names table */
663
664     output( "\n\t.align %d\n", get_alignment(2) );
665     output( ".L__wine_spec_ne_modtab:\n" );
666     output( ".L__wine_spec_ne_imptab:\n" );
667     output( "\t.byte 0,0\n" );
668
669     /* entry table */
670
671     output( "\n.L__wine_spec_ne_enttab:\n" );
672     output_entry_table( spec );
673     output( ".L__wine_spec_ne_enttab_end:\n" );
674
675     /* code segment */
676
677     output( "\n\t.align %d\n", get_alignment(2) );
678     output( ".L__wine_spec_code_segment:\n" );
679
680     for ( i = 0; i < nb_funcs; i++ )
681     {
682         unsigned int arg_types[2];
683         int nop_words, pos, argsize = 0;
684
685         if ( typelist[i]->type == TYPE_PASCAL )
686             argsize = get_function_argsize( typelist[i] );
687
688         /* build the arg types bit fields */
689         arg_types[0] = arg_types[1] = 0;
690         for (j = pos = 0; j < typelist[i]->u.func.nb_args && pos < 20; j++, pos++)
691         {
692             int type = 0;
693             switch (typelist[i]->u.func.args[j])
694             {
695             case ARG_WORD:   type = ARG16_WORD; break;
696             case ARG_SWORD:  type = ARG16_SWORD; break;
697             case ARG_SEGPTR: type = ARG16_LONG; break;
698             case ARG_SEGSTR: type = ARG16_SEGSTR; break;
699             case ARG_LONG:   type = ARG16_LONG; break;
700             case ARG_PTR:    type = ARG16_PTR; break;
701             case ARG_STR:    type = ARG16_STR; break;
702             case ARG_WSTR:   type = ARG16_PTR; break;
703             case ARG_FLOAT:  type = ARG16_LONG; break;
704             case ARG_INT128: type = ARG16_PTR; break;
705             case ARG_INT64:
706             case ARG_DOUBLE:
707                 type = ARG16_LONG;
708                 arg_types[pos / 10] |= type << (3 * (pos % 10));
709                 pos++;
710                 break;
711             }
712             if (pos < 20) arg_types[pos / 10] |= type << (3 * (pos % 10));
713         }
714         if (typelist[i]->type == TYPE_VARARGS && pos < 20)
715             arg_types[pos / 10] |= ARG16_VARARG << (3 * (pos % 10));
716
717         output( ".L__wine_spec_callfrom16_%s:\n", get_callfrom16_name(typelist[i]) );
718         output( "\tpushl $.L__wine_spec_call16_%s\n", get_relay_name(typelist[i]) );
719         output( "\tlcall $0,$0\n" );
720
721         if (typelist[i]->flags & FLAG_REGISTER)
722         {
723             nop_words = 4;
724         }
725         else if (typelist[i]->flags & FLAG_RET16)
726         {
727             output( "\torw %%ax,%%ax\n" );
728             output( "\tnop\n" );  /* so that the lretw is aligned */
729             nop_words = 2;
730         }
731         else
732         {
733             output( "\tshld $16,%%eax,%%edx\n" );
734             output( "\torl %%eax,%%eax\n" );
735             nop_words = 1;
736         }
737
738         if (argsize)
739         {
740             output( "\tlretw $%u\n", argsize );
741             nop_words--;
742         }
743         else output( "\tlretw\n" );
744
745         if (nop_words) output( "\t%s\n", nop_sequence[nop_words-1] );
746
747         /* the movl is here so that the code contains only valid instructions, */
748         /* it's never actually executed, we only care about the arg_types[] values */
749         output( "\t.short 0x86c7\n" );
750         output( "\t.long 0x%08x,0x%08x\n", arg_types[0], arg_types[1] );
751     }
752
753     for (i = 0; i <= spec->limit; i++)
754     {
755         ORDDEF *odp = spec->ordinals[i];
756         if (!odp || !is_function( odp )) continue;
757         output( ".L__wine_%s_%u:\n", make_c_identifier(spec->dll_name), i );
758         output( "\tpushw %%bp\n" );
759         output( "\tpushl $%s\n",
760                  asm_name( odp->type == TYPE_STUB ? get_stub_name( odp, spec ) : odp->link_name ));
761         output( "\tcallw .L__wine_spec_callfrom16_%s\n", get_callfrom16_name( odp ) );
762     }
763     output( ".L__wine_spec_code_segment_end:\n" );
764
765     /* data segment */
766
767     output( "\n.L__wine_spec_data_segment:\n" );
768     output( "\t.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n" );  /* instance data */
769     for (i = 0; i <= spec->limit; i++)
770     {
771         ORDDEF *odp = spec->ordinals[i];
772         if (!odp || odp->type != TYPE_VARIABLE) continue;
773         output( ".L__wine_%s_%u:\n", make_c_identifier(spec->dll_name), i );
774         output( "\t.long " );
775         for (j = 0; j < odp->u.var.n_values-1; j++)
776             output( "0x%08x,", odp->u.var.values[j] );
777         output( "0x%08x\n", odp->u.var.values[j] );
778     }
779     output( ".L__wine_spec_data_segment_end:\n" );
780
781     /* resource data */
782
783     if (spec->nb_resources)
784     {
785         output( "\n.L__wine_spec_resource_data:\n" );
786         output_res16_data( spec );
787     }
788
789     output( "\t.byte 0\n" );  /* make sure the last symbol points to something */
790
791     /* relay functions */
792
793     nb_funcs = sort_func_list( typelist, nb_funcs, relay_type_compare );
794     if (nb_funcs)
795     {
796         output( "\n/* relay functions */\n\n" );
797         output( "\t.text\n" );
798         for ( i = 0; i < nb_funcs; i++ ) output_call16_function( typelist[i] );
799         output( "\t.data\n" );
800         output( "wine_ldt_copy_ptr:\n" );
801         output( "\t.long %s\n", asm_name("wine_ldt_copy") );
802     }
803
804     free( typelist );
805 }
806
807
808 /*******************************************************************
809  *         output_spec16_file
810  *
811  * Output the complete data for a spec 16-bit file.
812  */
813 void output_spec16_file( DLLSPEC *spec16 )
814 {
815     DLLSPEC *spec32 = alloc_dll_spec();
816
817     resolve_imports( spec16 );
818     add_16bit_exports( spec32, spec16 );
819
820     output_standard_file_header();
821     output_module( spec32 );
822     output_module16( spec16 );
823     output_stubs( spec16 );
824     output_exports( spec32 );
825     output_imports( spec16 );
826     if (is_undefined( "__wine_call_from_16" )) output_asm_relays16();
827     if (spec16->main_module)
828     {
829         output( "\n\t%s\n", get_asm_string_section() );
830         output( ".L__wine_spec_main_module:\n" );
831         output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec16->main_module );
832     }
833     output_gnu_stack_note();
834     free_dll_spec( spec32 );
835 }
836
837 /*******************************************************************
838  *         output_fake_module16
839  *
840  * Create a fake 16-bit binary module.
841  */
842 void output_fake_module16( DLLSPEC *spec )
843 {
844     static const unsigned char code_segment[] = { 0x90, 0xc3 };
845     static const unsigned char data_segment[16] = { 0 };
846     static const char fakedll_signature[] = "Wine placeholder DLL";
847     const unsigned int cseg = 2;
848     const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
849     const unsigned int segtab = lfanew + 0x40;
850
851     unsigned int i, rsrctab, restab, namelen, modtab, imptab, enttab, cbenttab, codeseg, dataseg, rsrcdata;
852
853     init_output_buffer();
854
855     rsrctab = lfanew;
856     restab = segtab + 8 * cseg;
857     if (spec->nb_resources)
858     {
859         output_bin_res16_directory( spec, 0 );
860         align_output( 2 );
861         rsrctab = restab;
862         restab += output_buffer_pos;
863         free( output_buffer );
864         init_output_buffer();
865     }
866
867     namelen  = strlen( spec->dll_name );
868     modtab   = restab + ((namelen + 3) & ~1);
869     imptab   = modtab;
870     enttab   = modtab + 2;
871     cbenttab = 1;
872     codeseg  = (enttab + cbenttab + 1) & ~1;
873     dataseg  = codeseg + sizeof(code_segment);
874     rsrcdata = dataseg + sizeof(data_segment);
875
876     init_output_buffer();
877
878     put_word( 0x5a4d );       /* e_magic */
879     put_word( 0x40 );         /* e_cblp */
880     put_word( 0x01 );         /* e_cp */
881     put_word( 0 );            /* e_crlc */
882     put_word( lfanew / 16 );  /* e_cparhdr */
883     put_word( 0x0000 );       /* e_minalloc */
884     put_word( 0xffff );       /* e_maxalloc */
885     put_word( 0x0000 );       /* e_ss */
886     put_word( 0x00b8 );       /* e_sp */
887     put_word( 0 );            /* e_csum */
888     put_word( 0 );            /* e_ip */
889     put_word( 0 );            /* e_cs */
890     put_word( lfanew );       /* e_lfarlc */
891     put_word( 0 );            /* e_ovno */
892     put_dword( 0 );           /* e_res */
893     put_dword( 0 );
894     put_word( 0 );            /* e_oemid */
895     put_word( 0 );            /* e_oeminfo */
896     put_dword( 0 );           /* e_res2 */
897     put_dword( 0 );
898     put_dword( 0 );
899     put_dword( 0 );
900     put_dword( 0 );
901     put_dword( lfanew );
902
903     put_data( fakedll_signature, sizeof(fakedll_signature) );
904     align_output( 16 );
905
906     put_word( 0x454e );                    /* ne_magic */
907     put_byte( 0 );                         /* ne_ver */
908     put_byte( 0 );                         /* ne_rev */
909     put_word( enttab - lfanew );           /* ne_enttab */
910     put_word( cbenttab );                  /* ne_cbenttab */
911     put_dword( 0 );                        /* ne_crc */
912     put_word( NE_FFLAGS_SINGLEDATA |       /* ne_flags */
913               ((spec->characteristics & IMAGE_FILE_DLL) ? NE_FFLAGS_LIBMODULE : 0) );
914     put_word( 2 );                         /* ne_autodata */
915     put_word( spec->heap_size );           /* ne_heap */
916     put_word( 0 );                         /* ne_stack */
917     put_word( 0 ); put_word( 0 );          /* ne_csip */
918     put_word( 0 ); put_word( 2 );          /* ne_sssp */
919     put_word( cseg );                      /* ne_cseg */
920     put_word( 0 );                         /* ne_cmod */
921     put_word( 0 );                         /* ne_cbnrestab */
922     put_word( segtab - lfanew );           /* ne_segtab */
923     put_word( rsrctab - lfanew );          /* ne_rsrctab */
924     put_word( restab - lfanew );           /* ne_restab */
925     put_word( modtab - lfanew );           /* ne_modtab */
926     put_word( imptab - lfanew );           /* ne_imptab */
927     put_dword( 0 );                        /* ne_nrestab */
928     put_word( 0 );                         /* ne_cmovent */
929     put_word( 0 );                         /* ne_align */
930     put_word( 0 );                         /* ne_cres */
931     put_byte( 2 /*NE_OSFLAGS_WINDOWS*/ );  /* ne_exetyp */
932     put_byte( 8 /*NE_AFLAGS_FASTLOAD*/ );  /* ne_flagsothers */
933     put_word( 0 );                         /* ne_pretthunks */
934     put_word( 0 );                         /* ne_psegrefbytes */
935     put_word( 0 );                         /* ne_swaparea */
936     put_word( 0 );                         /* ne_expver */
937
938     /* segment table */
939     put_word( codeseg );
940     put_word( sizeof(code_segment) );
941     put_word( 0x2000 /* NE_SEGFLAGS_32BIT */ );
942     put_word( sizeof(code_segment) );
943     put_word( dataseg );
944     put_word( sizeof(data_segment) );
945     put_word( 0x0001 /* NE_SEGFLAGS_DATA */ );
946     put_word( sizeof(data_segment) );
947
948     /* resource directory */
949     if (spec->nb_resources)
950     {
951         output_bin_res16_directory( spec, rsrcdata );
952         align_output( 2 );
953     }
954
955     /* resident names table */
956     put_byte( namelen );
957     for (i = 0; i < namelen; i++) put_byte( toupper(spec->dll_name[i]) );
958     put_byte( 0 );
959     align_output( 2 );
960
961     /* imported names table */
962     put_word( 0 );
963
964     /* entry table */
965     put_byte( 0 );
966     align_output( 2 );
967
968     /* code segment */
969     put_data( code_segment, sizeof(code_segment) );
970
971     /* data segment */
972     put_data( data_segment, sizeof(data_segment) );
973
974     /* resource data */
975     output_bin_res16_data( spec );
976
977     flush_output_buffer();
978 }