import.c 52 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
#include "wine/list.h"
39 40
#include "build.h"

41 42 43 44 45 46 47
struct import_func
{
    const char *name;
    const char *export_name;
    int         ordinal;
};

48 49
struct import
{
50 51 52 53 54 55 56 57 58 59 60
    struct list         entry;       /* entry in global dll list */
    char               *dll_name;    /* exported file name of the dll */
    char               *c_name;      /* dll name as a C-compatible identifier */
    char               *full_name;   /* full name of the input file */
    dev_t               dev;         /* device/inode of the input file */
    ino_t               ino;
    ORDDEF            **exports;     /* functions exported from this dll */
    int                 nb_exports;  /* number of exported functions */
    struct import_func *imports;     /* functions we want to import from this dll */
    int                 nb_imports;  /* number of imported functions */
    int                 max_imports; /* size of imports array */
61 62
};

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

68
static struct list dll_imports = LIST_INIT( dll_imports );
69
static struct list dll_delayed = LIST_INIT( dll_delayed );
70

71 72 73 74
static struct strarray as_files;

static const char import_func_prefix[] = "__wine$func$";
static const char import_ord_prefix[]  = "__wine$ord$";
75 76 77 78 79 80 81 82 83 84

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' */
}
85

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

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

101
/* remove a name from a name table */
102
static inline void remove_name( struct strarray *table, unsigned int idx )
103 104
{
    assert( idx < table->count );
105 106
    memmove( table->str + idx, table->str + idx + 1,
             (table->count - idx - 1) * sizeof(*table->str) );
107 108 109 110
    table->count--;
}

/* locate a name in a (sorted) list */
111
static inline const char *find_name( const char *name, const struct strarray *table )
112 113 114
{
    char **res = NULL;

115
    if (table->count) res = bsearch( &name, table->str, table->count, sizeof(*table->str), name_cmp );
116 117 118
    return res ? *res : NULL;
}

119
/* sort a name table */
120
static inline void sort_names( struct strarray *table )
121
{
122
    if (table->count) qsort( table->str, table->count, sizeof(*table->str), name_cmp );
123 124
}

125
/* locate an export in a (sorted) export list */
126
static inline ORDDEF *find_export( const char *name, ORDDEF **table, int size )
127
{
128
    ORDDEF func, *odp, **res = NULL;
129

130
    func.name = xstrdup(name);
131
    func.ordinal = -1;
132 133
    odp = &func;
    if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
134
    free( func.name );
135
    return res ? *res : NULL;
136 137
}

138 139 140 141 142
/* free an import structure */
static void free_imports( struct import *imp )
{
    free( imp->exports );
    free( imp->imports );
143
    free( imp->dll_name );
144
    free( imp->c_name );
145
    free( imp->full_name );
146 147 148
    free( imp );
}

149 150 151
/* check whether a given dll is imported in delayed mode */
static int is_delayed_import( const char *name )
{
152
    unsigned int i;
153

154
    for (i = 0; i < delayed_imports.count; i++)
155
    {
156
        if (!strcmp( delayed_imports.str[i], name )) return 1;
157 158 159 160
    }
    return 0;
}

161 162
/* find an imported dll from its name */
static struct import *find_import_dll( const char *name )
163
{
164
    struct import *import;
165

166
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
167
        if (!strcasecmp( import->dll_name, name )) return import;
168
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
169
        if (!strcasecmp( import->dll_name, name )) return import;
170
    return NULL;
171 172
}

173 174 175
/* open the .so library for a given dll in a specified path */
static char *try_library_path( const char *path, const char *name )
{
176
    char *buffer;
177 178
    int fd;

179
    buffer = strmake( "%s/lib%s.def", path, name );
180

181
    /* check if the file exists */
182 183 184 185 186 187 188
    if ((fd = open( buffer, O_RDONLY )) != -1)
    {
        close( fd );
        return buffer;
    }
    free( buffer );
    return NULL;
189 190
}

191 192
/* find the .def import library for a given dll */
static char *find_library( const char *name )
193 194
{
    char *fullname;
195
    unsigned int i;
196

197
    for (i = 0; i < lib_path.count; i++)
198
    {
199
        if ((fullname = try_library_path( lib_path.str[i], name ))) return fullname;
200
    }
201 202
    fatal_error( "could not open .def file for %s\n", name );
    return NULL;
203 204
}

205
/* read in the list of exported symbols of an import library */
206
static DLLSPEC *read_import_lib( struct import *imp )
207 208
{
    FILE *f;
209
    int i;
210 211
    struct stat stat;
    struct import *prev_imp;
212
    DLLSPEC *spec = alloc_dll_spec();
213

214 215 216 217
    f = open_input_file( NULL, imp->full_name );
    fstat( fileno(f), &stat );
    imp->dev = stat.st_dev;
    imp->ino = stat.st_ino;
218
    if (!parse_def_file( f, spec )) exit( 1 );
219
    close_input_file( f );
220 221

    /* check if we already imported that library from a different file */
222
    if ((prev_imp = find_import_dll( spec->file_name )))
223 224 225 226
    {
        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 );
227 228
        free_dll_spec( spec );
        return NULL;  /* the same file was already loaded, ignore this one */
229
    }
230

231
    if (spec->nb_entry_points)
232
    {
233 234 235
        imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
        for (i = 0; i < spec->nb_entry_points; i++)
            imp->exports[imp->nb_exports++] = &spec->entry_points[i];
236
        qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
237
    }
238
    return spec;
239 240
}

