Example #1
0
/* check if dll will output relay thunks */
int has_relays( DLLSPEC *spec )
{
    int i;

    if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64) return 0;

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];
        if (needs_relay( odp )) return 1;
    }
    return 0;
}
Example #2
0
/*******************************************************************
 *         output_relay_debug
 *
 * Output entry points for relay debugging
 */
static void output_relay_debug( FILE *outfile, DLLSPEC *spec )
{
    unsigned int i, j, args, flags;

    /* first the table of entry point offsets */

    fprintf( outfile, "\t%s\n", get_asm_rodata_section() );
    fprintf( outfile, "\t.align %d\n", get_alignment(4) );
    fprintf( outfile, ".L__wine_spec_relay_entry_point_offsets:\n" );

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];

        if (needs_relay( odp ))
            fprintf( outfile, "\t.long .L__wine_spec_relay_entry_point_%d-__wine_spec_relay_entry_points\n", i );
        else
            fprintf( outfile, "\t.long 0\n" );
    }

    /* then the table of argument types */

    fprintf( outfile, "\t.align %d\n", get_alignment(4) );
    fprintf( outfile, ".L__wine_spec_relay_arg_types:\n" );

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];
        unsigned int mask = 0;

        if (needs_relay( odp ))
        {
            for (j = 0; j < 16 && odp->u.func.arg_types[j]; j++)
            {
                if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
                if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
            }
        }
        fprintf( outfile, "\t.long 0x%08x\n", mask );
    }

    /* then the relay thunks */

    fprintf( outfile, "\t.text\n" );
    fprintf( outfile, "__wine_spec_relay_entry_points:\n" );
    fprintf( outfile, "\tnop\n" );  /* to avoid 0 offset */

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];

        if (!needs_relay( odp )) continue;

        fprintf( outfile, "\t.align %d\n", get_alignment(4) );
        fprintf( outfile, ".L__wine_spec_relay_entry_point_%d:\n", i );

        if (odp->flags & FLAG_REGISTER)
            fprintf( outfile, "\tpushl %%eax\n" );
        else
            fprintf( outfile, "\tpushl %%esp\n" );

        args = strlen(odp->u.func.arg_types);
        flags = 0;
        if (odp->flags & FLAG_RET64) flags |= 1;
        if (odp->type == TYPE_STDCALL) flags |= 2;
        fprintf( outfile, "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) );

        if (UsePIC)
        {
            fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
            fprintf( outfile, "1:\tleal .L__wine_spec_relay_descr-1b(%%eax),%%eax\n" );
        }
        else fprintf( outfile, "\tmovl $.L__wine_spec_relay_descr,%%eax\n" );
        fprintf( outfile, "\tpushl %%eax\n" );

        if (odp->flags & FLAG_REGISTER)
        {
            fprintf( outfile, "\tcall *8(%%eax)\n" );
        }
        else
        {
            fprintf( outfile, "\tcall *4(%%eax)\n" );
            if (odp->type == TYPE_STDCALL)
                fprintf( outfile, "\tret $%u\n", args * get_ptr_size() );
            else
                fprintf( outfile, "\tret\n" );
        }
    }
}
Example #3
0
/*******************************************************************
 *         output_relay_debug
 *
 * Output entry points for relay debugging
 */
