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