241 242
/* build the dll exported name from the import lib name or path */
static char *get_dll_name( const char *name, const char *filename )
243
{
244
    char *ret;
245

246 247 248 249 250 251 252 253 254 255 256
    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
257
    {
258 259
        ret = xmalloc( strlen(name) + 5 );
        strcpy( ret, name );
260
    }
261 262 263 264 265 266 267
    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 )
{
268 269
    DLLSPEC *spec;
    char *dll_name = get_dll_name( name, filename );
270
    struct import *imp = xmalloc( sizeof(*imp) );
271

272
    memset( imp, 0, sizeof(*imp) );
273 274 275

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

277
    if (!(spec = read_import_lib( imp )))
278
    {
279 280
        free_imports( imp );
        return;
281
    }
282 283

    imp->dll_name = spec->file_name ? spec->file_name : dll_name;
284
    imp->c_name = make_c_identifier( imp->dll_name );
285 286

    if (is_delayed_import( dll_name ))
287 288 289
        list_add_tail( &dll_delayed, &imp->entry );
    else
        list_add_tail( &dll_imports, &imp->entry );
290 291
}

292 293 294 295 296 297
/* 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 );

298
    strarray_add( &delayed_imports, fullname, NULL );
299
    if ((imp = find_import_dll( fullname )))
300
    {
301 302
        list_remove( &imp->entry );
        list_add_tail( &dll_delayed, &imp->entry );
303 304 305
    }
}

306 307 308
/* add a symbol to the list of extra symbols that ld must resolve */
void add_extra_ld_symbol( const char *name )
{
309
    strarray_add( &extra_ld_symbols, name, NULL );
310 311
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
/* retrieve an imported dll, adding one if necessary */
struct import *add_static_import_dll( const char *name )
{
    struct import *import;
    char *dll_name = get_dll_name( name, NULL );

    if ((import = find_import_dll( dll_name ))) return import;

    import = xmalloc( sizeof(*import) );
    memset( import, 0, sizeof(*import) );

    import->dll_name = dll_name;
    import->full_name = xstrdup( dll_name );
    import->c_name = make_c_identifier( dll_name );

    if (is_delayed_import( dll_name ))
        list_add_tail( &dll_delayed, &import->entry );
    else
        list_add_tail( &dll_imports, &import->entry );
    return import;
}

334
/* add a function to the list of imports from a given dll */
335
static void add_import_func( struct import *imp, const char *name, const char *export_name, int ordinal )
336
{
337 338 339 340 341 342 343 344 345 346
    if (imp->nb_imports == imp->max_imports)
    {
        imp->max_imports *= 2;
        if (imp->max_imports < 32) imp->max_imports = 32;
        imp->imports = xrealloc( imp->imports, imp->max_imports * sizeof(*imp->imports) );
    }
    imp->imports[imp->nb_imports].name = name;
    imp->imports[imp->nb_imports].export_name = export_name;
    imp->imports[imp->nb_imports].ordinal = ordinal;
    imp->nb_imports++;
347
}
348

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
/* add an import for an undefined function of the form __wine$func$ */
static void add_undef_import( const char *name, int is_ordinal )
{
    char *p, *dll_name = xstrdup( name );
    int ordinal = 0;
    struct import *import;

    if (!(p = strchr( dll_name, '$' ))) return;
    *p++ = 0;
    while (*p >= '0' && *p <= '9') ordinal = 10 * ordinal + *p++ - '0';
    if (*p != '$') return;
    p++;

    import = add_static_import_dll( dll_name );
    if (is_ordinal)
        add_import_func( import, NULL, xstrdup( p ), ordinal );
    else
        add_import_func( import, xstrdup( p ), NULL, ordinal );
}

369 370
/* get the default entry point for a given spec file */
static const char *get_default_entry_point( const DLLSPEC *spec )
371
{
372
    if (spec->characteristics & IMAGE_FILE_DLL) return "__wine_spec_dll_entry";
373
    if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "__wine_spec_drv_entry";
374
    if (spec->type == SPEC_WIN16) return "__wine_spec_exe16_entry";
375 376
    return "__wine_spec_exe_entry";
}
377

378 379 380 381 382 383 384 385 386 387 388 389
/* 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;
}

390 391 392 393 394 395
/* 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" );
396
    if (delayed_imports.count) add_extra_ld_symbol( "__wine_spec_delay_load" );
397 398
}

399
/* check if a given imported dll is not needed, taking forwards into account */
400
static int check_unused( const struct import* imp, const DLLSPEC *spec )
401
{
402
    int i;
403
    const char *file_name = imp->dll_name;
404 405 406
    size_t len = strlen( file_name );
    const char *p = strchr( file_name, '.' );
    if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
407

408
    for (i = spec->base; i <= spec->limit; i++)
409
    {
410
        ORDDEF *odp = spec->ordinals[i];
411
        if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
412
        if (!strncasecmp( odp->link_name, file_name, len ) &&
413
            odp->link_name[len] == '.')
414
            return 0;  /* found a forward, it is used */
415
    }
416
    return 1;
417 418
}

419
/* check if a given forward does exist in one of the imported dlls */
420
static void check_undefined_forwards( DLLSPEC *spec )
421
{
422
    struct import *imp;
423
    char *link_name, *api_name, *dll_name, *p;
424
    int i;
425

426 427 428
    for (i = 0; i < spec->nb_entry_points; i++)
    {
        ORDDEF *odp = &spec->entry_points[i];
429

430
        if (!(odp->flags & FLAG_FORWARD)) continue;
431

432 433 434 435 436
        link_name = xstrdup( odp->link_name );
        p = strrchr( link_name, '.' );
        *p = 0;
        api_name = p + 1;
        dll_name = get_dll_name( link_name, NULL );
437

438
        if ((imp = find_import_dll( dll_name )))
439
        {
440 441
            if (!find_export( api_name, imp->exports, imp->nb_exports ))
                warning( "%s:%d: forward '%s' not found in %s\n",
442
                         spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
443
        }
444 445
        else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
                      spec->src_name, odp->lineno, odp->link_name );
446 447
        free( link_name );
        free( dll_name );
448 449 450
    }
}

451 452 453 454 455 456 457 458
/* 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];
459
        if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
460
        if (odp->flags & FLAG_FORWARD) continue;
461 462
        if (find_name( odp->link_name, &undef_symbols ))
        {
463 464 465 466 467 468
            switch(odp->type)
            {
            case TYPE_PASCAL:
            case TYPE_STDCALL:
            case TYPE_CDECL:
            case TYPE_VARARGS:
469
            case TYPE_THISCALL:
470 471 472
                if (link_ext_symbols)
                {
                    odp->flags |= FLAG_EXT_LINK;
473
                    strarray_add( &ext_link_imports, odp->link_name, NULL );
474 475 476 477 478 479 480 481 482
                }
                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;
            }
483 484 485 486 487 488 489
        }
    }
}

/* create a .o file that references all the undefined symbols we want to resolve */
static char *create_undef_symbols_file( DLLSPEC *spec )
{
490
    char *as_file, *obj_file;
491 492
    int i;
    unsigned int j;
493 494 495 496 497 498 499 500 501
    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];
502
        if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
503 504 505
        if (odp->flags & FLAG_FORWARD) continue;
        fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
    }
