From 5e3534ee411a8c5baea5022705eac0e3c7f3cc70 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 14 Dec 2017 11:44:57 +0100 Subject: [PATCH] ntdll: Fix handling of floating point arguments in relay debugging on ARM. Signed-off-by: Alexandre Julliard --- dlls/ntdll/relay.c | 114 ++++++++++++++++++++++++++++----------- tools/winebuild/spec32.c | 16 +++--- 2 files changed, 92 insertions(+), 38 deletions(-) diff --git a/dlls/ntdll/relay.c b/dlls/ntdll/relay.c index 5d784201ca2..a0c3cb1190f 100644 --- a/dlls/ntdll/relay.c +++ b/dlls/ntdll/relay.c @@ -468,6 +468,10 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi struct relay_private_data *data = descr->private; struct relay_entry_point *entry_point = data->entry_points + ordinal; unsigned int i, pos; +#ifndef __SOFTFP__ + unsigned int float_pos = 0, double_pos = 0; + const union fpregs { float s[16]; double d[8]; } *fpstack = (const union fpregs *)stack - 1; +#endif TRACE( "\1Call %s(", func_name( data, ordinal )); @@ -476,6 +480,7 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi switch (arg_types[i]) { case 'j': /* int64 */ + pos = (pos + 1) & ~1; TRACE( "%x%08x", stack[pos+1], stack[pos] ); pos += 2; break; @@ -489,6 +494,30 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi case 'w': /* wstr */ trace_string_w( stack[pos++] ); break; + case 'f': /* float */ +#ifndef __SOFTFP__ + if (!(float_pos % 2)) float_pos = max( float_pos, double_pos * 2 ); + if (float_pos < 16) + { + TRACE( "%g", fpstack->s[float_pos++] ); + break; + } +#endif + TRACE( "%g", *(const float *)&stack[pos++] ); + break; + case 'd': /* double */ +#ifndef __SOFTFP__ + double_pos = max( (float_pos + 1) / 2, double_pos ); + if (double_pos < 8) + { + TRACE( "%g", fpstack->d[double_pos++] ); + break; + } +#endif + pos = (pos + 1) & ~1; + TRACE( "%g", *(const double *)&stack[pos] ); + pos += 2; + break; case 'i': /* long */ default: TRACE( "%08x", stack[pos++] ); @@ -496,6 +525,14 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi } if (!is_ret_val( arg_types[i+1] )) TRACE( "," ); } + +#ifndef __SOFTFP__ + if (float_pos || double_pos) + { + pos |= 0x80000000; + stack = (const DWORD *)fpstack; /* retaddr is below the fp regs */ + } +#endif *nb_args = pos; TRACE( ") ret=%08x\n", stack[-1] ); return entry_point->orig_func; @@ -519,39 +556,56 @@ DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigne 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, +extern LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const DWORD *stack ); +__ASM_GLOBAL_FUNC( relay_call, ".arm\n\t" - "push {r4, r5, LR}\n\t" - "mov r4, r0\n\t" - "mov r5, SP\n\t" + "push {r4-r8,lr}\n\t" + "sub sp, #16\n\t" + "mov r6, r2\n\t" + "add r3, sp, #12\n\t" + "mov r7, r0\n\t" + "mov r8, r1\n\t" + "bl " __ASM_NAME("relay_trace_entry") "\n\t" + "mov ip, r0\n\t" /* entry point */ + "mov r5, sp\n\t" + "ldr r1, [sp, #12]\n\t" /* number of args */ "lsl r3, r1, #2\n\t" - "sub SP, SP, r3\n\t" - "and SP, SP, #~7\n" - "1:\tsub r3, r3, #4\n\t" + "subs r3, #16\n\t" /* first 4 args are in registers */ + "ble 2f\n\t" + "sub sp, r3\n\t" + "and sp, #~7\n" + "add r2, r6, #16\n\t" /* skip r0-r3 */ + "1:\tsubs r3, r3, #4\n\t" "ldr r0, [r2, r3]\n\t" - "str r0, [SP, r3]\n\t" - "cmp r3, #0\n\t" - "bgt 1b\n\t" - "cmp r1, #0\n\t" - "beq 3f\n\t" - "cmp r1, #2\n\t" - "bgt 2f\n\t" - "pop {r0-r1}\n\t" - "b 3f\n" - "2:\tpop {r0-r3}\n" - "3:\tblx r4\n\t" - "mov SP, r5\n\t" - "pop {r4, r5, PC}" ) - -static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const DWORD *stack ) -{ - unsigned int nb_args; - void *func = relay_trace_entry( descr, idx, stack, &nb_args ); - LONGLONG ret = call_entry_point( func, nb_args, stack ); - relay_trace_exit( descr, idx, stack[-1], ret ); - return ret; -} + "str r0, [sp, r3]\n\t" + "bgt 1b\n" + "2:\t" +#ifndef __SOFTFP__ + "tst r1, #0x80000000\n\t" + "ldm r6, {r0-r3}\n\t" + "vldmdbne r6!, {s0-s15}\n\t" +#else + "ldm r6, {r0-r3}\n\t" +#endif + "blx ip\n\t" + "mov sp, r5\n\t" + "ldr r2, [r6, #-4]\n\t" /* retaddr */ + "mov r4, r0\n\t" + "mov r5, r1\n\t" + "mov r0, r7\n\t" + "mov r1, r8\n\t" + "strd r4, [sp]\n\t" +#ifndef __SOFTFP__ + "vstr d0, [sp, #8]\n\t" /* preserve floating point retval */ + "bl " __ASM_NAME("relay_trace_exit") "\n\t" + "vldr d0, [sp, #8]\n\t" +#else + "bl " __ASM_NAME("relay_trace_exit") "\n\t" +#endif + "mov r0, r4\n\t" + "mov r1, r5\n\t" + "add sp, #16\n\t" + "pop {r4-r8,pc}" ) #elif defined(__aarch64__) diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index d028726bc16..3552eca74f2 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -255,16 +255,16 @@ static void output_relay_debug( DLLSPEC *spec ) case CPU_ARM: { unsigned int mask, val, count = 0; - unsigned int stack_size = min( 16, (get_args_size( odp ) + 7) & ~7 ); + int j, has_float = 0; + + if (strcmp( float_abi_option, "soft" )) + for (j = 0; j < odp->u.func.nb_args && !has_float; j++) + has_float = is_float_arg( odp, j ); val = (odp->u.func.args_str_offset << 16) | (i - spec->base); - switch (stack_size) - { - case 16: output( "\tpush {r0-r3}\n" ); break; - case 8: output( "\tpush {r0-r1}\n" ); break; - case 0: break; - } + output( "\tpush {r0-r3}\n" ); output( "\tmov r2, SP\n"); + if (has_float) output( "\tvpush {s0-s15}\n" ); output( "\tpush {LR}\n" ); output( "\tsub SP, #4\n"); for (mask = 0xff; mask; mask <<= 8) @@ -275,7 +275,7 @@ static void output_relay_debug( DLLSPEC *spec ) output( "\tldr IP, [r0, #4]\n"); output( "1:\tblx IP\n"); output( "\tldr IP, [SP, #4]\n" ); - output( "\tadd SP, #%u\n", stack_size + 8 ); + output( "\tadd SP, #%u\n", 24 + (has_float ? 64 : 0) ); output( "\tbx IP\n"); output( "2:\t.long .L__wine_spec_relay_descr-1b\n" ); break;