import.c 44 KB
Newer Older
1 2 3
/*
 * DLL imports support
 *
4 5
 * Copyright 2000, 2004 Alexandre Julliard
 * Copyright 2000 Eric Pouech
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22
#include "config.h"
23
#include "wine/port.h"
24

25
#include <assert.h>
26
#include <ctype.h>
27 28
#include <fcntl.h>
#include <stdio.h>
29
#include <string.h>
30
#include <stdarg.h>
31 32 33
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
34 35 36
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
37

38 39
#include "windef.h"
#include "winbase.h"
40 41 42 43
#include "build.h"

struct import
{
44 45 46 47
    DLLSPEC     *spec;        /* description of the imported dll */
    char        *full_name;   /* full name of the input file */
    dev_t        dev;         /* device/inode of the input file */
    ino_t        ino;
48
    int          delay;       /* delay or not dll loading ? */
49
    ORDDEF     **exports;     /* functions exported from this dll */
50
    int          nb_exports;  /* number of exported functions */
51
    ORDDEF     **imports;     /* functions we want to import from this dll */
52 53 54
    int          nb_imports;  /* number of imported functions */
};

55 56 57 58 59
struct name_table
{
    char **names;
    unsigned int count, size;
};
60

61 62
static struct name_table undef_symbols;    /* list of undefined symbols */
static struct name_table ignore_symbols;   /* list of symbols to ignore */
63
static struct name_table extra_ld_symbols; /* list of extra symbols that ld should resolve */
64
static struct name_table delayed_imports;  /* list of delayed import dlls */
65
static struct name_table ext_link_imports; /* list of external symbols to link to */
66

67
static struct import **dll_imports = NULL;
68 69 70 71
static int nb_imports = 0;      /* number of imported dlls (delayed or not) */
static int nb_delayed = 0;      /* number of delayed dlls */
static int total_imports = 0;   /* total number of imported functions */
static int total_delayed = 0;   /* total number of imported functions in delayed DLLs */
72

73 74 75 76 77 78 79 80 81 82

static inline const char *ppc_reg( int reg )
{
    static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
                                               "r8", "r9", "r10","r11","r12","r13","r14","r15",
                                               "r16","r17","r18","r19","r20","r21","r22","r23",
                                               "r24","r25","r26","r27","r28","r29","r30","r31" };
    if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
    return ppc_regs[reg] + 1;  /* skip the 'r' */
}
83

84 85 86
/* compare function names; helper for resolve_imports */
static int name_cmp( const void *name, const void *entry )
{
87
    return strcmp( *(const char* const *)name, *(const char* const *)entry );
88 89
}

90 91 92
/* compare function names; helper for resolve_imports */
static int func_cmp( const void *func1, const void *func2 )
{
93 94
    const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
    const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
95 96
    return strcmp( odp1->name ? odp1->name : odp1->export_name,
                   odp2->name ? odp2->name : odp2->export_name );
97 98
}

99 100
/* add a name to a name table */
inline static void add_name( struct name_table *table, const char *name )
101
{
102 103 104 105 106
    if (table->count == table->size)
    {
        table->size += (table->size / 2);
        if (table->size < 32) table->size = 32;
        table->names = xrealloc( table->names, table->size * sizeof(*table->names) );
Patrik Stridvall's avatar
Patrik Stridvall committed
107
    }
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
    table->names[table->count++] = xstrdup( name );
}

/* remove a name from a name table */
inline static void remove_name( struct name_table *table, unsigned int idx )
{
    assert( idx < table->count );
    free( table->names[idx] );
    memmove( table->names + idx, table->names + idx + 1,
             (table->count - idx - 1) * sizeof(*table->names) );
    table->count--;
}

/* make a name table empty */
inline static void empty_name_table( struct name_table *table )
{
    unsigned int i;

    for (i = 0; i < table->count; i++) free( table->names[i] );
    table->count = 0;
}
Patrik Stridvall's avatar
Patrik Stridvall committed
129

130 131 132 133 134 135
/* locate a name in a (sorted) list */
inline static const char *find_name( const char *name, const struct name_table *table )
{
    char **res = NULL;

    if (table->count) res = bsearch( &name, table->names, table->count, sizeof(*table->names), name_cmp );
136 137 138
    return res ? *res : NULL;
}

139 140 141 142 143 144
/* sort a name table */
inline static void sort_names( struct name_table *table )
{
    if (table->count) qsort( table->names, table->count, sizeof(*table->names), name_cmp );
}

145
/* locate an export in a (sorted) export list */
146
inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
147
{
148
    ORDDEF func, *odp, **res = NULL;
149

150
    func.name = (char *)name;
151
    func.ordinal = -1;
152 153 154
    odp = &func;
    if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
    return res ? *res : NULL;
155 156
}

157 158 159 160 161
/* free an import structure */
static void free_imports( struct import *imp )
{
    free( imp->exports );
    free( imp->imports );
162
    free_dll_spec( imp->spec );
163
    free( imp->full_name );
164 165 166
    free( imp );
}

167 168 169 170 171
/* check whether a given dll is imported in delayed mode */
static int is_delayed_import( const char *name )
{
    int i;

172
    for (i = 0; i < delayed_imports.count; i++)
173
    {
174
        if (!strcmp( delayed_imports.names[i], name )) return 1;
175 176 177 178
    }
    return 0;
}

179
/* check whether a given dll has already been imported */
180
static struct import *is_already_imported( const char *name )
181 182 183 184 185
{
    int i;

    for (i = 0; i < nb_imports; i++)
    {
186
        if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
187
    }
188
    return NULL;
189 190
}

