spec32.c 37.1 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * 32-bit spec files
 *
 * Copyright 1993 Robert J. Amstadt
 * Copyright 1995 Martin von Loewis
 * Copyright 1995, 1996, 1997 Alexandre Julliard
 * Copyright 1997 Eric Youngdale
 * Copyright 1999 Ulrich Weigand
9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * 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 <string.h>
31 32

#include "winbase.h"
33
#include "wine/exception.h"
34 35 36
#include "build.h"


37 38 39 40 41 42 43
static int string_compare( const void *ptr1, const void *ptr2 )
{
    const char * const *str1 = ptr1;
    const char * const *str2 = ptr2;
    return strcmp( *str1, *str2 );
}

44 45 46 47 48 49 50 51 52

/*******************************************************************
 *         make_internal_name
 *
 * Generate an internal name for an entry point. Used for stubs etc.
 */
static const char *make_internal_name( const ORDDEF *odp, const char *prefix )
{
    static char buffer[256];
53
    if (odp->name || odp->export_name)
54 55
    {
        char *p;
56
        sprintf( buffer, "__wine_%s_%s_%s", prefix, dll_file_name,
57
                 odp->name ? odp->name : odp->export_name );
58 59 60 61
        /* make sure name is a legal C identifier */
        for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
        if (!*p) return buffer;
    }
62
    sprintf( buffer, "__wine_%s_%s_%d", prefix, make_c_identifier(dll_file_name), odp->ordinal );
63 64 65
    return buffer;
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
/*******************************************************************
 *         AssignOrdinals
 *
 * Assign ordinals to all entry points.
 */
static void AssignOrdinals(void)
{
    int i, ordinal;

    if ( !nb_names ) return;

    /* start assigning from Base, or from 1 if no ordinal defined yet */
    if (Base == MAX_ORDINALS) Base = 1;
    for (i = 0, ordinal = Base; i < nb_names; i++)
    {
        if (Names[i]->ordinal != -1) continue;  /* already has an ordinal */
        while (Ordinals[ordinal]) ordinal++;
        if (ordinal >= MAX_ORDINALS)
        {
            current_line = Names[i]->lineno;
            fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
        }
        Names[i]->ordinal = ordinal;
        Ordinals[ordinal] = Names[i];
    }
    if (ordinal > Limit) Limit = ordinal;
}


95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/*******************************************************************
 *         output_debug
 *
 * Output the debug channels.
 */
static int output_debug( FILE *outfile )
{
    int i;

    if (!nb_debug_channels) return 0;
    qsort( debug_channels, nb_debug_channels, sizeof(debug_channels[0]), string_compare );

    for (i = 0; i < nb_debug_channels; i++)
        fprintf( outfile, "char __wine_dbch_%s[] = \"\\003%s\";\n",
                 debug_channels[i], debug_channels[i] );

    fprintf( outfile, "\nstatic char * const debug_channels[%d] =\n{\n", nb_debug_channels );
    for (i = 0; i < nb_debug_channels; i++)
    {
        fprintf( outfile, "    __wine_dbch_%s", debug_channels[i] );
        if (i < nb_debug_channels - 1) fprintf( outfile, ",\n" );
    }
    fprintf( outfile, "\n};\n\n" );
    fprintf( outfile, "static void *debug_registration;\n\n" );

    return nb_debug_channels;
}


124 125 126 127 128
/*******************************************************************
 *         output_exports
 *
 * Output the export table for a Win32 module.
 */
129
static int output_exports( FILE *outfile, int nr_exports )
130
{
131
    int i, fwd_size = 0, total_size = 0;
132

133 134 135
    if (!nr_exports) return 0;

    fprintf( outfile, "asm(\".data\\n\"\n" );
136
    fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
137
    fprintf( outfile, "    \"" __ASM_NAME("__wine_spec_exports") ":\\n\"\n" );
138 139

    /* export directory header */
140

141 142 143
    fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* Characteristics */
    fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* TimeDateStamp */
    fprintf( outfile, "    \"\\t.long 0\\n\"\n" );                 /* MajorVersion/MinorVersion */
144
    fprintf( outfile, "    \"\\t.long " __ASM_NAME("dllname") "\\n\"\n" ); /* Name */
145 146 147 148
    fprintf( outfile, "    \"\\t.long %d\\n\"\n", Base );          /* Base */
    fprintf( outfile, "    \"\\t.long %d\\n\"\n", nr_exports );    /* NumberOfFunctions */
    fprintf( outfile, "    \"\\t.long %d\\n\"\n", nb_names );      /* NumberOfNames */
    fprintf( outfile, "    \"\\t.long __wine_spec_exports_funcs\\n\"\n" ); /* AddressOfFunctions */
149 150
    if (nb_names)
    {
151 152
        fprintf( outfile, "    \"\\t.long __wine_spec_exp_name_ptrs\\n\"\n" );     /* AddressOfNames */
        fprintf( outfile, "    \"\\t.long __wine_spec_exp_ordinals\\n\"\n" );  /* AddressOfNameOrdinals */
153 154 155
    }
    else
    {
156 157
        fprintf( outfile, "    \"\\t.long 0\\n\"\n" );  /* AddressOfNames */
        fprintf( outfile, "    \"\\t.long 0\\n\"\n" );  /* AddressOfNameOrdinals */
158
    }
159
    total_size += 10 * sizeof(int);
160

161
    /* output the function pointers */
162

163
    fprintf( outfile, "    \"__wine_spec_exports_funcs:\\n\"\n" );
164 165 166
    for (i = Base; i <= Limit; i++)
    {
        ORDDEF *odp = Ordinals[i];
167
        if (!odp) fprintf( outfile, "    \"\\t.long 0\\n\"\n" );
168 169 170 171 172 173
        else switch(odp->type)
        {
        case TYPE_EXTERN:
        case TYPE_STDCALL:
        case TYPE_VARARGS:
        case TYPE_CDECL:
174 175 176 177 178
            if (!(odp->flags & FLAG_FORWARD))
            {
                fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") "\\n\"\n",
                         (odp->flags & FLAG_REGISTER) ? make_internal_name(odp,"regs") : odp->link_name );
            }
179 180 181 182 183
            else
            {
                fprintf( outfile, "    \"\\t.long __wine_spec_forwards+%d\\n\"\n", fwd_size );
                fwd_size += strlen(odp->link_name) + 1;
            }
184 185
            break;
        case TYPE_STUB:
186
            fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") "\\n\"\n", make_internal_name( odp, "stub" ) );
187 188 189 190 191
            break;
        default:
            assert(0);
        }
    }
