winebuild: Add -import entry point flag to generate hotpatchable import thunks.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-06-21 12:08:44 +02:00
parent dc8a941a7c
commit cf619dd419
6 changed files with 100 additions and 33 deletions

View File

@ -591,6 +591,7 @@ sub update_spec_file($)
$flags = $parent{flags};
$flags =~ s/-ordinal\s*// if $descr{ordinal} eq "@";
$flags =~ s/-noname\s*// if $descr{ordinal} eq "@";
$flags =~ s/-import\s*//;
if ($descr{flags} =~ /-private/) # preserve -private flag
{
$flags = "-private " . $flags unless $flags =~ /-private/;

View File

@ -168,21 +168,22 @@ struct strarray
};
/* entry point flags */
#define FLAG_NORELAY 0x01 /* don't use relay debugging for this function */
#define FLAG_NONAME 0x02 /* don't export function by name */
#define FLAG_RET16 0x04 /* function returns a 16-bit value */
#define FLAG_RET64 0x08 /* function returns a 64-bit value */
#define FLAG_REGISTER 0x10 /* use register calling convention */
#define FLAG_PRIVATE 0x20 /* function is private (cannot be imported) */
#define FLAG_ORDINAL 0x40 /* function should be imported by ordinal */
#define FLAG_THISCALL 0x80 /* use thiscall calling convention */
#define FLAG_FASTCALL 0x100 /* use fastcall calling convention */
#define FLAG_NORELAY 0x0001 /* don't use relay debugging for this function */
#define FLAG_NONAME 0x0002 /* don't export function by name */
#define FLAG_RET16 0x0004 /* function returns a 16-bit value */
#define FLAG_RET64 0x0008 /* function returns a 64-bit value */
#define FLAG_REGISTER 0x0010 /* use register calling convention */
#define FLAG_PRIVATE 0x0020 /* function is private (cannot be imported) */
#define FLAG_ORDINAL 0x0040 /* function should be imported by ordinal */
#define FLAG_THISCALL 0x0080 /* use thiscall calling convention */
#define FLAG_FASTCALL 0x0100 /* use fastcall calling convention */
#define FLAG_IMPORT 0x0200 /* export is imported from another module */
#define FLAG_FORWARD 0x200 /* function is a forwarded name */
#define FLAG_EXT_LINK 0x400 /* function links to an external symbol */
#define FLAG_EXPORT32 0x800 /* 32-bit export in 16-bit spec file */
#define FLAG_FORWARD 0x1000 /* function is a forwarded name */
#define FLAG_EXT_LINK 0x2000 /* function links to an external symbol */
#define FLAG_EXPORT32 0x4000 /* 32-bit export in 16-bit spec file */
#define FLAG_CPU(cpu) (0x01000 << (cpu))
#define FLAG_CPU(cpu) (0x10000 << (cpu))
#define FLAG_CPU_MASK (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0))
#define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64))
#define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64)

View File

@ -838,6 +838,11 @@ static void output_immediate_imports(void)
for (j = 0; j < import->nb_imports; j++)
{
struct import_func *func = &import->imports[j];
if (i)
{
if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
}
if (func->name)
output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
get_asm_ptr_keyword(), import->c_name, func->name );

View File

@ -70,6 +70,7 @@ static const char * const FlagNames[] =
"ordinal", /* FLAG_ORDINAL */
"thiscall", /* FLAG_THISCALL */
"fastcall", /* FLAG_FASTCALL */
"import", /* FLAG_IMPORT */
NULL
};

View File

@ -379,9 +379,11 @@ static void output_relay_debug( DLLSPEC *spec )
void output_exports( DLLSPEC *spec )
{
int i, fwd_size = 0;
int needs_imports = 0;
int needs_relay = has_relays( spec );
int nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
const char *func_ptr = (target_platform == PLATFORM_WINDOWS) ? ".rva" : get_asm_ptr_keyword();
const char *name;
if (!nr_exports) return;
@ -430,6 +432,13 @@ void output_exports( DLLSPEC *spec )
output( "\t%s .L__wine_spec_forwards+%u\n", func_ptr, fwd_size );
fwd_size += strlen(odp->link_name) + 1;
}
else if ((odp->flags & FLAG_IMPORT) && (target_cpu == CPU_x86 || target_cpu == CPU_x86_64))
{
name = odp->name ? odp->name : odp->export_name;
if (name) output( "\t%s %s_%s\n", func_ptr, asm_name("__wine_spec_imp"), name );
else output( "\t%s %s_%u\n", func_ptr, asm_name("__wine_spec_imp"), i );
needs_imports = 1;
}
else if (odp->flags & FLAG_EXT_LINK)
{
output( "\t%s %s_%s\n", func_ptr, asm_name("__wine_spec_ext_link"), odp->link_name );
@ -503,32 +512,75 @@ void output_exports( DLLSPEC *spec )
/* output relays */
if (target_platform == PLATFORM_WINDOWS)
if (needs_relay)
{
if (!needs_relay) return;
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
}
else
{
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_exports_end:\n" );
if (!needs_relay)
if (target_platform == PLATFORM_WINDOWS)
{
output( "\t%s 0\n", get_asm_ptr_keyword() );
return;
output( "\t.data\n" );
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
}
else
{
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_exports_end:\n" );
}
output( ".L__wine_spec_relay_descr:\n" );
output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() ); /* magic */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* relay func */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* private data */
output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
output_relay_debug( spec );
}
else if (target_platform != PLATFORM_WINDOWS)
{
output( "\t.align %d\n", get_alignment(get_ptr_size()) );
output( ".L__wine_spec_exports_end:\n" );
output( "\t%s 0\n", get_asm_ptr_keyword() );
}
output( ".L__wine_spec_relay_descr:\n" );
output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() ); /* magic */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* relay func */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* private data */
output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
/* output import thunks */
output_relay_debug( spec );
if (!needs_imports) return;
output( "\t.text\n" );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
if (!(odp->flags & FLAG_IMPORT)) continue;
name = odp->name ? odp->name : odp->export_name;
output( "\t.align %d\n", get_alignment(4) );
output( "\t.long 0x90909090,0x90909090\n" );
if (name) output( "%s_%s:\n", asm_name("__wine_spec_imp"), name );
else output( "%s_%u:\n", asm_name("__wine_spec_imp"), i );
output_cfi( ".cfi_startproc" );
switch (target_cpu)
{
case CPU_x86:
output( "\t.byte 0x8b,0xff,0x55,0x8b,0xec,0x5d\n" ); /* hotpatch prolog */
if (UsePIC)
{
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
output( "1:\tjmp *__imp_%s-1b(%%eax)\n", asm_name( get_link_name( odp )));
needs_get_pc_thunk = 1;
}
else output( "\tjmp *__imp_%s\n", asm_name( get_link_name( odp )));
break;
case CPU_x86_64:
output( "\t.byte 0x48\n" ); /* hotpatch prolog */
output( "\tjmp *__imp_%s(%%rip)\n", asm_name( get_link_name( odp )));
break;
default:
assert(0);
}
output_cfi( ".cfi_endproc" );
}
}

View File

@ -315,6 +315,13 @@ The function uses the
calling convention (first two parameters in %ecx/%edx registers on
i386).
.TP
.B -import
The function is imported from another module. This can be used instead
of a
.I forward
specification when an application expects to find the function's
implementation inside the dll.
.TP
.RE
.BI -arch= cpu\fR[\fB,\fIcpu\fR]
The entry point is only available on the specified CPU