base-hw/arm_v7a: Mark r1 as out in Kernel::call64

In case of arm_v7a Kernel::call64 the syscall will use both r0 and r1 as
output registers. Unfortunately the inline asm does not reflect this and
only r0 is explicitly specified as output. GCC manages to produce output
which we'd like to see. Clang on the other hand takes adventage of the fact
r1 should not be touched by swi and produces fewer instructions which do
what the code describes, but not what we actually want.

Basically the code which we want and is generated by GCC is:
  svc     0
  mov     r2, r0
  mov     r0, r1
  mov     r1, r2
  bx      lr

Clang on the other hand generates correct assembly given the code, but
incorrect given what the function is supposed to do:
  svc     0
  mov     r1, r0
  mov     r0, #0
  bx      lr

Both GCC and clang generate the same, expected assembly output when r1
is marked as output register from the inline asm swi call.

Fixes #3951
This commit is contained in:
Piotr Tworek 2020-11-13 01:16:19 +01:00 committed by Christian Helmuth
parent aa7f5bc95f
commit 5db2971903

View File

@ -60,7 +60,10 @@ Call_ret_64 Kernel::call64(Call_arg arg_0)
{
register Call_arg arg_0_reg asm("r0") = arg_0;
register Call_arg arg_1_reg asm("r1");
asm volatile(CALL_1_SWI);
/* in this particular case, both r0 and r1 are used as output */
asm volatile(CALL_1_SWI, "+r"(arg_1_reg));
return ((Call_ret_64)arg_0_reg) << 32 | (Call_ret_64)arg_1_reg;
}