192
    total_size += (Limit - Base + 1) * sizeof(int);
193 194 195

    if (nb_names)
    {
196
        /* output the function name pointers */
197

198 199 200
        int namepos = 0;

        fprintf( outfile, "    \"__wine_spec_exp_name_ptrs:\\n\"\n" );
201 202
        for (i = 0; i < nb_names; i++)
        {
203 204
            fprintf( outfile, "    \"\\t.long __wine_spec_exp_names+%d\\n\"\n", namepos );
            namepos += strlen(Names[i]->name) + 1;
205
        }
206 207 208 209
        total_size += nb_names * sizeof(int);

        /* output the function names */

210
        fprintf( outfile, "    \"\\t.text\\n\"\n" );
211 212
        fprintf( outfile, "    \"__wine_spec_exp_names:\\n\"\n" );
        for (i = 0; i < nb_names; i++)
213
            fprintf( outfile, "    \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", Names[i]->name );
214
        fprintf( outfile, "    \"\\t.data\\n\"\n" );
215 216 217

        /* output the function ordinals */

218
        fprintf( outfile, "    \"__wine_spec_exp_ordinals:\\n\"\n" );
219 220
        for (i = 0; i < nb_names; i++)
        {
221
            fprintf( outfile, "    \"\\t" __ASM_SHORT " %d\\n\"\n", Names[i]->ordinal - Base );
222 223 224 225
        }
        total_size += nb_names * sizeof(short);
        if (nb_names % 2)
        {
226
            fprintf( outfile, "    \"\\t" __ASM_SHORT " 0\\n\"\n" );
227
            total_size += sizeof(short);
228 229 230
        }
    }

231
    /* output forward strings */
232 233 234

    if (fwd_size)
    {
235
        fprintf( outfile, "    \"__wine_spec_forwards:\\n\"\n" );
236 237 238
        for (i = Base; i <= Limit; i++)
        {
            ORDDEF *odp = Ordinals[i];
239
            if (odp && (odp->flags & FLAG_FORWARD))
240
                fprintf( outfile, "    \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", odp->link_name );
241
        }
242
        fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
243
        total_size += (fwd_size + 3) & ~3;
244 245 246 247
    }

    /* output relays */

248
    if (debugging)
249
    {
250
        for (i = Base; i <= Limit; i++)
251
        {
252
            ORDDEF *odp = Ordinals[i];
253 254
            unsigned int j, args, mask = 0;
            const char *name;
255 256 257 258

            /* skip non-existent entry points */
            if (!odp) goto ignore;
            /* skip non-functions */
259
            if ((odp->type != TYPE_STDCALL) && (odp->type != TYPE_CDECL)) goto ignore;
260 261
            /* skip norelay and forward entry points */
            if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) goto ignore;
262 263 264 265 266 267 268

            for (j = 0; odp->u.func.arg_types[j]; j++)
            {
                if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
                if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
            }
            if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000;
269

270 271
            name = odp->link_name;
            args = strlen(odp->u.func.arg_types) * sizeof(int);
272
            if (odp->flags & FLAG_REGISTER) name = make_internal_name( odp, "regs" );
273

274 275 276
            switch(odp->type)
            {
            case TYPE_STDCALL:
277
                fprintf( outfile, "    \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name );
278
                fprintf( outfile, "    \"\\tret $%d\\n\"\n", args );
279
                fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask );
280 281
                break;
            case TYPE_CDECL:
282
                fprintf( outfile, "    \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name );
283
                fprintf( outfile, "    \"\\tret\\n\"\n" );
284
                fprintf( outfile, "    \"\\t" __ASM_SHORT " %d\\n\"\n", args );
285
                fprintf( outfile, "    \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask );
286 287 288 289
                break;
            default:
                assert(0);
            }
290
            continue;
291

292
        ignore:
293
            fprintf( outfile, "    \"\\t.long 0,0,0,0\\n\"\n" );
294
        }
295 296
    }

297 298
    fprintf( outfile, "    \"\\t.text\\n\"\n" );
    fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
299 300 301
    fprintf( outfile, ");\n\n" );

    return total_size;
302 303 304
}