506
    for (j = 0; j < extra_ld_symbols.count; j++)
507
        fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
508 509 510
    fclose( f );

    obj_file = get_temp_file_name( output_file_name, ".o" );
511
    assemble_file( as_file, obj_file );
512 513 514
    return obj_file;
}

515 516
/* combine a list of object files with ld into a single object file */
/* returns the name of the combined file */
517
static const char *ldcombine_files( DLLSPEC *spec, char **argv )
518
{
519
    char *ld_tmp_file, *undef_file;
520
    struct strarray args = get_ld_command();
521

522
    undef_file = create_undef_symbols_file( spec );
523
    ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
524

525 526
    strarray_add( &args, "-r", "-o", ld_tmp_file, undef_file, NULL );
    strarray_addv( &args, argv );
527
    spawn( args );
528 529 530
    return ld_tmp_file;
}

531
/* read in the list of undefined symbols */
532
void read_undef_symbols( DLLSPEC *spec, char **argv )
533
{
534
    size_t prefix_len;
535
    FILE *f;
536
    const char *prog = get_nm_command();
537
    char *cmd, buffer[1024], name_prefix[16];
538
    int err;
539 540 541
    const char *name;

    if (!argv[0]) return;
542

543
    add_extra_undef_symbols( spec );
544

545
    strcpy( name_prefix, asm_name("") );
546 547
    prefix_len = strlen( name_prefix );

548
    name = ldcombine_files( spec, argv );
549

550
    cmd = strmake( "%s -u %s", prog, name );
551 552
    if (!(f = popen( cmd, "r" )))
        fatal_error( "Cannot execute '%s'\n", cmd );
553 554 555 556 557 558

    while (fgets( buffer, sizeof(buffer), f ))
    {
        char *p = buffer + strlen(buffer) - 1;
        if (p < buffer) continue;
        if (*p == '\n') *p-- = 0;
559 560 561
        p = buffer;
        while (*p == ' ') p++;
        if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
562
        if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
563 564 565 566 567
        if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
            add_undef_import( p + strlen( import_func_prefix ), 0 );
        else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
            add_undef_import( p + strlen( import_ord_prefix ), 1 );
        else strarray_add( &undef_symbols, xstrdup( p ), NULL );
568
    }
569 570
    if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
    free( cmd );
571 572
}

573
void resolve_dll_imports( DLLSPEC *spec, struct list *list )
574
{
575
    unsigned int j;
576
    struct import *imp, *next;
577
    ORDDEF *odp;
578

579
    LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
580
    {
581
        for (j = 0; j < undef_symbols.count; j++)
582
        {
583
            odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
584
            if (odp)
585
            {
586 587 588
                if (odp->flags & FLAG_PRIVATE) continue;
                if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
                    warning( "winebuild: Data export '%s' cannot be imported from %s\n",
589
                             odp->link_name, imp->dll_name );
590 591
                else
                {
592 593
                    add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
                                     odp->export_name, odp->ordinal );
594 595
                    remove_name( &undef_symbols, j-- );
                }
596 597
            }
        }
598
        if (!imp->nb_imports)
599 600
        {
            /* the dll is not used, get rid of it */
601
            if (check_unused( imp, spec ))
602
                warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
603 604
            list_remove( &imp->entry );
            free_imports( imp );
605
        }
606
    }
607
}
608

609 610 611 612 613 614
/* resolve the imports for a Win32 module */
void resolve_imports( DLLSPEC *spec )
{
    check_undefined_forwards( spec );
    resolve_dll_imports( spec, &dll_imports );
    resolve_dll_imports( spec, &dll_delayed );
615 616
    sort_names( &undef_symbols );
    check_undefined_exports( spec );
617
}
618

619 620 621 622
/* check if symbol is still undefined */
int is_undefined( const char *name )
{
    return find_name( name, &undef_symbols ) != NULL;
623
}
624

625
/* output the get_pc thunk if needed */
626
void output_get_pc_thunk(void)
627
{
628
    assert( target_cpu == CPU_x86 );
629 630 631 632
    output( "\n\t.text\n" );
    output( "\t.align %d\n", get_alignment(4) );
    output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
    output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
633 634
    output_cfi( ".cfi_startproc" );
    output( "\tmovl (%%esp),%%eax\n" );
635
    output( "\tret\n" );
636
    output_cfi( ".cfi_endproc" );
637
    output_function_size( "__wine_spec_get_pc_thunk_eax" );
638 639
}

