sync winebuild with wine 1.1.13

svn path=/trunk/; revision=38972
This commit is contained in:
Christoph von Wittich 2009-01-20 11:44:30 +00:00
parent 7dfd3a9852
commit 6707cbf0a6
7 changed files with 415 additions and 145 deletions

View file

@ -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;

View file

@ -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 );
}

View file

@ -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];
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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