diff --git a/reactos/tools/winebuild/build.h b/reactos/tools/winebuild/build.h index 8543ef6067e..7f66b5b8b42 100644 --- a/reactos/tools/winebuild/build.h +++ b/reactos/tools/winebuild/build.h @@ -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 ); diff --git a/reactos/tools/winebuild/import.c b/reactos/tools/winebuild/import.c index 6f8bd28840f..a51eb30cbce 100644 --- a/reactos/tools/winebuild/import.c +++ b/reactos/tools/winebuild/import.c @@ -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 ); } diff --git a/reactos/tools/winebuild/parser.c b/reactos/tools/winebuild/parser.c index 5352b7a2ec7..1ea33766523 100644 --- a/reactos/tools/winebuild/parser.c +++ b/reactos/tools/winebuild/parser.c @@ -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" ) || diff --git a/reactos/tools/winebuild/relay.c b/reactos/tools/winebuild/relay.c index e53a8392b7d..ccf37ec78d3 100644 --- a/reactos/tools/winebuild/relay.c +++ b/reactos/tools/winebuild/relay.c @@ -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" ); } diff --git a/reactos/tools/winebuild/spec32.c b/reactos/tools/winebuild/spec32.c index ed500c7b176..bf45ffdb469 100644 --- a/reactos/tools/winebuild/spec32.c +++ b/reactos/tools/winebuild/spec32.c @@ -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 ); } diff --git a/reactos/tools/winebuild/utils.c b/reactos/tools/winebuild/utils.c index fbbfa455b41..85d552355a2 100644 --- a/reactos/tools/winebuild/utils.c +++ b/reactos/tools/winebuild/utils.c @@ -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) diff --git a/reactos/tools/winebuild/winebuild.man.in b/reactos/tools/winebuild/winebuild.man.in index a682a10646b..6c9bafcbdd5 100644 --- a/reactos/tools/winebuild/winebuild.man.in +++ b/reactos/tools/winebuild/winebuild.man.in @@ -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