Prevent crash when no URL is specified.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "windef.h"
34 #include "winbase.h"
35 #include "wine/exception.h"
36 #include "build.h"
37
38
39 #ifdef __APPLE__
40 # define __ASM_SKIP ".space"
41 #else
42 # define __ASM_SKIP ".skip"
43 #endif
44
45 static int string_compare( const void *ptr1, const void *ptr2 )
46 {
47     const char * const *str1 = ptr1;
48     const char * const *str2 = ptr2;
49     return strcmp( *str1, *str2 );
50 }
51
52
53 /*******************************************************************
54  *         make_internal_name
55  *
56  * Generate an internal name for an entry point. Used for stubs etc.
57  */
58 static const char *make_internal_name( const ORDDEF *odp, DLLSPEC *spec, const char *prefix )
59 {
60     static char buffer[256];
61     if (odp->name || odp->export_name)
62     {
63         char *p;
64         sprintf( buffer, "__wine_%s_%s_%s", prefix, spec->file_name,
65                  odp->name ? odp->name : odp->export_name );
66         /* make sure name is a legal C identifier */
67         for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
68         if (!*p) return buffer;
69     }
70     sprintf( buffer, "__wine_%s_%s_%d", prefix, make_c_identifier(spec->file_name), odp->ordinal );
71     return buffer;
72 }
73
74 /*******************************************************************
75  *         declare_weak_function
76  *
77  * Output a prototype for a weak function.
78  */
79 static void declare_weak_function( FILE *outfile, const char *ret_type, const char *name, const char *params)
80 {
81     fprintf( outfile, "#ifdef __GNUC__\n" );
82     fprintf( outfile, "# ifdef __APPLE__\n" );
83     fprintf( outfile, "extern %s %s(%s) __attribute__((weak_import));\n", ret_type, name, params );
84     fprintf( outfile, "static %s (*__wine_spec_weak_%s)(%s) = %s;\n", ret_type, name, params, name );
85     fprintf( outfile, "#define %s __wine_spec_weak_%s\n", name, name );
86     fprintf( outfile, "# else\n" );
87     fprintf( outfile, "extern %s %s(%s) __attribute__((weak));\n", ret_type, name, params );
88     fprintf( outfile, "# endif\n" );
89     fprintf( outfile, "#else\n" );
90     fprintf( outfile, "extern %s %s(%s);\n", ret_type, name, params );
91     fprintf( outfile, "static void __asm__dummy_%s(void)", name );
92     fprintf( outfile, " { asm(\".weak " __ASM_NAME("%s") "\"); }\n", name );
93     fprintf( outfile, "#endif\n\n" );
94 }
95
96
97 /*******************************************************************
98  *         output_debug
99  *
100  * Output the debug channels.
101  */
102 static int output_debug( FILE *outfile )
103 {
104     int i;
105
106     if (!nb_debug_channels) return 0;
107     qsort( debug_channels, nb_debug_channels, sizeof(debug_channels[0]), string_compare );
108
109     for (i = 0; i < nb_debug_channels; i++)
110         fprintf( outfile, "char __wine_dbch_%s[] = \"\\003%s\";\n",
111                  debug_channels[i], debug_channels[i] );
112
113     fprintf( outfile, "\nstatic char * const debug_channels[%d] =\n{\n", nb_debug_channels );
114     for (i = 0; i < nb_debug_channels; i++)
115     {
116         fprintf( outfile, "    __wine_dbch_%s", debug_channels[i] );
117         if (i < nb_debug_channels - 1) fprintf( outfile, ",\n" );
118     }
119     fprintf( outfile, "\n};\n\n" );
120     fprintf( outfile, "static void *debug_registration;\n\n" );
121
122     return nb_debug_channels;
123 }
124
125
126 /*******************************************************************
127  *         output_exports
128  *
129  * Output the export table for a Win32 module.
130  */
131 static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec )
132 {
133     int i, fwd_size = 0, total_size = 0;
134
135     if (!nr_exports) return 0;
136
137     fprintf( outfile, "asm(\".data\\n\"\n" );
138     fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
139     fprintf( outfile, "    \"" __ASM_NAME("__wine_spec_exports") ":\\n\"\n" );
140
141     /* export directory header */
142
143     fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* Characteristics */
144     fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* TimeDateStamp */
145     fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* MajorVersion/MinorVersion */
146     fprintf( outfile, "    \"\\t.long __wine_spec_exp_names\\n\"\n" ); /* Name */
147     fprintf( outfile, "    \"\\t.long %d\\n\"\n", spec->base );        /* Base */
148     fprintf( outfile, "    \"\\t.long %d\\n\"\n", nr_exports );        /* NumberOfFunctions */
149     fprintf( outfile, "    \"\\t.long %d\\n\"\n", spec->nb_names );    /* NumberOfNames */
150     fprintf( outfile, "    \"\\t.long __wine_spec_exports_funcs\\n\"\n" ); /* AddressOfFunctions */
151     if (spec->nb_names)
152     {
153         fprintf( outfile, "    \"\\t.long __wine_spec_exp_name_ptrs\\n\"\n" );     /* AddressOfNames */
154         fprintf( outfile, "    \"\\t.long __wine_spec_exp_ordinals\\n\"\n" );  /* AddressOfNameOrdinals */
155     }
156     else
157     {
158         fprintf( outfile, "    \"\\t.long 0\\n\"\n" );  /* AddressOfNames */
159         fprintf( outfile, "    \"\\t.long 0\\n\"\n" );  /* AddressOfNameOrdinals */
160     }
161     total_size += 10 * sizeof(int);
162
163     /* output the function pointers */
164
165     fprintf( outfile, "    \"__wine_spec_exports_funcs:\\n\"\n" );
166     for (i = spec->base; i <= spec->limit; i++)
167     {
168         ORDDEF *odp = spec->ordinals[i];
169         if (!odp) fprintf( outfile, "    \"\\t.long 0\\n\"\n" );
170         else switch(odp->type)
171         {
172         case TYPE_EXTERN:
173         case TYPE_STDCALL:
174         case TYPE_VARARGS:
175         case TYPE_CDECL:
176             if (!(odp->flags & FLAG_FORWARD))
177             {
178                 fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") "\\n\"\n",
179                          (odp->flags & FLAG_REGISTER) ? make_internal_name( odp, spec, "regs" )
180                          : odp->link_name );
181             }
182             else
183             {
184                 fprintf( outfile, "    \"\\t.long __wine_spec_forwards+%d\\n\"\n", fwd_size );
185                 fwd_size += strlen(odp->link_name) + 1;
186             }
187             break;
188         case TYPE_STUB:
189             fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") "\\n\"\n",
190                      make_internal_name( odp, spec, "stub" ) );
191             break;
192         default:
193             assert(0);
194         }
195     }
196     total_size += (spec->limit - spec->base + 1) * sizeof(int);
197
198     if (spec->nb_names)
199     {
200         /* output the function name pointers */
201
202         int namepos = strlen(spec->file_name) + 1;
203
204         fprintf( outfile, "    \"__wine_spec_exp_name_ptrs:\\n\"\n" );
205         for (i = 0; i < spec->nb_names; i++)
206         {
207             fprintf( outfile, "    \"\\t.long __wine_spec_exp_names+%d\\n\"\n", namepos );
208             namepos += strlen(spec->names[i]->name) + 1;
209         }
210         total_size += spec->nb_names * sizeof(int);
211     }
212
213     /* output the function names */
214
215     fprintf( outfile, "    \"\\t.text\\n\"\n" );
216     fprintf( outfile, "    \"__wine_spec_exp_names:\\n\"\n" );
217     fprintf( outfile, "    \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", spec->file_name );
218     for (i = 0; i < spec->nb_names; i++)
219         fprintf( outfile, "    \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", spec->names[i]->name );
220     fprintf( outfile, "    \"\\t.data\\n\"\n" );
221
222     if (spec->nb_names)
223     {
224         /* output the function ordinals */
225
226         fprintf( outfile, "    \"__wine_spec_exp_ordinals:\\n\"\n" );
227         for (i = 0; i < spec->nb_names; i++)
228         {
229             fprintf( outfile, "    \"\\t" __ASM_SHORT " %d\\n\"\n",
230                      spec->names[i]->ordinal - spec->base );
231         }
232         total_size += spec->nb_names * sizeof(short);
233         if (spec->nb_names % 2)
234         {
235             fprintf( outfile, "    \"\\t" __ASM_SHORT " 0\\n\"\n" );
236             total_size += sizeof(short);
237         }
238     }
239
240     /* output forward strings */
241
242     if (fwd_size)
243     {
244         fprintf( outfile, "    \"__wine_spec_forwards:\\n\"\n" );
245         for (i = spec->base; i <= spec->limit; i++)
246         {
247             ORDDEF *odp = spec->ordinals[i];
248             if (odp && (odp->flags & FLAG_FORWARD))
249                 fprintf( outfile, "    \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", odp->link_name );
250         }
251         fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
252         total_size += (fwd_size + 3) & ~3;
253     }
254
255     /* output relays */
256
257     if (debugging)
258     {
259         for (i = spec->base; i <= spec->limit; i++)
260         {
261             ORDDEF *odp = spec->ordinals[i];
262             unsigned int j, args, mask = 0;
263             const char *name;
264
265             /* skip nonexistent entry points */
266             if (!odp) goto ignore;
267             /* skip non-functions */
268             if ((odp->type != TYPE_STDCALL) && (odp->type != TYPE_CDECL)) goto ignore;
269             /* skip norelay and forward entry points */
270             if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) goto ignore;
271
272             for (j = 0; odp->u.func.arg_types[j]; j++)
273             {
274                 if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
275                 if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
276             }
277             if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000;
278
279             name = odp->link_name;
280             args = strlen(odp->u.func.arg_types) * sizeof(int);
281             if (odp->flags & FLAG_REGISTER) name = make_internal_name( odp, spec, "regs" );
282
283             switch(odp->type)
284             {
285             case TYPE_STDCALL:
286                 fprintf( outfile, "    \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name );
287                 fprintf( outfile, "    \"\\tret $%d\\n\"\n", args );
288                 fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask );
289                 break;
290             case TYPE_CDECL:
291                 fprintf( outfile, "    \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name );
292                 fprintf( outfile, "    \"\\tret\\n\"\n" );
293                 fprintf( outfile, "    \"\\t" __ASM_SHORT " %d\\n\"\n", args );
294                 fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask );
295                 break;
296             default:
297                 assert(0);
298             }
299             continue;
300
301         ignore:
302             fprintf( outfile, "    \"\\t.long 0,0,0,0\\n\"\n" );
303         }
304     }
305
306     fprintf( outfile, "    \"\\t.text\\n\"\n" );
307     fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
308     fprintf( outfile, ");\n\n" );
309
310     return total_size;
311 }
312
313
314 /*******************************************************************
315  *         output_stub_funcs
316  *
317  * Output the functions for stub entry points
318 */
319 static void output_stub_funcs( FILE *outfile, DLLSPEC *spec )
320 {
321     int i;
322
323     for (i = 0; i < spec->nb_entry_points; i++)
324     {
325         ORDDEF *odp = &spec->entry_points[i];
326         if (odp->type != TYPE_STUB) continue;
327         fprintf( outfile, "#ifdef __GNUC__\n" );
328         fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
329         fprintf( outfile, "#endif\n\n" );
330         fprintf( outfile, "struct exc_record {\n" );
331         fprintf( outfile, "  unsigned int code, flags;\n" );
332         fprintf( outfile, "  void *rec, *addr;\n" );
333         fprintf( outfile, "  unsigned int params;\n" );
334         fprintf( outfile, "  const void *info[15];\n" );
335         fprintf( outfile, "};\n\n" );
336         fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" );
337         fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
338         fprintf( outfile, "  struct exc_record rec;\n" );
339         fprintf( outfile, "  rec.code    = 0x%08x;\n", EXCEPTION_WINE_STUB );
340         fprintf( outfile, "  rec.flags   = %d;\n", EH_NONCONTINUABLE );
341         fprintf( outfile, "  rec.rec     = 0;\n" );
342         fprintf( outfile, "  rec.params  = 2;\n" );
343         fprintf( outfile, "  rec.info[0] = \"%s\";\n", spec->file_name );
344         fprintf( outfile, "  rec.info[1] = func;\n" );
345         fprintf( outfile, "#ifdef __GNUC__\n" );
346         fprintf( outfile, "  rec.addr = __builtin_return_address(1);\n" );
347         fprintf( outfile, "#else\n" );
348         fprintf( outfile, "  rec.addr = 0;\n" );
349         fprintf( outfile, "#endif\n" );
350         fprintf( outfile, "  for (;;) RtlRaiseException( &rec );\n}\n\n" );
351         break;
352     }
353
354     for (i = 0; i < spec->nb_entry_points; i++)
355     {
356         const ORDDEF *odp = &spec->entry_points[i];
357         if (odp->type != TYPE_STUB) continue;
358         fprintf( outfile, "void %s(void) ", make_internal_name( odp, spec, "stub" ) );
359         if (odp->name)
360             fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->name );
361         else if (odp->export_name)
362             fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->export_name );
363         else
364             fprintf( outfile, "{ __wine_unimplemented(\"%d\"); }\n", odp->ordinal );
365     }
366 }
367
368
369 /*******************************************************************
370  *         output_register_funcs
371  *
372  * Output the functions for register entry points
373  */
374 static void output_register_funcs( FILE *outfile, DLLSPEC *spec )
375 {
376     const char *name;
377     int i;
378
379     for (i = 0; i < spec->nb_entry_points; i++)
380     {
381         const ORDDEF *odp = &spec->entry_points[i];
382         if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
383         if (!(odp->flags & FLAG_REGISTER)) continue;
384         if (odp->flags & FLAG_FORWARD) continue;
385         name = make_internal_name( odp, spec, "regs" );
386         fprintf( outfile,
387                  "asm(\".align %d\\n\\t\"\n"
388                  "    \"" __ASM_FUNC("%s") "\\n\\t\"\n"
389                  "    \"" __ASM_NAME("%s") ":\\n\\t\"\n"
390                  "    \"call " __ASM_NAME("__wine_call_from_32_regs") "\\n\\t\"\n"
391                  "    \".long " __ASM_NAME("%s") "\\n\\t\"\n"
392                  "    \".byte %d,%d\");\n",
393                  get_alignment(4),
394                  name, name, odp->link_name,
395                  strlen(odp->u.func.arg_types) * sizeof(int),
396                  (odp->type == TYPE_CDECL) ? 0 : (strlen(odp->u.func.arg_types) * sizeof(int)) );
397     }
398 }
399
400
401 /*******************************************************************
402  *         output_dll_init
403  *
404  * Output code for calling a dll constructor and destructor.
405  */
406 void output_dll_init( FILE *outfile, const char *constructor, const char *destructor )
407 {
408     fprintf( outfile, "#ifndef __GNUC__\n" );
409     fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
410     fprintf( outfile, "#endif\n" );
411
412 #if defined(__i386__)
413     if (constructor)
414     {
415         fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
416         fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", constructor );
417         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
418     }
419     if (destructor)
420     {
421         fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
422         fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", destructor );
423         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
424     }
425 #elif defined(__sparc__)
426     if (constructor)
427     {
428         fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
429         fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", constructor );
430         fprintf( outfile, "    \"\\tnop\\n\"\n" );
431         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
432     }
433     if (destructor)
434     {
435         fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
436         fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", destructor );
437         fprintf( outfile, "    \"\\tnop\\n\"\n" );
438         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
439     }
440 #elif defined(__powerpc__)
441 # ifdef __APPLE__
442 /* Mach-O doesn't have an init section */
443     if (constructor)
444     {
445         fprintf( outfile, "asm(\"\\t.mod_init_func\\n\"\n" );
446         fprintf( outfile, "    \"\\t.align 2\\n\"\n" );
447         fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") "\\n\"\n", constructor );
448         fprintf( outfile, "    \"\\t.text\\n\");\n" );
449     }
450     if (destructor)
451     {
452         fprintf( outfile, "asm(\"\\t.mod_term_func\\n\"\n" );
453         fprintf( outfile, "    \"\\t.align 2\\n\"\n" );
454         fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") "\\n\"\n", destructor );
455         fprintf( outfile, "    \"\\t.text\\n\");\n" );
456     }
457 # else /* __APPLE__ */
458     if (constructor)
459     {
460         fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
461         fprintf( outfile, "    \"\\tbl " __ASM_NAME("%s") "\\n\"\n", constructor );
462         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
463     }
464     if (destructor)
465     {
466         fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
467         fprintf( outfile, "    \"\\tbl " __ASM_NAME("%s") "\\n\"\n", destructor );
468         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
469     }
470 # endif /* __APPLE__ */
471 #elif defined(__ALPHA__)
472     if (constructor)
473     {
474         fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
475         fprintf( outfile, "    \"\\tjsr $26," __ASM_NAME("%s") "\\n\"\n", constructor );
476         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
477     }
478     if (destructor)
479     {
480         fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
481         fprintf( outfile, "    \"\\tjsr $26," __ASM_NAME("%s") "\\n\"\n", destructor );
482         fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
483     }
484 #else
485 #error You need to define the DLL constructor for your architecture
486 #endif
487     fprintf( outfile, "#ifndef __GNUC__\n" );
488     fprintf( outfile, "}\n" );
489     fprintf( outfile, "#endif\n" );
490 }
491
492
493 /*******************************************************************
494  *         BuildSpec32File
495  *
496  * Build a Win32 C file from a spec file.
497  */
498 void BuildSpec32File( FILE *outfile, DLLSPEC *spec )
499 {
500     int exports_size = 0;
501     int nr_exports, nr_imports;
502     DWORD page_size;
503     const char *init_func = spec->init_func;
504
505 #ifdef HAVE_GETPAGESIZE
506     page_size = getpagesize();
507 #elif defined(__svr4__)
508     page_size = sysconf(_SC_PAGESIZE);
509 #elif defined(_WINDOWS)
510     {
511         SYSTEM_INFO si;
512         GetSystemInfo(&si);
513         page_size = si.dwPageSize;
514     }
515 #else
516 #   error Cannot get the page size on this platform
517 #endif
518
519     nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
520     resolve_imports( spec );
521     output_standard_file_header( outfile );
522
523     /* Reserve some space for the PE header */
524
525     fprintf( outfile, "extern char __wine_spec_pe_header[];\n" );
526     fprintf( outfile, "#ifndef __GNUC__\n" );
527     fprintf( outfile, "static void __asm__dummy_header(void) {\n" );
528     fprintf( outfile, "#endif\n" );
529     fprintf( outfile, "asm(\".text\\n\\t\"\n" );
530     fprintf( outfile, "    \".align %d\\n\"\n", get_alignment(page_size) );
531     fprintf( outfile, "    \"" __ASM_NAME("__wine_spec_pe_header") ":\\t" __ASM_SKIP " 65536\\n\\t\"\n" );
532     fprintf( outfile, "    \".data\\n\\t\"\n" );
533     fprintf( outfile, "    \".align %d\\n\"\n", get_alignment(4) );
534     fprintf( outfile, "    \"" __ASM_NAME("__wine_spec_data_start") ":\\t.long 1\");\n" );
535     fprintf( outfile, "#ifndef __GNUC__\n" );
536     fprintf( outfile, "}\n" );
537     fprintf( outfile, "#endif\n" );
538
539 #ifdef __APPLE__
540     fprintf( outfile, "static char _end[4];\n" );
541 #else
542     fprintf( outfile, "extern char _end[];\n" );
543 #endif
544     
545     fprintf( outfile, "extern int __wine_spec_data_start[], __wine_spec_exports[];\n\n" );
546
547 #ifdef __i386__
548     fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
549 #else
550     fprintf( outfile, "#define __stdcall\n\n" );
551 #endif
552
553     if (nr_exports)
554     {
555         /* Output the stub functions */
556
557         output_stub_funcs( outfile, spec );
558
559         fprintf( outfile, "#ifndef __GNUC__\n" );
560         fprintf( outfile, "static void __asm__dummy(void) {\n" );
561         fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
562
563         /* Output code for all register functions */
564
565         output_register_funcs( outfile, spec );
566
567         /* Output the exports and relay entry points */
568
569         exports_size = output_exports( outfile, nr_exports, spec );
570
571         fprintf( outfile, "#ifndef __GNUC__\n" );
572         fprintf( outfile, "}\n" );
573         fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
574     }
575
576     /* Output the DLL imports */
577
578     nr_imports = output_imports( outfile, spec );
579
580     /* Output the resources */
581
582     output_resources( outfile, spec );
583
584     /* Output the entry point function */
585
586     fprintf( outfile, "static int __wine_spec_init_state;\n" );
587     fprintf( outfile, "extern int __wine_main_argc;\n" );
588     fprintf( outfile, "extern char **__wine_main_argv;\n" );
589     fprintf( outfile, "extern char **__wine_main_environ;\n" );
590     fprintf( outfile, "extern unsigned short **__wine_main_wargv;\n" );
591 #ifdef __APPLE__
592     fprintf( outfile, "extern _dyld_func_lookup(char *, void *);" );
593     fprintf( outfile, "static void __wine_spec_hidden_init(int argc, char** argv, char** envp)\n" );
594     fprintf( outfile, "{\n" );
595     fprintf( outfile, "    void (*init)(void);\n" );
596     fprintf( outfile, "    _dyld_func_lookup(\"__dyld_make_delayed_module_initializer_calls\", (unsigned long *)&init);\n" );
597     fprintf( outfile, "    init();\n" );
598     fprintf( outfile, "}\n" );
599     fprintf( outfile, "static void __wine_spec_hidden_fini()\n" );
600     fprintf( outfile, "{\n" );
601     fprintf( outfile, "    void (*fini)(void);\n" );
602     fprintf( outfile, "    _dyld_func_lookup(\"__dyld_mod_term_funcs\", (unsigned long *)&fini);\n" );
603     fprintf( outfile, "    fini();\n" );
604     fprintf( outfile, "}\n" );
605     fprintf( outfile, "#define _init __wine_spec_hidden_init\n" );
606     fprintf( outfile, "#define _fini __wine_spec_hidden_fini\n" );
607 #else
608     fprintf( outfile, "extern void _init(int, char**, char**);\n" );
609     fprintf( outfile, "extern void _fini();\n" );
610 #endif
611
612     if (spec->characteristics & IMAGE_FILE_DLL)
613     {
614         if (init_func)
615             fprintf( outfile, "extern int __stdcall %s( void*, unsigned int, void* );\n\n", init_func );
616         else
617         {
618             declare_weak_function( outfile, "int __stdcall", "DllMain", "void*, unsigned int, void*" );
619             init_func = "DllMain";
620         }
621         fprintf( outfile,
622                  "static int __stdcall __wine_dll_main( void *inst, unsigned int reason, void *reserved )\n"
623                  "{\n"
624                  "    int ret;\n"
625                  "    if (reason == %d && __wine_spec_init_state == 1)\n"
626                  "        _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n"
627                  "    ret = %s ? %s( inst, reason, reserved ) : 1;\n"
628                  "    if (reason == %d && __wine_spec_init_state == 1) _fini();\n"
629                  "    return ret;\n"
630                  "}\n",
631                  DLL_PROCESS_ATTACH, init_func, init_func, DLL_PROCESS_DETACH );
632         init_func = "__wine_dll_main";
633     }
634     else switch(spec->subsystem)
635     {
636     case IMAGE_SUBSYSTEM_NATIVE:
637         if (init_func)
638             fprintf( outfile, "extern int __stdcall %s( void*, void* );\n\n", init_func );
639         else
640         {
641             declare_weak_function( outfile, "int __stdcall", "DriverEntry", "void*, void*");
642             init_func = "DriverEntry";
643         }
644         fprintf( outfile,
645                  "static int __stdcall __wine_driver_entry( void *obj, void *path )\n"
646                  "{\n"
647                  "    int ret;\n"
648                  "    if (__wine_spec_init_state == 1)\n"
649                  "        _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n"
650                  "    ret = %s ? %s( obj, path ) : 0;\n"
651                  "    if (__wine_spec_init_state == 1) _fini();\n"
652                  "    return ret;\n"
653                  "}\n",
654                  init_func, init_func );
655         init_func = "__wine_driver_entry";
656         break;
657     case IMAGE_SUBSYSTEM_WINDOWS_GUI:
658     case IMAGE_SUBSYSTEM_WINDOWS_CUI:
659         if (init_func)
660             fprintf( outfile, "extern int %s( int argc, char *argv[] );\n", init_func );
661         else
662         {
663             declare_weak_function( outfile, "int", "main", "int argc, char *argv[]" );
664             declare_weak_function( outfile, "int", "wmain", "int argc, unsigned short *argv[]" );
665             declare_weak_function( outfile, "int __stdcall", "WinMain", "void *,void *,char *,int" );
666         }
667         fprintf( outfile,
668                  "\ntypedef struct {\n"
669                  "    unsigned int cb;\n"
670                  "    char *lpReserved, *lpDesktop, *lpTitle;\n"
671                  "    unsigned int dwX, dwY, dwXSize, dwYSize;\n"
672                  "    unsigned int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;\n"
673                  "    unsigned short wShowWindow, cbReserved2;\n"
674                  "    char *lpReserved2;\n"
675                  "    void *hStdInput, *hStdOutput, *hStdError;\n"
676                  "} STARTUPINFOA;\n"
677                  "extern char * __stdcall GetCommandLineA(void);\n"
678                  "extern void * __stdcall GetModuleHandleA(char *);\n"
679                  "extern void __stdcall GetStartupInfoA(STARTUPINFOA *);\n"
680                  "extern void __stdcall ExitProcess(unsigned int);\n"
681                  "static void __wine_exe_main(void)\n"
682                  "{\n"
683                  "    int ret;\n"
684                  "    if (__wine_spec_init_state == 1)\n"
685                  "        _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" );
686         if (init_func)
687             fprintf( outfile,
688                      "    ret = %s( __wine_main_argc, __wine_main_argv );\n", init_func );
689         else
690             fprintf( outfile,
691                      "    if (WinMain) {\n"
692                      "        STARTUPINFOA info;\n"
693                      "        char *cmdline = GetCommandLineA();\n"
694                      "        int bcount=0, in_quotes=0;\n"
695                      "        while (*cmdline) {\n"
696                      "            if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n"
697                      "            else if (*cmdline=='\\\\') bcount++;\n"
698                      "            else if (*cmdline=='\\\"') {\n"
699                      "                if ((bcount & 1)==0) in_quotes=!in_quotes;\n"
700                      "                bcount=0;\n"
701                      "            }\n"
702                      "            else bcount=0;\n"
703                      "            cmdline++;\n"
704                      "        }\n"
705                      "        while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n"
706                      "        GetStartupInfoA( &info );\n"
707                      "        if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n"
708                      "        ret = WinMain( GetModuleHandleA(0), 0, cmdline, info.wShowWindow );\n"
709                      "    }\n"
710                      "    else if (wmain) ret = wmain( __wine_main_argc, __wine_main_wargv );\n"
711                      "    else ret = main( __wine_main_argc, __wine_main_argv );\n" );
712         fprintf( outfile,
713                  "    if (__wine_spec_init_state == 1) _fini();\n"
714                  "    ExitProcess( ret );\n"
715                  "}\n\n" );
716         init_func = "__wine_exe_main";
717         break;
718     }
719
720     /* Output the NT header */
721
722     /* this is the IMAGE_NT_HEADERS structure, but we cannot include winnt.h here */
723     fprintf( outfile, "static const struct image_nt_headers\n{\n" );
724     fprintf( outfile, "  int Signature;\n" );
725     fprintf( outfile, "  struct file_header {\n" );
726     fprintf( outfile, "    short Machine;\n" );
727     fprintf( outfile, "    short NumberOfSections;\n" );
728     fprintf( outfile, "    int   TimeDateStamp;\n" );
729     fprintf( outfile, "    void *PointerToSymbolTable;\n" );
730     fprintf( outfile, "    int   NumberOfSymbols;\n" );
731     fprintf( outfile, "    short SizeOfOptionalHeader;\n" );
732     fprintf( outfile, "    short Characteristics;\n" );
733     fprintf( outfile, "  } FileHeader;\n" );
734     fprintf( outfile, "  struct opt_header {\n" );
735     fprintf( outfile, "    short Magic;\n" );
736     fprintf( outfile, "    char  MajorLinkerVersion, MinorLinkerVersion;\n" );
737     fprintf( outfile, "    int   SizeOfCode;\n" );
738     fprintf( outfile, "    int   SizeOfInitializedData;\n" );
739     fprintf( outfile, "    int   SizeOfUninitializedData;\n" );
740     fprintf( outfile, "    void *AddressOfEntryPoint;\n" );
741     fprintf( outfile, "    void *BaseOfCode;\n" );
742     fprintf( outfile, "    void *BaseOfData;\n" );
743     fprintf( outfile, "    void *ImageBase;\n" );
744     fprintf( outfile, "    int   SectionAlignment;\n" );
745     fprintf( outfile, "    int   FileAlignment;\n" );
746     fprintf( outfile, "    short MajorOperatingSystemVersion;\n" );
747     fprintf( outfile, "    short MinorOperatingSystemVersion;\n" );
748     fprintf( outfile, "    short MajorImageVersion;\n" );
749     fprintf( outfile, "    short MinorImageVersion;\n" );
750     fprintf( outfile, "    short MajorSubsystemVersion;\n" );
751     fprintf( outfile, "    short MinorSubsystemVersion;\n" );
752     fprintf( outfile, "    int   Win32VersionValue;\n" );
753     fprintf( outfile, "    void *SizeOfImage;\n" );
754     fprintf( outfile, "    int   SizeOfHeaders;\n" );
755     fprintf( outfile, "    int   CheckSum;\n" );
756     fprintf( outfile, "    short Subsystem;\n" );
757     fprintf( outfile, "    short DllCharacteristics;\n" );
758     fprintf( outfile, "    int   SizeOfStackReserve;\n" );
759     fprintf( outfile, "    int   SizeOfStackCommit;\n" );
760     fprintf( outfile, "    int   SizeOfHeapReserve;\n" );
761     fprintf( outfile, "    int   SizeOfHeapCommit;\n" );
762     fprintf( outfile, "    int   LoaderFlags;\n" );
763     fprintf( outfile, "    int   NumberOfRvaAndSizes;\n" );
764     fprintf( outfile, "    struct { const void *VirtualAddress; int Size; } DataDirectory[%d];\n",
765              IMAGE_NUMBEROF_DIRECTORY_ENTRIES );
766     fprintf( outfile, "  } OptionalHeader;\n" );
767     fprintf( outfile, "} nt_header = {\n" );
768     fprintf( outfile, "  0x%04x,\n", IMAGE_NT_SIGNATURE );   /* Signature */
769 #ifdef __i386__
770     fprintf( outfile, "  { 0x%04x,\n", IMAGE_FILE_MACHINE_I386 );  /* Machine */
771 #elif defined(__powerpc__)
772     fprintf( outfile, "  { 0x%04x,\n", IMAGE_FILE_MACHINE_POWERPC ); /* Machine */
773 #elif defined(__ALPHA__)
774     fprintf( outfile, "  { 0x%04x,\n", IMAGE_FILE_MACHINE_ALPHA ); /* Machine */
775 #else
776     fprintf( outfile, "  { 0x%04x,\n", IMAGE_FILE_MACHINE_UNKNOWN );  /* Machine */
777 #endif
778     fprintf( outfile, "    0, 0, 0, 0,\n" );
779     fprintf( outfile, "    sizeof(nt_header.OptionalHeader),\n" ); /* SizeOfOptionalHeader */
780     fprintf( outfile, "    0x%04x },\n", spec->characteristics );  /* Characteristics */
781
782     fprintf( outfile, "  { 0x%04x,\n", IMAGE_NT_OPTIONAL_HDR_MAGIC );  /* Magic */
783     fprintf( outfile, "    0, 0,\n" );                   /* Major/MinorLinkerVersion */
784     fprintf( outfile, "    0, 0, 0,\n" );                /* SizeOfCode/Data */
785     fprintf( outfile, "    %s,\n", init_func );          /* AddressOfEntryPoint */
786     fprintf( outfile, "    0, __wine_spec_data_start,\n" );              /* BaseOfCode/Data */
787     fprintf( outfile, "    __wine_spec_pe_header,\n" );  /* ImageBase */
788     fprintf( outfile, "    %ld,\n", page_size );         /* SectionAlignment */
789     fprintf( outfile, "    %ld,\n", page_size );         /* FileAlignment */
790     fprintf( outfile, "    1, 0,\n" );                   /* Major/MinorOperatingSystemVersion */
791     fprintf( outfile, "    0, 0,\n" );                   /* Major/MinorImageVersion */
792     fprintf( outfile, "    %d,\n", spec->subsystem_major );             /* MajorSubsystemVersion */
793     fprintf( outfile, "    %d,\n", spec->subsystem_minor );             /* MinorSubsystemVersion */
794     fprintf( outfile, "    0,\n" );                      /* Win32VersionValue */
795     fprintf( outfile, "    _end,\n" );                   /* SizeOfImage */
796     fprintf( outfile, "    %ld,\n", page_size );         /* SizeOfHeaders */
797     fprintf( outfile, "    0,\n" );                      /* CheckSum */
798     fprintf( outfile, "    0x%04x,\n", spec->subsystem );/* Subsystem */
799     fprintf( outfile, "    0,\n" );                      /* DllCharacteristics */
800     fprintf( outfile, "    %d, %ld,\n",                  /* SizeOfStackReserve/Commit */
801              (spec->stack_size ? spec->stack_size : 1024) * 1024, page_size );
802     fprintf( outfile, "    %d, %ld,\n",                  /* SizeOfHeapReserve/Commit */
803              (spec->heap_size ? spec->heap_size : 1024) * 1024, page_size );
804     fprintf( outfile, "    0,\n" );                      /* LoaderFlags */
805     fprintf( outfile, "    %d,\n", IMAGE_NUMBEROF_DIRECTORY_ENTRIES );  /* NumberOfRvaAndSizes */
806     fprintf( outfile, "    {\n" );
807     fprintf( outfile, "      { %s, %d },\n",  /* IMAGE_DIRECTORY_ENTRY_EXPORT */
808              exports_size ? "__wine_spec_exports" : "0", exports_size );
809     fprintf( outfile, "      { %s, %s },\n",  /* IMAGE_DIRECTORY_ENTRY_IMPORT */
810              nr_imports ? "&imports" : "0", nr_imports ? "sizeof(imports)" : "0" );
811     fprintf( outfile, "      { %s, %s },\n",   /* IMAGE_DIRECTORY_ENTRY_RESOURCE */
812              spec->nb_resources ? "&resources" : "0",
813              spec->nb_resources ? "sizeof(resources)" : "0" );
814     fprintf( outfile, "    }\n  }\n};\n\n" );
815
816     /* Output the DLL constructor */
817
818     fprintf( outfile,
819              "void __wine_spec_init(void)\n"
820              "{\n"
821              "    extern void __wine_dll_register( const struct image_nt_headers *, const char * );\n"
822              "    __wine_spec_init_state = 1;\n"
823              "    __wine_dll_register( &nt_header, \"%s\" );\n"
824              "}\n\n",
825              spec->file_name );
826
827     output_dll_init( outfile, "__wine_spec_init_ctor", NULL );
828     fprintf( outfile,
829              "void __wine_spec_init_ctor(void)\n"
830              "{\n"
831              "    if (__wine_spec_init_state) return;\n"
832              "    __wine_spec_init();\n"
833              "    __wine_spec_init_state = 2;\n"
834              "}\n" );
835 }
836
837
838 /*******************************************************************
839  *         BuildDef32File
840  *
841  * Build a Win32 def file from a spec file.
842  */
843 void BuildDef32File( FILE *outfile, DLLSPEC *spec )
844 {
845     const char *name;
846     int i;
847
848     if (spec_file_name)
849         fprintf( outfile, "; File generated automatically from %s; do not edit!\n\n",
850                  spec_file_name );
851     else
852         fprintf( outfile, "; File generated automatically; do not edit!\n\n" );
853
854     fprintf(outfile, "LIBRARY %s\n\n", spec->file_name);
855
856     fprintf(outfile, "EXPORTS\n");
857
858     /* Output the exports and relay entry points */
859
860     for(i = 0; i < spec->nb_entry_points; i++)
861     {
862         const ORDDEF *odp = &spec->entry_points[i];
863         int is_data = 0;
864
865         if (!odp) continue;
866         if (odp->flags & FLAG_REGISTER) continue;
867         if (odp->type == TYPE_STUB) continue;
868
869         if (odp->name) name = odp->name;
870         else if (odp->export_name) name = odp->export_name;
871         else continue;
872
873         fprintf(outfile, "  %s", name);
874
875         switch(odp->type)
876         {
877         case TYPE_EXTERN:
878             is_data = 1;
879             /* fall through */
880         case TYPE_VARARGS:
881         case TYPE_CDECL:
882             /* try to reduce output */
883             if(strcmp(name, odp->link_name) || (odp->flags & FLAG_FORWARD))
884                 fprintf(outfile, "=%s", odp->link_name);
885             break;
886         case TYPE_STDCALL:
887         {
888             int at_param = strlen(odp->u.func.arg_types) * sizeof(int);
889             if (!kill_at) fprintf(outfile, "@%d", at_param);
890             if  (odp->flags & FLAG_FORWARD)
891             {
892                 fprintf(outfile, "=%s", odp->link_name);
893             }
894             else if (strcmp(name, odp->link_name)) /* try to reduce output */
895             {
896                 fprintf(outfile, "=%s", odp->link_name);
897                 if (!kill_at) fprintf(outfile, "@%d", at_param);
898             }
899             break;
900         }
901         default:
902             assert(0);
903         }
904         fprintf( outfile, " @%d", odp->ordinal );
905         if (!odp->name) fprintf( outfile, " NONAME" );
906         if (is_data) fprintf( outfile, " DATA" );
907         if (odp->flags & FLAG_PRIVATE) fprintf( outfile, " PRIVATE" );
908         fprintf( outfile, "\n" );
909     }
910 }
911
912
913 /*******************************************************************
914  *         BuildDebugFile
915  *
916  * Build the debugging channels source file.
917  */
918 void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv )
919 {
920     int nr_debug;
921     char *prefix, *p;
922
923     while (*argv)
924     {
925         if (!parse_debug_channels( srcdir, *argv++ )) exit(1);
926     }
927
928     output_standard_file_header( outfile );
929     nr_debug = output_debug( outfile );
930     if (!nr_debug)
931     {
932         fprintf( outfile, "/* no debug channels found for this module */\n" );
933         return;
934     }
935
936     if (output_file_name)
937     {
938         if ((p = strrchr( output_file_name, '/' ))) p++;
939         prefix = xstrdup( p ? p : output_file_name );
940         if ((p = strchr( prefix, '.' ))) *p = 0;
941         strcpy( p, make_c_identifier(p) );
942     }
943     else prefix = xstrdup( "_" );
944
945     /* Output the DLL constructor */
946
947     fprintf( outfile,
948              "#ifdef __GNUC__\n"
949              "void __wine_dbg_%s_init(void) __attribute__((constructor));\n"
950              "void __wine_dbg_%s_fini(void) __attribute__((destructor));\n"
951              "#else\n"
952              "static void __asm__dummy_dll_init(void) {\n",
953              prefix, prefix );
954
955 #if defined(__i386__)
956     fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
957     fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
958     fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
959     fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
960     fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
961 #elif defined(__sparc__)
962     fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
963     fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
964     fprintf( outfile, "    \"\\tnop\\n\"\n" );
965     fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
966     fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
967     fprintf( outfile, "    \"\\tnop\\n\"\n" );
968     fprintf( outfile, "    \"\\t.section\t\\\".text\\\"\\n\");\n" );
969 #elif defined(__powerpc__)
970 # ifdef __APPLE__
971         fprintf( outfile, "asm(\"\\t.mod_init_func\\n\"\n" );
972         fprintf( outfile, "    \"\\t.align 2\\n\"\n" );
973         fprintf( outfile, "    \"\\t.long " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
974         fprintf( outfile, "    \"\\t.text\\n\");\n" );
975         fprintf( outfile, "asm(\"\\t.mod_term_func\\n\"\n" );
976         fprintf( outfile, "    \"\\t.align 2\\n\"\n" );
977         fprintf( outfile, "    \"\\t.long " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
978         fprintf( outfile, "    \"\\t.text\\n\");\n" );
979 # else
980     fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
981     fprintf( outfile, "    \"\\tbl " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
982     fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
983     fprintf( outfile, "    \"\\tbl " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
984     fprintf( outfile, "    \"\\t.text\\n\");\n" );
985 # endif
986 #elif defined(__ALPHA__)
987     fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
988     fprintf( outfile, "    \"\\tjsr $26," __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
989     fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
990     fprintf( outfile, "    \"\\tjsr $26," __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
991     fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
992 #else
993 #error You need to define the DLL constructor for your architecture
994 #endif
995     fprintf( outfile, "}\n#endif /* defined(__GNUC__) */\n\n" );
996
997     fprintf( outfile,
998              "void __wine_dbg_%s_init(void)\n"
999              "{\n"
1000              "    extern void *__wine_dbg_register( char * const *, int );\n"
1001              "    if (!debug_registration) debug_registration = __wine_dbg_register( debug_channels, %d );\n"
1002              "}\n\n", prefix, nr_debug );
1003     fprintf( outfile,
1004              "void __wine_dbg_%s_fini(void)\n"
1005              "{\n"
1006              "    extern void __wine_dbg_unregister( void* );\n"
1007              "    __wine_dbg_unregister( debug_registration );\n"
1008              "}\n", prefix );
1009
1010     free( prefix );
1011 }