Allocate entry points dynamically to allow for a larger number of
[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
11 #include <assert.h>
12 #include <ctype.h>
13 #include <unistd.h>
14
15 #include "config.h"
16 #include "winbase.h"
17 #include "wine/exception.h"
18 #include "build.h"
19
20
21 static int string_compare( const void *ptr1, const void *ptr2 )
22 {
23     const char * const *str1 = ptr1;
24     const char * const *str2 = ptr2;
25     return strcmp( *str1, *str2 );
26 }
27
28
29 /*******************************************************************
30  *         make_internal_name
31  *
32  * Generate an internal name for an entry point. Used for stubs etc.
33  */
34 static const char *make_internal_name( const ORDDEF *odp, const char *prefix )
35 {
36     static char buffer[256];
37     if (odp->name[0]) sprintf( buffer, "__wine_%s_%s_%s", prefix, DLLName, odp->name );
38     else sprintf( buffer, "__wine_%s_%s_%d", prefix, DLLName, odp->ordinal );
39     return buffer;
40 }
41
42 /*******************************************************************
43  *         AssignOrdinals
44  *
45  * Assign ordinals to all entry points.
46  */
47 static void AssignOrdinals(void)
48 {
49     int i, ordinal;
50
51     if ( !nb_names ) return;
52
53     /* start assigning from Base, or from 1 if no ordinal defined yet */
54     if (Base == MAX_ORDINALS) Base = 1;
55     for (i = 0, ordinal = Base; i < nb_names; i++)
56     {
57         if (Names[i]->ordinal != -1) continue;  /* already has an ordinal */
58         while (Ordinals[ordinal]) ordinal++;
59         if (ordinal >= MAX_ORDINALS)
60         {
61             current_line = Names[i]->lineno;
62             fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
63         }
64         Names[i]->ordinal = ordinal;
65         Ordinals[ordinal] = Names[i];
66     }
67     if (ordinal > Limit) Limit = ordinal;
68 }
69
70
71 /*******************************************************************
72  *         output_debug
73  *
74  * Output the debug channels.
75  */
76 static int output_debug( FILE *outfile )
77 {
78     int i;
79
80     if (!nb_debug_channels) return 0;
81     qsort( debug_channels, nb_debug_channels, sizeof(debug_channels[0]), string_compare );
82
83     for (i = 0; i < nb_debug_channels; i++)
84         fprintf( outfile, "char __wine_dbch_%s[] = \"\\003%s\";\n",
85                  debug_channels[i], debug_channels[i] );
86
87     fprintf( outfile, "\nstatic char * const debug_channels[%d] =\n{\n", nb_debug_channels );
88     for (i = 0; i < nb_debug_channels; i++)
89     {
90         fprintf( outfile, "    __wine_dbch_%s", debug_channels[i] );
91         if (i < nb_debug_channels - 1) fprintf( outfile, ",\n" );
92     }
93     fprintf( outfile, "\n};\n\n" );
94     fprintf( outfile, "static void *debug_registration;\n\n" );
95
96     return nb_debug_channels;
97 }
98
99
100 /*******************************************************************
101  *         output_exports
102  *
103  * Output the export table for a Win32 module.
104  */
105 static int output_exports( FILE *outfile, int nr_exports )
106 {
107     int i, fwd_size = 0, total_size = 0;
108     char *p;
109
110     if (!nr_exports) return 0;
111
112     fprintf( outfile, "asm(\".data\\n\"\n" );
113     fprintf( outfile, "    \"\\t.align 4\\n\"\n" );
114     fprintf( outfile, "    \"" PREFIX "__wine_spec_exports:\\n\"\n" );
115
116     /* export directory header */
117
118     fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* Characteristics */
119     fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* TimeDateStamp */
120     fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* MajorVersion/MinorVersion */
121     fprintf( outfile, "    \"\\t.long " PREFIX "dllname\\n\"\n" ); /* Name */
122     fprintf( outfile, "    \"\\t.long %d\\n\"\n", Base );          /* Base */
123     fprintf( outfile, "    \"\\t.long %d\\n\"\n", nr_exports );    /* NumberOfFunctions */
124     fprintf( outfile, "    \"\\t.long %d\\n\"\n", nb_names );      /* NumberOfNames */
125     fprintf( outfile, "    \"\\t.long __wine_spec_exports_funcs\\n\"\n" ); /* AddressOfFunctions */
126     if (nb_names)
127     {
128         fprintf( outfile, "    \"\\t.long __wine_spec_exp_name_ptrs\\n\"\n" );     /* AddressOfNames */
129         fprintf( outfile, "    \"\\t.long __wine_spec_exp_ordinals\\n\"\n" );  /* AddressOfNameOrdinals */
130     }
131     else
132     {
133         fprintf( outfile, "    \"\\t.long 0\\n\"\n" );  /* AddressOfNames */
134         fprintf( outfile, "    \"\\t.long 0\\n\"\n" );  /* AddressOfNameOrdinals */
135     }
136     total_size += 10 * sizeof(int);
137
138     /* output the function pointers */
139
140     fprintf( outfile, "    \"__wine_spec_exports_funcs:\\n\"\n" );
141     for (i = Base; i <= Limit; i++)
142     {
143         ORDDEF *odp = Ordinals[i];
144         if (!odp) fprintf( outfile, "    \"\\t.long 0\\n\"\n" );
145         else switch(odp->type)
146         {
147         case TYPE_EXTERN:
148             fprintf( outfile, "    \"\\t.long " PREFIX "%s\\n\"\n", odp->link_name );
149             break;
150         case TYPE_STDCALL:
151         case TYPE_VARARGS:
152         case TYPE_CDECL:
153             fprintf( outfile, "    \"\\t.long " PREFIX "%s\\n\"\n", odp->link_name);
154             break;
155         case TYPE_STUB:
156             fprintf( outfile, "    \"\\t.long " PREFIX "%s\\n\"\n", make_internal_name( odp, "stub" ) );
157             break;
158         case TYPE_REGISTER:
159             fprintf( outfile, "    \"\\t.long " PREFIX "%s\\n\"\n", make_internal_name( odp, "regs" ) );
160             break;
161         case TYPE_VARIABLE:
162             fprintf( outfile, "    \"\\t.long " PREFIX "%s\\n\"\n", make_internal_name( odp, "var" ) );
163             break;
164         case TYPE_FORWARD:
165             fprintf( outfile, "    \"\\t.long __wine_spec_forwards+%d\\n\"\n", fwd_size );
166             fwd_size += strlen(odp->link_name) + 1;
167             break;
168         default:
169             assert(0);
170         }
171     }
172     total_size += (Limit - Base + 1) * sizeof(int);
173
174     if (nb_names)
175     {
176         /* output the function name pointers */
177
178         int namepos = 0;
179
180         fprintf( outfile, "    \"__wine_spec_exp_name_ptrs:\\n\"\n" );
181         for (i = 0; i < nb_names; i++)
182         {
183             fprintf( outfile, "    \"\\t.long __wine_spec_exp_names+%d\\n\"\n", namepos );
184             namepos += strlen(Names[i]->name) + 1;
185         }
186         total_size += nb_names * sizeof(int);
187
188         /* output the function names */
189
190         fprintf( outfile, "    \"\\t.text\\n\"\n" );
191         fprintf( outfile, "    \"__wine_spec_exp_names:\\n\"\n" );
192         for (i = 0; i < nb_names; i++)
193             fprintf( outfile, "    \"\\t" STRING " \\\"%s\\\"\\n\"\n", Names[i]->name );
194         fprintf( outfile, "    \"\\t.data\\n\"\n" );
195
196         /* output the function ordinals */
197
198         fprintf( outfile, "    \"__wine_spec_exp_ordinals:\\n\"\n" );
199         for (i = 0; i < nb_names; i++)
200         {
201             fprintf( outfile, "    \"\\t.short %d\\n\"\n", Names[i]->ordinal - Base );
202         }
203         total_size += nb_names * sizeof(short);
204         if (nb_names % 2)
205         {
206             fprintf( outfile, "    \"\\t.short 0\\n\"\n" );
207             total_size += sizeof(short);
208         }
209     }
210
211     /* output forward strings */
212
213     if (fwd_size)
214     {
215         fprintf( outfile, "    \"__wine_spec_forwards:\\n\"\n" );
216         for (i = Base; i <= Limit; i++)
217         {
218             ORDDEF *odp = Ordinals[i];
219             if (odp && odp->type == TYPE_FORWARD)
220                 fprintf( outfile, "    \"\\t" STRING " \\\"%s\\\"\\n\"\n", odp->link_name );
221         }
222         fprintf( outfile, "    \"\\t.align 4\\n\"\n" );
223         total_size += (fwd_size + 3) & ~3;
224     }
225
226     /* output relays */
227
228     if (debugging)
229     {
230         for (i = Base; i <= Limit; i++)
231         {
232             ORDDEF *odp = Ordinals[i];
233             unsigned int j, mask = 0;
234
235             /* skip non-existent entry points */
236             if (!odp) goto ignore;
237             /* skip non-functions */
238             if ((odp->type != TYPE_STDCALL) &&
239                 (odp->type != TYPE_CDECL) &&
240                 (odp->type != TYPE_REGISTER)) goto ignore;
241             /* skip norelay entry points */
242             if (odp->flags & FLAG_NORELAY) goto ignore;
243
244             for (j = 0; odp->u.func.arg_types[j]; j++)
245             {
246                 if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
247                 if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
248             }
249             if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000;
250
251             switch(odp->type)
252             {
253             case TYPE_STDCALL:
254                 fprintf( outfile, "    \"\\tjmp " PREFIX "%s\\n\"\n", odp->link_name );
255                 fprintf( outfile, "    \"\\tret $%d\\n\"\n",
256                          strlen(odp->u.func.arg_types) * sizeof(int) );
257                 fprintf( outfile, "    \"\\t.long " PREFIX "%s,0x%08x\\n\"\n",
258                          odp->link_name, mask );
259                 break;
260             case TYPE_CDECL:
261                 fprintf( outfile, "    \"\\tjmp " PREFIX "%s\\n\"\n", odp->link_name );
262                 fprintf( outfile, "    \"\\tret\\n\"\n" );
263                 fprintf( outfile, "    \"\\t.short %d\\n\"\n",
264                          strlen(odp->u.func.arg_types) * sizeof(int) );
265                 fprintf( outfile, "    \"\\t.long " PREFIX "%s,0x%08x\\n\"\n",
266                          odp->link_name, mask );
267                 break;
268             case TYPE_REGISTER:
269                 fprintf( outfile, "    \"\\tjmp " PREFIX "%s\\n\"\n",
270                          make_internal_name( odp, "regs" ) );
271                 fprintf( outfile, "    \"\\tret\\n\"\n" );
272                 fprintf( outfile, "    \"\\t.short 0x%04x\\n\"\n",
273                          0x8000 | strlen(odp->u.func.arg_types) * sizeof(int) );
274                 fprintf( outfile, "    \"\\t.long " PREFIX "%s,0x%08x\\n\"\n",
275                          make_internal_name( odp, "regs" ), mask );
276                 break;
277             default:
278                 assert(0);
279             }
280             continue;
281
282         ignore:
283             fprintf( outfile, "    \"\\t.long 0,0,0,0\\n\"\n" );
284         }
285     }
286
287
288     /* output __wine_dllexport symbols */
289
290     for (i = 0; i < nb_names; i++)
291     {
292         if (Names[i]->flags & FLAG_NOIMPORT) continue;
293         /* check for invalid characters in the name */
294         for (p = Names[i]->name; *p; p++)
295             if (!isalnum(*p) && *p != '_' && *p != '.') goto next;
296         fprintf( outfile, "    \"\\t.globl " PREFIX "__wine_dllexport_%s_%s\\n\"\n",
297                  DLLName, Names[i]->name );
298         fprintf( outfile, "    \"" PREFIX "__wine_dllexport_%s_%s:\\n\"\n",
299                  DLLName, Names[i]->name );
300     next:
301     }
302     fprintf( outfile, "    \"\\t.long 0xffffffff\\n\"\n" );
303
304     /* output variables */
305
306     for (i = 0; i < nb_entry_points; i++)
307     {
308         ORDDEF *odp = EntryPoints[i];
309         if (odp->type == TYPE_VARIABLE)
310         {
311             int j;
312             fprintf( outfile, "    \"%s:\\n\"\n", make_internal_name( odp, "var" ) );
313             fprintf( outfile, "    \"\\t.long " );
314             for (j = 0; j < odp->u.var.n_values; j++)
315             {
316                 fprintf( outfile, "0x%08x", odp->u.var.values[j] );
317                 if (j < odp->u.var.n_values-1) fputc( ',', outfile );
318             }
319             fprintf( outfile, "\\n\"\n" );
320         }
321     }
322
323     fprintf( outfile, ");\n\n" );
324
325     return total_size;
326 }
327
328
329 /*******************************************************************
330  *         output_stub_funcs
331  *
332  * Output the functions for stub entry points
333 */
334 static void output_stub_funcs( FILE *outfile )
335 {
336     int i;
337
338     for (i = 0; i < nb_entry_points; i++)
339     {
340         ORDDEF *odp = EntryPoints[i];
341         if (odp->type != TYPE_STUB) continue;
342         fprintf( outfile, "#ifdef __GNUC__\n" );
343         fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
344         fprintf( outfile, "#endif\n\n" );
345         fprintf( outfile, "struct exc_record {\n" );
346         fprintf( outfile, "  unsigned int code, flags;\n" );
347         fprintf( outfile, "  void *rec, *addr;\n" );
348         fprintf( outfile, "  unsigned int params;\n" );
349         fprintf( outfile, "  const void *info[15];\n" );
350         fprintf( outfile, "};\n\n" );
351         fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" );
352         fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
353         fprintf( outfile, "  struct exc_record rec;\n" );
354         fprintf( outfile, "  rec.code    = 0x%08x;\n", EXCEPTION_WINE_STUB );
355         fprintf( outfile, "  rec.flags   = %d;\n", EH_NONCONTINUABLE );
356         fprintf( outfile, "  rec.rec     = 0;\n" );
357         fprintf( outfile, "  rec.params  = 2;\n" );
358         fprintf( outfile, "  rec.info[0] = dllname;\n" );
359         fprintf( outfile, "  rec.info[1] = func;\n" );
360         fprintf( outfile, "#ifdef __GNUC__\n" );
361         fprintf( outfile, "  rec.addr = __builtin_return_address(1);\n" );
362         fprintf( outfile, "#else\n" );
363         fprintf( outfile, "  rec.addr = 0;\n" );
364         fprintf( outfile, "#endif\n" );
365         fprintf( outfile, "  for (;;) RtlRaiseException( &rec );\n}\n\n" );
366         break;
367     }
368
369     for (i = 0; i < nb_entry_points; i++)
370     {
371         ORDDEF *odp = EntryPoints[i];
372         if (odp->type != TYPE_STUB) continue;
373         fprintf( outfile, "void %s(void) ", make_internal_name( odp, "stub" ) );
374         if (odp->name[0])
375             fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->name );
376         else
377             fprintf( outfile, "{ __wine_unimplemented(\"%d\"); }\n", odp->ordinal );
378     }
379 }
380
381
382 /*******************************************************************
383  *         output_register_funcs
384  *
385  * Output the functions for register entry points
386  */
387 static void output_register_funcs( FILE *outfile )
388 {
389     const char *name;
390     int i;
391
392     for (i = 0; i < nb_entry_points; i++)
393     {
394         ORDDEF *odp = EntryPoints[i];
395         if (odp->type != TYPE_REGISTER) continue;
396         name = make_internal_name( odp, "regs" );
397         fprintf( outfile,
398                  "asm(\".align 4\\n\\t\"\n"
399                  "    \"" __ASM_FUNC("%s") "\\n\\t\"\n"
400                  "    \"" PREFIX "%s:\\n\\t\"\n"
401                  "    \"call " PREFIX "CALL32_Regs\\n\\t\"\n"
402                  "    \".long " PREFIX "%s\\n\\t\"\n"
403                  "    \".byte %d,%d\");\n",
404                  name, name, odp->link_name,
405                  4 * strlen(odp->u.func.arg_types), 4 * strlen(odp->u.func.arg_types) );
406     }
407 }
408
409
410 /*******************************************************************
411  *         BuildSpec32File
412  *
413  * Build a Win32 C file from a spec file.
414  */
415 void BuildSpec32File( FILE *outfile )
416 {
417     int exports_size = 0;
418     int nr_exports, nr_imports, nr_resources, nr_debug;
419     int characteristics, subsystem;
420     DWORD page_size;
421
422 #ifdef HAVE_GETPAGESIZE
423     page_size = getpagesize();
424 #else
425 # ifdef __svr4__
426     page_size = sysconf(_SC_PAGESIZE);
427 # else
428 #   error Cannot get the page size on this platform
429 # endif
430 #endif
431
432     AssignOrdinals();
433     nr_exports = Base <= Limit ? Limit - Base + 1 : 0;
434
435     resolve_imports( outfile );
436
437     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
438              input_file_name );
439
440     /* Reserve some space for the PE header */
441
442     fprintf( outfile, "extern char pe_header[];\n" );
443     fprintf( outfile, "asm(\".section .text\\n\\t\"\n" );
444     fprintf( outfile, "    \".align %ld\\n\"\n", page_size );
445     fprintf( outfile, "    \"pe_header:\\t.fill %ld,1,0\\n\\t\");\n", page_size );
446
447     fprintf( outfile, "static const char dllname[] = \"%s\";\n\n", DLLName );
448     fprintf( outfile, "extern int __wine_spec_exports[];\n\n" );
449
450 #ifdef __i386__
451     fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
452 #else
453     fprintf( outfile, "#define __stdcall\n\n" );
454 #endif
455
456     if (nr_exports)
457     {
458         /* Output the stub functions */
459
460         output_stub_funcs( outfile );
461
462         fprintf( outfile, "#ifndef __GNUC__\n" );
463         fprintf( outfile, "static void __asm__dummy(void) {\n" );
464         fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
465
466         /* Output code for all register functions */
467
468         output_register_funcs( outfile );
469
470         /* Output the exports and relay entry points */
471
472         exports_size = output_exports( outfile, nr_exports );
473
474         fprintf( outfile, "#ifndef __GNUC__\n" );
475         fprintf( outfile, "}\n" );
476         fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
477     }
478
479     /* Output the DLL imports */
480
481     nr_imports = output_imports( outfile );
482
483     /* Output the resources */
484
485     nr_resources = output_resources( outfile );
486
487     /* Output the debug channels */
488
489     nr_debug = output_debug( outfile );
490
491     /* Output LibMain function */
492
493     characteristics = subsystem = 0;
494     switch(SpecMode)
495     {
496     case SPEC_MODE_DLL:
497         if (init_func) fprintf( outfile, "extern void %s();\n", init_func );
498         characteristics = IMAGE_FILE_DLL;
499         break;
500     case SPEC_MODE_GUIEXE:
501         if (!init_func) init_func = "WinMain";
502         fprintf( outfile,
503                  "\n#include <winbase.h>\n"
504                  "int _ARGC;\n"
505                  "char **_ARGV;\n"
506                  "extern int __stdcall %s(HINSTANCE,HINSTANCE,LPSTR,INT);\n"
507                  "static void __wine_exe_main(void)\n"
508                  "{\n"
509                  "    extern int __wine_get_main_args( char ***argv );\n"
510                  "    STARTUPINFOA info;\n"
511                  "    LPSTR cmdline = GetCommandLineA();\n"
512                  "    while (*cmdline && *cmdline != ' ') cmdline++;\n"
513                  "    if (*cmdline) cmdline++;\n"
514                  "    GetStartupInfoA( &info );\n"
515                  "    if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = 1;\n"
516                  "    _ARGC = __wine_get_main_args( &_ARGV );\n"
517                  "    ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
518                  "}\n\n", init_func, init_func );
519         init_func = "__wine_exe_main";
520         subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
521         break;
522     case SPEC_MODE_GUIEXE_UNICODE:
523         if (!init_func) init_func = "WinMain";
524         fprintf( outfile,
525                  "\n#include <winbase.h>\n"
526                  "int _ARGC;\n"
527                  "WCHAR **_ARGV;\n"
528                  "extern int __stdcall %s(HINSTANCE,HINSTANCE,LPSTR,INT);\n"
529                  "static void __wine_exe_main(void)\n"
530                  "{\n"
531                  "    extern int __wine_get_wmain_args( WCHAR ***argv );\n"
532                  "    STARTUPINFOA info;\n"
533                  "    LPSTR cmdline = GetCommandLineA();\n"
534                  "    while (*cmdline && *cmdline != ' ') cmdline++;\n"
535                  "    if (*cmdline) cmdline++;\n"
536                  "    GetStartupInfoA( &info );\n"
537                  "    if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = 1;\n"
538                  "    _ARGC = __wine_get_wmain_args( &_ARGV );\n"
539                  "    ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
540                  "}\n\n", init_func, init_func );
541         init_func = "__wine_exe_main";
542         subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
543         break;
544     case SPEC_MODE_CUIEXE:
545         if (!init_func) init_func = "main";
546         fprintf( outfile,
547                  "\nint _ARGC;\n"
548                  "char **_ARGV;\n"
549                  "extern void __stdcall ExitProcess(int);\n"
550                  "static void __wine_exe_main(void)\n"
551                  "{\n"
552                  "    extern int %s( int argc, char *argv[] );\n"
553                  "    extern int __wine_get_main_args( char ***argv );\n"
554                  "    _ARGC = __wine_get_main_args( &_ARGV );\n"
555                  "    ExitProcess( %s( _ARGC, _ARGV ) );\n"
556                  "}\n\n", init_func, init_func );
557         init_func = "__wine_exe_main";
558         subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
559         break;
560     case SPEC_MODE_CUIEXE_UNICODE:
561         if (!init_func) init_func = "wmain";
562         fprintf( outfile,
563                  "\ntypedef unsigned short WCHAR;\n"
564                  "int _ARGC;\n"
565                  "WCHAR **_ARGV;\n"
566                  "extern void __stdcall ExitProcess(int);\n"
567                  "static void __wine_exe_main(void)\n"
568                  "{\n"
569                  "    extern int %s( int argc, WCHAR *argv[] );\n"
570                  "    extern int __wine_get_wmain_args( WCHAR ***argv );\n"
571                  "    _ARGC = __wine_get_wmain_args( &_ARGV );\n"
572                  "    ExitProcess( %s( _ARGC, _ARGV ) );\n"
573                  "}\n\n", init_func, init_func );
574         init_func = "__wine_exe_main";
575         subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
576         break;
577     }
578
579     /* Output the NT header */
580
581     /* this is the IMAGE_NT_HEADERS structure, but we cannot include winnt.h here */
582     fprintf( outfile, "static const struct image_nt_headers\n{\n" );
583     fprintf( outfile, "  int Signature;\n" );
584     fprintf( outfile, "  struct file_header {\n" );
585     fprintf( outfile, "    short Machine;\n" );
586     fprintf( outfile, "    short NumberOfSections;\n" );
587     fprintf( outfile, "    int   TimeDateStamp;\n" );
588     fprintf( outfile, "    void *PointerToSymbolTable;\n" );
589     fprintf( outfile, "    int   NumberOfSymbols;\n" );
590     fprintf( outfile, "    short SizeOfOptionalHeader;\n" );
591     fprintf( outfile, "    short Characteristics;\n" );
592     fprintf( outfile, "  } FileHeader;\n" );
593     fprintf( outfile, "  struct opt_header {\n" );
594     fprintf( outfile, "    short Magic;\n" );
595     fprintf( outfile, "    char  MajorLinkerVersion, MinorLinkerVersion;\n" );
596     fprintf( outfile, "    int   SizeOfCode;\n" );
597     fprintf( outfile, "    int   SizeOfInitializedData;\n" );
598     fprintf( outfile, "    int   SizeOfUninitializedData;\n" );
599     fprintf( outfile, "    void *AddressOfEntryPoint;\n" );
600     fprintf( outfile, "    void *BaseOfCode;\n" );
601     fprintf( outfile, "    void *BaseOfData;\n" );
602     fprintf( outfile, "    void *ImageBase;\n" );
603     fprintf( outfile, "    int   SectionAlignment;\n" );
604     fprintf( outfile, "    int   FileAlignment;\n" );
605     fprintf( outfile, "    short MajorOperatingSystemVersion;\n" );
606     fprintf( outfile, "    short MinorOperatingSystemVersion;\n" );
607     fprintf( outfile, "    short MajorImageVersion;\n" );
608     fprintf( outfile, "    short MinorImageVersion;\n" );
609     fprintf( outfile, "    short MajorSubsystemVersion;\n" );
610     fprintf( outfile, "    short MinorSubsystemVersion;\n" );
611     fprintf( outfile, "    int   Win32VersionValue;\n" );
612     fprintf( outfile, "    int   SizeOfImage;\n" );
613     fprintf( outfile, "    int   SizeOfHeaders;\n" );
614     fprintf( outfile, "    int   CheckSum;\n" );
615     fprintf( outfile, "    short Subsystem;\n" );
616     fprintf( outfile, "    short DllCharacteristics;\n" );
617     fprintf( outfile, "    int   SizeOfStackReserve;\n" );
618     fprintf( outfile, "    int   SizeOfStackCommit;\n" );
619     fprintf( outfile, "    int   SizeOfHeapReserve;\n" );
620     fprintf( outfile, "    int   SizeOfHeapCommit;\n" );
621     fprintf( outfile, "    int   LoaderFlags;\n" );
622     fprintf( outfile, "    int   NumberOfRvaAndSizes;\n" );
623     fprintf( outfile, "    struct { const void *VirtualAddress; int Size; } DataDirectory[%d];\n",
624              IMAGE_NUMBEROF_DIRECTORY_ENTRIES );
625     fprintf( outfile, "  } OptionalHeader;\n" );
626     fprintf( outfile, "} nt_header = {\n" );
627     fprintf( outfile, "  0x%04x,\n", IMAGE_NT_SIGNATURE );   /* Signature */
628
629     fprintf( outfile, "  { 0x%04x,\n", IMAGE_FILE_MACHINE_I386 );  /* Machine */
630     fprintf( outfile, "    0, 0, 0, 0,\n" );
631     fprintf( outfile, "    sizeof(nt_header.OptionalHeader),\n" ); /* SizeOfOptionalHeader */
632     fprintf( outfile, "    0x%04x },\n", characteristics );        /* Characteristics */
633
634     fprintf( outfile, "  { 0x%04x,\n", IMAGE_NT_OPTIONAL_HDR_MAGIC );  /* Magic */
635     fprintf( outfile, "    0, 0,\n" );                   /* Major/MinorLinkerVersion */
636     fprintf( outfile, "    0, 0, 0,\n" );                /* SizeOfCode/Data */
637     fprintf( outfile, "    %s,\n", init_func ? init_func : "0" );  /* AddressOfEntryPoint */
638     fprintf( outfile, "    0, 0,\n" );                   /* BaseOfCode/Data */
639     fprintf( outfile, "    pe_header,\n" );              /* ImageBase */
640     fprintf( outfile, "    %ld,\n", page_size );         /* SectionAlignment */
641     fprintf( outfile, "    %ld,\n", page_size );         /* FileAlignment */
642     fprintf( outfile, "    1, 0,\n" );                   /* Major/MinorOperatingSystemVersion */
643     fprintf( outfile, "    0, 0,\n" );                   /* Major/MinorImageVersion */
644     fprintf( outfile, "    4, 0,\n" );                   /* Major/MinorSubsystemVersion */
645     fprintf( outfile, "    0,\n" );                      /* Win32VersionValue */
646     fprintf( outfile, "    %ld,\n", page_size );         /* SizeOfImage */
647     fprintf( outfile, "    %ld,\n", page_size );         /* SizeOfHeaders */
648     fprintf( outfile, "    0,\n" );                      /* CheckSum */
649     fprintf( outfile, "    0x%04x,\n", subsystem );      /* Subsystem */
650     fprintf( outfile, "    0, 0, 0, 0, 0, 0,\n" );
651     fprintf( outfile, "    %d,\n", IMAGE_NUMBEROF_DIRECTORY_ENTRIES );  /* NumberOfRvaAndSizes */
652     fprintf( outfile, "    {\n" );
653     fprintf( outfile, "      { %s, %d },\n",  /* IMAGE_DIRECTORY_ENTRY_EXPORT */
654              exports_size ? "__wine_spec_exports" : "0", exports_size );
655     fprintf( outfile, "      { %s, %s },\n",  /* IMAGE_DIRECTORY_ENTRY_IMPORT */
656              nr_imports ? "&imports" : "0", nr_imports ? "sizeof(imports)" : "0" );
657     fprintf( outfile, "      { %s, %s },\n",   /* IMAGE_DIRECTORY_ENTRY_RESOURCE */
658              nr_resources ? "&resources" : "0", nr_resources ? "sizeof(resources)" : "0" );
659     fprintf( outfile, "    }\n  }\n};\n\n" );
660
661     /* Output the DLL constructor */
662
663     fprintf( outfile, "#ifndef __GNUC__\n" );
664     fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
665     fprintf( outfile, "#endif /* defined(__GNUC__) */\n" );
666     fprintf( outfile, "asm(\"\\t.section\t.init ,\\\"ax\\\"\\n\"\n" );
667     fprintf( outfile, "    \"\\tcall " PREFIX "__wine_spec_%s_init\\n\"\n", DLLName );
668     fprintf( outfile, "    \"\\t.previous\\n\");\n" );
669     if (nr_debug)
670     {
671         fprintf( outfile, "asm(\"\\t.section\t.fini ,\\\"ax\\\"\\n\"\n" );
672         fprintf( outfile, "    \"\\tcall " PREFIX "__wine_spec_%s_fini\\n\"\n", DLLName );
673         fprintf( outfile, "    \"\\t.previous\\n\");\n" );
674     }
675     fprintf( outfile, "#ifndef __GNUC__\n" );
676     fprintf( outfile, "}\n" );
677     fprintf( outfile, "#endif /* defined(__GNUC__) */\n\n" );
678
679     fprintf( outfile,
680              "void __wine_spec_%s_init(void)\n"
681              "{\n"
682              "    extern void __wine_dll_register( const struct image_nt_headers *, const char * );\n"
683              "    extern void *__wine_dbg_register( char * const *, int );\n"
684              "    __wine_dll_register( &nt_header, \"%s\" );\n",
685              DLLName, DLLFileName );
686     if (nr_debug)
687         fprintf( outfile, "    debug_registration = __wine_dbg_register( debug_channels, %d );\n",
688                  nr_debug );
689     fprintf( outfile, "}\n" );
690     if (nr_debug)
691     {
692         fprintf( outfile,
693                  "\nvoid __wine_spec_%s_fini(void)\n"
694                  "{\n"
695                  "    extern void __wine_dbg_unregister( void* );\n"
696                  "    __wine_dbg_unregister( debug_registration );\n"
697                  "}\n", DLLName );
698     }
699 }