msvcp71: Fixed basic_filebuf class layout.
[wine] / tools / winebuild / spec32.c
1 /*
2  * 32-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 #include <stdarg.h>
31 #include <string.h>
32
33 #include "build.h"
34
35 #define IMAGE_FILE_MACHINE_UNKNOWN 0
36 #define IMAGE_FILE_MACHINE_I386    0x014c
37 #define IMAGE_FILE_MACHINE_POWERPC 0x01f0
38 #define IMAGE_FILE_MACHINE_AMD64   0x8664
39 #define IMAGE_FILE_MACHINE_ARMNT   0x01C4
40 /* Wine extension */
41 #define IMAGE_FILE_MACHINE_SPARC   0x2000
42 #define IMAGE_FILE_MACHINE_ARM64   0x01C5
43
44 #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
45 #define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
46
47 #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
48 #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
49 #define IMAGE_ROM_OPTIONAL_HDR_MAGIC  0x107
50
51 /* check if entry point needs a relay thunk */
52 static inline int needs_relay( const ORDDEF *odp )
53 {
54     /* skip nonexistent entry points */
55     if (!odp) return 0;
56     /* skip non-functions */
57     switch (odp->type)
58     {
59     case TYPE_STDCALL:
60     case TYPE_CDECL:
61     case TYPE_THISCALL:
62         break;
63     case TYPE_STUB:
64         if (odp->u.func.nb_args != -1) break;
65         /* fall through */
66     default:
67         return 0;
68     }
69     /* skip norelay and forward entry points */
70     if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) return 0;
71     /* skip register entry points on x86_64 */
72     if (target_cpu == CPU_x86_64 && (odp->flags & FLAG_REGISTER)) return 0;
73     return 1;
74 }
75
76 static int is_float_arg( const ORDDEF *odp, int arg )
77 {
78     if (arg >= odp->u.func.nb_args) return 0;
79     return (odp->u.func.args[arg] == ARG_FLOAT || odp->u.func.args[arg] == ARG_DOUBLE);
80 }
81
82 /* check if dll will output relay thunks */
83 int has_relays( DLLSPEC *spec )
84 {
85     int i;
86
87     if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64 && target_cpu != CPU_ARM) return 0;
88
89     for (i = spec->base; i <= spec->limit; i++)
90     {
91         ORDDEF *odp = spec->ordinals[i];
92         if (needs_relay( odp )) return 1;
93     }
94     return 0;
95 }
96
97 /*******************************************************************
98  *         output_relay_debug
99  *
100  * Output entry points for relay debugging
101  */
102 static void output_relay_debug( DLLSPEC *spec )
103 {
104     int i, j;
105     unsigned int pos, args, flags;
106
107     /* first the table of entry point offsets */
108
109     output( "\t%s\n", get_asm_rodata_section() );
110     output( "\t.align %d\n", get_alignment(4) );
111     output( ".L__wine_spec_relay_entry_point_offsets:\n" );
112
113     for (i = spec->base; i <= spec->limit; i++)
114     {
115         ORDDEF *odp = spec->ordinals[i];
116
117         if (needs_relay( odp ))
118             output( "\t.long .L__wine_spec_relay_entry_point_%d-__wine_spec_relay_entry_points\n", i );
119         else
120             output( "\t.long 0\n" );
121     }
122
123     /* then the table of argument types */
124
125     output( "\t.align %d\n", get_alignment(4) );
126     output( ".L__wine_spec_relay_arg_types:\n" );
127
128     for (i = spec->base; i <= spec->limit; i++)
129     {
130         ORDDEF *odp = spec->ordinals[i];
131         unsigned int mask = 0;
132
133         if (needs_relay( odp ))
134         {
135             for (j = pos = 0; pos < 16 && j < odp->u.func.nb_args; j++)
136             {
137                 switch (odp->u.func.args[j])
138                 {
139                 case ARG_STR:    mask |= 1 << (2 * pos++); break;
140                 case ARG_WSTR:   mask |= 2 << (2 * pos++); break;
141                 case ARG_INT64:
142                 case ARG_DOUBLE: pos += 8 / get_ptr_size(); break;
143                 case ARG_INT128: pos += (target_cpu == CPU_x86) ? 4 : 1; break;
144                 default:         pos++; break;
145                 }
146             }
147         }
148         output( "\t.long 0x%08x\n", mask );
149     }
150
151     /* then the relay thunks */
152
153     output( "\t.text\n" );
154     output( "__wine_spec_relay_entry_points:\n" );
155     output( "\tnop\n" );  /* to avoid 0 offset */
156
157     for (i = spec->base; i <= spec->limit; i++)
158     {
159         ORDDEF *odp = spec->ordinals[i];
160
161         if (!needs_relay( odp )) continue;
162
163         output( "\t.align %d\n", get_alignment(4) );
164         output( ".L__wine_spec_relay_entry_point_%d:\n", i );
165         output_cfi( ".cfi_startproc" );
166
167         args = get_args_size(odp) / get_ptr_size();
168         flags = 0;
169
170         switch (target_cpu)
171         {
172         case CPU_x86:
173             if (odp->type == TYPE_THISCALL)  /* add the this pointer */
174             {
175                 output( "\tpopl %%eax\n" );
176                 output( "\tpushl %%ecx\n" );
177                 output( "\tpushl %%eax\n" );
178                 flags |= 2;
179             }
180             if (odp->flags & FLAG_REGISTER)
181                 output( "\tpushl %%eax\n" );
182             else
183                 output( "\tpushl %%esp\n" );
184             output_cfi( ".cfi_adjust_cfa_offset 4" );
185
186             if (odp->flags & FLAG_RET64) flags |= 1;
187             output( "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) );
188             output_cfi( ".cfi_adjust_cfa_offset 4" );
189
190             if (UsePIC)
191             {
192                 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
193                 output( "1:\tleal .L__wine_spec_relay_descr-1b(%%eax),%%eax\n" );
194             }
195             else output( "\tmovl $.L__wine_spec_relay_descr,%%eax\n" );
196             output( "\tpushl %%eax\n" );
197             output_cfi( ".cfi_adjust_cfa_offset 4" );
198
199             if (odp->flags & FLAG_REGISTER)
200             {
201                 output( "\tcall *8(%%eax)\n" );
202             }
203             else
204             {
205                 output( "\tcall *4(%%eax)\n" );
206                 output_cfi( ".cfi_adjust_cfa_offset -12" );
207                 if (odp->type == TYPE_STDCALL || odp->type == TYPE_THISCALL)
208                     output( "\tret $%u\n", args * get_ptr_size() );
209                 else
210                     output( "\tret\n" );
211             }
212             break;
213
214         case CPU_ARM:
215             switch (args)
216             {
217             default: output( "\tpush {r0-r3}\n" ); break;
218             case 3:  output( "\tpush {r0-r2}\n" ); break;
219             case 2:  output( "\tpush {r0-r1}\n" ); break;
220             case 1:  output( "\tpush {r0}\n" ); break;
221             case 0:  break;
222             }
223             output( "\tpush {LR}\n" );
224             output( "\tmov r2, SP\n");
225             if (odp->flags & FLAG_RET64) flags |= 1;
226             output( "\tmov r1, #%u\n", (flags << 24) );
227             if (args) output( "\tadd r1, #%u\n", (args << 16) );
228             if ((i - spec->base) & 0xf000) output( "\tadd r1, #%u\n", (i - spec->base) & 0xf000 );
229             if ((i - spec->base) & 0x0f00) output( "\tadd r1, #%u\n", (i - spec->base) & 0x0f00 );
230             if ((i - spec->base) & 0x00f0) output( "\tadd r1, #%u\n", (i - spec->base) & 0x00f0 );
231             if ((i - spec->base) & 0x000f) output( "\tadd r1, #%u\n", (i - spec->base) & 0x000f );
232             output( "\tldr r0, [PC, #0]\n");
233             output( "\tmov PC, PC\n");
234             output( "\t.long .L__wine_spec_relay_descr\n" );
235             output( "\tldr r3, [r0, #4]\n");
236             output( "\tblx r3\n");
237             output( "\tpop {r3}\n" );
238             if (args) output( "\tadd SP, SP, #%u\n", min(args*4, 16) );
239             output( "\tbx r3\n");
240             break;
241
242         case CPU_x86_64:
243             output( "\tsubq $40,%%rsp\n" );
244             output_cfi( ".cfi_adjust_cfa_offset 40" );
245             switch (args)
246             {
247             default: output( "\tmovq %%%s,72(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
248             /* fall through */
249             case 3:  output( "\tmovq %%%s,64(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
250             /* fall through */
251             case 2:  output( "\tmovq %%%s,56(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
252             /* fall through */
253             case 1:  output( "\tmovq %%%s,48(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
254             /* fall through */
255             case 0:  break;
256             }
257             output( "\tleaq 40(%%rsp),%%r8\n" );
258             output( "\tmovq $%u,%%rdx\n", (flags << 24) | (args << 16) | (i - spec->base) );
259             output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
260             output( "\tcallq *8(%%rcx)\n" );
261             output( "\taddq $40,%%rsp\n" );
262             output_cfi( ".cfi_adjust_cfa_offset -40" );
263             output( "\tret\n" );
264             break;
265
266         default:
267             assert(0);
268         }
269         output_cfi( ".cfi_endproc" );
270     }
271 }
272
273 /*******************************************************************
274  *         output_exports
275  *
276  * Output the export table for a Win32 module.
277  */
278 void output_exports( DLLSPEC *spec )
279 {
280     int i, fwd_size = 0;
281     int nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
282
283     if (!nr_exports) return;
284
285     output( "\n/* export table */\n\n" );
286     output( "\t.data\n" );
287     output( "\t.align %d\n", get_alignment(4) );
288     output( ".L__wine_spec_exports:\n" );
289
290     /* export directory header */
291
292     output( "\t.long 0\n" );                       /* Characteristics */
293     output( "\t.long 0\n" );                       /* TimeDateStamp */
294     output( "\t.long 0\n" );                       /* MajorVersion/MinorVersion */
295     output( "\t.long .L__wine_spec_exp_names-.L__wine_spec_rva_base\n" ); /* Name */
296     output( "\t.long %u\n", spec->base );          /* Base */
297     output( "\t.long %u\n", nr_exports );          /* NumberOfFunctions */
298     output( "\t.long %u\n", spec->nb_names );      /* NumberOfNames */
299     output( "\t.long .L__wine_spec_exports_funcs-.L__wine_spec_rva_base\n" ); /* AddressOfFunctions */
300     if (spec->nb_names)
301     {
302         output( "\t.long .L__wine_spec_exp_name_ptrs-.L__wine_spec_rva_base\n" ); /* AddressOfNames */
303         output( "\t.long .L__wine_spec_exp_ordinals-.L__wine_spec_rva_base\n" );  /* AddressOfNameOrdinals */
304     }
305     else
306     {
307         output( "\t.long 0\n" );  /* AddressOfNames */
308         output( "\t.long 0\n" );  /* AddressOfNameOrdinals */
309     }
310
311     /* output the function pointers */
312
313     output( "\n.L__wine_spec_exports_funcs:\n" );
314     for (i = spec->base; i <= spec->limit; i++)
315     {
316         ORDDEF *odp = spec->ordinals[i];
317         if (!odp) output( "\t%s 0\n", get_asm_ptr_keyword() );
318         else switch(odp->type)
319         {
320         case TYPE_EXTERN:
321         case TYPE_STDCALL:
322         case TYPE_VARARGS:
323         case TYPE_CDECL:
324         case TYPE_THISCALL:
325             if (odp->flags & FLAG_FORWARD)
326             {
327                 output( "\t%s .L__wine_spec_forwards+%u\n", get_asm_ptr_keyword(), fwd_size );
328                 fwd_size += strlen(odp->link_name) + 1;
329             }
330             else if (odp->flags & FLAG_EXT_LINK)
331             {
332                 output( "\t%s %s_%s\n",
333                          get_asm_ptr_keyword(), asm_name("__wine_spec_ext_link"), odp->link_name );
334             }
335             else
336             {
337                 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
338             }
339             break;
340         case TYPE_STUB:
341             output( "\t%s %s\n", get_asm_ptr_keyword(),
342                      asm_name( get_stub_name( odp, spec )) );
343             break;
344         default:
345             assert(0);
346         }
347     }
348
349     if (spec->nb_names)
350     {
351         /* output the function name pointers */
352
353         int namepos = strlen(spec->file_name) + 1;
354
355         output( "\n.L__wine_spec_exp_name_ptrs:\n" );
356         for (i = 0; i < spec->nb_names; i++)
357         {
358             output( "\t.long .L__wine_spec_exp_names+%u-.L__wine_spec_rva_base\n", namepos );
359             namepos += strlen(spec->names[i]->name) + 1;
360         }
361
362         /* output the function ordinals */
363
364         output( "\n.L__wine_spec_exp_ordinals:\n" );
365         for (i = 0; i < spec->nb_names; i++)
366         {
367             output( "\t%s %d\n",
368                      get_asm_short_keyword(), spec->names[i]->ordinal - spec->base );
369         }
370         if (spec->nb_names % 2)
371         {
372             output( "\t%s 0\n", get_asm_short_keyword() );
373         }
374     }
375
376     /* output the export name strings */
377
378     output( "\n.L__wine_spec_exp_names:\n" );
379     output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
380     for (i = 0; i < spec->nb_names; i++)
381         output( "\t%s \"%s\"\n",
382                  get_asm_string_keyword(), spec->names[i]->name );
383
384     /* output forward strings */
385
386     if (fwd_size)
387     {
388         output( "\n.L__wine_spec_forwards:\n" );
389         for (i = spec->base; i <= spec->limit; i++)
390         {
391             ORDDEF *odp = spec->ordinals[i];
392             if (odp && (odp->flags & FLAG_FORWARD))
393                 output( "\t%s \"%s\"\n", get_asm_string_keyword(), odp->link_name );
394         }
395     }
396     output( "\t.align %d\n", get_alignment(get_ptr_size()) );
397     output( ".L__wine_spec_exports_end:\n" );
398
399     /* output relays */
400
401     if (!has_relays( spec ))
402     {
403         output( "\t%s 0\n", get_asm_ptr_keyword() );
404         return;
405     }
406
407     output( ".L__wine_spec_relay_descr:\n" );
408     output( "\t%s 0xdeb90001\n", get_asm_ptr_keyword() );  /* magic */
409     output( "\t%s 0,0\n", get_asm_ptr_keyword() );         /* relay funcs */
410     output( "\t%s 0\n", get_asm_ptr_keyword() );           /* private data */
411     output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
412     output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
413     output( "\t%s .L__wine_spec_relay_arg_types\n", get_asm_ptr_keyword() );
414
415     output_relay_debug( spec );
416 }
417
418
419 /*******************************************************************
420  *         output_asm_constructor
421  *
422  * Output code for calling a dll constructor.
423  */
424 static void output_asm_constructor( const char *constructor )
425 {
426     if (target_platform == PLATFORM_APPLE)
427     {
428         /* Mach-O doesn't have an init section */
429         output( "\n\t.mod_init_func\n" );
430         output( "\t.align %d\n", get_alignment(4) );
431         output( "\t.long %s\n", asm_name(constructor) );
432     }
433     else
434     {
435         switch(target_cpu)
436         {
437         case CPU_x86:
438         case CPU_x86_64:
439             output( "\n\t.section \".init\",\"ax\"\n" );
440             output( "\tcall %s\n", asm_name(constructor) );
441             break;
442         case CPU_SPARC:
443             output( "\n\t.section \".init\",\"ax\"\n" );
444             output( "\tcall %s\n", asm_name(constructor) );
445             output( "\tnop\n" );
446             break;
447         case CPU_ARM:
448             output( "\n\t.section \".text\",\"ax\"\n" );
449             output( "\tblx %s\n", asm_name(constructor) );
450             break;
451         case CPU_ARM64:
452         case CPU_POWERPC:
453             output( "\n\t.section \".init\",\"ax\"\n" );
454             output( "\tbl %s\n", asm_name(constructor) );
455             break;
456         }
457     }
458 }
459
460
461 /*******************************************************************
462  *         output_module
463  *
464  * Output the module data.
465  */
466 void output_module( DLLSPEC *spec )
467 {
468     int machine = 0;
469     unsigned int page_size = get_page_size();
470
471     /* Reserve some space for the PE header */
472
473     switch (target_platform)
474     {
475     case PLATFORM_APPLE:
476         output( "\t.text\n" );
477         output( "\t.align %d\n", get_alignment(page_size) );
478         output( "__wine_spec_pe_header:\n" );
479         output( "\t.space 65536\n" );
480         break;
481     case PLATFORM_SOLARIS:
482         output( "\n\t.section \".text\",\"ax\"\n" );
483         output( "__wine_spec_pe_header:\n" );
484         output( "\t.skip %u\n", 65536 + page_size );
485         break;
486     default:
487         switch(target_cpu)
488         {
489         case CPU_x86:
490         case CPU_x86_64:
491         case CPU_SPARC:
492             output( "\n\t.section \".init\",\"ax\"\n" );
493             output( "\tjmp 1f\n" );
494             break;
495         case CPU_ARM:
496             output( "\n\t.section \".text\",\"ax\"\n" );
497             output( "\tb 1f\n" );
498             break;
499         case CPU_ARM64:
500         case CPU_POWERPC:
501             output( "\n\t.section \".init\",\"ax\"\n" );
502             output( "\tb 1f\n" );
503             break;
504         }
505         output( "__wine_spec_pe_header:\n" );
506         output( "\t.skip %u\n", 65536 + page_size );
507         output( "1:\n" );
508         break;
509     }
510
511     /* Output the NT header */
512
513     output( "\n\t.data\n" );
514     output( "\t.align %d\n", get_alignment(get_ptr_size()) );
515     output( "%s\n", asm_globl("__wine_spec_nt_header") );
516     output( ".L__wine_spec_rva_base:\n" );
517
518     output( "\t.long 0x4550\n" );         /* Signature */
519     switch(target_cpu)
520     {
521     case CPU_x86:     machine = IMAGE_FILE_MACHINE_I386; break;
522     case CPU_x86_64:  machine = IMAGE_FILE_MACHINE_AMD64; break;
523     case CPU_ARM:     machine = IMAGE_FILE_MACHINE_ARMNT; break;
524     case CPU_ARM64:   machine = IMAGE_FILE_MACHINE_ARM64; break;
525     case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break;
526     case CPU_SPARC:   machine = IMAGE_FILE_MACHINE_SPARC; break;
527     }
528     output( "\t%s 0x%04x\n",              /* Machine */
529              get_asm_short_keyword(), machine );
530     output( "\t%s 0\n",                   /* NumberOfSections */
531              get_asm_short_keyword() );
532     output( "\t.long 0\n" );              /* TimeDateStamp */
533     output( "\t.long 0\n" );              /* PointerToSymbolTable */
534     output( "\t.long 0\n" );              /* NumberOfSymbols */
535     output( "\t%s %d\n",                  /* SizeOfOptionalHeader */
536              get_asm_short_keyword(),
537              get_ptr_size() == 8 ? IMAGE_SIZEOF_NT_OPTIONAL64_HEADER : IMAGE_SIZEOF_NT_OPTIONAL32_HEADER );
538     output( "\t%s 0x%04x\n",              /* Characteristics */
539              get_asm_short_keyword(), spec->characteristics );
540     output( "\t%s 0x%04x\n",              /* Magic */
541              get_asm_short_keyword(),
542              get_ptr_size() == 8 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC : IMAGE_NT_OPTIONAL_HDR32_MAGIC );
543     output( "\t.byte 0\n" );              /* MajorLinkerVersion */
544     output( "\t.byte 0\n" );              /* MinorLinkerVersion */
545     output( "\t.long 0\n" );              /* SizeOfCode */
546     output( "\t.long 0\n" );              /* SizeOfInitializedData */
547     output( "\t.long 0\n" );              /* SizeOfUninitializedData */
548     /* note: we expand the AddressOfEntryPoint field on 64-bit by overwriting the BaseOfCode field */
549     output( "\t%s %s\n",                  /* AddressOfEntryPoint */
550             get_asm_ptr_keyword(), spec->init_func ? asm_name(spec->init_func) : "0" );
551     if (get_ptr_size() == 4)
552     {
553         output( "\t.long 0\n" );          /* BaseOfCode */
554         output( "\t.long 0\n" );          /* BaseOfData */
555     }
556     output( "\t%s __wine_spec_pe_header\n",         /* ImageBase */
557              get_asm_ptr_keyword() );
558     output( "\t.long %u\n", page_size );  /* SectionAlignment */
559     output( "\t.long %u\n", page_size );  /* FileAlignment */
560     output( "\t%s 1,0\n",                 /* Major/MinorOperatingSystemVersion */
561              get_asm_short_keyword() );
562     output( "\t%s 0,0\n",                 /* Major/MinorImageVersion */
563              get_asm_short_keyword() );
564     output( "\t%s %u,%u\n",               /* Major/MinorSubsystemVersion */
565              get_asm_short_keyword(), spec->subsystem_major, spec->subsystem_minor );
566     output( "\t.long 0\n" );                          /* Win32VersionValue */
567     output( "\t.long %s-.L__wine_spec_rva_base\n",    /* SizeOfImage */
568              asm_name("_end") );
569     output( "\t.long %u\n", page_size );  /* SizeOfHeaders */
570     output( "\t.long 0\n" );              /* CheckSum */
571     output( "\t%s 0x%04x\n",              /* Subsystem */
572              get_asm_short_keyword(), spec->subsystem );
573     output( "\t%s 0x%04x\n",              /* DllCharacteristics */
574             get_asm_short_keyword(), spec->dll_characteristics );
575     output( "\t%s %u,%u\n",               /* SizeOfStackReserve/Commit */
576              get_asm_ptr_keyword(), (spec->stack_size ? spec->stack_size : 1024) * 1024, page_size );
577     output( "\t%s %u,%u\n",               /* SizeOfHeapReserve/Commit */
578              get_asm_ptr_keyword(), (spec->heap_size ? spec->heap_size : 1024) * 1024, page_size );
579     output( "\t.long 0\n" );              /* LoaderFlags */
580     output( "\t.long 16\n" );             /* NumberOfRvaAndSizes */
581
582     if (spec->base <= spec->limit)   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
583         output( "\t.long .L__wine_spec_exports-.L__wine_spec_rva_base,"
584                  ".L__wine_spec_exports_end-.L__wine_spec_exports\n" );
585     else
586         output( "\t.long 0,0\n" );
587
588     if (has_imports())   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
589         output( "\t.long .L__wine_spec_imports-.L__wine_spec_rva_base,"
590                  ".L__wine_spec_imports_end-.L__wine_spec_imports\n" );
591     else
592         output( "\t.long 0,0\n" );
593
594     if (spec->nb_resources)   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
595         output( "\t.long .L__wine_spec_resources-.L__wine_spec_rva_base,"
596                  ".L__wine_spec_resources_end-.L__wine_spec_resources\n" );
597     else
598         output( "\t.long 0,0\n" );
599
600     output( "\t.long 0,0\n" );  /* DataDirectory[3] */
601     output( "\t.long 0,0\n" );  /* DataDirectory[4] */
602     output( "\t.long 0,0\n" );  /* DataDirectory[5] */
603     output( "\t.long 0,0\n" );  /* DataDirectory[6] */
604     output( "\t.long 0,0\n" );  /* DataDirectory[7] */
605     output( "\t.long 0,0\n" );  /* DataDirectory[8] */
606     output( "\t.long 0,0\n" );  /* DataDirectory[9] */
607     output( "\t.long 0,0\n" );  /* DataDirectory[10] */
608     output( "\t.long 0,0\n" );  /* DataDirectory[11] */
609     output( "\t.long 0,0\n" );  /* DataDirectory[12] */
610     output( "\t.long 0,0\n" );  /* DataDirectory[13] */
611     output( "\t.long 0,0\n" );  /* DataDirectory[14] */
612     output( "\t.long 0,0\n" );  /* DataDirectory[15] */
613
614     output( "\n\t%s\n", get_asm_string_section() );
615     output( "%s\n", asm_globl("__wine_spec_file_name") );
616     output( ".L__wine_spec_file_name:\n" );
617     output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
618     if (target_platform == PLATFORM_APPLE)
619         output( "\t.lcomm %s,4\n", asm_name("_end") );
620
621     output_asm_constructor( "__wine_spec_init_ctor" );
622 }
623
624
625 /*******************************************************************
626  *         BuildSpec32File
627  *
628  * Build a Win32 C file from a spec file.
629  */
630 void BuildSpec32File( DLLSPEC *spec )
631 {
632     resolve_imports( spec );
633     output_standard_file_header();
634     output_module( spec );
635     output_stubs( spec );
636     output_exports( spec );
637     output_imports( spec );
638     if (is_undefined( "__wine_call_from_regs" )) output_asm_relays();
639     output_resources( spec );
640     output_gnu_stack_note();
641 }
642
643
644 /*******************************************************************
645  *         output_fake_module
646  *
647  * Build a fake binary module from a spec file.
648  */
649 void output_fake_module( DLLSPEC *spec )
650 {
651     static const unsigned char dll_code_section[] = { 0x31, 0xc0,          /* xor %eax,%eax */
652                                                       0xc2, 0x0c, 0x00 };  /* ret $12 */
653
654     static const unsigned char exe_code_section[] = { 0xb8, 0x01, 0x00, 0x00, 0x00,  /* movl $1,%eax */
655                                                       0xc2, 0x04, 0x00 };            /* ret $4 */
656
657     static const char fakedll_signature[] = "Wine placeholder DLL";
658     const unsigned int page_size = get_page_size();
659     const unsigned int section_align = page_size;
660     const unsigned int file_align = 0x200;
661     const unsigned int reloc_size = 8;
662     const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
663     const unsigned int nb_sections = 2 + (spec->nb_resources != 0);
664     const unsigned int text_size = (spec->characteristics & IMAGE_FILE_DLL) ?
665                                     sizeof(dll_code_section) : sizeof(exe_code_section);
666     unsigned char *resources;
667     unsigned int resources_size;
668     unsigned int image_size = 3 * section_align;
669
670     resolve_imports( spec );
671     output_bin_resources( spec, 3 * section_align );
672     resources = output_buffer;
673     resources_size = output_buffer_pos;
674     if (resources_size) image_size += (resources_size + section_align - 1) & ~(section_align - 1);
675
676     init_output_buffer();
677
678     put_word( 0x5a4d );       /* e_magic */
679     put_word( 0x40 );         /* e_cblp */
680     put_word( 0x01 );         /* e_cp */
681     put_word( 0 );            /* e_crlc */
682     put_word( lfanew / 16 );  /* e_cparhdr */
683     put_word( 0x0000 );       /* e_minalloc */
684     put_word( 0xffff );       /* e_maxalloc */
685     put_word( 0x0000 );       /* e_ss */
686     put_word( 0x00b8 );       /* e_sp */
687     put_word( 0 );            /* e_csum */
688     put_word( 0 );            /* e_ip */
689     put_word( 0 );            /* e_cs */
690     put_word( lfanew );       /* e_lfarlc */
691     put_word( 0 );            /* e_ovno */
692     put_dword( 0 );           /* e_res */
693     put_dword( 0 );
694     put_word( 0 );            /* e_oemid */
695     put_word( 0 );            /* e_oeminfo */
696     put_dword( 0 );           /* e_res2 */
697     put_dword( 0 );
698     put_dword( 0 );
699     put_dword( 0 );
700     put_dword( 0 );
701     put_dword( lfanew );
702
703     put_data( fakedll_signature, sizeof(fakedll_signature) );
704     align_output( 16 );
705
706     put_dword( 0x4550 );                             /* Signature */
707     switch(target_cpu)
708     {
709     case CPU_x86:     put_word( IMAGE_FILE_MACHINE_I386 ); break;
710     case CPU_x86_64:  put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
711     case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
712     case CPU_SPARC:   put_word( IMAGE_FILE_MACHINE_SPARC ); break;
713     case CPU_ARM:     put_word( IMAGE_FILE_MACHINE_ARMNT ); break;
714     case CPU_ARM64:   put_word( IMAGE_FILE_MACHINE_ARM64 ); break;
715     }
716     put_word( nb_sections );                         /* NumberOfSections */
717     put_dword( 0 );                                  /* TimeDateStamp */
718     put_dword( 0 );                                  /* PointerToSymbolTable */
719     put_dword( 0 );                                  /* NumberOfSymbols */
720     put_word( get_ptr_size() == 8 ?
721               IMAGE_SIZEOF_NT_OPTIONAL64_HEADER :
722               IMAGE_SIZEOF_NT_OPTIONAL32_HEADER );   /* SizeOfOptionalHeader */
723     put_word( spec->characteristics );               /* Characteristics */
724     put_word( get_ptr_size() == 8 ?
725               IMAGE_NT_OPTIONAL_HDR64_MAGIC :
726               IMAGE_NT_OPTIONAL_HDR32_MAGIC );       /* Magic */
727     put_byte(  0 );                                  /* MajorLinkerVersion */
728     put_byte(  0 );                                  /* MinorLinkerVersion */
729     put_dword( text_size );                          /* SizeOfCode */
730     put_dword( 0 );                                  /* SizeOfInitializedData */
731     put_dword( 0 );                                  /* SizeOfUninitializedData */
732     put_dword( section_align );                      /* AddressOfEntryPoint */
733     put_dword( section_align );                      /* BaseOfCode */
734     if (get_ptr_size() == 4) put_dword( 0 );         /* BaseOfData */
735     put_pword( 0x10000000 );                         /* ImageBase */
736     put_dword( section_align );                      /* SectionAlignment */
737     put_dword( file_align );                         /* FileAlignment */
738     put_word( 1 );                                   /* MajorOperatingSystemVersion */
739     put_word( 0 );                                   /* MinorOperatingSystemVersion */
740     put_word( 0 );                                   /* MajorImageVersion */
741     put_word( 0 );                                   /* MinorImageVersion */
742     put_word( spec->subsystem_major );               /* MajorSubsystemVersion */
743     put_word( spec->subsystem_minor );               /* MinorSubsystemVersion */
744     put_dword( 0 );                                  /* Win32VersionValue */
745     put_dword( image_size );                         /* SizeOfImage */
746     put_dword( file_align );                         /* SizeOfHeaders */
747     put_dword( 0 );                                  /* CheckSum */
748     put_word( spec->subsystem );                     /* Subsystem */
749     put_word( spec->dll_characteristics );           /* DllCharacteristics */
750     put_pword( (spec->stack_size ? spec->stack_size : 1024) * 1024 ); /* SizeOfStackReserve */
751     put_pword( page_size );                          /* SizeOfStackCommit */
752     put_pword( (spec->heap_size ? spec->heap_size : 1024) * 1024 );   /* SizeOfHeapReserve */
753     put_pword( page_size );                          /* SizeOfHeapCommit */
754     put_dword( 0 );                                  /* LoaderFlags */
755     put_dword( 16 );                                 /* NumberOfRvaAndSizes */
756
757     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
758     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
759     if (resources_size)   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
760     {
761         put_dword( 3 * section_align );
762         put_dword( resources_size );
763     }
764     else
765     {
766         put_dword( 0 );
767         put_dword( 0 );
768     }
769
770     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] */
771     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] */
772     put_dword( 2 * section_align );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
773     put_dword( reloc_size );
774     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] */
775     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT] */
776     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR] */
777     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] */
778     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG] */
779     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] */
780     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] */
781     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT] */
782     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] */
783     put_dword( 0 ); put_dword( 0 );   /* DataDirectory[15] */
784
785     /* .text section */
786     put_data( ".text\0\0", 8 );    /* Name */
787     put_dword( section_align );    /* VirtualSize */
788     put_dword( section_align );    /* VirtualAddress */
789     put_dword( text_size );        /* SizeOfRawData */
790     put_dword( file_align );       /* PointerToRawData */
791     put_dword( 0 );                /* PointerToRelocations */
792     put_dword( 0 );                /* PointerToLinenumbers */
793     put_word( 0 );                 /* NumberOfRelocations */
794     put_word( 0 );                 /* NumberOfLinenumbers */
795     put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics  */
796
797     /* .reloc section */
798     put_data( ".reloc\0", 8 );     /* Name */
799     put_dword( section_align );    /* VirtualSize */
800     put_dword( 2 * section_align );/* VirtualAddress */
801     put_dword( reloc_size );       /* SizeOfRawData */
802     put_dword( 2 * file_align );   /* PointerToRawData */
803     put_dword( 0 );                /* PointerToRelocations */
804     put_dword( 0 );                /* PointerToLinenumbers */
805     put_word( 0 );                 /* NumberOfRelocations */
806     put_word( 0 );                 /* NumberOfLinenumbers */
807     put_dword( 0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ ); /* Characteristics */
808
809     /* .rsrc section */
810     if (resources_size)
811     {
812         put_data( ".rsrc\0\0", 8 );    /* Name */
813         put_dword( (resources_size + section_align - 1) & ~(section_align - 1) ); /* VirtualSize */
814         put_dword( 3 * section_align );/* VirtualAddress */
815         put_dword( resources_size );   /* SizeOfRawData */
816         put_dword( 3 * file_align );   /* PointerToRawData */
817         put_dword( 0 );                /* PointerToRelocations */
818         put_dword( 0 );                /* PointerToLinenumbers */
819         put_word( 0 );                 /* NumberOfRelocations */
820         put_word( 0 );                 /* NumberOfLinenumbers */
821         put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ ); /* Characteristics */
822     }
823
824     /* .text contents */
825     align_output( file_align );
826     if (spec->characteristics & IMAGE_FILE_DLL)
827         put_data( dll_code_section, sizeof(dll_code_section) );
828     else
829         put_data( exe_code_section, sizeof(exe_code_section) );
830
831     /* .reloc contents */
832     align_output( file_align );
833     put_dword( 0 );   /* VirtualAddress */
834     put_dword( 0 );   /* SizeOfBlock */
835
836     /* .rsrc contents */
837     if (resources_size)
838     {
839         align_output( file_align );
840         put_data( resources, resources_size );
841     }
842     flush_output_buffer();
843 }
844
845
846 /*******************************************************************
847  *         output_def_file
848  *
849  * Build a Win32 def file from a spec file.
850  */
851 void output_def_file( DLLSPEC *spec, int include_private )
852 {
853     DLLSPEC *spec32 = NULL;
854     const char *name;
855     int i, total;
856
857     if (spec->type == SPEC_WIN16)
858     {
859         spec32 = alloc_dll_spec();
860         add_16bit_exports( spec32, spec );
861         spec = spec32;
862     }
863
864     if (spec_file_name)
865         output( "; File generated automatically from %s; do not edit!\n\n",
866                  spec_file_name );
867     else
868         output( "; File generated automatically; do not edit!\n\n" );
869
870     output( "LIBRARY %s\n\n", spec->file_name);
871     output( "EXPORTS\n");
872
873     /* Output the exports and relay entry points */
874
875     for (i = total = 0; i < spec->nb_entry_points; i++)
876     {
877         const ORDDEF *odp = &spec->entry_points[i];
878         int is_data = 0;
879
880         if (!odp) continue;
881
882         if (odp->name) name = odp->name;
883         else if (odp->export_name) name = odp->export_name;
884         else continue;
885
886         if (!(odp->flags & FLAG_PRIVATE)) total++;
887         else if (!include_private) continue;
888
889         if (odp->type == TYPE_STUB) continue;
890
891         output( "  %s", name );
892
893         switch(odp->type)
894         {
895         case TYPE_EXTERN:
896             is_data = 1;
897             /* fall through */
898         case TYPE_VARARGS:
899         case TYPE_CDECL:
900         case TYPE_THISCALL:
901             /* try to reduce output */
902             if(strcmp(name, odp->link_name) || (odp->flags & FLAG_FORWARD))
903                 output( "=%s", odp->link_name );
904             break;
905         case TYPE_STDCALL:
906         {
907             int at_param = get_args_size( odp );
908             if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param );
909             if  (odp->flags & FLAG_FORWARD)
910             {
911                 output( "=%s", odp->link_name );
912             }
913             else if (strcmp(name, odp->link_name)) /* try to reduce output */
914             {
915                 output( "=%s", odp->link_name );
916                 if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param );
917             }
918             break;
919         }
920         default:
921             assert(0);
922         }
923         output( " @%d", odp->ordinal );
924         if (!odp->name || (odp->flags & FLAG_ORDINAL)) output( " NONAME" );
925         if (is_data) output( " DATA" );
926         if (odp->flags & FLAG_PRIVATE) output( " PRIVATE" );
927         output( "\n" );
928     }
929     if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
930     if (spec32) free_dll_spec( spec32 );
931 }