191 192 193
/* open the .so library for a given dll in a specified path */
static char *try_library_path( const char *path, const char *name )
{
194
    char *buffer;
195 196
    int fd;

197
    buffer = xmalloc( strlen(path) + strlen(name) + 9 );
198 199
    sprintf( buffer, "%s/lib%s.def", path, name );

200
    /* check if the file exists */
201 202 203 204 205 206 207
    if ((fd = open( buffer, O_RDONLY )) != -1)
    {
        close( fd );
        return buffer;
    }
    free( buffer );
    return NULL;
208 209
}

210 211
/* find the .def import library for a given dll */
static char *find_library( const char *name )
212 213 214 215 216 217 218 219
{
    char *fullname;
    int i;

    for (i = 0; i < nb_lib_paths; i++)
    {
        if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
    }
220 221
    fatal_error( "could not open .def file for %s\n", name );
    return NULL;
222 223
}

224
/* read in the list of exported symbols of an import library */
225
static int read_import_lib( struct import *imp )
226 227
{
    FILE *f;
228
    int i, ret;
229 230
    struct stat stat;
    struct import *prev_imp;
231
    DLLSPEC *spec = imp->spec;
232

233 234 235 236
    f = open_input_file( NULL, imp->full_name );
    fstat( fileno(f), &stat );
    imp->dev = stat.st_dev;
    imp->ino = stat.st_ino;
237 238 239
    ret = parse_def_file( f, spec );
    close_input_file( f );
    if (!ret) return 0;
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

    /* check if we already imported that library from a different file */
    if ((prev_imp = is_already_imported( spec->file_name )))
    {
        if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
            fatal_error( "%s and %s have the same export name '%s'\n",
                         prev_imp->full_name, imp->full_name, spec->file_name );
        return 0;  /* the same file was already loaded, ignore this one */
    }

    if (is_delayed_import( spec->file_name ))
    {
        imp->delay = 1;
        nb_delayed++;
    }
255

256
    imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
257

258 259 260
    for (i = 0; i < spec->nb_entry_points; i++)
    {
        ORDDEF *odp = &spec->entry_points[i];
261

262 263 264
        if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
        if (odp->flags & FLAG_PRIVATE) continue;
        imp->exports[imp->nb_exports++] = odp;
265
    }
266
    imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
267 268
    if (imp->nb_exports)
        qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
269
    return 1;
270 271
}

272 273
/* build the dll exported name from the import lib name or path */
static char *get_dll_name( const char *name, const char *filename )
274
{
275
    char *ret;
276

277 278 279 280 281 282 283 284 285 286 287
    if (filename)
    {
        const char *basename = strrchr( filename, '/' );
        if (!basename) basename = filename;
        else basename++;
        if (!strncmp( basename, "lib", 3 )) basename += 3;
        ret = xmalloc( strlen(basename) + 5 );
        strcpy( ret, basename );
        if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
    }
    else
288
    {
289 290
        ret = xmalloc( strlen(name) + 5 );
        strcpy( ret, name );
291
    }
292 293 294 295 296 297 298 299
    if (!strchr( ret, '.' )) strcat( ret, ".dll" );
    return ret;
}

/* add a dll to the list of imports */
void add_import_dll( const char *name, const char *filename )
{
    struct import *imp = xmalloc( sizeof(*imp) );
300

301
    imp->spec            = alloc_dll_spec();
302 303
    imp->spec->file_name = get_dll_name( name, filename );
    imp->delay           = 0;
304 305
    imp->imports         = NULL;
    imp->nb_imports      = 0;
306 307 308 309 310
    imp->exports         = NULL;
    imp->nb_exports      = 0;

    if (filename) imp->full_name = xstrdup( filename );
    else imp->full_name = find_library( name );
311

312
    if (read_import_lib( imp ))
313 314 315 316
    {
        dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
        dll_imports[nb_imports++] = imp;
    }
317 318 319 320 321
    else
    {
        free_imports( imp );
        if (nb_errors) exit(1);
    }
322 323
}

324 325 326 327 328 329
/* add a library to the list of delayed imports */
void add_delayed_import( const char *name )
{
    struct import *imp;
    char *fullname = get_dll_name( name, NULL );

330
    add_name( &delayed_imports, fullname );
331 332 333 334 335
    if ((imp = is_already_imported( fullname )) && !imp->delay)
    {
        imp->delay = 1;
        nb_delayed++;
    }
336
    free( fullname );
337 338
}

339 340 341 342 343 344 345 346 347 348 349
/* remove an imported dll, based on its index in the dll_imports array */
static void remove_import_dll( int index )
{
    struct import *imp = dll_imports[index];

    memmove( &dll_imports[index], &dll_imports[index+1], sizeof(imp) * (nb_imports - index - 1) );
    nb_imports--;
    if (imp->delay) nb_delayed--;
    free_imports( imp );
}

350 351
/* add a symbol to the ignored symbol list */
/* if the name starts with '-' the symbol is removed instead */
352 353
void add_ignore_symbol( const char *name )
{
354
    unsigned int i;
355 356

    if (name[0] == '-')  /* remove it */
357
    {
358 359
        if (!name[1]) empty_name_table( &ignore_symbols );  /* remove everything */
        else for (i = 0; i < ignore_symbols.count; i++)
360
        {
361
            if (!strcmp( ignore_symbols.names[i], name+1 )) remove_name( &ignore_symbols, i-- );
362
        }
363
    }
364
    else add_name( &ignore_symbols, name );
365 366
}

367 368 369 370 371 372
/* add a symbol to the list of extra symbols that ld must resolve */
void add_extra_ld_symbol( const char *name )
{
    add_name( &extra_ld_symbols, name );
}