640
/* output a single import thunk */
641
static void output_import_thunk( const char *name, const char *table, int pos )
642
{
643 644 645
    output( "\n\t.align %d\n", get_alignment(4) );
    output( "\t%s\n", func_declaration(name) );
    output( "%s\n", asm_globl(name) );
646
    output_cfi( ".cfi_startproc" );
647

648
    switch(target_cpu)
649
    {
650 651
    case CPU_x86:
        if (!UsePIC)
652
        {
653
            output( "\tjmp *(%s+%d)\n", table, pos );
654 655 656
        }
        else
        {
657 658
            output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
            output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
659
            needs_get_pc_thunk = 1;
660
        }
661
        break;
662
    case CPU_x86_64:
663
        output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
664
        break;
665
    case CPU_ARM:
666 667 668
        output( "\tldr IP,1f\n");
        output( "\tldr PC,[PC,IP]\n" );
        output( "1:\t.long %s+%u-(1b+4)\n", table, pos );
669
        break;
670 671 672 673 674 675 676 677 678 679 680
    case CPU_ARM64:
        output( "\tadr x9, 1f\n" );
        output( "\tldur x9, [x9, #0]\n" );
        if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 );
        if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 );
        if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 );
        if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f );
        output( "\tldur x9, [x9, #0]\n" );
        output( "\tbr x9\n" );
        output( "1:\t.quad %s\n", table );
        break;
681
    case CPU_POWERPC:
682
        output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) );
683 684
        if (target_platform == PLATFORM_APPLE)
        {
685 686
            output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos );
            output( "\tla  %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
687 688 689
        }
        else
        {
690 691
            output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos );
            output( "\tla  %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
692
        }
693 694 695
        output( "\tlwz   %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) );
        output( "\tmtctr %s\n", ppc_reg(31) );
        output( "\tmr    %s, %s\n", ppc_reg(31), ppc_reg(0) );
696
        output( "\tbctr\n" );
697
        break;
698
    }
699
    output_cfi( ".cfi_endproc" );
700
    output_function_size( name );
701 702
}

703 704
/* check if we need an import directory */
int has_imports(void)
705
{
706
    return !list_empty( &dll_imports );
707 708 709
}

/* output the import table of a Win32 module */
710
static void output_immediate_imports(void)
711
{
712 713
    int j;
    struct import *import;
714

715
    if (list_empty( &dll_imports )) return;  /* no immediate imports */
716

717 718
    /* main import header */

719 720 721 722
    output( "\n/* import table */\n" );
    output( "\n\t.data\n" );
    output( "\t.align %d\n", get_alignment(4) );
    output( ".L__wine_spec_imports:\n" );
723 724 725

    /* list of dlls */

726 727
    j = 0;
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
728
    {
729 730
        output( "\t.long .L__wine_spec_import_data_names+%d-.L__wine_spec_rva_base\n",  /* OriginalFirstThunk */
                 j * get_ptr_size() );
731 732 733
        output( "\t.long 0\n" );     /* TimeDateStamp */
        output( "\t.long 0\n" );     /* ForwarderChain */
        output( "\t.long .L__wine_spec_import_name_%s-.L__wine_spec_rva_base\n", /* Name */
734
                 import->c_name );
735
        output( "\t.long .L__wine_spec_import_data_ptrs+%d-.L__wine_spec_rva_base\n",  /* FirstThunk */
736
                 j * get_ptr_size() );
737
        j += import->nb_imports + 1;
738
    }
739 740 741 742 743 744 745
    output( "\t.long 0\n" );     /* OriginalFirstThunk */
    output( "\t.long 0\n" );     /* TimeDateStamp */
    output( "\t.long 0\n" );     /* ForwarderChain */
    output( "\t.long 0\n" );     /* Name */
    output( "\t.long 0\n" );     /* FirstThunk */

    output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
746
    output( ".L__wine_spec_import_data_names:\n" );
747
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
748
    {
749
        for (j = 0; j < import->nb_imports; j++)
750
        {
751 752
            struct import_func *func = &import->imports[j];
            if (func->name)
753
                output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
754
                        get_asm_ptr_keyword(), import->c_name, func->name );
755
            else
756 757
            {
                if (get_ptr_size() == 8)
758
                    output( "\t.quad 0x800000000000%04x\n", func->ordinal );
759
                else
760
                    output( "\t.long 0x8000%04x\n", func->ordinal );
761
            }
762
        }
763
        output( "\t%s 0\n", get_asm_ptr_keyword() );
764
    }
765
    output( ".L__wine_spec_import_data_ptrs:\n" );
766
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
767
    {
768
        for (j = 0; j < import->nb_imports; j++) output( "\t%s 0\n", get_asm_ptr_keyword() );
769 770
        output( "\t%s 0\n", get_asm_ptr_keyword() );
    }
771
    output( ".L__wine_spec_imports_end:\n" );
772

773
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
774
    {
775
        for (j = 0; j < import->nb_imports; j++)
776
        {
777 778 779 780 781 782
            struct import_func *func = &import->imports[j];
            if (!func->name) continue;
            output( "\t.align %d\n", get_alignment(2) );
            output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
            output( "\t.short %d\n", func->ordinal );
            output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
783
        }
784 785
    }

786
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
787
    {
788
        output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
789
                import->c_name, get_asm_string_keyword(), import->dll_name );
790
    }
791 792 793
}

/* output the import thunks of a Win32 module */
794
static void output_immediate_import_thunks(void)
795
{
796 797
    int j, pos;
    struct import *import;
798 799
    static const char import_thunks[] = "__wine_spec_import_thunks";

800
    if (list_empty( &dll_imports )) return;
801

802 803 804 805
    output( "\n/* immediate import thunks */\n\n" );
    output( "\t.text\n" );
    output( "\t.align %d\n", get_alignment(8) );
    output( "%s:\n", asm_name(import_thunks));
806

807 808
    pos = 0;
    LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
809
    {
810
        for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
811
        {
812 813
            struct import_func *func = &import->imports[j];
            output_import_thunk( func->name ? func->name : func->export_name,
814
                                 ".L__wine_spec_import_data_ptrs", pos );
815
        }
816
        pos += get_ptr_size();
817
    }
818
    output_function_size( import_thunks );
819 820 821
}