305 306 307 308 309 310 311 312 313
/*******************************************************************
 *         output_stub_funcs
 *
 * Output the functions for stub entry points
*/
static void output_stub_funcs( FILE *outfile )
{
    int i;

314
    for (i = 0; i < nb_entry_points; i++)
315
    {
316
        ORDDEF *odp = EntryPoints[i];
317 318 319
        if (odp->type != TYPE_STUB) continue;
        fprintf( outfile, "#ifdef __GNUC__\n" );
        fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
320 321 322 323 324 325 326 327
        fprintf( outfile, "#endif\n\n" );
        fprintf( outfile, "struct exc_record {\n" );
        fprintf( outfile, "  unsigned int code, flags;\n" );
        fprintf( outfile, "  void *rec, *addr;\n" );
        fprintf( outfile, "  unsigned int params;\n" );
        fprintf( outfile, "  const void *info[15];\n" );
        fprintf( outfile, "};\n\n" );
        fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" );
328
        fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
329
        fprintf( outfile, "  struct exc_record rec;\n" );
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
        fprintf( outfile, "  rec.code    = 0x%08x;\n", EXCEPTION_WINE_STUB );
        fprintf( outfile, "  rec.flags   = %d;\n", EH_NONCONTINUABLE );
        fprintf( outfile, "  rec.rec     = 0;\n" );
        fprintf( outfile, "  rec.params  = 2;\n" );
        fprintf( outfile, "  rec.info[0] = dllname;\n" );
        fprintf( outfile, "  rec.info[1] = func;\n" );
        fprintf( outfile, "#ifdef __GNUC__\n" );
        fprintf( outfile, "  rec.addr = __builtin_return_address(1);\n" );
        fprintf( outfile, "#else\n" );
        fprintf( outfile, "  rec.addr = 0;\n" );
        fprintf( outfile, "#endif\n" );
        fprintf( outfile, "  for (;;) RtlRaiseException( &rec );\n}\n\n" );
        break;
    }

345
    for (i = 0; i < nb_entry_points; i++)
346
    {
347
        ORDDEF *odp = EntryPoints[i];
348
        if (odp->type != TYPE_STUB) continue;
349
        fprintf( outfile, "void %s(void) ", make_internal_name( odp, "stub" ) );
350
        if (odp->name)
351
            fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->name );
352 353
        else if (odp->export_name)
            fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->export_name );
354
        else
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
            fprintf( outfile, "{ __wine_unimplemented(\"%d\"); }\n", odp->ordinal );
    }
}


/*******************************************************************
 *         output_register_funcs
 *
 * Output the functions for register entry points
 */
static void output_register_funcs( FILE *outfile )
{
    const char *name;
    int i;

370
    for (i = 0; i < nb_entry_points; i++)
371
    {
372
        ORDDEF *odp = EntryPoints[i];
373 374
        if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
        if (!(odp->flags & FLAG_REGISTER)) continue;
375
        if (odp->flags & FLAG_FORWARD) continue;
376 377
        name = make_internal_name( odp, "regs" );
        fprintf( outfile,
378
                 "asm(\".align %d\\n\\t\"\n"
379
                 "    \"" __ASM_FUNC("%s") "\\n\\t\"\n"
380 381 382
                 "    \"" __ASM_NAME("%s") ":\\n\\t\"\n"
                 "    \"call " __ASM_NAME("__wine_call_from_32_regs") "\\n\\t\"\n"
                 "    \".long " __ASM_NAME("%s") "\\n\\t\"\n"
383
                 "    \".byte %d,%d\");\n",
384
                 get_alignment(4),
385
                 name, name, odp->link_name,
386 387
                 strlen(odp->u.func.arg_types) * sizeof(int),
                 (odp->type == TYPE_CDECL) ? 0 : (strlen(odp->u.func.arg_types) * sizeof(int)) );
388 389 390 391
    }
}


392 393 394 395 396 397 398 399 400 401 402 403 404 405
/*******************************************************************
 *         output_dll_init
 *
 * Output code for calling a dll constructor and destructor.
 */