373
/* add a function to the list of imports from a given dll */
374
static void add_import_func( struct import *imp, ORDDEF *func )
375 376
{
    imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
377
    imp->imports[imp->nb_imports++] = func;
378
    total_imports++;
379
    if (imp->delay) total_delayed++;
380
}
381

382 383
/* get the default entry point for a given spec file */
static const char *get_default_entry_point( const DLLSPEC *spec )
384
{
385
    if (spec->characteristics & IMAGE_FILE_DLL) return "__wine_spec_dll_entry";
386
    if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "__wine_spec_drv_entry";
387 388
    return "__wine_spec_exe_entry";
}
389

390 391 392 393 394 395 396 397 398 399 400 401
/* check if the spec file exports any stubs */
static int has_stubs( const DLLSPEC *spec )
{
    int i;
    for (i = 0; i < spec->nb_entry_points; i++)
    {
        ORDDEF *odp = &spec->entry_points[i];
        if (odp->type == TYPE_STUB) return 1;
    }
    return 0;
}

402 403 404 405 406 407 408
/* add the extra undefined symbols that will be contained in the generated spec file itself */
static void add_extra_undef_symbols( DLLSPEC *spec )
{
    if (!spec->init_func) spec->init_func = xstrdup( get_default_entry_point(spec) );
    add_extra_ld_symbol( spec->init_func );
    if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
    if (nb_delayed) add_extra_ld_symbol( "__wine_spec_delay_load" );
409 410
}

411
/* check if a given imported dll is not needed, taking forwards into account */
412
static int check_unused( const struct import* imp, const DLLSPEC *spec )
413
{
414
    int i;
415 416 417 418
    const char *file_name = imp->spec->file_name;
    size_t len = strlen( file_name );
    const char *p = strchr( file_name, '.' );
    if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
419

420
    for (i = spec->base; i <= spec->limit; i++)
421
    {
422
        ORDDEF *odp = spec->ordinals[i];
423
        if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
424
        if (!strncasecmp( odp->link_name, file_name, len ) &&
425
            odp->link_name[len] == '.')
426
            return 0;  /* found a forward, it is used */
427
    }
428
    return 1;
429 430
}

431 432 433 434 435 436 437 438 439 440 441 442
/* flag the dll exports that link to an undefined symbol */
static void check_undefined_exports( DLLSPEC *spec )
{
    int i;

    for (i = 0; i < spec->nb_entry_points; i++)
    {
        ORDDEF *odp = &spec->entry_points[i];
        if (odp->type == TYPE_STUB) continue;
        if (odp->flags & FLAG_FORWARD) continue;
        if (find_name( odp->link_name, &undef_symbols ))
        {
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
            switch(odp->type)
            {
            case TYPE_PASCAL:
            case TYPE_STDCALL:
            case TYPE_CDECL:
            case TYPE_VARARGS:
                if (link_ext_symbols)
                {
                    odp->flags |= FLAG_EXT_LINK;
                    add_name( &ext_link_imports, odp->link_name );
                }
                else error( "%s:%d: function '%s' not defined\n",
                            spec->src_name, odp->lineno, odp->link_name );
                break;
            default:
                error( "%s:%d: external symbol '%s' is not a function\n",
                       spec->src_name, odp->lineno, odp->link_name );
                break;
            }
462 463 464 465 466 467 468
        }
    }
}

/* create a .o file that references all the undefined symbols we want to resolve */
static char *create_undef_symbols_file( DLLSPEC *spec )
{
469
    char *as_file, *obj_file;
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
    unsigned int i;
    FILE *f;

    as_file = get_temp_file_name( output_file_name, ".s" );
    if (!(f = fopen( as_file, "w" ))) fatal_error( "Cannot create %s\n", as_file );
    fprintf( f, "\t.data\n" );

    for (i = 0; i < spec->nb_entry_points; i++)
    {
        ORDDEF *odp = &spec->entry_points[i];
        if (odp->type == TYPE_STUB) continue;
        if (odp->flags & FLAG_FORWARD) continue;
        fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
    }
    for (i = 0; i < extra_ld_symbols.count; i++)
        fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.names[i]) );
    fclose( f );

    obj_file = get_temp_file_name( output_file_name, ".o" );
489
    assemble_file( as_file, obj_file );
490 491 492
    return obj_file;
}

493 494
/* combine a list of object files with ld into a single object file */
/* returns the name of the combined file */
495
static const char *ldcombine_files( DLLSPEC *spec, char **argv )
496
{
497
    unsigned int i, len = 0;
498
    char *cmd, *p, *ld_tmp_file, *undef_file;
499
    int err;
500

501 502
    undef_file = create_undef_symbols_file( spec );
    len += strlen(undef_file) + 1;
503
    ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
504
    if (!ld_command) ld_command = xstrdup("ld");
505
    for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
506
    cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command)  );
507
    p += sprintf( cmd, "%s -r -o %s %s", ld_command, ld_tmp_file, undef_file );
508 509
    for (i = 0; argv[i]; i++)
        p += sprintf( p, " %s", argv[i] );
510
    if (verbose) fprintf( stderr, "%s\n", cmd );
511
    err = system( cmd );
512
    if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
513 514 515 516
    free( cmd );
    return ld_tmp_file;
}

