From 6707cbf0a648c1b208872456689174bcd7cd5795 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Tue, 20 Jan 2009 11:44:30 +0000 Subject: [PATCH] sync winebuild with wine 1.1.13 svn path=/trunk/; revision=38972 --- reactos/tools/winebuild/build.h | 12 +- reactos/tools/winebuild/import.c | 91 +++++++----- reactos/tools/winebuild/main.c | 61 ++++---- reactos/tools/winebuild/parser.c | 43 ++++-- reactos/tools/winebuild/relay.c | 240 +++++++++++++++++++++++++++---- reactos/tools/winebuild/spec32.c | 87 ++++++----- reactos/tools/winebuild/utils.c | 26 ++++ 7 files changed, 415 insertions(+), 145 deletions(-) diff --git a/reactos/tools/winebuild/build.h b/reactos/tools/winebuild/build.h index e14b1ae9304..279bdef25af 100644 --- a/reactos/tools/winebuild/build.h +++ b/reactos/tools/winebuild/build.h @@ -128,14 +128,16 @@ extern enum target_platform target_platform; #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_I386 0x10 /* function is i386 only */ -#define FLAG_REGISTER 0x20 /* use register calling convention */ -#define FLAG_PRIVATE 0x40 /* function is private (cannot be imported) */ -#define FLAG_ORDINAL 0x80 /* function should be imported by ordinal */ +#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_FORWARD 0x100 /* function is a forwarded name */ #define FLAG_EXT_LINK 0x200 /* function links to an external symbol */ +#define FLAG_CPU(cpu) (0x01000 << (cpu)) +#define FLAG_CPU_MASK 0x1f000 + #define MAX_ORDINALS 65535 /* global functions */ @@ -178,6 +180,7 @@ extern DLLSPEC *alloc_dll_spec(void); extern void free_dll_spec( DLLSPEC *spec ); extern const char *make_c_identifier( const char *str ); extern const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec ); +extern enum target_cpu get_cpu_from_name( const char *name ); extern unsigned int get_alignment(unsigned int align); extern unsigned int get_page_size(void); extern unsigned int get_ptr_size(void); @@ -230,6 +233,7 @@ extern int kill_at; extern int verbose; extern int save_temps; extern int link_ext_symbols; +extern int force_pointer_size; extern char *input_file_name; extern char *spec_file_name; diff --git a/reactos/tools/winebuild/import.c b/reactos/tools/winebuild/import.c index e5223ecfe4d..cea90918953 100644 --- a/reactos/tools/winebuild/import.c +++ b/reactos/tools/winebuild/import.c @@ -970,22 +970,22 @@ static void output_delayed_import_thunks( const DLLSPEC *spec ) output( "\tjmp *%%eax\n" ); break; case CPU_x86_64: - output( "\tpushq %%rdi\n" ); - output( "\tpushq %%rsi\n" ); output( "\tpushq %%rdx\n" ); output( "\tpushq %%rcx\n" ); output( "\tpushq %%r8\n" ); output( "\tpushq %%r9\n" ); - output( "\tsubq $8,%%rsp\n" ); - output( "\tmovq %%r11,%%rdi\n" ); + output( "\tpushq %%r10\n" ); + output( "\tpushq %%r11\n" ); + output( "\tsubq $40,%%rsp\n" ); + output( "\tmovq %%rax,%%rcx\n" ); output( "\tcall %s\n", asm_name("__wine_spec_delay_load") ); - output( "\taddq $8,%%rsp\n" ); + output( "\taddq $40,%%rsp\n" ); + output( "\tpopq %%r11\n" ); + output( "\tpopq %%r10\n" ); output( "\tpopq %%r9\n" ); output( "\tpopq %%r8\n" ); output( "\tpopq %%rcx\n" ); output( "\tpopq %%rdx\n" ); - output( "\tpopq %%rsi\n" ); - output( "\tpopq %%rdi\n" ); output( "\tjmp *%%rax\n" ); break; case CPU_SPARC: @@ -1068,7 +1068,7 @@ static void output_delayed_import_thunks( const DLLSPEC *spec ) output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") ); break; case CPU_x86_64: - output( "\tmovq $%d,%%r11\n", (idx << 16) | j ); + output( "\tmovq $%d,%%rax\n", (idx << 16) | j ); output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") ); break; case CPU_SPARC: @@ -1191,45 +1191,64 @@ void output_stubs( DLLSPEC *spec ) output( "\t%s\n", func_declaration(name) ); output( "%s:\n", asm_name(name) ); - /* 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" ); + switch (target_cpu) + { + 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" ); - output( "\tsubl $4,%%esp\n" ); - if (UsePIC) - { - output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); - output( "1:" ); - if (exp_name) + output( "\tsubl $4,%%esp\n" ); + if (UsePIC) { - output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name ); + output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); + output( "1:" ); + if (exp_name) + { + output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name ); + output( "\tpushl %%ecx\n" ); + count++; + } + else + output( "\tpushl $%d\n", odp->ordinal ); + output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" ); output( "\tpushl %%ecx\n" ); - count++; } else - output( "\tpushl $%d\n", odp->ordinal ); - output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" ); - output( "\tpushl %%ecx\n" ); - } - else - { + { + if (exp_name) + { + output( "\tpushl $.L%s_string\n", name ); + count++; + } + else + output( "\tpushl $%d\n", odp->ordinal ); + output( "\tpushl $.L__wine_spec_file_name\n" ); + } + output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") ); + break; + case CPU_x86_64: + output( "\tleaq .L__wine_spec_file_name(%%rip),%%rdi\n" ); if (exp_name) { - output( "\tpushl $.L%s_string\n", name ); + output( "leaq .L%s_string(%%rip),%%rsi\n", name ); count++; } else - output( "\tpushl $%d\n", odp->ordinal ); - output( "\tpushl $.L__wine_spec_file_name\n" ); + output( "\tmovq $%d,%%rsi\n", odp->ordinal ); + output( "\tsubq $8,%%rsp\n" ); + output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") ); + break; + default: + assert(0); } - output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") ); output_function_size( name ); } diff --git a/reactos/tools/winebuild/main.c b/reactos/tools/winebuild/main.c index e80b08e402d..44094f71b33 100644 --- a/reactos/tools/winebuild/main.c +++ b/reactos/tools/winebuild/main.c @@ -47,6 +47,7 @@ int kill_at = 0; int verbose = 0; int save_temps = 0; int link_ext_symbols = 0; +int force_pointer_size = 0; #if defined(TARGET_i386) enum target_cpu target_cpu = CPU_x86; @@ -95,23 +96,6 @@ enum exec_mode_values static enum exec_mode_values exec_mode = MODE_NONE; -static const struct -{ - const char *name; - enum target_cpu cpu; -} cpu_names[] = -{ - { "i386", CPU_x86 }, - { "i486", CPU_x86 }, - { "i586", CPU_x86 }, - { "i686", CPU_x86 }, - { "i786", CPU_x86 }, - { "x86_64", CPU_x86_64 }, - { "sparc", CPU_SPARC }, - { "alpha", CPU_ALPHA }, - { "powerpc", CPU_POWERPC } -}; - static const struct { const char *name; @@ -176,13 +160,8 @@ static void set_target( const char *target ) if (!(p = strchr( spec, '-' ))) fatal_error( "Invalid target specification '%s'\n", target ); *p++ = 0; - for (i = 0; i < sizeof(cpu_names)/sizeof(cpu_names[0]); i++) - { - if (!strcmp( cpu_names[i].name, spec )) break; - } - if (i < sizeof(cpu_names)/sizeof(cpu_names[0])) target_cpu = cpu_names[i].cpu; - else fatal_error( "Unrecognized CPU '%s'\n", spec ); - + if ((target_cpu = get_cpu_from_name( spec )) == -1) + fatal_error( "Unrecognized CPU '%s'\n", spec ); platform = p; if ((p = strrchr( p, '-' ))) platform = p + 1; @@ -239,6 +218,7 @@ static const char usage_str[] = "Usage: winebuild [OPTIONS] [FILES]\n\n" "Options:\n" " --as-cmd=AS Command to use for assembling (default: as)\n" +" -b, --target=TARGET Specify target CPU and platform for cross-compiling\n" " -d, --delay-lib=LIB Import the specified library in delayed mode\n" " -D SYM Ignored for C flags compatibility\n" " -e, --entry=FUNC Set the DLL entry point function (default: DllMain)\n" @@ -255,6 +235,7 @@ static const char usage_str[] = " --ld-cmd=LD Command to use for linking (default: ld)\n" " -l, --library=LIB Import the specified library\n" " -L, --library-path=DIR Look for imports libraries in DIR\n" +" -m32, -m64 Force building 32-bit resp. 64-bit code\n" " -M, --main-module=MODULE Set the name of the main module for a Win16 dll\n" " --nm-cmd=NM Command to use to get undefined symbols (default: nm)\n" " --nxcompat=y|n Set the NX compatibility flag (default: yes)\n" @@ -263,7 +244,6 @@ static const char usage_str[] = " -r, --res=RSRC.RES Load resources from RSRC.RES\n" " --save-temps Do not delete the generated intermediate files\n" " --subsystem=SUBSYS Set the subsystem (one of native, windows, console)\n" -" --target=TARGET Specify target CPU and platform for cross-compiling\n" " -u, --undefined=SYMBOL Add an undefined reference to SYMBOL when linking\n" " -v, --verbose Display the programs invoked\n" " --version Print the version and exit\n" @@ -291,12 +271,11 @@ enum long_options_values LONG_OPT_RELAY32, LONG_OPT_SAVE_TEMPS, LONG_OPT_SUBSYSTEM, - LONG_OPT_TARGET, LONG_OPT_VERSION, LONG_OPT_PEDLL }; -static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:u:vw"; +static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:b:d:e:f:hi:kl:m:o:r:u:vw"; static const struct option long_options[] = { @@ -312,10 +291,10 @@ static const struct option long_options[] = { "relay32", 0, 0, LONG_OPT_RELAY32 }, { "save-temps", 0, 0, LONG_OPT_SAVE_TEMPS }, { "subsystem", 1, 0, LONG_OPT_SUBSYSTEM }, - { "target", 1, 0, LONG_OPT_TARGET }, { "version", 0, 0, LONG_OPT_VERSION }, { "pedll", 1, 0, LONG_OPT_PEDLL }, /* aliases for short options */ + { "target", 1, 0, 'b' }, { "delay-lib", 1, 0, 'd' }, { "export", 1, 0, 'E' }, { "entry", 1, 0, 'e' }, @@ -385,12 +364,21 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) ); lib_path[nb_lib_paths++] = xstrdup( optarg ); break; + case 'm': + if (strcmp( optarg, "32" ) && strcmp( optarg, "64" )) + fatal_error( "Invalid -m option '%s', expected -m32 or -m64\n", optarg ); + if (!strcmp( optarg, "32" )) force_pointer_size = 4; + else force_pointer_size = 8; + break; case 'M': spec->type = SPEC_WIN16; break; case 'N': spec->dll_name = xstrdup( optarg ); break; + case 'b': + set_target( optarg ); + break; case 'd': add_delayed_import( optarg ); break; @@ -495,9 +483,6 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) case LONG_OPT_SUBSYSTEM: set_subsystem( optarg, spec ); break; - case LONG_OPT_TARGET: - set_target( optarg ); - break; case LONG_OPT_VERSION: printf( "winebuild version " PACKAGE_VERSION "\n" ); exit(0); @@ -515,6 +500,20 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) if (spec->file_name && !strchr( spec->file_name, '.' )) strcat( spec->file_name, exec_mode == MODE_EXE ? ".exe" : ".dll" ); + switch (target_cpu) + { + case CPU_x86: + if (force_pointer_size == 8) target_cpu = CPU_x86_64; + break; + case CPU_x86_64: + if (force_pointer_size == 4) target_cpu = CPU_x86; + break; + default: + if (force_pointer_size == 8) + fatal_error( "Cannot build 64-bit code for this CPU\n" ); + break; + } + return &argv[optind]; } diff --git a/reactos/tools/winebuild/parser.c b/reactos/tools/winebuild/parser.c index 304899dfa22..a323bd452c0 100644 --- a/reactos/tools/winebuild/parser.c +++ b/reactos/tools/winebuild/parser.c @@ -67,7 +67,6 @@ static const char * const FlagNames[] = "noname", /* FLAG_NONAME */ "ret16", /* FLAG_RET16 */ "ret64", /* FLAG_RET64 */ - "i386", /* FLAG_I386 */ "register", /* FLAG_REGISTER */ "private", /* FLAG_PRIVATE */ "ordinal", /* FLAG_ORDINAL */ @@ -378,7 +377,7 @@ static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec ) { odp->u.func.arg_types[0] = '\0'; odp->link_name = xstrdup(""); - odp->flags |= FLAG_I386; /* don't bother generating stubs for Winelib */ + odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64); /* don't bother generating stubs for Winelib */ return 1; } @@ -428,14 +427,38 @@ static const char *parse_spec_flags( ORDDEF *odp ) do { if (!(token = GetToken(0))) break; - for (i = 0; FlagNames[i]; i++) - if (!strcmp( FlagNames[i], token )) break; - if (!FlagNames[i]) + if (!strncmp( token, "arch=", 5)) { - error( "Unknown flag '%s'\n", token ); - return NULL; + char *args = xstrdup( token + 5 ); + char *cpu_name = strtok( args, "," ); + while (cpu_name) + { + enum target_cpu cpu = get_cpu_from_name( cpu_name ); + if (cpu == -1) + { + error( "Unknown architecture '%s'\n", cpu_name ); + return NULL; + } + odp->flags |= FLAG_CPU( cpu ); + cpu_name = strtok( NULL, "," ); + } + free( args ); + } + else if (!strcmp( token, "i386" )) /* backwards compatibility */ + { + odp->flags |= FLAG_CPU(CPU_x86); + } + else + { + for (i = 0; FlagNames[i]; i++) + if (!strcmp( FlagNames[i], token )) break; + if (!FlagNames[i]) + { + error( "Unknown flag '%s'\n", token ); + return NULL; + } + odp->flags |= 1 << i; } - odp->flags |= 1 << i; token = GetToken(0); } while (token && *token == '-'); @@ -507,9 +530,9 @@ static int parse_spec_ordinal( int ordinal, DLLSPEC *spec ) assert( 0 ); } - if ((target_cpu != CPU_x86) && (odp->flags & FLAG_I386)) + if ((odp->flags & FLAG_CPU_MASK) && !(odp->flags & FLAG_CPU(target_cpu))) { - /* ignore this entry point on non-Intel archs */ + /* ignore this entry point */ spec->nb_entry_points--; return 1; } diff --git a/reactos/tools/winebuild/relay.c b/reactos/tools/winebuild/relay.c index 4ec0dbfb2f3..8b08cde8bea 100644 --- a/reactos/tools/winebuild/relay.c +++ b/reactos/tools/winebuild/relay.c @@ -741,9 +741,10 @@ static void BuildCallTo32CBClient( BOOL isEx ) * * Stack layout: * ... - * (ebp+16) first arg - * (ebp+12) ret addr to user code - * (ebp+8) eax saved by relay code + * (ebp+20) first arg + * (ebp+16) ret addr to user code + * (ebp+12) func to call (relative to relay code ret addr) + * (ebp+8) number of args * (ebp+4) ret addr to relay code * (ebp+0) saved ebp * (ebp-128) buffer area to allow stack frame manipulation @@ -770,17 +771,16 @@ static void BuildCallFrom32Regs(void) output( "\tpushl %%ebp\n" ); output( "\tmovl %%esp,%%ebp\n "); - output( "\tleal -%d(%%esp), %%esp\n", STACK_SPACE + 4 /* for context arg */); + output( "\tleal -%d(%%esp),%%esp\n", STACK_SPACE ); /* Build the context structure */ + output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eax) - STACK_SPACE ); output( "\tpushfl\n" ); output( "\tpopl %%eax\n" ); output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(EFlags) - STACK_SPACE ); output( "\tmovl 0(%%ebp),%%eax\n" ); output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Ebp) - STACK_SPACE ); - output( "\tmovl 8(%%ebp),%%eax\n" ); - output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eax) - STACK_SPACE ); output( "\tmovl %%ebx,%d(%%ebp)\n", CONTEXTOFFSET(Ebx) - STACK_SPACE ); output( "\tmovl %%ecx,%d(%%ebp)\n", CONTEXTOFFSET(Ecx) - STACK_SPACE ); output( "\tmovl %%edx,%d(%%ebp)\n", CONTEXTOFFSET(Edx) - STACK_SPACE ); @@ -805,31 +805,30 @@ static void BuildCallFrom32Regs(void) output( "\tmovl $0x%x,%%eax\n", CONTEXT86_FULL ); output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(ContextFlags) - STACK_SPACE ); - output( "\tmovl 12(%%ebp),%%eax\n" ); /* Get %eip at time of call */ + output( "\tmovl 16(%%ebp),%%eax\n" ); /* Get %eip at time of call */ output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eip) - STACK_SPACE ); /* Transfer the arguments */ - output( "\tmovl 4(%%ebp),%%ebx\n" ); /* get relay code addr */ - output( "\tmovzbl 4(%%ebx),%%ecx\n" ); /* fetch number of args to copy */ - output( "\tsubl %%ecx,%%esp\n" ); + output( "\tmovl 8(%%ebp),%%ecx\n" ); /* fetch number of args to copy */ + output( "\tleal 4(,%%ecx,4),%%edx\n" ); /* add 4 for context arg */ + output( "\tsubl %%edx,%%esp\n" ); output( "\tandl $~15,%%esp\n" ); - output( "\tleal 16(%%ebp),%%esi\n" ); /* get %esp at time of call */ + output( "\tleal 20(%%ebp),%%esi\n" ); /* get %esp at time of call */ output( "\tmovl %%esp,%%edi\n" ); - output( "\tshrl $2,%%ecx\n" ); + output( "\ttest %%ecx,%%ecx\n" ); output( "\tjz 1f\n" ); output( "\tcld\n" ); output( "\trep\n\tmovsl\n" ); /* copy args */ output( "1:\tleal %d(%%ebp),%%eax\n", -STACK_SPACE ); /* get addr of context struct */ output( "\tmovl %%eax,(%%edi)\n" ); /* and pass it as extra arg */ - output( "\tmovzbl 5(%%ebx),%%eax\n" ); /* fetch number of args to remove */ - output( "\tleal 16(%%ebp,%%eax),%%eax\n" ); - output( "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Esp) - STACK_SPACE ); + output( "\tmovl %%esi,%d(%%ebp)\n", CONTEXTOFFSET(Esp) - STACK_SPACE ); /* Call the entry point */ - output( "\taddl (%%ebx),%%ebx\n" ); - output( "\tcall *%%ebx\n" ); + output( "\tmovl 4(%%ebp),%%eax\n" ); /* get relay code addr */ + output( "\taddl 12(%%ebp),%%eax\n" ); + output( "\tcall *%%eax\n" ); output( "\tleal -%d(%%ebp),%%ecx\n", STACK_SPACE ); /* Restore the context structure */ @@ -975,9 +974,182 @@ void BuildRelays16(void) output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") ); if (UsePIC) output( "wine_ldt_copy_ptr:\t.long %s\n", asm_name("wine_ldt_copy") ); + + output( "\t.text\n" ); + output( "%s:\n\n", asm_name("__wine_spec_thunk_text_32") ); + BuildCallFrom32Regs(); + output_function_size( "__wine_spec_thunk_text_32" ); + output_gnu_stack_note(); } + +/******************************************************************* + * build_call_from_regs_x86_64 + * + * Build the register saving code for a 'register' entry point. + * + * Stack layout: + * ... + * (rsp+16) first arg + * (rsp+8) ret addr to user code + * (rsp) ret addr to relay code + * (rsp-128) buffer area to allow stack frame manipulation + * + * Parameters: + * %rcx number of args + * %rdx entry point + */ +static void build_call_from_regs_x86_64(void) +{ + static const int STACK_SPACE = 128 + 0x4d0; /* size of x86_64 context */ + + /* Function header */ + + function_header( "__wine_call_from_regs" ); + + output( "\tsubq $%u,%%rsp\n", STACK_SPACE ); + + /* save registers into the context */ + + output( "\tmovq %%rax,0x78(%%rsp)\n" ); + output( "\tmovq %u(%%rsp),%%rax\n", STACK_SPACE + 16 ); /* saved %rcx on stack */ + output( "\tmovq %%rax,0x80(%%rsp)\n" ); + output( "\tmovq %u(%%rsp),%%rax\n", STACK_SPACE + 24 ); /* saved %rdx on stack */ + output( "\tmovq %%rax,0x88(%%rsp)\n" ); + output( "\tmovq %%rbx,0x90(%%rsp)\n" ); + output( "\tleaq %u(%%rsp),%%rax\n", STACK_SPACE + 16 ); + output( "\tmovq %%rax,0x98(%%rsp)\n" ); + output( "\tmovq %%rbp,0xa0(%%rsp)\n" ); + output( "\tmovq %%rsi,0xa8(%%rsp)\n" ); + output( "\tmovq %%rdi,0xb0(%%rsp)\n" ); + output( "\tmovq %%r8,0xb8(%%rsp)\n" ); + output( "\tmovq %%r9,0xc0(%%rsp)\n" ); + output( "\tmovq %%r10,0xc8(%%rsp)\n" ); + output( "\tmovq %%r11,0xd0(%%rsp)\n" ); + output( "\tmovq %%r12,0xd8(%%rsp)\n" ); + output( "\tmovq %%r13,0xe0(%%rsp)\n" ); + output( "\tmovq %%r14,0xe8(%%rsp)\n" ); + output( "\tmovq %%r15,0xf0(%%rsp)\n" ); + output( "\tmovq %u(%%rsp),%%rax\n", STACK_SPACE + 8 ); + output( "\tmovq %%rax,0xf8(%%rsp)\n" ); + + output( "\tstmxcsr 0x34(%%rsp)\n" ); + output( "\tfxsave 0x100(%%rsp)\n" ); + output( "\tmovdqa %%xmm0,0x1a0(%%rsp)\n" ); + output( "\tmovdqa %%xmm1,0x1b0(%%rsp)\n" ); + output( "\tmovdqa %%xmm2,0x1c0(%%rsp)\n" ); + output( "\tmovdqa %%xmm3,0x1d0(%%rsp)\n" ); + output( "\tmovdqa %%xmm4,0x1e0(%%rsp)\n" ); + output( "\tmovdqa %%xmm5,0x1f0(%%rsp)\n" ); + output( "\tmovdqa %%xmm6,0x200(%%rsp)\n" ); + output( "\tmovdqa %%xmm7,0x210(%%rsp)\n" ); + output( "\tmovdqa %%xmm8,0x220(%%rsp)\n" ); + output( "\tmovdqa %%xmm9,0x230(%%rsp)\n" ); + output( "\tmovdqa %%xmm10,0x240(%%rsp)\n" ); + output( "\tmovdqa %%xmm11,0x250(%%rsp)\n" ); + output( "\tmovdqa %%xmm12,0x260(%%rsp)\n" ); + output( "\tmovdqa %%xmm13,0x270(%%rsp)\n" ); + output( "\tmovdqa %%xmm14,0x280(%%rsp)\n" ); + output( "\tmovdqa %%xmm15,0x290(%%rsp)\n" ); + + output( "\tmovw %%cs,0x38(%%rsp)\n" ); + output( "\tmovw %%ds,0x3a(%%rsp)\n" ); + output( "\tmovw %%es,0x3c(%%rsp)\n" ); + output( "\tmovw %%fs,0x3e(%%rsp)\n" ); + output( "\tmovw %%gs,0x40(%%rsp)\n" ); + output( "\tmovw %%ss,0x42(%%rsp)\n" ); + output( "\tpushfq\n" ); + output( "\tpopq %%rax\n" ); + output( "\tmovl %%eax,0x44(%%rsp)\n" ); + + output( "\tmovl $0x%x,0x30(%%rsp)\n", 0x0010000f ); + + /* transfer the arguments */ + + output( "\tmovq %%r8,%u(%%rsp)\n", STACK_SPACE + 32 ); + output( "\tmovq %%r9,%u(%%rsp)\n", STACK_SPACE + 40 ); + output( "\tmovq $4,%%rax\n" ); + output( "\tleaq %u(%%rsp),%%rsi\n", STACK_SPACE + 16 ); + output( "\tcmpq %%rax,%%rcx\n" ); + output( "\tcmovgq %%rcx,%%rax\n" ); + output( "\tmovq %%rsp,%%rbx\n" ); + output( "\tleaq 16(,%%rax,8),%%rax\n" ); /* add 8 for context arg and 8 for rounding */ + output( "\tandq $~15,%%rax\n" ); + output( "\tsubq %%rax,%%rsp\n" ); + output( "\tmovq %%rsp,%%rdi\n" ); + output( "\tjrcxz 1f\n" ); + output( "\tcld\n" ); + output( "\trep\n\tmovsq\n" ); + output( "1:\tmovq %%rbx,0(%%rdi)\n" ); /* context arg */ + + /* call the entry point */ + + output( "\tmovq %%rdx,%%rax\n" ); + output( "\tmovq 0(%%rsp),%%rcx\n" ); + output( "\tmovq 8(%%rsp),%%rdx\n" ); + output( "\tmovq 16(%%rsp),%%r8\n" ); + output( "\tmovq 24(%%rsp),%%r9\n" ); + output( "\tcallq *%%rax\n" ); + + /* restore the context structure */ + + output( "1:\tmovq 0x80(%%rbx),%%rcx\n" ); + output( "\tmovq 0x88(%%rbx),%%rdx\n" ); + output( "\tmovq 0xa0(%%rbx),%%rbp\n" ); + output( "\tmovq 0xa8(%%rbx),%%rsi\n" ); + output( "\tmovq 0xb0(%%rbx),%%rdi\n" ); + output( "\tmovq 0xb8(%%rbx),%%r8\n" ); + output( "\tmovq 0xc0(%%rbx),%%r9\n" ); + output( "\tmovq 0xc8(%%rbx),%%r10\n" ); + output( "\tmovq 0xd0(%%rbx),%%r11\n" ); + output( "\tmovq 0xd8(%%rbx),%%r12\n" ); + output( "\tmovq 0xe0(%%rbx),%%r13\n" ); + output( "\tmovq 0xe8(%%rbx),%%r14\n" ); + output( "\tmovq 0xf0(%%rbx),%%r15\n" ); + + output( "\tmovdqa 0x1a0(%%rbx),%%xmm0\n" ); + output( "\tmovdqa 0x1b0(%%rbx),%%xmm1\n" ); + output( "\tmovdqa 0x1c0(%%rbx),%%xmm2\n" ); + output( "\tmovdqa 0x1d0(%%rbx),%%xmm3\n" ); + output( "\tmovdqa 0x1e0(%%rbx),%%xmm4\n" ); + output( "\tmovdqa 0x1f0(%%rbx),%%xmm5\n" ); + output( "\tmovdqa 0x200(%%rbx),%%xmm6\n" ); + output( "\tmovdqa 0x210(%%rbx),%%xmm7\n" ); + output( "\tmovdqa 0x220(%%rbx),%%xmm8\n" ); + output( "\tmovdqa 0x230(%%rbx),%%xmm9\n" ); + output( "\tmovdqa 0x240(%%rbx),%%xmm10\n" ); + output( "\tmovdqa 0x250(%%rbx),%%xmm11\n" ); + output( "\tmovdqa 0x260(%%rbx),%%xmm12\n" ); + output( "\tmovdqa 0x270(%%rbx),%%xmm13\n" ); + output( "\tmovdqa 0x280(%%rbx),%%xmm14\n" ); + output( "\tmovdqa 0x290(%%rbx),%%xmm15\n" ); + output( "\tfxrstor 0x100(%%rbx)\n" ); + output( "\tldmxcsr 0x34(%%rbx)\n" ); + + output( "\tmovl 0x44(%%rbx),%%eax\n" ); + output( "\tpushq %%rax\n" ); + output( "\tpopfq\n" ); + + output( "\tmovq 0x98(%%rbx),%%rax\n" ); /* stack pointer */ + output( "\tpushq 0xf8(%%rbx)\n" ); /* return address */ + output( "\tpopq -8(%%rax)\n" ); + output( "\tpushq 0x78(%%rbx)\n" ); /* rax */ + output( "\tpopq -16(%%rax)\n" ); + output( "\tmovq 0x90(%%rbx),%%rbx\n" ); + output( "\tleaq -16(%%rax),%%rsp\n" ); + output( "\tpopq %%rax\n" ); + output( "\tret\n" ); + + output_function_size( "__wine_call_from_regs" ); + + function_header( "__wine_restore_regs" ); + output( "\tmovq %%rcx,%%rbx\n" ); + output( "\tjmp 1b\n" ); + output_function_size( "__wine_restore_regs" ); +} + + /******************************************************************* * BuildRelays32 * @@ -985,21 +1157,29 @@ void BuildRelays16(void) */ void BuildRelays32(void) { - if (target_cpu != CPU_x86) + switch (target_cpu) { + case CPU_x86: + output( "/* File generated automatically. Do not edit! */\n\n" ); + output( "\t.text\n" ); + output( "%s:\n\n", asm_name("__wine_spec_thunk_text_32") ); + + /* 32-bit register entry point */ + BuildCallFrom32Regs(); + + output_function_size( "__wine_spec_thunk_text_32" ); + output_gnu_stack_note(); + break; + + case CPU_x86_64: + output( "/* File generated automatically. Do not edit! */\n\n" ); + output( "\t.text\n" ); + build_call_from_regs_x86_64(); + output_gnu_stack_note(); + break; + + default: output( "/* File not used with this architecture. Do not edit! */\n\n" ); return; } - - /* File header */ - - output( "/* File generated automatically. Do not edit! */\n\n" ); - output( "\t.text\n" ); - output( "%s:\n\n", asm_name("__wine_spec_thunk_text_32") ); - - /* 32-bit register entry point */ - BuildCallFrom32Regs(); - - output_function_size( "__wine_spec_thunk_text_32" ); - output_gnu_stack_note(); } diff --git a/reactos/tools/winebuild/spec32.c b/reactos/tools/winebuild/spec32.c index afbeb0583fd..4cafbae333b 100644 --- a/reactos/tools/winebuild/spec32.c +++ b/reactos/tools/winebuild/spec32.c @@ -52,7 +52,7 @@ int has_relays( DLLSPEC *spec ) { int i; - if (target_cpu != CPU_x86) return 0; + if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64) return 0; for (i = spec->base; i <= spec->limit; i++) { @@ -146,36 +146,58 @@ static void output_relay_debug( DLLSPEC *spec ) output( "\t.align %d\n", get_alignment(4) ); output( ".L__wine_spec_relay_entry_point_%d:\n", i ); - if (odp->flags & FLAG_REGISTER) - output( "\tpushl %%eax\n" ); - else - output( "\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; - output( "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) ); - if (UsePIC) + switch (target_cpu) { - 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() ); + case CPU_x86: + if (odp->flags & FLAG_REGISTER) + output( "\tpushl %%eax\n" ); else - output( "\tret\n" ); + 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); } } } @@ -307,8 +329,8 @@ static void output_exports( DLLSPEC *spec ) /* output relays */ - /* we only support relay debugging on i386 */ - if (target_cpu != CPU_x86) + /* we only support relay debugging on i386 and x86_64 */ + if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64) { output( "\t%s 0\n", get_asm_ptr_keyword() ); return; @@ -605,11 +627,8 @@ void BuildDef32File( DLLSPEC *spec ) switch(odp->type) { case TYPE_EXTERN: - output( " %s", name ); is_data = 1; - if(strcmp(name, odp->link_name) || (odp->flags & FLAG_FORWARD)) - output( "=%s", odp->link_name ); - break; + /* fall through */ case TYPE_VARARGS: case TYPE_CDECL: /* try to reduce output */ @@ -621,7 +640,7 @@ void BuildDef32File( DLLSPEC *spec ) { int at_param = strlen(odp->u.func.arg_types) * get_ptr_size(); output( " %s", name ); - if (!kill_at) output( "@%d", at_param ); + if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param ); if (odp->flags & FLAG_FORWARD) { output( "=%s", odp->link_name ); @@ -629,7 +648,7 @@ void BuildDef32File( DLLSPEC *spec ) else if (strcmp(name, odp->link_name)) /* try to reduce output */ { output( "=%s", odp->link_name ); - if (!kill_at) output( "@%d", at_param ); + if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param ); } break; } diff --git a/reactos/tools/winebuild/utils.c b/reactos/tools/winebuild/utils.c index b0972abc1cd..d2b42317049 100644 --- a/reactos/tools/winebuild/utils.c +++ b/reactos/tools/winebuild/utils.c @@ -38,6 +38,23 @@ static const char *tmp_files[MAX_TMP_FILES]; static unsigned int nb_tmp_files; +static const struct +{ + const char *name; + enum target_cpu cpu; +} cpu_names[] = +{ + { "i386", CPU_x86 }, + { "i486", CPU_x86 }, + { "i586", CPU_x86 }, + { "i686", CPU_x86 }, + { "i786", CPU_x86 }, + { "x86_64", CPU_x86_64 }, + { "sparc", CPU_SPARC }, + { "alpha", CPU_ALPHA }, + { "powerpc", CPU_POWERPC } +}; + /* atexit handler to clean tmp files */ static void cleanup_tmp_files(void) { @@ -416,6 +433,15 @@ const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec ) return buffer; } +/* parse a cpu name and return the corresponding value */ +enum target_cpu get_cpu_from_name( const char *name ) +{ + unsigned int i; + + for (i = 0; i < sizeof(cpu_names)/sizeof(cpu_names[0]); i++) + if (!strcmp( cpu_names[i].name, name )) return cpu_names[i].cpu; + return -1; +} /***************************************************************** * Function: get_alignment