void output_dll_init( FILE *outfile, const char *constructor, const char *destructor )
{
    fprintf( outfile, "#ifndef __GNUC__\n" );
    fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
    fprintf( outfile, "#endif\n" );

#if defined(__i386__)
    if (constructor)
    {
406
        fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
407
        fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", constructor );
408
        fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
409 410 411
    }
    if (destructor)
    {
412
        fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
413
        fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", destructor );
414
        fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
415 416 417 418
    }
#elif defined(__sparc__)
    if (constructor)
    {
419
        fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
420
        fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", constructor );
421
        fprintf( outfile, "    \"\\tnop\\n\"\n" );
422
        fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
423 424 425
    }
    if (destructor)
    {
426
        fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
427
        fprintf( outfile, "    \"\\tcall " __ASM_NAME("%s") "\\n\"\n", destructor );
428
        fprintf( outfile, "    \"\\tnop\\n\"\n" );
429
        fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
430 431 432 433
    }
#elif defined(__PPC__)
    if (constructor)
    {
434
        fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
435
        fprintf( outfile, "    \"\\tbl " __ASM_NAME("%s") "\\n\"\n", constructor );
436
        fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
437 438 439
    }
    if (destructor)
    {
440
        fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
441
        fprintf( outfile, "    \"\\tbl " __ASM_NAME("%s") "\\n\"\n", destructor );
442
        fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
443 444 445 446 447 448 449 450 451 452
    }
#else
#error You need to define the DLL constructor for your architecture
#endif
    fprintf( outfile, "#ifndef __GNUC__\n" );
    fprintf( outfile, "}\n" );
    fprintf( outfile, "#endif\n" );
}


453 454 455 456 457
/*******************************************************************
 *         BuildSpec32File
 *
 * Build a Win32 C file from a spec file.
 */