/* output the delayed import table of a Win32 module */
822
static void output_delayed_imports( const DLLSPEC *spec )
823
{
824 825
    int j, mod;
    struct import *import;
826

827
    if (list_empty( &dll_delayed )) return;
828

829 830 831 832
    output( "\n/* delayed imports */\n\n" );
    output( "\t.data\n" );
    output( "\t.align %d\n", get_alignment(get_ptr_size()) );
    output( "%s\n", asm_globl("__wine_spec_delay_imports") );
833 834 835

    /* list of dlls */

836
    j = mod = 0;
837
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
838
    {
839
        output( "\t%s 0\n", get_asm_ptr_keyword() );   /* grAttrs */
840 841
        output( "\t%s .L__wine_delay_name_%s\n",       /* szName */
                 get_asm_ptr_keyword(), import->c_name );
842
        output( "\t%s .L__wine_delay_modules+%d\n",    /* phmod */
843
                 get_asm_ptr_keyword(), mod * get_ptr_size() );
844
        output( "\t%s .L__wine_delay_IAT+%d\n",        /* pIAT */
845
                 get_asm_ptr_keyword(), j * get_ptr_size() );
846
        output( "\t%s .L__wine_delay_INT+%d\n",        /* pINT */
847
                 get_asm_ptr_keyword(), j * get_ptr_size() );
848 849 850
        output( "\t%s 0\n", get_asm_ptr_keyword() );   /* pBoundIAT */
        output( "\t%s 0\n", get_asm_ptr_keyword() );   /* pUnloadIAT */
        output( "\t%s 0\n", get_asm_ptr_keyword() );   /* dwTimeStamp */
851
        j += import->nb_imports;
852
        mod++;
853
    }
854 855 856 857 858 859 860 861 862 863
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* grAttrs */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* szName */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* phmod */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* pIAT */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* pINT */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* pBoundIAT */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* pUnloadIAT */
    output( "\t%s 0\n", get_asm_ptr_keyword() );   /* dwTimeStamp */

    output( "\n.L__wine_delay_IAT:\n" );
864
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
865
    {
866
        for (j = 0; j < import->nb_imports; j++)
867
        {
868 869
            struct import_func *func = &import->imports[j];
            const char *name = func->name ? func->name : func->export_name;
870 871
            output( "\t%s .L__wine_delay_imp_%s_%s\n",
                    get_asm_ptr_keyword(), import->c_name, name );
872 873
        }
    }
874

875
    output( "\n.L__wine_delay_INT:\n" );
876
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
877
    {
878
        for (j = 0; j < import->nb_imports; j++)
879
        {
880 881 882
            struct import_func *func = &import->imports[j];
            if (!func->name)
                output( "\t%s %d\n", get_asm_ptr_keyword(), func->ordinal );
883
            else
884
                output( "\t%s .L__wine_delay_data_%s_%s\n",
885
                        get_asm_ptr_keyword(), import->c_name, func->name );
886 887
        }
    }
888

889
    output( "\n.L__wine_delay_modules:\n" );
890
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
891
    {
892
        output( "\t%s 0\n", get_asm_ptr_keyword() );
893 894
    }

895
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
896
    {
897 898
        output( ".L__wine_delay_name_%s:\n", import->c_name );
        output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
899 900
    }

901
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
902
    {
903
        for (j = 0; j < import->nb_imports; j++)
904
        {
905 906 907 908
            struct import_func *func = &import->imports[j];
            if (!func->name) continue;
            output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
            output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
909 910
        }
    }
911
    output_function_size( "__wine_spec_delay_imports" );
912 913 914
}