517
/* read in the list of undefined symbols */
518
void read_undef_symbols( DLLSPEC *spec, char **argv )
519
{
520
    size_t prefix_len;
521
    FILE *f;
522
    char *cmd, buffer[1024], name_prefix[16];
523
    int err;
524 525 526
    const char *name;

    if (!argv[0]) return;
527

528
    add_extra_undef_symbols( spec );
529

530
    strcpy( name_prefix, asm_name("") );
531 532
    prefix_len = strlen( name_prefix );

533
    name = ldcombine_files( spec, argv );
534

535
    if (!nm_command) nm_command = xstrdup("nm");
536 537 538 539
    cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
    sprintf( cmd, "%s -u %s", nm_command, name );
    if (!(f = popen( cmd, "r" )))
        fatal_error( "Cannot execute '%s'\n", cmd );
540 541 542 543 544 545

    while (fgets( buffer, sizeof(buffer), f ))
    {
        char *p = buffer + strlen(buffer) - 1;
        if (p < buffer) continue;
        if (*p == '\n') *p-- = 0;
546 547 548
        p = buffer;
        while (*p == ' ') p++;
        if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
549
        if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
550
        add_name( &undef_symbols, p );
551
    }
552 553
    if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
    free( cmd );
554 555 556
}

/* resolve the imports for a Win32 module */
557
int resolve_imports( DLLSPEC *spec )
558
{
559
    unsigned int i, j, removed;
560
    ORDDEF *odp;
561

562
    sort_names( &ignore_symbols );
563 564 565 566 567

    for (i = 0; i < nb_imports; i++)
    {
        struct import *imp = dll_imports[i];

568
        for (j = removed = 0; j < undef_symbols.count; j++)
569
        {
570 571
            if (find_name( undef_symbols.names[j], &ignore_symbols )) continue;
            odp = find_export( undef_symbols.names[j], imp->exports, imp->nb_exports );
572
            if (odp)
573
            {
574
                add_import_func( imp, odp );
575 576
                remove_name( &undef_symbols, j-- );
                removed++;
577 578
            }
        }
579
        if (!removed && check_unused( imp, spec ))
580 581
        {
            /* the dll is not used, get rid of it */
582
            warning( "%s imported but no symbols used\n", imp->spec->file_name );
583 584 585
            remove_import_dll( i );
            i--;
        }
586
    }
587 588 589 590

    sort_names( &undef_symbols );
    check_undefined_exports( spec );

591 592
    return 1;
}
593