458
void BuildSpec32File( FILE *outfile )
459
{
460
    int exports_size = 0;
461
    int nr_exports, nr_imports, nr_resources;
462
    int characteristics, subsystem;
463
    DWORD page_size;
464
    char constructor[100];
465 466 467

#ifdef HAVE_GETPAGESIZE
    page_size = getpagesize();
468
#elif defined(__svr4__)
469
    page_size = sysconf(_SC_PAGESIZE);
470 471 472 473 474 475 476
#elif defined(_WINDOWS)
    {
        SYSTEM_INFO si;
        GetSystemInfo(&si);
        page_size = si.dwPageSize;
    }
#else
477 478 479 480 481 482
#   error Cannot get the page size on this platform
#endif

    AssignOrdinals();
    nr_exports = Base <= Limit ? Limit - Base + 1 : 0;

Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
483
    resolve_imports();
484
    output_standard_file_header( outfile );
485 486 487 488

    /* Reserve some space for the PE header */

    fprintf( outfile, "extern char pe_header[];\n" );
489 490 491 492
    fprintf( outfile, "#ifndef __GNUC__\n" );
    fprintf( outfile, "static void __asm__dummy_header(void) {\n" );
    fprintf( outfile, "#endif\n" );
    fprintf( outfile, "asm(\".section \\\".text\\\"\\n\\t\"\n" );
493
    fprintf( outfile, "    \".align %d\\n\"\n", get_alignment(page_size) );
494
    fprintf( outfile, "    \"" __ASM_NAME("pe_header") ":\\t.skip 65536\\n\\t\");\n" );
495 496 497
    fprintf( outfile, "#ifndef __GNUC__\n" );
    fprintf( outfile, "}\n" );
    fprintf( outfile, "#endif\n" );
498

499
    fprintf( outfile, "const char dllname[] = \"%s\";\n\n", dll_file_name );
500
    fprintf( outfile, "extern int __wine_spec_exports[];\n\n" );
501

502 503 504 505 506 507
#ifdef __i386__
    fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
#else
    fprintf( outfile, "#define __stdcall\n\n" );
#endif

508 509 510
    if (nr_exports)
    {
        /* Output the stub functions */
511

512
        output_stub_funcs( outfile );
513

514 515 516
        fprintf( outfile, "#ifndef __GNUC__\n" );
        fprintf( outfile, "static void __asm__dummy(void) {\n" );
        fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
517

518
        /* Output code for all register functions */
519

520
        output_register_funcs( outfile );
521

522
        /* Output the exports and relay entry points */
523

524
        exports_size = output_exports( outfile, nr_exports );
525

526 527 528 529
        fprintf( outfile, "#ifndef __GNUC__\n" );
        fprintf( outfile, "}\n" );
        fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
    }
530 531 532

    /* Output the DLL imports */

533
    nr_imports = output_imports( outfile );
534

535 536 537 538
    /* Output the resources */

    nr_resources = output_resources( outfile );

539 540
    /* Output LibMain function */

541
    characteristics = subsystem = 0;
542 543 544 545
    switch(SpecMode)
    {
    case SPEC_MODE_DLL:
        if (init_func) fprintf( outfile, "extern void %s();\n", init_func );
546 547 548 549 550 551 552 553 554 555
        else
        {
            fprintf( outfile, "#ifdef __GNUC__\n" );
            fprintf( outfile, "extern void DllMain() __attribute__((weak));\n" );
            fprintf( outfile, "#else\n" );
            fprintf( outfile, "extern void DllMain();\n" );
            fprintf( outfile, "static void __asm__dummy_dllmain(void)" );
            fprintf( outfile, " { asm(\".weak " __ASM_NAME("DllMain") "\"); }\n" );
            fprintf( outfile, "#endif\n" );
        }
556
        characteristics = IMAGE_FILE_DLL;
557 558 559 560
        break;
    case SPEC_MODE_GUIEXE:
        if (!init_func) init_func = "WinMain";
        fprintf( outfile,
561 562 563 564 565 566 567 568 569
                 "\ntypedef struct {\n"
                 "    unsigned int cb;\n"
                 "    char *lpReserved, *lpDesktop, *lpTitle;\n"
                 "    unsigned int dwX, dwY, dwXSize, dwYSize;\n"
                 "    unsigned int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;\n"
                 "    unsigned short wShowWindow, cbReserved2;\n"
                 "    char *lpReserved2;\n"
                 "    void *hStdInput, *hStdOutput, *hStdError;\n"
                 "} STARTUPINFOA;\n"
570 571
                 "int _ARGC;\n"
                 "char **_ARGV;\n"
572 573 574 575 576
                 "extern int __stdcall %s(void *,void *,char *,int);\n"
                 "extern char * __stdcall GetCommandLineA(void);\n"
                 "extern void * __stdcall GetModuleHandleA(char *);\n"
                 "extern void __stdcall GetStartupInfoA(STARTUPINFOA *);\n"
                 "extern void __stdcall ExitProcess(unsigned int);\n"
577
                 "static void __wine_exe_main(void)\n"
578
                 "{\n"
579 580
                 "    extern int __wine_main_argc;\n"
                 "    extern char **__wine_main_argv;\n"
581
                 "    STARTUPINFOA info;\n"
582
                 "    char *cmdline = GetCommandLineA();\n"
583 584 585 586 587 588 589 590 591 592 593 594
                 "    int bcount=0, in_quotes=0;\n"
                 "    while (*cmdline) {\n"
                 "        if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n"
                 "        else if (*cmdline=='\\\\') bcount++;\n"
                 "        else if (*cmdline=='\\\"') {\n"
                 "            if ((bcount & 1)==0) in_quotes=!in_quotes;\n"
                 "            bcount=0;\n"
                 "        }\n"
                 "        else bcount=0;\n"
                 "        cmdline++;\n"
                 "    }\n"
                 "    while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n"
595
                 "    GetStartupInfoA( &info );\n"
596
                 "    if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n"
597 598
                 "    _ARGC = __wine_main_argc;\n"
                 "    _ARGV = __wine_main_argv;\n"
599 600
                 "    ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
                 "}\n\n", init_func, init_func );
601 602 603 604 605 606
        init_func = "__wine_exe_main";
        subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
        break;
    case SPEC_MODE_GUIEXE_UNICODE:
        if (!init_func) init_func = "WinMain";
        fprintf( outfile,
607 608 609 610 611 612 613 614 615 616
                 "\ntypedef unsigned short WCHAR;\n"
                 "typedef struct {\n"
                 "    unsigned int cb;\n"
                 "    char *lpReserved, *lpDesktop, *lpTitle;\n"
                 "    unsigned int dwX, dwY, dwXSize, dwYSize;\n"
                 "    unsigned int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;\n"
                 "    unsigned short wShowWindow, cbReserved2;\n"
                 "    char *lpReserved2;\n"
                 "    void *hStdInput, *hStdOutput, *hStdError;\n"
                 "} STARTUPINFOA;\n"
617 618
                 "int _ARGC;\n"
                 "WCHAR **_ARGV;\n"
619 620 621 622 623
                 "extern int __stdcall %s(void *,void *,char *,int);\n"
                 "extern char * __stdcall GetCommandLineA(void);\n"
                 "extern void * __stdcall GetModuleHandleA(char *);\n"
                 "extern void __stdcall GetStartupInfoA(STARTUPINFOA *);\n"
                 "extern void __stdcall ExitProcess(unsigned int);\n"
624 625
                 "static void __wine_exe_main(void)\n"
                 "{\n"
626 627
                 "    extern int __wine_main_argc;\n"
                 "    extern WCHAR **__wine_main_wargv;\n"
628
                 "    STARTUPINFOA info;\n"
629
                 "    char *cmdline = GetCommandLineA();\n"
630 631 632 633 634 635 636 637 638 639 640 641
                 "    int bcount=0, in_quotes=0;\n"
                 "    while (*cmdline) {\n"
                 "        if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n"
                 "        else if (*cmdline=='\\\\') bcount++;\n"
                 "        else if (*cmdline=='\\\"') {\n"
                 "            if ((bcount & 1)==0) in_quotes=!in_quotes;\n"
                 "            bcount=0;\n"
                 "        }\n"
                 "        else bcount=0;\n"
                 "        cmdline++;\n"
                 "    }\n"
                 "    while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n"
642
                 "    GetStartupInfoA( &info );\n"
643
                 "    if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n"
644 645
                 "    _ARGC = __wine_main_argc;\n"
                 "    _ARGV = __wine_main_wargv;\n"
646 647
                 "    ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
                 "}\n\n", init_func, init_func );
648
        init_func = "__wine_exe_main";
649
        subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
650 651
        break;
    case SPEC_MODE_CUIEXE:
652
        if (!init_func) init_func = "main";
653
        fprintf( outfile,
654
                 "\nint _ARGC;\n"
655
                 "char **_ARGV;\n"
656
                 "extern void __stdcall ExitProcess(int);\n"
657
                 "static void __wine_exe_main(void)\n"
658 659
                 "{\n"
                 "    extern int %s( int argc, char *argv[] );\n"
660 661 662 663
                 "    extern int __wine_main_argc;\n"
                 "    extern char **__wine_main_argv;\n"
                 "    _ARGC = __wine_main_argc;\n"
                 "    _ARGV = __wine_main_argv;\n"
664 665
                 "    ExitProcess( %s( _ARGC, _ARGV ) );\n"
                 "}\n\n", init_func, init_func );
666
        init_func = "__wine_exe_main";
667 668
        subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
        break;
669 670 671 672 673 674 675 676 677 678
    case SPEC_MODE_CUIEXE_UNICODE:
        if (!init_func) init_func = "wmain";
        fprintf( outfile,
                 "\ntypedef unsigned short WCHAR;\n"
                 "int _ARGC;\n"
                 "WCHAR **_ARGV;\n"
                 "extern void __stdcall ExitProcess(int);\n"
                 "static void __wine_exe_main(void)\n"
                 "{\n"
                 "    extern int %s( int argc, WCHAR *argv[] );\n"
679 680 681 682
                 "    extern int __wine_main_argc;\n"
                 "    extern WCHAR **__wine_main_wargv;\n"
                 "    _ARGC = __wine_main_argc;\n"
                 "    _ARGV = __wine_main_wargv;\n"
683 684 685
                 "    ExitProcess( %s( _ARGC, _ARGV ) );\n"
                 "}\n\n", init_func, init_func );
        init_func = "__wine_exe_main";
686
        subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
687 688 689
        break;
    }

690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
    /* Output the NT header */

    /* this is the IMAGE_NT_HEADERS structure, but we cannot include winnt.h here */
    fprintf( outfile, "static const struct image_nt_headers\n{\n" );
    fprintf( outfile, "  int Signature;\n" );
    fprintf( outfile, "  struct file_header {\n" );
    fprintf( outfile, "    short Machine;\n" );
    fprintf( outfile, "    short NumberOfSections;\n" );
    fprintf( outfile, "    int   TimeDateStamp;\n" );
    fprintf( outfile, "    void *PointerToSymbolTable;\n" );
    fprintf( outfile, "    int   NumberOfSymbols;\n" );
    fprintf( outfile, "    short SizeOfOptionalHeader;\n" );
    fprintf( outfile, "    short Characteristics;\n" );
    fprintf( outfile, "  } FileHeader;\n" );
    fprintf( outfile, "  struct opt_header {\n" );
    fprintf( outfile, "    short Magic;\n" );
    fprintf( outfile, "    char  MajorLinkerVersion, MinorLinkerVersion;\n" );
    fprintf( outfile, "    int   SizeOfCode;\n" );
    fprintf( outfile, "    int   SizeOfInitializedData;\n" );
    fprintf( outfile, "    int   SizeOfUninitializedData;\n" );
    fprintf( outfile, "    void *AddressOfEntryPoint;\n" );
    fprintf( outfile, "    void *BaseOfCode;\n" );
    fprintf( outfile, "    void *BaseOfData;\n" );
    fprintf( outfile, "    void *ImageBase;\n" );
    fprintf( outfile, "    int   SectionAlignment;\n" );
    fprintf( outfile, "    int   FileAlignment;\n" );
    fprintf( outfile, "    short MajorOperatingSystemVersion;\n" );
    fprintf( outfile, "    short MinorOperatingSystemVersion;\n" );
    fprintf( outfile, "    short MajorImageVersion;\n" );
    fprintf( outfile, "    short MinorImageVersion;\n" );
    fprintf( outfile, "    short MajorSubsystemVersion;\n" );
    fprintf( outfile, "    short MinorSubsystemVersion;\n" );
    fprintf( outfile, "    int   Win32VersionValue;\n" );
    fprintf( outfile, "    int   SizeOfImage;\n" );
    fprintf( outfile, "    int   SizeOfHeaders;\n" );
    fprintf( outfile, "    int   CheckSum;\n" );
    fprintf( outfile, "    short Subsystem;\n" );
    fprintf( outfile, "    short DllCharacteristics;\n" );
    fprintf( outfile, "    int   SizeOfStackReserve;\n" );
    fprintf( outfile, "    int   SizeOfStackCommit;\n" );
    fprintf( outfile, "    int   SizeOfHeapReserve;\n" );
    fprintf( outfile, "    int   SizeOfHeapCommit;\n" );
    fprintf( outfile, "    int   LoaderFlags;\n" );
    fprintf( outfile, "    int   NumberOfRvaAndSizes;\n" );
734
    fprintf( outfile, "    struct { const void *VirtualAddress; int Size; } DataDirectory[%d];\n",
735 736 737 738 739 740 741 742 743 744 745 746 747
             IMAGE_NUMBEROF_DIRECTORY_ENTRIES );
    fprintf( outfile, "  } OptionalHeader;\n" );
    fprintf( outfile, "} nt_header = {\n" );
    fprintf( outfile, "  0x%04x,\n", IMAGE_NT_SIGNATURE );   /* Signature */

    fprintf( outfile, "  { 0x%04x,\n", IMAGE_FILE_MACHINE_I386 );  /* Machine */
    fprintf( outfile, "    0, 0, 0, 0,\n" );
    fprintf( outfile, "    sizeof(nt_header.OptionalHeader),\n" ); /* SizeOfOptionalHeader */
    fprintf( outfile, "    0x%04x },\n", characteristics );        /* Characteristics */

    fprintf( outfile, "  { 0x%04x,\n", IMAGE_NT_OPTIONAL_HDR_MAGIC );  /* Magic */
    fprintf( outfile, "    0, 0,\n" );                   /* Major/MinorLinkerVersion */
    fprintf( outfile, "    0, 0, 0,\n" );                /* SizeOfCode/Data */
748
    fprintf( outfile, "    %s,\n", init_func ? init_func : "DllMain" );  /* AddressOfEntryPoint */
749 750 751 752 753 754 755 756 757 758 759 760
    fprintf( outfile, "    0, 0,\n" );                   /* BaseOfCode/Data */
    fprintf( outfile, "    pe_header,\n" );              /* ImageBase */
    fprintf( outfile, "    %ld,\n", page_size );         /* SectionAlignment */
    fprintf( outfile, "    %ld,\n", page_size );         /* FileAlignment */
    fprintf( outfile, "    1, 0,\n" );                   /* Major/MinorOperatingSystemVersion */
    fprintf( outfile, "    0, 0,\n" );                   /* Major/MinorImageVersion */
    fprintf( outfile, "    4, 0,\n" );                   /* Major/MinorSubsystemVersion */
    fprintf( outfile, "    0,\n" );                      /* Win32VersionValue */
    fprintf( outfile, "    %ld,\n", page_size );         /* SizeOfImage */
    fprintf( outfile, "    %ld,\n", page_size );         /* SizeOfHeaders */
    fprintf( outfile, "    0,\n" );                      /* CheckSum */
    fprintf( outfile, "    0x%04x,\n", subsystem );      /* Subsystem */
761 762 763 764
    fprintf( outfile, "    0,\n" );                      /* DllCharacteristics */
    fprintf( outfile, "    %d, 0,\n", stack_size*1024 ); /* SizeOfStackReserve/Commit */
    fprintf( outfile, "    %d, 0,\n", DLLHeapSize*1024 );/* SizeOfHeapReserve/Commit */
    fprintf( outfile, "    0,\n" );                      /* LoaderFlags */
765 766
    fprintf( outfile, "    %d,\n", IMAGE_NUMBEROF_DIRECTORY_ENTRIES );  /* NumberOfRvaAndSizes */
    fprintf( outfile, "    {\n" );
767 768
    fprintf( outfile, "      { %s, %d },\n",  /* IMAGE_DIRECTORY_ENTRY_EXPORT */
             exports_size ? "__wine_spec_exports" : "0", exports_size );
769 770
    fprintf( outfile, "      { %s, %s },\n",  /* IMAGE_DIRECTORY_ENTRY_IMPORT */
             nr_imports ? "&imports" : "0", nr_imports ? "sizeof(imports)" : "0" );
771 772
    fprintf( outfile, "      { %s, %s },\n",   /* IMAGE_DIRECTORY_ENTRY_RESOURCE */
             nr_resources ? "&resources" : "0", nr_resources ? "sizeof(resources)" : "0" );
773
    fprintf( outfile, "    }\n  }\n};\n\n" );
774 775 776

    /* Output the DLL constructor */

777
    sprintf( constructor, "__wine_spec_%s_init", make_c_identifier(dll_file_name) );
778
    output_dll_init( outfile, constructor, NULL );
779 780

    fprintf( outfile,
781
             "void %s(void)\n"
782 783 784
             "{\n"
             "    extern void __wine_dll_register( const struct image_nt_headers *, const char * );\n"
             "    extern void *__wine_dbg_register( char * const *, int );\n"
785 786
             "    __wine_dll_register( &nt_header, \"%s\" );\n"
             "}\n",
787
             constructor, dll_file_name );
788
}
789 790 791 792 793 794 795 796 797


