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