594
/* output the get_pc thunk if needed */
595
void output_get_pc_thunk( FILE *outfile )
596 597 598 599 600 601 602 603 604 605 606 607 608
{
    if (target_cpu != CPU_x86) return;
    if (!UsePIC) return;
    fprintf( outfile, "\n\t.text\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(4) );
    fprintf( outfile, "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
    fprintf( outfile, "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
    fprintf( outfile, "\tpopl %%eax\n" );
    fprintf( outfile, "\tpushl %%eax\n" );
    fprintf( outfile, "\tret\n" );
    output_function_size( outfile, "__wine_spec_get_pc_thunk_eax" );
}

609 610 611
/* output a single import thunk */
static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
{
612 613
    fprintf( outfile, "\n\t.align %d\n", get_alignment(4) );
    fprintf( outfile, "\t%s\n", func_declaration(name) );
614
    fprintf( outfile, "%s\n", asm_globl(name) );
615

616
    switch(target_cpu)
617
    {
618 619
    case CPU_x86:
        if (!UsePIC)
620
        {
621
            fprintf( outfile, "\tjmp *(%s+%d)\n", table, pos );
622 623 624
        }
        else
        {
625 626
            fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
            fprintf( outfile, "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
627
        }
628
        break;
629 630 631
    case CPU_x86_64:
        fprintf( outfile, "\tjmpq *%s+%d(%%rip)\n", table, pos );
        break;
632 633 634
    case CPU_SPARC:
        if ( !UsePIC )
        {
635 636 637 638
            fprintf( outfile, "\tsethi %%hi(%s+%d), %%g1\n", table, pos );
            fprintf( outfile, "\tld [%%g1+%%lo(%s+%d)], %%g1\n", table, pos );
            fprintf( outfile, "\tjmp %%g1\n" );
            fprintf( outfile, "\tnop\n" );
639 640 641 642 643
        }
        else
        {
            /* Hmpf.  Stupid sparc assembler always interprets global variable
               names as GOT offsets, so we have to do it the long way ... */
644 645 646 647 648 649 650 651
            fprintf( outfile, "\tsave %%sp, -96, %%sp\n" );
            fprintf( outfile, "0:\tcall 1f\n" );
            fprintf( outfile, "\tnop\n" );
            fprintf( outfile, "1:\tsethi %%hi(%s+%d-0b), %%g1\n", table, pos );
            fprintf( outfile, "\tor %%g1, %%lo(%s+%d-0b), %%g1\n", table, pos );
            fprintf( outfile, "\tld [%%g1+%%o7], %%g1\n" );
            fprintf( outfile, "\tjmp %%g1\n" );
            fprintf( outfile, "\trestore\n" );
652 653 654
        }
        break;
    case CPU_ALPHA:
655 656 657
        fprintf( outfile, "\tlda $0,%s\n", table );
        fprintf( outfile, "\tlda $0,%d($0)\n", pos );
        fprintf( outfile, "\tjmp $31,($0)\n" );
658 659
        break;
    case CPU_POWERPC:
660 661 662 663 664 665
        fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
        fprintf( outfile, "\tstw  %s, 0(%s)\n",    ppc_reg(9), ppc_reg(1) );
        fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
        fprintf( outfile, "\tstw  %s, 0(%s)\n",    ppc_reg(8), ppc_reg(1) );
        fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
        fprintf( outfile, "\tstw  %s, 0(%s)\n",    ppc_reg(7), ppc_reg(1) );
666 667
        if (target_platform == PLATFORM_APPLE)
        {
668 669
            fprintf( outfile, "\tlis %s, ha16(%s+%d)\n", ppc_reg(9), table, pos );
            fprintf( outfile, "\tla  %s, lo16(%s+%d)(%s)\n", ppc_reg(8), table, pos, ppc_reg(9) );
670 671 672
        }
        else
        {
673
            fprintf( outfile, "\tlis %s, (%s+%d)@h\n", ppc_reg(9), table, pos );
674
            fprintf( outfile, "\tla  %s, (%s+%d)@l(%s)\n", ppc_reg(8), table, pos, ppc_reg(9) );
675
        }
676 677 678 679 680 681 682 683 684
        fprintf( outfile, "\tlwz  %s, 0(%s)\n", ppc_reg(7), ppc_reg(8) );
        fprintf( outfile, "\tmtctr %s\n", ppc_reg(7) );
        fprintf( outfile, "\tlwz  %s, 0(%s)\n",   ppc_reg(7), ppc_reg(1) );
        fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
        fprintf( outfile, "\tlwz  %s, 0(%s)\n",   ppc_reg(8), ppc_reg(1) );
        fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
        fprintf( outfile, "\tlwz  %s, 0(%s)\n",   ppc_reg(9), ppc_reg(1) );
        fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
        fprintf( outfile, "\tbctr\n" );
685
        break;
686 687 688 689
    }
    output_function_size( outfile, name );
}

690 691
/* check if we need an import directory */
int has_imports(void)
692
{
693
    return (nb_imports - nb_delayed) > 0;
694 695 696 697 698 699 700 701 702 703
}

/* output the import table of a Win32 module */
static void output_immediate_imports( FILE *outfile )
{
    int i, j;
    const char *dll_name;

    if (nb_imports == nb_delayed) return;  /* no immediate imports */

704 705
    /* main import header */

706 707 708 709
    fprintf( outfile, "\n/* import table */\n" );
    fprintf( outfile, "\n\t.data\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(4) );
    fprintf( outfile, ".L__wine_spec_imports:\n" );
710 711 712 713 714

    /* list of dlls */

    for (i = j = 0; i < nb_imports; i++)
    {
715
        if (dll_imports[i]->delay) continue;
716
        dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
717 718 719
        fprintf( outfile, "\t.long 0\n" );     /* OriginalFirstThunk */
        fprintf( outfile, "\t.long 0\n" );     /* TimeDateStamp */
        fprintf( outfile, "\t.long 0\n" );     /* ForwarderChain */
720 721 722
        fprintf( outfile, "\t.long .L__wine_spec_import_name_%s-.L__wine_spec_rva_base\n", /* Name */
                 dll_name );
        fprintf( outfile, "\t.long .L__wine_spec_import_data_ptrs+%d-.L__wine_spec_rva_base\n",  /* FirstThunk */
723
                 j * get_ptr_size() );
724 725
        j += dll_imports[i]->nb_imports + 1;
    }
726 727 728 729 730 731 732 733
    fprintf( outfile, "\t.long 0\n" );     /* OriginalFirstThunk */
    fprintf( outfile, "\t.long 0\n" );     /* TimeDateStamp */
    fprintf( outfile, "\t.long 0\n" );     /* ForwarderChain */
    fprintf( outfile, "\t.long 0\n" );     /* Name */
    fprintf( outfile, "\t.long 0\n" );     /* FirstThunk */

    fprintf( outfile, "\n\t.align %d\n", get_alignment(get_ptr_size()) );
    fprintf( outfile, ".L__wine_spec_import_data_ptrs:\n" );
734 735 736 737 738 739 740 741
    for (i = 0; i < nb_imports; i++)
    {
        if (dll_imports[i]->delay) continue;
        dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
        for (j = 0; j < dll_imports[i]->nb_imports; j++)
        {
            ORDDEF *odp = dll_imports[i]->imports[j];
            if (!(odp->flags & FLAG_NONAME))
742
                fprintf( outfile, "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
743
                         get_asm_ptr_keyword(), dll_name, odp->name );
744
            else
745 746 747 748 749 750
            {
                if (get_ptr_size() == 8)
                    fprintf( outfile, "\t.quad 0x800000000000%04x\n", odp->ordinal );
                else
                    fprintf( outfile, "\t.long 0x8000%04x\n", odp->ordinal );
            }
751
        }
752
        fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
753
    }
754
    fprintf( outfile, ".L__wine_spec_imports_end:\n" );
755 756 757

    for (i = 0; i < nb_imports; i++)
    {
758
        if (dll_imports[i]->delay) continue;
759
        dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
760
        for (j = 0; j < dll_imports[i]->nb_imports; j++)
761
        {
762 763
            ORDDEF *odp = dll_imports[i]->imports[j];
            if (!(odp->flags & FLAG_NONAME))
764
            {
765 766 767 768
                fprintf( outfile, "\t.align %d\n", get_alignment(2) );
                fprintf( outfile, ".L__wine_spec_import_data_%s_%s:\n", dll_name, odp->name );
                fprintf( outfile, "\t%s %d\n", get_asm_short_keyword(), odp->ordinal );
                fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name );
769
            }
770
        }
771 772
    }

773 774 775 776
    for (i = 0; i < nb_imports; i++)
    {
        if (dll_imports[i]->delay) continue;
        dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
777
        fprintf( outfile, ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
778 779
                 dll_name, get_asm_string_keyword(), dll_imports[i]->spec->file_name );
    }
780 781 782 783 784 785 786 787 788 789
}

/* output the import thunks of a Win32 module */
static void output_immediate_import_thunks( FILE *outfile )
{
    int i, j, pos;
    int nb_imm = nb_imports - nb_delayed;
    static const char import_thunks[] = "__wine_spec_import_thunks";

    if (!nb_imm) return;
790

791 792 793 794
    fprintf( outfile, "\n/* immediate import thunks */\n\n" );
    fprintf( outfile, "\t.text\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(8) );
    fprintf( outfile, "%s:\n", asm_name(import_thunks));
795

796
    for (i = pos = 0; i < nb_imports; i++)
797
    {
798
        if (dll_imports[i]->delay) continue;
799
        for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size())
800
        {
801
            ORDDEF *odp = dll_imports[i]->imports[j];
802
            output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
803
                                 ".L__wine_spec_import_data_ptrs", pos );
804
        }
805
        pos += get_ptr_size();
806
    }
807
    output_function_size( outfile, import_thunks );
808 809 810
}

/* output the delayed import table of a Win32 module */
811
static void output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
812
{
813
    int i, j, mod;
814

815
    if (!nb_delayed) return;
816

817 818 819
    fprintf( outfile, "\n/* delayed imports */\n\n" );
    fprintf( outfile, "\t.data\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
820
    fprintf( outfile, "%s\n", asm_globl("__wine_spec_delay_imports") );
821 822 823

    /* list of dlls */

824
    for (i = j = mod = 0; i < nb_imports; i++)
825 826
    {
        if (!dll_imports[i]->delay) continue;
827 828
        fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* grAttrs */
        fprintf( outfile, "\t%s .L__wine_delay_name_%d\n",       /* szName */
829
                 get_asm_ptr_keyword(), i );
830
        fprintf( outfile, "\t%s .L__wine_delay_modules+%d\n",    /* phmod */
831
                 get_asm_ptr_keyword(), mod * get_ptr_size() );
832
        fprintf( outfile, "\t%s .L__wine_delay_IAT+%d\n",        /* pIAT */
833
                 get_asm_ptr_keyword(), j * get_ptr_size() );
834
        fprintf( outfile, "\t%s .L__wine_delay_INT+%d\n",        /* pINT */
835
                 get_asm_ptr_keyword(), j * get_ptr_size() );
836 837 838
        fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* pBoundIAT */
        fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* pUnloadIAT */
        fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* dwTimeStamp */
839
        j += dll_imports[i]->nb_imports;
840
        mod++;
841
    }
842 843 844 845 846 847 848 849 850 851
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* grAttrs */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* szName */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* phmod */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* pIAT */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* pINT */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* pBoundIAT */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* pUnloadIAT */
    fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );   /* dwTimeStamp */

    fprintf( outfile, "\n.L__wine_delay_IAT:\n" );
852 853 854 855 856
    for (i = 0; i < nb_imports; i++)
    {
        if (!dll_imports[i]->delay) continue;
        for (j = 0; j < dll_imports[i]->nb_imports; j++)
        {
857 858
            ORDDEF *odp = dll_imports[i]->imports[j];
            const char *name = odp->name ? odp->name : odp->export_name;
859
            fprintf( outfile, "\t%s .L__wine_delay_imp_%d_%s\n",
860
                     get_asm_ptr_keyword(), i, name );
861 862
        }
    }
863

864
    fprintf( outfile, "\n.L__wine_delay_INT:\n" );
865 866 867 868 869
    for (i = 0; i < nb_imports; i++)
    {
        if (!dll_imports[i]->delay) continue;
        for (j = 0; j < dll_imports[i]->nb_imports; j++)
        {
870
            ORDDEF *odp = dll_imports[i]->imports[j];
871
            if (!odp->name)
872
                fprintf( outfile, "\t%s %d\n", get_asm_ptr_keyword(), odp->ordinal );
873
            else
874
                fprintf( outfile, "\t%s .L__wine_delay_data_%d_%s\n",
875
                         get_asm_ptr_keyword(), i, odp->name );
876 877
        }
    }
878

879
    fprintf( outfile, "\n.L__wine_delay_modules:\n" );
880 881
    for (i = 0; i < nb_imports; i++)
    {
882
        if (dll_imports[i]->delay) fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
883 884 885 886 887
    }

    for (i = 0; i < nb_imports; i++)
    {
        if (!dll_imports[i]->delay) continue;
888 889
        fprintf( outfile, ".L__wine_delay_name_%d:\n", i );
        fprintf( outfile, "\t%s \"%s\"\n",
890 891 892
                 get_asm_string_keyword(), dll_imports[i]->spec->file_name );
    }

893 894 895 896 897
    for (i = 0; i < nb_imports; i++)
    {
        if (!dll_imports[i]->delay) continue;
        for (j = 0; j < dll_imports[i]->nb_imports; j++)
        {
898
            ORDDEF *odp = dll_imports[i]->imports[j];
899
            if (!odp->name) continue;
900 901
            fprintf( outfile, ".L__wine_delay_data_%d_%s:\n", i, odp->name );
            fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name );
902 903
        }
    }
904
    output_function_size( outfile, "__wine_spec_delay_imports" );
905 906 907 908 909
}

/* output the delayed import thunks of a Win32 module */
static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
{
910
    int i, idx, j, pos, extra_stack_storage = 0;
911 912
    static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
    static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
913

914
    if (!nb_delayed) return;
915

916 917 918 919 920 921
    fprintf( outfile, "\n/* delayed import thunks */\n\n" );
    fprintf( outfile, "\t.text\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(8) );
    fprintf( outfile, "%s:\n", asm_name(delayed_import_loaders));
    fprintf( outfile, "\t%s\n", func_declaration("__wine_delay_load_asm") );
    fprintf( outfile, "%s:\n", asm_name("__wine_delay_load_asm") );
922 923 924
    switch(target_cpu)
    {
    case CPU_x86:
925 926 927 928 929 930 931
        fprintf( outfile, "\tpushl %%ecx\n" );
        fprintf( outfile, "\tpushl %%edx\n" );
        fprintf( outfile, "\tpushl %%eax\n" );
        fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
        fprintf( outfile, "\tpopl %%edx\n" );
        fprintf( outfile, "\tpopl %%ecx\n" );
        fprintf( outfile, "\tjmp *%%eax\n" );
932
        break;
933 934 935 936 937 938 939 940 941
    case CPU_x86_64:
        fprintf( outfile, "\tpushq %%rdi\n" );
        fprintf( outfile, "\tsubq $8,%%rsp\n" );
        fprintf( outfile, "\tmovq %%r11,%%rdi\n" );
        fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
        fprintf( outfile, "\taddq $8,%%rsp\n" );
        fprintf( outfile, "\tpopq %%rdi\n" );
        fprintf( outfile, "\tjmp *%%rax\n" );
        break;
942
    case CPU_SPARC:
943 944 945 946 947
        fprintf( outfile, "\tsave %%sp, -96, %%sp\n" );
        fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
        fprintf( outfile, "\tmov %%g1, %%o0\n" );
        fprintf( outfile, "\tjmp %%o0\n" );
        fprintf( outfile, "\trestore\n" );
948 949
        break;
    case CPU_ALPHA:
950 951
        fprintf( outfile, "\tjsr $26,%s\n", asm_name("__wine_spec_delay_load") );
        fprintf( outfile, "\tjmp $31,($0)\n" );
952 953 954 955 956
        break;
    case CPU_POWERPC:
        if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;

        /* Save all callee saved registers into a stackframe. */
957 958 959 960 961 962 963 964 965 966 967
        fprintf( outfile, "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(3),  4+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(4),  8+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
968 969

        /* r0 -> r3 (arg1) */
970
        fprintf( outfile, "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
971 972

        /* save return address */
973 974
        fprintf( outfile, "\tmflr %s\n", ppc_reg(0));
        fprintf( outfile, "\tstw  %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
975 976

        /* Call the __wine_delay_load function, arg1 is arg1. */
977
        fprintf( outfile, "\tbl %s\n", asm_name("__wine_spec_delay_load") );
978 979

        /* Load return value from call into ctr register */
980
        fprintf( outfile, "\tmtctr %s\n", ppc_reg(3));
981 982

        /* restore all saved registers and drop stackframe. */
983 984 985 986 987 988 989 990 991 992
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(3),  4+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(4),  8+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tlwz  %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
993 994

        /* Load return value from call into return register */
995 996 997
        fprintf( outfile, "\tlwz  %s,  %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
        fprintf( outfile, "\tmtlr %s\n", ppc_reg(0));
        fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1),  48+extra_stack_storage);
998 999

        /* branch to ctr register. */
1000
        fprintf( outfile, "\tbctr\n");
1001 1002
        break;
    }
1003
    output_function_size( outfile, "__wine_delay_load_asm" );
1004
    fprintf( outfile, "\n" );
1005

1006 1007 1008
    for (i = idx = 0; i < nb_imports; i++)
    {
        if (!dll_imports[i]->delay) continue;
1009 1010
        for (j = 0; j < dll_imports[i]->nb_imports; j++)
        {
1011 1012 1013
            ORDDEF *odp = dll_imports[i]->imports[j];
            const char *name = odp->name ? odp->name : odp->export_name;

1014
            fprintf( outfile, ".L__wine_delay_imp_%d_%s:\n", i, name );
1015 1016 1017
            switch(target_cpu)
            {
            case CPU_x86:
1018 1019
                fprintf( outfile, "\tmovl $%d, %%eax\n", (idx << 16) | j );
                fprintf( outfile, "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1020
                break;
1021 1022 1023 1024
            case CPU_x86_64:
                fprintf( outfile, "\tmovq $%d,%%r11\n", (idx << 16) | j );
                fprintf( outfile, "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
                break;
1025
            case CPU_SPARC:
1026 1027
                fprintf( outfile, "\tset %d, %%g1\n", (idx << 16) | j );
                fprintf( outfile, "\tb,a %s\n", asm_name("__wine_delay_load_asm") );
1028 1029
                break;
            case CPU_ALPHA:
1030 1031 1032
                fprintf( outfile, "\tlda $0,%d($31)\n", j);
                fprintf( outfile, "\tldah $0,%d($0)\n", idx);
                fprintf( outfile, "\tjmp $31,%s\n", asm_name("__wine_delay_load_asm") );
1033 1034 1035 1036 1037 1038 1039
                break;
            case CPU_POWERPC:
                switch(target_platform)
                {
                case PLATFORM_APPLE:
                    /* On Darwin we can use r0 and r2 */
                    /* Upper part in r2 */
1040
                    fprintf( outfile, "\tlis %s, %d\n", ppc_reg(2), idx);
1041
                    /* Lower part + r2 -> r0, Note we can't use r0 directly */
1042 1043
                    fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
                    fprintf( outfile, "\tb %s\n", asm_name("__wine_delay_load_asm") );
1044 1045 1046 1047
                    break;
                default:
                    /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
                    /* Save r13 on the stack */
1048 1049
                    fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
                    fprintf( outfile, "\tstw  %s, 0(%s)\n",    ppc_reg(13), ppc_reg(1));
1050
                    /* Upper part in r13 */
1051
                    fprintf( outfile, "\tlis %s, %d\n", ppc_reg(13), idx);
1052
                    /* Lower part + r13 -> r0, Note we can't use r0 directly */
1053
                    fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
1054
                    /* Restore r13 */
1055 1056 1057
                    fprintf( outfile, "\tstw  %s, 0(%s)\n",    ppc_reg(13), ppc_reg(1));
                    fprintf( outfile, "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
                    fprintf( outfile, "\tb %s\n", asm_name("__wine_delay_load_asm") );
1058 1059 1060 1061
                    break;
                }
                break;
            }
1062 1063 1064
        }
        idx++;
    }
1065
    output_function_size( outfile, delayed_import_loaders );
1066

1067 1068
    fprintf( outfile, "\n\t.align %d\n", get_alignment(get_ptr_size()) );
    fprintf( outfile, "%s:\n", asm_name(delayed_import_thunks));
1069
    for (i = pos = 0; i < nb_imports; i++)
1070 1071
    {
        if (!dll_imports[i]->delay) continue;
1072
        for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size())
1073
        {
1074
            ORDDEF *odp = dll_imports[i]->imports[j];
1075
            output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1076
                                 ".L__wine_delay_IAT", pos );
1077 1078
        }
    }
1079
    output_function_size( outfile, delayed_import_thunks );
1080 1081
}

1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
/* output import stubs for exported entry points that link to external symbols */
static void output_external_link_imports( FILE *outfile, DLLSPEC *spec )
{
    unsigned int i, pos;

    if (!ext_link_imports.count) return;  /* nothing to do */

    sort_names( &ext_link_imports );

    /* get rid of duplicate names */
    for (i = 1; i < ext_link_imports.count; i++)
    {
        if (!strcmp( ext_link_imports.names[i-1], ext_link_imports.names[i] ))
            remove_name( &ext_link_imports, i-- );
    }

    fprintf( outfile, "\n/* external link thunks */\n\n" );
    fprintf( outfile, "\t.data\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
    fprintf( outfile, ".L__wine_spec_external_links:\n" );
    for (i = 0; i < ext_link_imports.count; i++)
        fprintf( outfile, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.names[i]) );

    fprintf( outfile, "\n\t.text\n" );
    fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
    fprintf( outfile, "%s:\n", asm_name("__wine_spec_external_link_thunks") );

    for (i = pos = 0; i < ext_link_imports.count; i++)
    {
        char buffer[256];
        sprintf( buffer, "__wine_spec_ext_link_%s", ext_link_imports.names[i] );
        output_import_thunk( outfile, buffer, ".L__wine_spec_external_links", pos );
        pos += get_ptr_size();
    }
    output_function_size( outfile, "__wine_spec_external_link_thunks" );
}

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
/*******************************************************************
 *         output_stubs
 *
 * Output the functions for stub entry points
 */
void output_stubs( FILE *outfile, DLLSPEC *spec )
{
    const char *name, *exp_name;
    int i, pos;

    if (!has_stubs( spec )) return;

    fprintf( outfile, "\n/* stub functions */\n\n" );
    fprintf( outfile, "\t.text\n" );

    for (i = pos = 0; i < spec->nb_entry_points; i++)
    {
        ORDDEF *odp = &spec->entry_points[i];
        if (odp->type != TYPE_STUB) continue;

        name = get_stub_name( odp, spec );
        exp_name = odp->name ? odp->name : odp->export_name;
        fprintf( outfile, "\t.align %d\n", get_alignment(4) );
        fprintf( outfile, "\t%s\n", func_declaration(name) );
        fprintf( outfile, "%s:\n", asm_name(name) );
1144
        fprintf( outfile, "\tsubl $4,%%esp\n" );
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172

        if (UsePIC)
        {
            fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
            fprintf( outfile, "1:" );
            if (exp_name)
            {
                fprintf( outfile, "\tleal .L__wine_stub_strings+%d-1b(%%eax),%%ecx\n", pos );
                fprintf( outfile, "\tpushl %%ecx\n" );
                pos += strlen(exp_name) + 1;
            }
            else
                fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
            fprintf( outfile, "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
            fprintf( outfile, "\tpushl %%ecx\n" );
        }
        else
        {
            if (exp_name)
            {
                fprintf( outfile, "\tpushl $.L__wine_stub_strings+%d\n", pos );
                pos += strlen(exp_name) + 1;
            }
            else
                fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
            fprintf( outfile, "\tpushl $.L__wine_spec_file_name\n" );
        }
        fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1173
        output_function_size( outfile, name );
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    }

    if (pos)
    {
        fprintf( outfile, "\t%s\n", get_asm_string_section() );
        fprintf( outfile, ".L__wine_stub_strings:\n" );
        for (i = 0; i < spec->nb_entry_points; i++)
        {
            ORDDEF *odp = &spec->entry_points[i];
            if (odp->type != TYPE_STUB) continue;
            exp_name = odp->name ? odp->name : odp->export_name;
            if (exp_name)
                fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
        }
    }
}

1191 1192
/* output the import and delayed import tables of a Win32 module */
void output_imports( FILE *outfile, DLLSPEC *spec )
1193
{
1194
    output_immediate_imports( outfile );
1195
    output_delayed_imports( outfile, spec );
1196
    output_immediate_import_thunks( outfile );
1197
    output_delayed_import_thunks( outfile, spec );
1198
    output_external_link_imports( outfile, spec );
1199 1200
    if (nb_imports || ext_link_imports.count || has_stubs(spec) || has_relays(spec))
        output_get_pc_thunk( outfile );
1201
}