/*******************************************************************
 *         BuildDef32File
 *
 * Build a Win32 def file from a spec file.
 */
void BuildDef32File(FILE *outfile)
{
798
    const char *name;
799 800 801 802 803 804 805
    int i;

    AssignOrdinals();

    fprintf(outfile, "; File generated automatically from %s; do not edit!\n\n",
            input_file_name );

806
    fprintf(outfile, "LIBRARY %s\n\n", dll_file_name);
807 808 809 810 811 812 813 814

    fprintf(outfile, "EXPORTS\n");

    /* Output the exports and relay entry points */

    for(i = 0; i < nb_entry_points; i++)
    {
        ORDDEF *odp = EntryPoints[i];
815
        int is_data = 0;
816 817

        if (!odp) continue;
818
        if (odp->flags & FLAG_REGISTER) continue;
819
        if (odp->type == TYPE_STUB) continue;
820

821 822 823 824 825
        if (odp->name) name = odp->name;
        else if (odp->export_name) name = odp->export_name;
        else continue;

        fprintf(outfile, "  %s", name);
826 827 828 829

        switch(odp->type)
        {
        case TYPE_EXTERN:
830 831
            is_data = 1;
            /* fall through */
832 833 834
        case TYPE_VARARGS:
        case TYPE_CDECL:
            /* try to reduce output */
835
            if(strcmp(name, odp->link_name) || (odp->flags & FLAG_FORWARD))
836 837 838 839 840
                fprintf(outfile, "=%s", odp->link_name);
            break;
        case TYPE_STDCALL:
        {
            int at_param = strlen(odp->u.func.arg_types) * sizeof(int);
841
            if (!kill_at) fprintf(outfile, "@%d", at_param);
842 843 844 845 846
            if  (odp->flags & FLAG_FORWARD)
            {
                fprintf(outfile, "=%s", odp->link_name);
            }
            else if (strcmp(name, odp->link_name)) /* try to reduce output */
847 848
            {
                fprintf(outfile, "=%s", odp->link_name);
849
                if (!kill_at) fprintf(outfile, "@%d", at_param);
850 851 852 853 854 855
            }
            break;
        }
        default:
            assert(0);
        }
856 857 858 859 860
        fprintf( outfile, " @%d", odp->ordinal );
        if (!odp->name) fprintf( outfile, " NONAME" );
        if (is_data) fprintf( outfile, " DATA" );
        if (odp->flags & FLAG_PRIVATE) fprintf( outfile, " PRIVATE" );
        fprintf( outfile, "\n" );
861 862
    }
}
863 864 865 866 867 868 869