static void output_relay_debug( DLLSPEC *spec )
{
    int i, j;
    unsigned int pos, args, flags;

    /* first the table of entry point offsets */

    output( "\t%s\n", get_asm_rodata_section() );
    output( "\t.align %d\n", get_alignment(4) );
    output( ".L__wine_spec_relay_entry_point_offsets:\n" );

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];

        if (needs_relay( odp ))
            output( "\t.long .L__wine_spec_relay_entry_point_%d-__wine_spec_relay_entry_points\n", i );
        else
            output( "\t.long 0\n" );
    }

    /* then the table of argument types */

    output( "\t.align %d\n", get_alignment(4) );
    output( ".L__wine_spec_relay_arg_types:\n" );

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];
        unsigned int mask = 0;

        if (needs_relay( odp ))
        {
            for (j = pos = 0; pos < 16 && j < odp->u.func.nb_args; j++)
            {
                switch (odp->u.func.args[j])
                {
                case ARG_STR:    mask |= 1 << (2 * pos++); break;
                case ARG_WSTR:   mask |= 2 << (2 * pos++); break;
                case ARG_INT64:
                case ARG_DOUBLE: pos += 8 / get_ptr_size(); break;
                case ARG_INT128: pos += (target_cpu == CPU_x86) ? 4 : 1; break;
                default:         pos++; break;
                }
            }
        }
        output( "\t.long 0x%08x\n", mask );
    }

    /* then the relay thunks */

    output( "\t.text\n" );
    output( "__wine_spec_relay_entry_points:\n" );
    output( "\tnop\n" );  /* to avoid 0 offset */

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];

        if (!needs_relay( odp )) continue;

        output( "\t.align %d\n", get_alignment(4) );
        output( ".L__wine_spec_relay_entry_point_%d:\n", i );
        output_cfi( ".cfi_startproc" );

        args = get_args_size(odp) / get_ptr_size();
        flags = 0;

        switch (target_cpu)
        {
        case CPU_x86:
            if (odp->type == TYPE_THISCALL)  /* add the this pointer */
            {
                output( "\tpopl %%eax\n" );
                output( "\tpushl %%ecx\n" );
                output( "\tpushl %%eax\n" );
                flags |= 2;
            }
            if (odp->flags & FLAG_REGISTER)
                output( "\tpushl %%eax\n" );
            else
                output( "\tpushl %%esp\n" );
            output_cfi( ".cfi_adjust_cfa_offset 4" );

            if (odp->flags & FLAG_RET64) flags |= 1;
            output( "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) );
            output_cfi( ".cfi_adjust_cfa_offset 4" );

            if (UsePIC)
            {
                output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
                output( "1:\tleal .L__wine_spec_relay_descr-1b(%%eax),%%eax\n" );
            }
            else output( "\tmovl $.L__wine_spec_relay_descr,%%eax\n" );
            output( "\tpushl %%eax\n" );
            output_cfi( ".cfi_adjust_cfa_offset 4" );

            if (odp->flags & FLAG_REGISTER)
            {
                output( "\tcall *8(%%eax)\n" );
            }
            else
            {
                output( "\tcall *4(%%eax)\n" );
                output_cfi( ".cfi_adjust_cfa_offset -12" );
                if (odp->type == TYPE_STDCALL || odp->type == TYPE_THISCALL)
                    output( "\tret $%u\n", args * get_ptr_size() );
                else
                    output( "\tret\n" );
            }
            break;

        case CPU_x86_64:
            output( "\tsubq $40,%%rsp\n" );
            output_cfi( ".cfi_adjust_cfa_offset 40" );
            switch (args)
            {
            default: output( "\tmovq %%%s,72(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
            /* fall through */
            case 3:  output( "\tmovq %%%s,64(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
            /* fall through */
            case 2:  output( "\tmovq %%%s,56(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
            /* fall through */
            case 1:  output( "\tmovq %%%s,48(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
            /* fall through */
            case 0:  break;
            }
            output( "\tleaq 40(%%rsp),%%r8\n" );
            output( "\tmovq $%u,%%rdx\n", (flags << 24) | (args << 16) | (i - spec->base) );
            output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
            output( "\tcallq *8(%%rcx)\n" );
            output( "\taddq $40,%%rsp\n" );
            output_cfi( ".cfi_adjust_cfa_offset -40" );
            output( "\tret\n" );
            break;

        default:
            assert(0);
        }
        output_cfi( ".cfi_endproc" );
    }
}
Example #4
0
/*******************************************************************
 *         output_relay_debug
 *
 * Output entry points for relay debugging
 */
static void output_relay_debug( DLLSPEC *spec )
{
    int i;
    unsigned int j, args, flags;

    /* first the table of entry point offsets */

    output( "\t%s\n", get_asm_rodata_section() );
    output( "\t.align %d\n", get_alignment(4) );
    output( ".L__wine_spec_relay_entry_point_offsets:\n" );

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];

        if (needs_relay( odp ))
            output( "\t.long .L__wine_spec_relay_entry_point_%d-__wine_spec_relay_entry_points\n", i );
        else
            output( "\t.long 0\n" );
    }

    /* then the table of argument types */

    output( "\t.align %d\n", get_alignment(4) );
    output( ".L__wine_spec_relay_arg_types:\n" );

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];
        unsigned int mask = 0;

        if (needs_relay( odp ))
        {
            for (j = 0; j < 16 && odp->u.func.arg_types[j]; j++)
            {
                if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
                if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
            }
        }
        output( "\t.long 0x%08x\n", mask );
    }

    /* then the relay thunks */

    output( "\t.text\n" );
    output( "__wine_spec_relay_entry_points:\n" );
    output( "\tnop\n" );  /* to avoid 0 offset */

    for (i = spec->base; i <= spec->limit; i++)
    {
        ORDDEF *odp = spec->ordinals[i];

        if (!needs_relay( odp )) continue;

        output( "\t.align %d\n", get_alignment(4) );
        output( ".L__wine_spec_relay_entry_point_%d:\n", i );

        args = strlen(odp->u.func.arg_types);
        flags = 0;

        switch (target_cpu)
        {
        case CPU_x86:
            if (odp->flags & FLAG_REGISTER)
                output( "\tpushl %%eax\n" );
            else
                output( "\tpushl %%esp\n" );

            if (odp->flags & FLAG_RET64) flags |= 1;
            output( "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) );

            if (UsePIC)
            {
                output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
                output( "1:\tleal .L__wine_spec_relay_descr-1b(%%eax),%%eax\n" );
            }
            else output( "\tmovl $.L__wine_spec_relay_descr,%%eax\n" );
            output( "\tpushl %%eax\n" );

            if (odp->flags & FLAG_REGISTER)
            {
                output( "\tcall *8(%%eax)\n" );
            }
            else
            {
                output( "\tcall *4(%%eax)\n" );
                if (odp->type == TYPE_STDCALL)
                    output( "\tret $%u\n", args * get_ptr_size() );
                else
                    output( "\tret\n" );
            }
            break;

        case CPU_x86_64:
            output( "\tmovq %%rcx,8(%%rsp)\n" );
            output( "\tmovq %%rdx,16(%%rsp)\n" );
            output( "\tmovq %%r8,24(%%rsp)\n" );
            output( "\tmovq %%r9,32(%%rsp)\n" );
            output( "\tmovq %%rsp,%%r8\n" );
            output( "\tmovq $%u,%%rdx\n", (flags << 24) | (args << 16) | (i - spec->base) );
            output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
            output( "\tsubq $40,%%rsp\n" );
            output( "\tcallq *%u(%%rcx)\n", (odp->flags & FLAG_REGISTER) ? 16 : 8 );
            output( "\taddq $40,%%rsp\n" );
            output( "\tret\n" );
            break;

        default:
            assert(0);
        }
    }
}