/* output the delayed import thunks of a Win32 module */
915
static void output_delayed_import_thunks( const DLLSPEC *spec )
916
{
917 918
    int idx, j, pos, extra_stack_storage = 0;
    struct import *import;
919 920
    static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
    static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
921

922
    if (list_empty( &dll_delayed )) return;
923

924 925 926 927 928 929
    output( "\n/* delayed import thunks */\n\n" );
    output( "\t.text\n" );
    output( "\t.align %d\n", get_alignment(8) );
    output( "%s:\n", asm_name(delayed_import_loaders));
    output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
    output( "%s:\n", asm_name("__wine_delay_load_asm") );
930
    output_cfi( ".cfi_startproc" );
931 932 933
    switch(target_cpu)
    {
    case CPU_x86:
934
        output( "\tpushl %%ecx\n" );
935
        output_cfi( ".cfi_adjust_cfa_offset 4" );
936
        output( "\tpushl %%edx\n" );
937
        output_cfi( ".cfi_adjust_cfa_offset 4" );
938
        output( "\tpushl %%eax\n" );
939
        output_cfi( ".cfi_adjust_cfa_offset 4" );
940
        output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
941
        output_cfi( ".cfi_adjust_cfa_offset -4" );
942
        output( "\tpopl %%edx\n" );
943
        output_cfi( ".cfi_adjust_cfa_offset -4" );
944
        output( "\tpopl %%ecx\n" );
945
        output_cfi( ".cfi_adjust_cfa_offset -4" );
946
        output( "\tjmp *%%eax\n" );
947
        break;
948
    case CPU_x86_64:
949
        output( "\tsubq $88,%%rsp\n" );
950
        output_cfi( ".cfi_adjust_cfa_offset 88" );
951 952 953 954 955 956
        output( "\tmovq %%rdx,80(%%rsp)\n" );
        output( "\tmovq %%rcx,72(%%rsp)\n" );
        output( "\tmovq %%r8,64(%%rsp)\n" );
        output( "\tmovq %%r9,56(%%rsp)\n" );
        output( "\tmovq %%r10,48(%%rsp)\n" );
        output( "\tmovq %%r11,40(%%rsp)\n" );
957
        output( "\tmovq %%rax,%%rcx\n" );
958
        output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
959 960 961 962 963 964 965
        output( "\tmovq 40(%%rsp),%%r11\n" );
        output( "\tmovq 48(%%rsp),%%r10\n" );
        output( "\tmovq 56(%%rsp),%%r9\n" );
        output( "\tmovq 64(%%rsp),%%r8\n" );
        output( "\tmovq 72(%%rsp),%%rcx\n" );
        output( "\tmovq 80(%%rsp),%%rdx\n" );
        output( "\taddq $88,%%rsp\n" );
966
        output_cfi( ".cfi_adjust_cfa_offset -88" );
967
        output( "\tjmp *%%rax\n" );
968
        break;
969
    case CPU_ARM:
970 971 972 973 974 975 976 977 978
        output( "\tpush {r0-r3,FP,LR}\n" );
        output( "\tmov r0,IP\n" );
        output( "\tldr IP,2f\n");
        output( "\tadd IP,PC\n");
        output( "\tblx IP\n");
        output( "1:\tmov IP,r0\n");
        output( "\tpop {r0-r3,FP,LR}\n" );
        output( "\tbx IP\n");
        output( "2:\t.long %s-1b\n", asm_name("__wine_spec_delay_load") );
979
        break;
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
    case CPU_ARM64:
        output( "\tstp x29, x30, [sp,#-16]!\n" );
        output( "\tmov x29, sp\n" );
        output( "\tadr x9, 1f\n" );
        output( "\tldur x9, [x9, #0]\n" );
        output( "\tblr x9\n" );
        output( "\tmov x9, x0\n" );
        output( "\tldp x29, x30, [sp],#16\n" );
        output( "\tldp x0, x1, [sp,#16]\n" );
        output( "\tldp x2, x3, [sp,#32]\n" );
        output( "\tldp x4, x5, [sp,#48]\n" );
        output( "\tldp x6, x7, [sp],#80\n" );
        output( "\tbr x9\n" ); /* or "ret x9" */
        output( "1:\t.quad %s\n", asm_name("__wine_spec_delay_load") );
        break;
995 996 997 998
    case CPU_POWERPC:
        if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;

        /* Save all callee saved registers into a stackframe. */
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
        output( "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(3),  4+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(4),  8+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1010 1011

        /* r0 -> r3 (arg1) */
1012
        output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
1013 1014

        /* save return address */
1015 1016
        output( "\tmflr %s\n", ppc_reg(0));
        output( "\tstw  %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1017 1018

        /* Call the __wine_delay_load function, arg1 is arg1. */
1019
        output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1020 1021

        /* Load return value from call into ctr register */
1022
        output( "\tmtctr %s\n", ppc_reg(3));
1023 1024

        /* restore all saved registers and drop stackframe. */
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(3),  4+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(4),  8+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
        output( "\tlwz  %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1035 1036

        /* Load return value from call into return register */
1037 1038 1039
        output( "\tlwz  %s,  %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
        output( "\tmtlr %s\n", ppc_reg(0));
        output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1),  48+extra_stack_storage);
1040 1041

        /* branch to ctr register. */
1042
        output( "\tbctr\n");
1043 1044
        break;
    }
1045
    output_cfi( ".cfi_endproc" );
1046 1047
    output_function_size( "__wine_delay_load_asm" );
    output( "\n" );
1048

1049
    idx = 0;
1050
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1051
    {
1052
        for (j = 0; j < import->nb_imports; j++)
1053
        {
1054 1055
            struct import_func *func = &import->imports[j];
            const char *name = func->name ? func->name : func->export_name;
1056

1057
            output( ".L__wine_delay_imp_%s_%s:\n", import->c_name, name );
1058
            output_cfi( ".cfi_startproc" );
1059 1060 1061
            switch(target_cpu)
            {
            case CPU_x86:
1062 1063
                output( "\tmovl $%d, %%eax\n", (idx << 16) | j );
                output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1064
                break;
1065
            case CPU_x86_64:
1066
                output( "\tmovq $%d,%%rax\n", (idx << 16) | j );
1067
                output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1068
                break;
1069
            case CPU_ARM:
1070 1071 1072 1073 1074 1075 1076
            {
                unsigned int mask, count = 0, val = (idx << 16) | j;

                for (mask = 0xff; mask; mask <<= 8)
                    if (val & mask) output( "\t%s IP,#%u\n", count++ ? "add" : "mov", val & mask );
                if (!count) output( "\tmov IP,#0\n" );
                output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1077
                break;
1078
            }
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
            case CPU_ARM64:
                output( "\tstp x6, x7, [sp,#-80]!\n" );
                output( "\tstp x4, x5, [sp,#48]\n" );
                output( "\tstp x2, x3, [sp,#32]\n" );
                output( "\tstp x0, x1, [sp,#16]\n" );
                output( "\tmov x0, #%d\n", idx );
                output( "\tmov x1, #16384\n" );
                output( "\tmul x1, x0, x1\n" );
                output( "\tmov x0, x1\n" );
                output( "\tmov x1, #4\n" );
                output( "\tmul x1, x0, x1\n" );
                output( "\tmov x0, x1\n" );
                output( "\tadd x0, x0, #%d\n", j );
                output( "\tadr x9, 1f\n" );
                output( "\tldur x9, [x9, #0]\n" );
                output( "\tbr x9\n" );
                output( "1:\t.quad %s\n", asm_name("__wine_delay_load_asm") );
                break;
1097 1098 1099 1100 1101 1102
            case CPU_POWERPC:
                switch(target_platform)
                {
                case PLATFORM_APPLE:
                    /* On Darwin we can use r0 and r2 */
                    /* Upper part in r2 */
1103
                    output( "\tlis %s, %d\n", ppc_reg(2), idx);
1104
                    /* Lower part + r2 -> r0, Note we can't use r0 directly */
1105 1106
                    output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
                    output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1107 1108 1109 1110
                    break;
                default:
                    /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
                    /* Save r13 on the stack */
1111 1112
                    output( "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
                    output( "\tstw  %s, 0(%s)\n",    ppc_reg(13), ppc_reg(1));
1113
                    /* Upper part in r13 */
1114
                    output( "\tlis %s, %d\n", ppc_reg(13), idx);
1115
                    /* Lower part + r13 -> r0, Note we can't use r0 directly */
1116
                    output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
1117
                    /* Restore r13 */
1118 1119 1120
                    output( "\tstw  %s, 0(%s)\n",    ppc_reg(13), ppc_reg(1));
                    output( "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
                    output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1121 1122 1123 1124
                    break;
                }
                break;
            }
1125
            output_cfi( ".cfi_endproc" );
1126 1127 1128
        }
        idx++;
    }
1129
    output_function_size( delayed_import_loaders );
1130

1131 1132
    output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
    output( "%s:\n", asm_name(delayed_import_thunks));
1133
    pos = 0;
1134
    LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1135
    {
1136
        for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1137
        {
1138 1139
            struct import_func *func = &import->imports[j];
            output_import_thunk( func->name ? func->name : func->export_name,
1140
                                 ".L__wine_delay_IAT", pos );
1141 1142
        }
    }
1143
    output_function_size( delayed_import_thunks );
1144 1145
}

1146
/* output import stubs for exported entry points that link to external symbols */
1147
static void output_external_link_imports( DLLSPEC *spec )
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
{
    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++)
    {
1158
        if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1159 1160 1161
            remove_name( &ext_link_imports, i-- );
    }

1162 1163 1164 1165
    output( "\n/* external link thunks */\n\n" );
    output( "\t.data\n" );
    output( "\t.align %d\n", get_alignment(get_ptr_size()) );
    output( ".L__wine_spec_external_links:\n" );
1166
    for (i = 0; i < ext_link_imports.count; i++)
1167
        output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1168

1169 1170 1171
    output( "\n\t.text\n" );
    output( "\t.align %d\n", get_alignment(get_ptr_size()) );
    output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1172 1173 1174

    for (i = pos = 0; i < ext_link_imports.count; i++)
    {
1175
        char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1176
        output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1177
        free( buffer );
1178 1179
        pos += get_ptr_size();
    }
1180
    output_function_size( "__wine_spec_external_link_thunks" );
1181 1182
}

1183 1184 1185 1186 1187
/*******************************************************************
 *         output_stubs
 *
 * Output the functions for stub entry points
 */
1188
void output_stubs( DLLSPEC *spec )
1189 1190
{
    const char *name, *exp_name;
1191
    int i, count;
1192 1193 1194

    if (!has_stubs( spec )) return;

1195 1196
    output( "\n/* stub functions */\n\n" );
    output( "\t.text\n" );
1197

1198
    for (i = count = 0; i < spec->nb_entry_points; i++)
1199 1200 1201 1202 1203 1204
    {
        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;
1205 1206 1207
        output( "\t.align %d\n", get_alignment(4) );
        output( "\t%s\n", func_declaration(name) );
        output( "%s:\n", asm_name(name) );
1208
        output_cfi( ".cfi_startproc" );
1209

1210
        switch (target_cpu)
1211
        {
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
        case CPU_x86:
            /* flesh out the stub a bit to make safedisc happy */
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );
            output(" \tnop\n" );

1224 1225
            output( "\tsubl $12,%%esp\n" );
            output_cfi( ".cfi_adjust_cfa_offset 12" );
1226
            if (UsePIC)
1227
            {
1228 1229
                output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
                output( "1:" );
1230
                needs_get_pc_thunk = 1;
1231 1232 1233
                if (exp_name)
                {
                    output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1234
                    output( "\tmovl %%ecx,4(%%esp)\n" );
1235 1236 1237
                    count++;
                }
                else
1238
                    output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1239
                output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1240
                output( "\tmovl %%ecx,(%%esp)\n" );
1241 1242
            }
            else
1243 1244 1245
            {
                if (exp_name)
                {
1246
                    output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1247 1248 1249
                    count++;
                }
                else
1250 1251
                    output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
                output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1252 1253 1254 1255
            }
            output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
            break;
        case CPU_x86_64:
1256
            output( "\tsubq $8,%%rsp\n" );
1257
            output_cfi( ".cfi_adjust_cfa_offset 8" );
1258
            output( "\tleaq .L__wine_spec_file_name(%%rip),%%rdi\n" );
1259 1260
            if (exp_name)
            {
1261
                output( "leaq .L%s_string(%%rip),%%rsi\n", name );
1262
                count++;
1263 1264
            }
            else
1265 1266 1267
                output( "\tmovq $%d,%%rsi\n", odp->ordinal );
            output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
            break;
1268
        case CPU_ARM:
1269 1270 1271 1272
            output( "\tldr r0,2f\n");
            output( "\tadd r0,PC\n");
            output( "\tldr r1,2f+4\n");
            output( "1:" );
1273 1274
            if (exp_name)
            {
1275
                output( "\tadd r1,PC\n");
1276 1277 1278
                count++;
            }
            output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1279 1280 1281
            output( "2:\t.long .L__wine_spec_file_name-1b\n" );
            if (exp_name) output( "\t.long .L%s_string-2b\n", name );
            else output( "\t.long %u\n", odp->ordinal );
1282
            break;
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
        case CPU_ARM64:
            output( "\tadr x0, 2f\n" );
            output( "\tldur x0, [x0, #0]\n" );
            output( "\tadr x1, 2f+8\n" );
            output( "\tldur x1, [x1, #0]\n" );
            output( "\tadr x2, 1f\n" );
            output( "\tldur x2, [x2, #0]\n" );
            output( "\tblr x2\n" );
            output( "1:\t.quad %s\n", asm_name("__wine_spec_unimplemented_stub") );
            output( "2:\t.quad %s\n", asm_name("__wine_spec_file_name") );
            if (exp_name)
            {
                output( "\t.quad .L%s_string\n", name );
                count++;
            }
            else output( "\t.quad %u\n", odp->ordinal );
            break;
1300 1301
        default:
            assert(0);
1302
        }
1303
        output_cfi( ".cfi_endproc" );
1304
        output_function_size( name );
1305 1306
    }

1307
    if (count)
1308
    {
1309
        output( "\t%s\n", get_asm_string_section() );
1310 1311 1312 1313 1314 1315
        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)
1316 1317 1318
            {
                name = get_stub_name( odp, spec );
                output( ".L%s_string:\n", name );
1319
                output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1320
            }
1321 1322 1323 1324
        }
    }
}

