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