/*******************************************************************
 *         BuildDebugFile
 *
 * Build the debugging channels source file.
 */
870
void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv )
871 872 873 874
{
    int nr_debug;
    char *prefix, *p;

875 876 877 878
    while (*argv)
    {
        if (!parse_debug_channels( srcdir, *argv++ )) exit(1);
    }
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
    output_standard_file_header( outfile );
    nr_debug = output_debug( outfile );
    if (!nr_debug)
    {
        fprintf( outfile, "/* no debug channels found for this module */\n" );
        return;
    }

    if (output_file_name)
    {
        if ((p = strrchr( output_file_name, '/' ))) p++;
        prefix = xstrdup( p ? p : output_file_name );
        if ((p = strchr( prefix, '.' ))) *p = 0;
        strcpy( p, make_c_identifier(p) );
    }
    else prefix = xstrdup( "_" );

    /* Output the DLL constructor */

    fprintf( outfile,
             "#ifdef __GNUC__\n"
             "static void __wine_dbg_%s_init(void) __attribute__((constructor));\n"
             "static void __wine_dbg_%s_fini(void) __attribute__((destructor));\n"
             "#else\n"
             "static void __asm__dummy_dll_init(void) {\n",
             prefix, prefix );

#if defined(__i386__)
908
    fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
909
    fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
910
    fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
911
    fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
912
    fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
913
#elif defined(__sparc__)
914
    fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
915
    fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
916
    fprintf( outfile, "    \"\\tnop\\n\"\n" );
917
    fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
918
    fprintf( outfile, "    \"\\tcall " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
919
    fprintf( outfile, "    \"\\tnop\\n\"\n" );
920
    fprintf( outfile, "    \"\\t.section\t\\\".text\\\"\\n\");\n" );
921
#elif defined(__PPC__)
922
    fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
923
    fprintf( outfile, "    \"\\tbl " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
924
    fprintf( outfile, "    \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
925
    fprintf( outfile, "    \"\\tbl " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
926
    fprintf( outfile, "    \"\\t.section\\t\\\".text\\\"\\n\");\n" );
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
#else
#error You need to define the DLL constructor for your architecture
#endif
    fprintf( outfile, "}\n#endif /* defined(__GNUC__) */\n" );

    fprintf( outfile,
             "\n#ifdef __GNUC__\n"
             "static\n"
             "#endif\n"
             "void __wine_dbg_%s_init(void)\n"
             "{\n"
             "    extern void *__wine_dbg_register( char * const *, int );\n"
             "    debug_registration = __wine_dbg_register( debug_channels, %d );\n"
             "}\n", prefix, nr_debug );
    fprintf( outfile,
             "\n#ifdef __GNUC__\n"
             "static\n"
             "#endif\n"
             "void __wine_dbg_%s_fini(void)\n"
             "{\n"
             "    extern void __wine_dbg_unregister( void* );\n"
             "    __wine_dbg_unregister( debug_registration );\n"
             "}\n", prefix );

    free( prefix );
}