1325
/* output the import and delayed import tables of a Win32 module */
1326
void output_imports( DLLSPEC *spec )
1327
{
1328 1329 1330 1331 1332
    output_immediate_imports();
    output_delayed_imports( spec );
    output_immediate_import_thunks();
    output_delayed_import_thunks( spec );
    output_external_link_imports( spec );
1333
}
1334

1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
/* create a new asm temp file */
static void new_output_as_file( const char *prefix )
{
    char *name = get_temp_file_name( prefix, ".s" );

    if (output_file) fclose( output_file );
    if (!(output_file = fopen( name, "w" )))
        fatal_error( "Unable to create output file '%s'\n", name );
    strarray_add( &as_files, name, NULL );
}

/* assemble all the asm files */
static void assemble_files( const char *prefix )
{
    unsigned int i;

    if (output_file) fclose( output_file );
    output_file = NULL;

    for (i = 0; i < as_files.count; i++)
    {
        char *obj = get_temp_file_name( prefix, ".o" );
        assemble_file( as_files.str[i], obj );
        as_files.str[i] = obj;
    }
}

/* build a library from the current asm files and any additional object files in argv */
static void build_library( const char *output_name, char **argv, int create )
{
    struct strarray args = find_tool( "ar", NULL );
    struct strarray ranlib = find_tool( "ranlib", NULL );

    strarray_add( &args, create ? "rc" : "r", output_name, NULL );
    strarray_addall( &args, as_files );
    strarray_addv( &args, argv );
    if (create) unlink( output_name );
    spawn( args );

    strarray_add( &ranlib, output_name, NULL );
    spawn( ranlib );
}

