forked from Mirrors/wine-wine
ntdll: Display floating point arguments in relay debugging on i386 and x86-64.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>oldstable
parent
83bbeab9b2
commit
8c1bb2aa61
|
@ -44,14 +44,13 @@ struct relay_descr /* descriptor for a module */
|
||||||
{
|
{
|
||||||
void *magic; /* signature */
|
void *magic; /* signature */
|
||||||
void *relay_call; /* functions to call from relay thunks */
|
void *relay_call; /* functions to call from relay thunks */
|
||||||
void *relay_call_regs; /* no longer used */
|
|
||||||
void *private; /* reserved for the relay code private data */
|
void *private; /* reserved for the relay code private data */
|
||||||
const char *entry_point_base; /* base address of entry point thunks */
|
const char *entry_point_base; /* base address of entry point thunks */
|
||||||
const unsigned int *entry_point_offsets; /* offsets of entry points thunks */
|
const unsigned int *entry_point_offsets; /* offsets of entry points thunks */
|
||||||
const unsigned int *arg_types; /* table of argument types for all entry points */
|
const char *args_string; /* string describing the arguments */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RELAY_DESCR_MAGIC ((void *)0xdeb90001)
|
#define RELAY_DESCR_MAGIC ((void *)0xdeb90002)
|
||||||
#define IS_INTARG(x) (((ULONG_PTR)(x) >> 16) == 0)
|
#define IS_INTARG(x) (((ULONG_PTR)(x) >> 16) == 0)
|
||||||
|
|
||||||
/* private data built at dll load time */
|
/* private data built at dll load time */
|
||||||
|
@ -295,49 +294,85 @@ static BOOL check_from_module( const WCHAR **includelist, const WCHAR **excludel
|
||||||
return show;
|
return show;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* RELAY_PrintArgs
|
static BOOL is_ret_val( char type )
|
||||||
*/
|
|
||||||
static inline void RELAY_PrintArgs( const INT_PTR *args, int nb_args, unsigned int typemask )
|
|
||||||
{
|
{
|
||||||
while (nb_args--)
|
return type >= 'A' && type <= 'Z';
|
||||||
{
|
|
||||||
if ((typemask & 3) && !IS_INTARG(*args))
|
|
||||||
{
|
|
||||||
if (typemask & 2)
|
|
||||||
TRACE( "%08lx %s", *args, debugstr_w((LPCWSTR)*args) );
|
|
||||||
else
|
|
||||||
TRACE( "%08lx %s", *args, debugstr_a((LPCSTR)*args) );
|
|
||||||
}
|
|
||||||
else TRACE( "%08lx", *args );
|
|
||||||
if (nb_args) TRACE( "," );
|
|
||||||
args++;
|
|
||||||
typemask >>= 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *func_name( struct relay_private_data *data, unsigned int ordinal )
|
||||||
|
{
|
||||||
|
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
||||||
|
|
||||||
|
if (entry_point->name)
|
||||||
|
return wine_dbg_sprintf( "%s.%s", data->dllname, entry_point->name );
|
||||||
|
else
|
||||||
|
return wine_dbg_sprintf( "%s.%u", data->dllname, data->base + ordinal );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace_string_a( INT_PTR ptr )
|
||||||
|
{
|
||||||
|
if (!IS_INTARG( ptr )) TRACE( "%08lx %s", ptr, debugstr_a( (char *)ptr ));
|
||||||
|
else TRACE( "%08lx", ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace_string_w( INT_PTR ptr )
|
||||||
|
{
|
||||||
|
if (!IS_INTARG( ptr )) TRACE( "%08lx %s", ptr, debugstr_w( (WCHAR *)ptr ));
|
||||||
|
else TRACE( "%08lx", ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* relay_trace_entry
|
* relay_trace_entry
|
||||||
*
|
|
||||||
* stack points to the return address, i.e. the first argument is stack[1].
|
|
||||||
*/
|
*/
|
||||||
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr,
|
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
|
||||||
unsigned int idx, const INT_PTR *stack )
|
const DWORD *stack, unsigned int *nb_args )
|
||||||
{
|
{
|
||||||
WORD ordinal = LOWORD(idx);
|
WORD ordinal = LOWORD(idx);
|
||||||
BYTE nb_args = LOBYTE(HIWORD(idx));
|
const char *arg_types = descr->args_string + HIWORD(idx);
|
||||||
struct relay_private_data *data = descr->private;
|
struct relay_private_data *data = descr->private;
|
||||||
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
||||||
|
unsigned int i, pos;
|
||||||
|
|
||||||
if (TRACE_ON(relay))
|
TRACE( "\1Call %s(", func_name( data, ordinal ));
|
||||||
|
|
||||||
|
for (i = pos = 0; !is_ret_val( arg_types[i] ); i++)
|
||||||
{
|
{
|
||||||
if (entry_point->name)
|
switch (arg_types[i])
|
||||||
TRACE( "\1Call %s.%s(", data->dllname, entry_point->name );
|
{
|
||||||
else
|
case 'j': /* int64 */
|
||||||
TRACE( "\1Call %s.%u(", data->dllname, data->base + ordinal );
|
TRACE( "%x%08x", stack[pos+1], stack[pos] );
|
||||||
RELAY_PrintArgs( stack + 1, nb_args, descr->arg_types[ordinal] );
|
pos += 2;
|
||||||
TRACE( ") ret=%08lx\n", stack[0] );
|
break;
|
||||||
|
case 'k': /* int128 */
|
||||||
|
TRACE( "{%08x,%08x,%08x,%08x}", stack[pos], stack[pos+1], stack[pos+2], stack[pos+3] );
|
||||||
|
pos += 4;
|
||||||
|
break;
|
||||||
|
case 's': /* str */
|
||||||
|
trace_string_a( stack[pos++] );
|
||||||
|
break;
|
||||||
|
case 'w': /* wstr */
|
||||||
|
trace_string_w( stack[pos++] );
|
||||||
|
break;
|
||||||
|
case 'f': /* float */
|
||||||
|
TRACE( "%g", *(const float *)&stack[pos++] );
|
||||||
|
break;
|
||||||
|
case 'd': /* double */
|
||||||
|
TRACE( "%g", *(const double *)&stack[pos] );
|
||||||
|
pos += 2;
|
||||||
|
break;
|
||||||
|
case 'i': /* long */
|
||||||
|
default:
|
||||||
|
TRACE( "%08x", stack[pos++] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!is_ret_val( arg_types[i+1] )) TRACE( "," );
|
||||||
}
|
}
|
||||||
|
*nb_args = pos;
|
||||||
|
if (arg_types[0] == 't') *nb_args |= 0x80000000; /* thiscall */
|
||||||
|
TRACE( ") ret=%08x\n", stack[-1] );
|
||||||
return entry_point->orig_func;
|
return entry_point->orig_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,63 +380,21 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr,
|
||||||
* relay_trace_exit
|
* relay_trace_exit
|
||||||
*/
|
*/
|
||||||
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
|
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
|
||||||
const INT_PTR *stack, LONGLONG retval )
|
void *retaddr, LONGLONG retval )
|
||||||
{
|
{
|
||||||
WORD ordinal = LOWORD(idx);
|
const char *arg_types = descr->args_string + HIWORD(idx);
|
||||||
BYTE flags = HIBYTE(HIWORD(idx));
|
|
||||||
struct relay_private_data *data = descr->private;
|
|
||||||
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
|
||||||
|
|
||||||
if (entry_point->name)
|
TRACE( "\1Ret %s()", func_name( descr->private, LOWORD(idx) ));
|
||||||
TRACE( "\1Ret %s.%s()", data->dllname, entry_point->name );
|
|
||||||
else
|
|
||||||
TRACE( "\1Ret %s.%u()", data->dllname, data->base + ordinal );
|
|
||||||
|
|
||||||
if (flags & 1) /* 64-bit return value */
|
while (!is_ret_val( *arg_types )) arg_types++;
|
||||||
TRACE( " retval=%08x%08x ret=%08lx\n",
|
if (*arg_types == 'J') /* int64 return value */
|
||||||
(UINT)(retval >> 32), (UINT)retval, stack[0] );
|
TRACE( " retval=%08x%08x ret=%08x\n",
|
||||||
|
(UINT)(retval >> 32), (UINT)retval, (UINT)retaddr );
|
||||||
else
|
else
|
||||||
TRACE( " retval=%08lx ret=%08lx\n", (UINT_PTR)retval, stack[0] );
|
TRACE( " retval=%08x ret=%08x\n", (UINT)retval, (UINT)retaddr );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __i386__
|
extern LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx );
|
||||||
|
|
||||||
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
|
|
||||||
__ASM_GLOBAL_FUNC( call_entry_point,
|
|
||||||
"pushl %ebp\n\t"
|
|
||||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
|
||||||
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
|
|
||||||
"movl %esp,%ebp\n\t"
|
|
||||||
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
|
|
||||||
"pushl %esi\n\t"
|
|
||||||
__ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
|
|
||||||
"pushl %edi\n\t"
|
|
||||||
__ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
|
|
||||||
"movl 12(%ebp),%edx\n\t"
|
|
||||||
"shll $2,%edx\n\t"
|
|
||||||
"jz 1f\n\t"
|
|
||||||
"subl %edx,%esp\n\t"
|
|
||||||
"andl $~15,%esp\n\t"
|
|
||||||
"movl 12(%ebp),%ecx\n\t"
|
|
||||||
"movl 16(%ebp),%esi\n\t"
|
|
||||||
"movl %esp,%edi\n\t"
|
|
||||||
"cld\n\t"
|
|
||||||
"rep; movsl\n"
|
|
||||||
"testl $2,20(%ebp)\n\t" /* (flags & 2) -> thiscall */
|
|
||||||
"jz 1f\n\t"
|
|
||||||
"popl %ecx\n\t"
|
|
||||||
"1:\tcall *8(%ebp)\n\t"
|
|
||||||
"leal -8(%ebp),%esp\n\t"
|
|
||||||
"popl %edi\n\t"
|
|
||||||
__ASM_CFI(".cfi_same_value %edi\n\t")
|
|
||||||
"popl %esi\n\t"
|
|
||||||
__ASM_CFI(".cfi_same_value %esi\n\t")
|
|
||||||
"popl %ebp\n\t"
|
|
||||||
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
|
|
||||||
__ASM_CFI(".cfi_same_value %ebp\n\t")
|
|
||||||
"ret" )
|
|
||||||
|
|
||||||
extern LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack );
|
|
||||||
__ASM_GLOBAL_FUNC( relay_call,
|
__ASM_GLOBAL_FUNC( relay_call,
|
||||||
"pushl %ebp\n\t"
|
"pushl %ebp\n\t"
|
||||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||||
|
@ -415,22 +408,24 @@ __ASM_GLOBAL_FUNC( relay_call,
|
||||||
"pushl %ecx\n\t"
|
"pushl %ecx\n\t"
|
||||||
__ASM_CFI(".cfi_rel_offset %ecx,-12\n\t")
|
__ASM_CFI(".cfi_rel_offset %ecx,-12\n\t")
|
||||||
/* trace the parameters */
|
/* trace the parameters */
|
||||||
"pushl 16(%ebp)\n\t"
|
"pushl %eax\n\t"
|
||||||
|
"pushl %esp\n\t" /* number of args return ptr */
|
||||||
|
"leal 20(%ebp),%esi\n\t" /* stack */
|
||||||
|
"pushl %esi\n\t"
|
||||||
"pushl 12(%ebp)\n\t"
|
"pushl 12(%ebp)\n\t"
|
||||||
"pushl 8(%ebp)\n\t"
|
"pushl 8(%ebp)\n\t"
|
||||||
"call " __ASM_NAME("relay_trace_entry") "\n\t"
|
"call " __ASM_NAME("relay_trace_entry") "\n\t"
|
||||||
/* copy the arguments*/
|
/* copy the arguments*/
|
||||||
"movzbl 14(%ebp),%ecx\n\t" /* number of args */
|
"movl -16(%ebp),%ecx\n\t" /* number of args */
|
||||||
"jecxz 1f\n\t"
|
"jecxz 1f\n\t"
|
||||||
|
"andl $0x7fffffff,%ecx\n\t"
|
||||||
"leal 0(,%ecx,4),%edx\n\t"
|
"leal 0(,%ecx,4),%edx\n\t"
|
||||||
"subl %edx,%esp\n\t"
|
"subl %edx,%esp\n\t"
|
||||||
"andl $~15,%esp\n\t"
|
"andl $~15,%esp\n\t"
|
||||||
"movl 16(%ebp),%esi\n\t"
|
|
||||||
"addl $4,%esi\n\t"
|
|
||||||
"movl %esp,%edi\n\t"
|
"movl %esp,%edi\n\t"
|
||||||
"cld\n\t"
|
"cld\n\t"
|
||||||
"rep; movsl\n\t"
|
"rep; movsl\n\t"
|
||||||
"testb $2,15(%ebp)\n\t" /* (flags & 2) -> thiscall */
|
"testl $0x80000000,-16(%ebp)\n\t" /* thiscall */
|
||||||
"jz 1f\n\t"
|
"jz 1f\n\t"
|
||||||
"popl %ecx\n"
|
"popl %ecx\n"
|
||||||
/* call the entry point */
|
/* call the entry point */
|
||||||
|
@ -458,11 +453,73 @@ __ASM_GLOBAL_FUNC( relay_call,
|
||||||
"popl %ebp\n\t"
|
"popl %ebp\n\t"
|
||||||
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
|
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
|
||||||
__ASM_CFI(".cfi_same_value %ebp\n\t")
|
__ASM_CFI(".cfi_same_value %ebp\n\t")
|
||||||
"ret $12" )
|
"ret $8" )
|
||||||
|
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
|
|
||||||
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
|
/***********************************************************************
|
||||||
|
* relay_trace_entry
|
||||||
|
*/
|
||||||
|
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
|
||||||
|
const DWORD *stack, unsigned int *nb_args )
|
||||||
|
{
|
||||||
|
WORD ordinal = LOWORD(idx);
|
||||||
|
const char *arg_types = descr->args_string + HIWORD(idx);
|
||||||
|
struct relay_private_data *data = descr->private;
|
||||||
|
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
||||||
|
unsigned int i, pos;
|
||||||
|
|
||||||
|
TRACE( "\1Call %s(", func_name( data, ordinal ));
|
||||||
|
|
||||||
|
for (i = pos = 0; !is_ret_val( arg_types[i] ); i++)
|
||||||
|
{
|
||||||
|
switch (arg_types[i])
|
||||||
|
{
|
||||||
|
case 'j': /* int64 */
|
||||||
|
TRACE( "%x%08x", stack[pos+1], stack[pos] );
|
||||||
|
pos += 2;
|
||||||
|
break;
|
||||||
|
case 'k': /* int128 */
|
||||||
|
TRACE( "{%08x,%08x,%08x,%08x}", stack[pos], stack[pos+1], stack[pos+2], stack[pos+3] );
|
||||||
|
pos += 4;
|
||||||
|
break;
|
||||||
|
case 's': /* str */
|
||||||
|
trace_string_a( stack[pos++] );
|
||||||
|
break;
|
||||||
|
case 'w': /* wstr */
|
||||||
|
trace_string_w( stack[pos++] );
|
||||||
|
break;
|
||||||
|
case 'i': /* long */
|
||||||
|
default:
|
||||||
|
TRACE( "%08x", stack[pos++] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!is_ret_val( arg_types[i+1] )) TRACE( "," );
|
||||||
|
}
|
||||||
|
*nb_args = pos;
|
||||||
|
TRACE( ") ret=%08x\n", stack[-1] );
|
||||||
|
return entry_point->orig_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* relay_trace_exit
|
||||||
|
*/
|
||||||
|
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
|
||||||
|
DWORD retaddr, LONGLONG retval )
|
||||||
|
{
|
||||||
|
const char *arg_types = descr->args_string + HIWORD(idx);
|
||||||
|
|
||||||
|
TRACE( "\1Ret %s()", func_name( descr->private, LOWORD(idx) ));
|
||||||
|
|
||||||
|
while (!is_ret_val( *arg_types )) arg_types++;
|
||||||
|
if (*arg_types == 'J') /* int64 return value */
|
||||||
|
TRACE( " retval=%08x%08x ret=%08x\n",
|
||||||
|
(UINT)(retval >> 32), (UINT)retval, retaddr );
|
||||||
|
else
|
||||||
|
TRACE( " retval=%08x ret=%08x\n", (UINT)retval, retaddr );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const DWORD *args );
|
||||||
__ASM_GLOBAL_FUNC( call_entry_point,
|
__ASM_GLOBAL_FUNC( call_entry_point,
|
||||||
".arm\n\t"
|
".arm\n\t"
|
||||||
"push {r4, r5, LR}\n\t"
|
"push {r4, r5, LR}\n\t"
|
||||||
|
@ -487,19 +544,64 @@ __ASM_GLOBAL_FUNC( call_entry_point,
|
||||||
"mov SP, r5\n\t"
|
"mov SP, r5\n\t"
|
||||||
"pop {r4, r5, PC}" )
|
"pop {r4, r5, PC}" )
|
||||||
|
|
||||||
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack )
|
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const DWORD *stack )
|
||||||
{
|
{
|
||||||
BYTE nb_args = LOBYTE(HIWORD(idx));
|
unsigned int nb_args;
|
||||||
BYTE flags = HIBYTE(HIWORD(idx));
|
void *func = relay_trace_entry( descr, idx, stack, &nb_args );
|
||||||
void *func = relay_trace_entry( descr, idx, stack );
|
LONGLONG ret = call_entry_point( func, nb_args, stack );
|
||||||
LONGLONG ret = call_entry_point( func, nb_args, stack + 1, flags );
|
relay_trace_exit( descr, idx, stack[-1], ret );
|
||||||
relay_trace_exit( descr, idx, stack, ret );
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
|
|
||||||
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
|
/***********************************************************************
|
||||||
|
* relay_trace_entry
|
||||||
|
*/
|
||||||
|
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
|
||||||
|
const INT_PTR *stack, unsigned int *nb_args )
|
||||||
|
{
|
||||||
|
WORD ordinal = LOWORD(idx);
|
||||||
|
const char *arg_types = descr->args_string + HIWORD(idx);
|
||||||
|
struct relay_private_data *data = descr->private;
|
||||||
|
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
TRACE( "\1Call %s(", func_name( data, ordinal ));
|
||||||
|
|
||||||
|
for (i = 0; !is_ret_val( arg_types[i] ); i++)
|
||||||
|
{
|
||||||
|
switch (arg_types[i])
|
||||||
|
{
|
||||||
|
case 's': /* str */
|
||||||
|
trace_string_a( stack[i] );
|
||||||
|
break;
|
||||||
|
case 'w': /* wstr */
|
||||||
|
trace_string_w( stack[i] );
|
||||||
|
break;
|
||||||
|
case 'i': /* long */
|
||||||
|
default:
|
||||||
|
TRACE( "%08lx", stack[i] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!is_ret_val( arg_types[i + 1] )) TRACE( "," );
|
||||||
|
}
|
||||||
|
*nb_args = i;
|
||||||
|
TRACE( ") ret=%08lx\n", stack[-1] );
|
||||||
|
return entry_point->orig_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* relay_trace_exit
|
||||||
|
*/
|
||||||
|
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
|
||||||
|
INT_PTR retaddr, INT_PTR retval )
|
||||||
|
{
|
||||||
|
TRACE( "\1Ret %s() retval=%08lx ret=%08lx\n",
|
||||||
|
func_name( descr->private, LOWORD(idx) ), retval, retaddr );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args );
|
||||||
__ASM_GLOBAL_FUNC( call_entry_point,
|
__ASM_GLOBAL_FUNC( call_entry_point,
|
||||||
"stp x29, x30, [SP,#-16]!\n\t"
|
"stp x29, x30, [SP,#-16]!\n\t"
|
||||||
"stp x19, x20, [SP,#-16]!\n\t"
|
"stp x19, x20, [SP,#-16]!\n\t"
|
||||||
|
@ -544,43 +646,97 @@ __ASM_GLOBAL_FUNC( call_entry_point,
|
||||||
|
|
||||||
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack )
|
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack )
|
||||||
{
|
{
|
||||||
BYTE nb_args = LOBYTE(HIWORD(idx));
|
unsigned int nb_args;
|
||||||
BYTE flags = HIBYTE(HIWORD(idx));
|
void *func = relay_trace_entry( descr, idx, stack, &nb_args );
|
||||||
void *func = relay_trace_entry( descr, idx, stack + 3 );
|
LONGLONG ret = call_entry_point( func, nb_args, stack );
|
||||||
LONGLONG ret = call_entry_point( func, nb_args, stack + 4, flags );
|
relay_trace_exit( descr, idx, stack[-1], ret );
|
||||||
relay_trace_exit( descr, idx, stack + 3, ret );
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
extern void * WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack );
|
/***********************************************************************
|
||||||
|
* relay_trace_entry
|
||||||
|
*/
|
||||||
|
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
|
||||||
|
const INT_PTR *stack, unsigned int *nb_args )
|
||||||
|
{
|
||||||
|
WORD ordinal = LOWORD(idx);
|
||||||
|
const char *arg_types = descr->args_string + HIWORD(idx);
|
||||||
|
struct relay_private_data *data = descr->private;
|
||||||
|
struct relay_entry_point *entry_point = data->entry_points + ordinal;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
TRACE( "\1Call %s(", func_name( data, ordinal ));
|
||||||
|
|
||||||
|
for (i = 0; !is_ret_val( arg_types[i] ); i++)
|
||||||
|
{
|
||||||
|
switch (arg_types[i])
|
||||||
|
{
|
||||||
|
case 's': /* str */
|
||||||
|
trace_string_a( stack[i] );
|
||||||
|
break;
|
||||||
|
case 'w': /* wstr */
|
||||||
|
trace_string_w( stack[i] );
|
||||||
|
break;
|
||||||
|
case 'f': /* float */
|
||||||
|
TRACE( "%g", *(const float *)&stack[i] );
|
||||||
|
break;
|
||||||
|
case 'd': /* double */
|
||||||
|
TRACE( "%g", *(const double *)&stack[i] );
|
||||||
|
break;
|
||||||
|
case 'i': /* long */
|
||||||
|
default:
|
||||||
|
TRACE( "%08lx", stack[i] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!is_ret_val( arg_types[i] )) TRACE( "," );
|
||||||
|
}
|
||||||
|
*nb_args = i;
|
||||||
|
TRACE( ") ret=%08lx\n", stack[-1] );
|
||||||
|
return entry_point->orig_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* relay_trace_exit
|
||||||
|
*/
|
||||||
|
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
|
||||||
|
INT_PTR retaddr, INT_PTR retval )
|
||||||
|
{
|
||||||
|
TRACE( "\1Ret %s() retval=%08lx ret=%08lx\n",
|
||||||
|
func_name( descr->private, LOWORD(idx) ), retval, retaddr );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern INT_PTR WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack );
|
||||||
__ASM_GLOBAL_FUNC( relay_call,
|
__ASM_GLOBAL_FUNC( relay_call,
|
||||||
"pushq %rbp\n\t"
|
"pushq %rbp\n\t"
|
||||||
__ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
|
__ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
|
||||||
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
|
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
|
||||||
"movq %rsp,%rbp\n\t"
|
"movq %rsp,%rbp\n\t"
|
||||||
__ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
|
__ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
|
||||||
"subq $0x30,%rsp\n\t"
|
"leaq -0x48(%rbp),%rsp\n\t"
|
||||||
"movq %rsi,0x20(%rsp)\n\t"
|
"andq $~15,%rsp\n\t"
|
||||||
|
"movq %rcx,-32(%rbp)\n\t"
|
||||||
|
__ASM_CFI(".cfi_rel_offset %rcx,-32\n\t")
|
||||||
|
"movq %rdx,-24(%rbp)\n\t"
|
||||||
|
__ASM_CFI(".cfi_rel_offset %rdx,-24\n\t")
|
||||||
|
"movq %rsi,-16(%rbp)\n\t"
|
||||||
__ASM_CFI(".cfi_rel_offset %rsi,-16\n\t")
|
__ASM_CFI(".cfi_rel_offset %rsi,-16\n\t")
|
||||||
"movq %rdi,0x28(%rsp)\n\t"
|
"movq %rdi,-8(%rbp)\n\t"
|
||||||
__ASM_CFI(".cfi_rel_offset %rdi,-8\n\t")
|
__ASM_CFI(".cfi_rel_offset %rdi,-8\n\t")
|
||||||
/* trace the parameters */
|
/* trace the parameters */
|
||||||
"movq %rcx,0x10(%rbp)\n\t"
|
"leaq 24(%rbp),%r8\n\t" /* stack */
|
||||||
"movq %rdx,0x18(%rbp)\n\t"
|
"leaq -40(%rbp),%r9\n\t"
|
||||||
"movq %r8,0x20(%rbp)\n\t"
|
|
||||||
"call " __ASM_NAME("relay_trace_entry") "\n\t"
|
"call " __ASM_NAME("relay_trace_entry") "\n\t"
|
||||||
/* copy the arguments */
|
/* copy the arguments */
|
||||||
"movzbq 0x1a(%rbp),%rdx\n\t" /* number of args */
|
"movl -40(%rbp),%edx\n\t" /* number of args */
|
||||||
"movq $4,%rcx\n\t"
|
"movq $4,%rcx\n\t"
|
||||||
"cmp %rcx,%rdx\n\t"
|
"cmp %rcx,%rdx\n\t"
|
||||||
"cmovgq %rdx,%rcx\n\t"
|
"cmovgq %rdx,%rcx\n\t"
|
||||||
"leaq -16(,%rcx,8),%rdx\n\t"
|
"leaq -16(,%rcx,8),%rdx\n\t"
|
||||||
"andq $~15,%rdx\n\t"
|
"andq $~15,%rdx\n\t"
|
||||||
"subq %rdx,%rsp\n\t"
|
"subq %rdx,%rsp\n\t"
|
||||||
"movq 0x20(%rbp),%r8\n\t" /* original stack */
|
"leaq 24(%rbp),%rsi\n\t" /* original stack */
|
||||||
"leaq 8(%r8),%rsi\n\t"
|
|
||||||
"movq %rsp,%rdi\n\t"
|
"movq %rsp,%rdi\n\t"
|
||||||
"rep; movsq\n\t"
|
"rep; movsq\n\t"
|
||||||
/* call the entry point */
|
/* call the entry point */
|
||||||
|
@ -594,20 +750,19 @@ __ASM_GLOBAL_FUNC( relay_call,
|
||||||
"movq 24(%rsp),%xmm3\n\t"
|
"movq 24(%rsp),%xmm3\n\t"
|
||||||
"callq *%rax\n\t"
|
"callq *%rax\n\t"
|
||||||
/* trace the return value */
|
/* trace the return value */
|
||||||
"leaq -0x30(%rbp),%rsp\n\t"
|
"movq -32(%rbp),%rcx\n\t"
|
||||||
"movq 0x10(%rbp),%rcx\n\t"
|
"movq -24(%rbp),%rdx\n\t"
|
||||||
"movq 0x18(%rbp),%rdx\n\t"
|
"movq 16(%rbp),%r8\n\t" /* retaddr */
|
||||||
"movq 0x20(%rbp),%r8\n\t"
|
|
||||||
"movq %rax,%rsi\n\t"
|
"movq %rax,%rsi\n\t"
|
||||||
"movaps %xmm0,0x10(%rbp)\n\t"
|
"movaps %xmm0,32(%rsp)\n\t"
|
||||||
"movq %rax,%r9\n\t"
|
"movq %rax,%r9\n\t"
|
||||||
"call " __ASM_NAME("relay_trace_exit") "\n\t"
|
"call " __ASM_NAME("relay_trace_exit") "\n\t"
|
||||||
/* restore return value and return */
|
/* restore return value and return */
|
||||||
"movq %rsi,%rax\n\t"
|
"movq %rsi,%rax\n\t"
|
||||||
"movaps 0x10(%rbp),%xmm0\n\t"
|
"movaps 32(%rsp),%xmm0\n\t"
|
||||||
"movq 0x20(%rsp),%rsi\n\t"
|
"movq -16(%rbp),%rsi\n\t"
|
||||||
__ASM_CFI(".cfi_same_value %rsi\n\t")
|
__ASM_CFI(".cfi_same_value %rsi\n\t")
|
||||||
"movq 0x28(%rsp),%rdi\n\t"
|
"movq -8(%rbp),%rdi\n\t"
|
||||||
__ASM_CFI(".cfi_same_value %rdi\n\t")
|
__ASM_CFI(".cfi_same_value %rdi\n\t")
|
||||||
"movq %rbp,%rsp\n\t"
|
"movq %rbp,%rsp\n\t"
|
||||||
__ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
|
__ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
|
||||||
|
|
|
@ -86,6 +86,7 @@ typedef struct
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int nb_args;
|
int nb_args;
|
||||||
|
int args_str_offset;
|
||||||
enum arg_type args[MAX_ARGUMENTS];
|
enum arg_type args[MAX_ARGUMENTS];
|
||||||
} ORD_FUNCTION;
|
} ORD_FUNCTION;
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,88 @@ static int has_relays( DLLSPEC *spec )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmp_func_args( const void *p1, const void *p2 )
|
||||||
|
{
|
||||||
|
const ORDDEF *odp1 = *(const ORDDEF **)p1;
|
||||||
|
const ORDDEF *odp2 = *(const ORDDEF **)p2;
|
||||||
|
|
||||||
|
return odp2->u.func.nb_args - odp1->u.func.nb_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_arg_string( ORDDEF *odp, char str[MAX_ARGUMENTS + 1] )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < odp->u.func.nb_args; i++)
|
||||||
|
{
|
||||||
|
switch (odp->u.func.args[i])
|
||||||
|
{
|
||||||
|
case ARG_STR: str[i] = 's'; break;
|
||||||
|
case ARG_WSTR: str[i] = 'w'; break;
|
||||||
|
case ARG_FLOAT: str[i] = 'f'; break;
|
||||||
|
case ARG_DOUBLE: str[i] = 'd'; break;
|
||||||
|
case ARG_INT64:
|
||||||
|
case ARG_INT128:
|
||||||
|
if (get_ptr_size() == 4)
|
||||||
|
{
|
||||||
|
str[i] = (odp->u.func.args[i] == ARG_INT64) ? 'j' : 'k';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case ARG_LONG:
|
||||||
|
case ARG_PTR:
|
||||||
|
default:
|
||||||
|
str[i] = 'i';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target_cpu == CPU_x86 && odp->type == TYPE_THISCALL) str[0] = 't';
|
||||||
|
|
||||||
|
/* append return value */
|
||||||
|
if (get_ptr_size() == 4 && (odp->flags & FLAG_RET64))
|
||||||
|
strcpy( str + i, "J" );
|
||||||
|
else
|
||||||
|
strcpy( str + i, "I" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* build_args_string
|
||||||
|
*/
|
||||||
|
static char *build_args_string( DLLSPEC *spec )
|
||||||
|
{
|
||||||
|
int i, count = 0, len = 1;
|
||||||
|
char *p, *buffer;
|
||||||
|
char str[MAX_ARGUMENTS + 2];
|
||||||
|
ORDDEF **funcs;
|
||||||
|
|
||||||
|
funcs = xmalloc( (spec->limit + 1 - spec->base) * sizeof(*funcs) );
|
||||||
|
for (i = spec->base; i <= spec->limit; i++)
|
||||||
|
{
|
||||||
|
ORDDEF *odp = spec->ordinals[i];
|
||||||
|
|
||||||
|
if (!needs_relay( odp )) continue;
|
||||||
|
funcs[count++] = odp;
|
||||||
|
len += odp->u.func.nb_args + 1;
|
||||||
|
}
|
||||||
|
/* sort functions by decreasing number of arguments */
|
||||||
|
qsort( funcs, count, sizeof(*funcs), cmp_func_args );
|
||||||
|
buffer = xmalloc( len );
|
||||||
|
buffer[0] = 0;
|
||||||
|
/* build the arguments string, reusing substrings where possible */
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
get_arg_string( funcs[i], str );
|
||||||
|
if (!(p = strstr( buffer, str )))
|
||||||
|
{
|
||||||
|
p = buffer + strlen( buffer );
|
||||||
|
strcpy( p, str );
|
||||||
|
}
|
||||||
|
funcs[i]->u.func.args_str_offset = p - buffer;
|
||||||
|
}
|
||||||
|
free( funcs );
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* output_relay_debug
|
* output_relay_debug
|
||||||
*
|
*
|
||||||
|
@ -101,8 +183,7 @@ static int has_relays( DLLSPEC *spec )
|
||||||
*/
|
*/
|
||||||
static void output_relay_debug( DLLSPEC *spec )
|
static void output_relay_debug( DLLSPEC *spec )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i;
|
||||||
unsigned int pos, args, flags;
|
|
||||||
|
|
||||||
/* first the table of entry point offsets */
|
/* first the table of entry point offsets */
|
||||||
|
|
||||||
|
@ -120,33 +201,10 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
output( "\t.long 0\n" );
|
output( "\t.long 0\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* then the table of argument types */
|
/* then the strings of argument types */
|
||||||
|
|
||||||
output( "\t.align %d\n", get_alignment(4) );
|
output( ".L__wine_spec_relay_args_string:\n" );
|
||||||
output( ".L__wine_spec_relay_arg_types:\n" );
|
output( "\t%s \"%s\"\n", get_asm_string_keyword(), build_args_string( spec ));
|
||||||
|
|
||||||
for (i = spec->base; i <= spec->limit; i++)
|
|
||||||
{
|
|
||||||
ORDDEF *odp = spec->ordinals[i];
|
|
||||||
unsigned int mask = 0;
|
|
||||||
|
|
||||||
if (needs_relay( odp ))
|
|
||||||
{
|
|
||||||
for (j = pos = 0; pos < 16 && j < odp->u.func.nb_args; j++)
|
|
||||||
{
|
|
||||||
switch (odp->u.func.args[j])
|
|
||||||
{
|
|
||||||
case ARG_STR: mask |= 1 << (2 * pos++); break;
|
|
||||||
case ARG_WSTR: mask |= 2 << (2 * pos++); break;
|
|
||||||
case ARG_INT64:
|
|
||||||
case ARG_DOUBLE: pos += 8 / get_ptr_size(); break;
|
|
||||||
case ARG_INT128: pos += (target_cpu == CPU_x86) ? 4 : 1; break;
|
|
||||||
default: pos++; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output( "\t.long 0x%08x\n", mask );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* then the relay thunks */
|
/* then the relay thunks */
|
||||||
|
|
||||||
|
@ -164,9 +222,6 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
output( ".L__wine_spec_relay_entry_point_%d:\n", i );
|
output( ".L__wine_spec_relay_entry_point_%d:\n", i );
|
||||||
output_cfi( ".cfi_startproc" );
|
output_cfi( ".cfi_startproc" );
|
||||||
|
|
||||||
args = get_args_size(odp) / get_ptr_size();
|
|
||||||
flags = 0;
|
|
||||||
|
|
||||||
switch (target_cpu)
|
switch (target_cpu)
|
||||||
{
|
{
|
||||||
case CPU_x86:
|
case CPU_x86:
|
||||||
|
@ -175,13 +230,8 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
output( "\tpopl %%eax\n" );
|
output( "\tpopl %%eax\n" );
|
||||||
output( "\tpushl %%ecx\n" );
|
output( "\tpushl %%ecx\n" );
|
||||||
output( "\tpushl %%eax\n" );
|
output( "\tpushl %%eax\n" );
|
||||||
flags |= 2;
|
|
||||||
}
|
}
|
||||||
output( "\tpushl %%esp\n" );
|
output( "\tpushl $%u\n", (odp->u.func.args_str_offset << 16) | (i - spec->base) );
|
||||||
output_cfi( ".cfi_adjust_cfa_offset 4" );
|
|
||||||
|
|
||||||
if (odp->flags & FLAG_RET64) flags |= 1;
|
|
||||||
output( "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) );
|
|
||||||
output_cfi( ".cfi_adjust_cfa_offset 4" );
|
output_cfi( ".cfi_adjust_cfa_offset 4" );
|
||||||
|
|
||||||
if (UsePIC)
|
if (UsePIC)
|
||||||
|
@ -195,9 +245,9 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
output_cfi( ".cfi_adjust_cfa_offset 4" );
|
output_cfi( ".cfi_adjust_cfa_offset 4" );
|
||||||
|
|
||||||
output( "\tcall *4(%%eax)\n" );
|
output( "\tcall *4(%%eax)\n" );
|
||||||
output_cfi( ".cfi_adjust_cfa_offset -12" );
|
output_cfi( ".cfi_adjust_cfa_offset -8" );
|
||||||
if (odp->type == TYPE_STDCALL || odp->type == TYPE_THISCALL)
|
if (odp->type == TYPE_STDCALL || odp->type == TYPE_THISCALL)
|
||||||
output( "\tret $%u\n", args * get_ptr_size() );
|
output( "\tret $%u\n", get_args_size( odp ));
|
||||||
else
|
else
|
||||||
output( "\tret\n" );
|
output( "\tret\n" );
|
||||||
break;
|
break;
|
||||||
|
@ -205,18 +255,17 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
case CPU_ARM:
|
case CPU_ARM:
|
||||||
{
|
{
|
||||||
unsigned int mask, val, count = 0;
|
unsigned int mask, val, count = 0;
|
||||||
unsigned int stack_size = min( 16, (args * 4 + 7) & ~7 );
|
unsigned int stack_size = min( 16, (get_args_size( odp ) + 7) & ~7 );
|
||||||
|
|
||||||
if (odp->flags & FLAG_RET64) flags |= 1;
|
val = (odp->u.func.args_str_offset << 16) | (i - spec->base);
|
||||||
val = (flags << 24) | (args << 16) | (i - spec->base);
|
|
||||||
switch (stack_size)
|
switch (stack_size)
|
||||||
{
|
{
|
||||||
case 16: output( "\tpush {r0-r3}\n" ); break;
|
case 16: output( "\tpush {r0-r3}\n" ); break;
|
||||||
case 8: output( "\tpush {r0-r1}\n" ); break;
|
case 8: output( "\tpush {r0-r1}\n" ); break;
|
||||||
case 0: break;
|
case 0: break;
|
||||||
}
|
}
|
||||||
output( "\tpush {LR}\n" );
|
|
||||||
output( "\tmov r2, SP\n");
|
output( "\tmov r2, SP\n");
|
||||||
|
output( "\tpush {LR}\n" );
|
||||||
output( "\tsub SP, #4\n");
|
output( "\tsub SP, #4\n");
|
||||||
for (mask = 0xff; mask; mask <<= 8)
|
for (mask = 0xff; mask; mask <<= 8)
|
||||||
if (val & mask) output( "\t%s r1,#%u\n", count++ ? "add" : "mov", val & mask );
|
if (val & mask) output( "\t%s r1,#%u\n", count++ ? "add" : "mov", val & mask );
|
||||||
|
@ -233,7 +282,7 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
}
|
}
|
||||||
|
|
||||||
case CPU_ARM64:
|
case CPU_ARM64:
|
||||||
switch (args)
|
switch (odp->u.func.nb_args)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case 8:
|
case 8:
|
||||||
|
@ -250,12 +299,10 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 0: break;
|
case 0: break;
|
||||||
}
|
}
|
||||||
|
output( "\tmov x2, SP\n");
|
||||||
output( "\tstp x29, x30, [SP,#-16]!\n" );
|
output( "\tstp x29, x30, [SP,#-16]!\n" );
|
||||||
output( "\tstp x8, x9, [SP,#-16]!\n" );
|
output( "\tstp x8, x9, [SP,#-16]!\n" );
|
||||||
output( "\tmov x2, SP\n");
|
output( "\tmov w1, #%u\n", odp->u.func.args_str_offset << 16 );
|
||||||
if (odp->flags & FLAG_RET64) flags |= 1;
|
|
||||||
output( "\tmov w1, #%u\n", (flags << 24) );
|
|
||||||
if (args) output( "\tadd w1, w1, #%u\n", (args << 16) );
|
|
||||||
if (i - spec->base) output( "\tadd w1, w1, #%u\n", i - spec->base );
|
if (i - spec->base) output( "\tadd w1, w1, #%u\n", i - spec->base );
|
||||||
output( "\tadrp x0, .L__wine_spec_relay_descr\n");
|
output( "\tadrp x0, .L__wine_spec_relay_descr\n");
|
||||||
output( "\tadd x0, x0, #:lo12:.L__wine_spec_relay_descr\n");
|
output( "\tadd x0, x0, #:lo12:.L__wine_spec_relay_descr\n");
|
||||||
|
@ -263,31 +310,27 @@ static void output_relay_debug( DLLSPEC *spec )
|
||||||
output( "\tblr x3\n");
|
output( "\tblr x3\n");
|
||||||
output( "\tadd SP, SP, #16\n" );
|
output( "\tadd SP, SP, #16\n" );
|
||||||
output( "\tldp x29, x30, [SP], #16\n" );
|
output( "\tldp x29, x30, [SP], #16\n" );
|
||||||
if (args) output( "\tadd SP, SP, #%u\n", 8 * ((min(args, 8) + 1) & 0xe) );
|
if (odp->u.func.nb_args)
|
||||||
|
output( "\tadd SP, SP, #%u\n", 8 * ((min(odp->u.func.nb_args, 8) + 1) & ~1) );
|
||||||
output( "\tret\n");
|
output( "\tret\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_x86_64:
|
case CPU_x86_64:
|
||||||
output( "\tsubq $40,%%rsp\n" );
|
switch (odp->u.func.nb_args)
|
||||||
output_cfi( ".cfi_adjust_cfa_offset 40" );
|
|
||||||
switch (args)
|
|
||||||
{
|
{
|
||||||
default: output( "\tmovq %%%s,72(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
|
default: output( "\tmovq %%%s,32(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 3: output( "\tmovq %%%s,64(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
|
case 3: output( "\tmovq %%%s,24(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 2: output( "\tmovq %%%s,56(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
|
case 2: output( "\tmovq %%%s,16(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 1: output( "\tmovq %%%s,48(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
|
case 1: output( "\tmovq %%%s,8(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 0: break;
|
case 0: break;
|
||||||
}
|
}
|
||||||
output( "\tleaq 40(%%rsp),%%r8\n" );
|
output( "\tmovl $%u,%%edx\n", (odp->u.func.args_str_offset << 16) | (i - spec->base) );
|
||||||
output( "\tmovq $%u,%%rdx\n", (flags << 24) | (args << 16) | (i - spec->base) );
|
|
||||||
output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
|
output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
|
||||||
output( "\tcallq *8(%%rcx)\n" );
|
output( "\tcallq *8(%%rcx)\n" );
|
||||||
output( "\taddq $40,%%rsp\n" );
|
|
||||||
output_cfi( ".cfi_adjust_cfa_offset -40" );
|
|
||||||
output( "\tret\n" );
|
output( "\tret\n" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -432,12 +475,12 @@ void output_exports( DLLSPEC *spec )
|
||||||
}
|
}
|
||||||
|
|
||||||
output( ".L__wine_spec_relay_descr:\n" );
|
output( ".L__wine_spec_relay_descr:\n" );
|
||||||
output( "\t%s 0xdeb90001\n", get_asm_ptr_keyword() ); /* magic */
|
output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() ); /* magic */
|
||||||
output( "\t%s 0,0\n", get_asm_ptr_keyword() ); /* relay funcs */
|
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 0\n", get_asm_ptr_keyword() ); /* private data */
|
||||||
output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
|
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_entry_point_offsets\n", get_asm_ptr_keyword() );
|
||||||
output( "\t%s .L__wine_spec_relay_arg_types\n", get_asm_ptr_keyword() );
|
output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
|
||||||
|
|
||||||
output_relay_debug( spec );
|
output_relay_debug( spec );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue