Sync to Wine-0_9_4:

Alexandre Julliard <julliard@winehq.org>
- winebuild: Allow -register flag for Win32 too.
  This way it can be used as hint for the relay code.
- ntdll: Make __wine_call_from_32_restore_regs take a context pointer.
  Changed exception raise functions to call it explicitly.
- ntdll: New implementation of relay thunks.
  New implementation of relay thunks that doesn't require modifying code
  on the fly, so that the thunks can be put in the text section.
  Some performance improvements.

svn path=/trunk/; revision=20344
This commit is contained in:
Gé van Geldorp 2005-12-26 22:51:29 +00:00
parent f839c3ab83
commit a7c00fd10a
7 changed files with 149 additions and 54 deletions

View file

@ -189,6 +189,7 @@ extern const char *asm_globl( const char *func );
extern const char *get_asm_ptr_keyword(void);
extern const char *get_asm_string_keyword(void);
extern const char *get_asm_short_keyword(void);
extern const char *get_asm_rodata_section(void);
extern const char *get_asm_string_section(void);
extern void output_function_size( FILE *outfile, const char *name );
@ -199,6 +200,7 @@ extern void add_extra_ld_symbol( const char *name );
extern void read_undef_symbols( DLLSPEC *spec, char **argv );
extern int resolve_imports( DLLSPEC *spec );
extern int has_imports(void);
extern int has_relays( DLLSPEC *spec );
extern void output_get_pc_thunk( FILE *outfile );
extern void output_stubs( FILE *outfile, DLLSPEC *spec );
extern void output_imports( FILE *outfile, DLLSPEC *spec );

View file

@ -1245,5 +1245,6 @@ void output_imports( FILE *outfile, DLLSPEC *spec )
output_immediate_import_thunks( outfile );
output_delayed_import_thunks( outfile, spec );
output_external_link_imports( outfile, spec );
if (nb_imports || ext_link_imports.count || has_stubs(spec)) output_get_pc_thunk( outfile );
if (nb_imports || ext_link_imports.count || has_stubs(spec) || has_relays(spec))
output_get_pc_thunk( outfile );
}

View file

@ -516,12 +516,6 @@ static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
odp->ordinal = ordinal;
}
if (spec->type == SPEC_WIN32 && odp->flags & FLAG_REGISTER)
{
error( "-register flag not supported for Win32 entry points\n" );
goto error;
}
if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE))
{
if (!strcmp( odp->name, "DllRegisterServer" ) ||

View file

@ -849,7 +849,7 @@ static void BuildCallFrom32Regs( FILE *outfile )
output_function_size( outfile, "__wine_call_from_32_regs" );
function_header( outfile, "__wine_call_from_32_restore_regs" );
fprintf( outfile, "\tleal 4(%%esp),%%ecx\n" );
fprintf( outfile, "\tmovl 4(%%esp),%%ecx\n" );
fprintf( outfile, "\tjmp 2b\n" );
output_function_size( outfile, "__wine_call_from_32_restore_regs" );
}

View file

@ -37,7 +37,32 @@
#include "build.h"
/* check if entry point needs a relay thunk */
static inline int needs_relay( const ORDDEF *odp )
{
/* skip nonexistent entry points */
if (!odp) return 0;
/* skip non-functions */
if ((odp->type != TYPE_STDCALL) && (odp->type != TYPE_CDECL)) return 0;
/* skip norelay and forward entry points */
if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) return 0;
return 1;
}
/* check if dll will output relay thunks */
int has_relays( DLLSPEC *spec )
{
unsigned int i;
if (target_cpu != CPU_x86) return 0;
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (needs_relay( odp )) return 1;
}
return 0;
}
/*******************************************************************
* make_internal_name
@ -61,6 +86,101 @@ static const char *make_internal_name( const ORDDEF *odp, DLLSPEC *spec, const c
}
/*******************************************************************
* 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" );
}
}
}
/*******************************************************************
* output_exports
*
@ -183,58 +303,27 @@ static void output_exports( FILE *outfile, DLLSPEC *spec )
fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->link_name );
}
}
fprintf( outfile, "\t.align %d\n", get_alignment(4) );
fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
fprintf( outfile, ".L__wine_spec_exports_end:\n" );
/* output relays */
/* we only support relay debugging on i386 */
if (target_cpu == CPU_x86)
if (target_cpu != CPU_x86)
{
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
unsigned int j, args, mask = 0;
/* skip nonexistent entry points */
if (!odp) goto ignore;
/* skip non-functions */
if ((odp->type != TYPE_STDCALL) && (odp->type != TYPE_CDECL)) goto ignore;
/* skip norelay and forward entry points */
if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) goto ignore;
for (j = 0; odp->u.func.arg_types[j]; j++)
{
if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
}
if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000;
args = strlen(odp->u.func.arg_types) * get_ptr_size();
switch(odp->type)
{
case TYPE_STDCALL:
fprintf( outfile, "\tjmp %s\n", asm_name(odp->link_name) );
fprintf( outfile, "\tret $%d\n", args );
fprintf( outfile, "\t.long %s,0x%08x\n", asm_name(odp->link_name), mask );
break;
case TYPE_CDECL:
fprintf( outfile, "\tjmp %s\n", asm_name(odp->link_name) );
fprintf( outfile, "\tret\n" );
fprintf( outfile, "\t%s %d\n", get_asm_short_keyword(), args );
fprintf( outfile, "\t.long %s,0x%08x\n", asm_name(odp->link_name), mask );
break;
default:
assert(0);
}
continue;
ignore:
fprintf( outfile, "\t.long 0,0,0,0\n" );
}
fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
return;
}
else fprintf( outfile, "\t.long 0\n" );
fprintf( outfile, ".L__wine_spec_relay_descr:\n" );
fprintf( outfile, "\t%s 0xdeb90001\n", get_asm_ptr_keyword() ); /* magic */
fprintf( outfile, "\t%s 0,0\n", get_asm_ptr_keyword() ); /* relay funcs */
fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* private data */
fprintf( outfile, "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
fprintf( outfile, "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
fprintf( outfile, "\t%s .L__wine_spec_relay_arg_types\n", get_asm_ptr_keyword() );
output_relay_debug( outfile, spec );
}

View file

@ -585,6 +585,15 @@ const char *get_asm_short_keyword(void)
}
}
const char *get_asm_rodata_section(void)
{
switch (target_platform)
{
case PLATFORM_APPLE: return ".const";
default: return ".section .rodata";
}
}
const char *get_asm_string_section(void)
{
switch (target_platform)

View file

@ -260,7 +260,7 @@ The function returns a 64-bit value (Win32 only).
The entry point is only available on i386 platforms.
.TP
.B -register
The function uses CPU register to pass arguments (Win16 only).
The function uses CPU register to pass arguments.
.TP
.B -private
The function cannot be imported from other dlls, it can only be