/* create a Windows-style import library */
static void build_windows_import_lib( DLLSPEC *spec )
1380
{
1381
    struct strarray args;
1382
    char *def_file;
1383
    const char *as_flags, *m_flag;
1384 1385 1386 1387 1388

    def_file = get_temp_file_name( output_file_name, ".def" );
    fclose( output_file );
    if (!(output_file = fopen( def_file, "w" )))
        fatal_error( "Unable to create output file '%s'\n", def_file );
1389
    output_def_file( spec, 0 );
1390 1391 1392
    fclose( output_file );
    output_file = NULL;

1393
    args = find_tool( "dlltool", NULL );
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
    switch (target_cpu)
    {
        case CPU_x86:
            m_flag = "i386";
            as_flags = "--as-flags=--32";
            break;
        case CPU_x86_64:
            m_flag = "i386:x86-64";
            as_flags = "--as-flags=--64";
            break;
        default:
            m_flag = NULL;
            break;
    }
1408
    strarray_add( &args, "-k", "-l", output_file_name, "-d", def_file, NULL );
1409
    if (m_flag)
1410
        strarray_add( &args, "-m", m_flag, as_flags, NULL );
1411
    spawn( args );
1412 1413 1414 1415 1416 1417 1418 1419 1420
}

/* create a Unix-style import library */
static void build_unix_import_lib( DLLSPEC *spec )
{
    static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._@";
    int i, total;
    const char *name, *prefix;
    char *dll_name = xstrdup( spec->file_name );
1421

1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
    if (strendswith( dll_name, ".dll" )) dll_name[strlen(dll_name) - 4] = 0;
    if (strspn( dll_name, valid_chars ) < strlen( dll_name ))
        fatal_error( "%s contains invalid characters\n", spec->file_name );

    /* entry points */

    for (i = total = 0; i < spec->nb_entry_points; i++)
    {
        const ORDDEF *odp = &spec->entry_points[i];

        if (odp->name) name = odp->name;
        else if (odp->export_name) name = odp->export_name;
        else continue;

        if (odp->flags & FLAG_PRIVATE) continue;
        total++;

        /* C++ mangled names cannot be imported */
        if (strpbrk( name, "?@" )) continue;

        switch(odp->type)
        {
        case TYPE_VARARGS:
        case TYPE_CDECL:
        case TYPE_STDCALL:
        case TYPE_THISCALL:
            prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
            new_output_as_file( spec->file_name );
            output( "\t.text\n" );
            output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
            output( "\t%s\n", func_declaration( name ) );
            output( "%s\n", asm_globl( name ) );
            output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
                    asm_name( prefix ), dll_name, odp->ordinal, name );
            output_function_size( name );
1457
            output_gnu_stack_note();
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
            break;

        default:
            break;
        }
    }
    if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );

    if (!as_files.count)  /* create a dummy file to avoid empty import libraries */
    {
        new_output_as_file( spec->file_name );
        output( "\t.text\n" );
    }

    assemble_files( spec->file_name );
    free( dll_name );
}

/* output an import library for a Win32 module and additional object files */
void output_import_lib( DLLSPEC *spec, char **argv )
{
    if (target_platform == PLATFORM_WINDOWS)
    {
        build_windows_import_lib( spec );
        if (argv[0]) build_library( output_file_name, argv, 0 );
    }
    else
1485
    {
1486 1487
        build_unix_import_lib( spec );
        build_library( output_file_name, argv, 1 );
1488 1489 1490
    }
    output_file_name = NULL;
}