xtensa: fix semihosting arguments potentially begin optimized out

The compiler was not informed that the assembly block should be
treated as a memory barrier and could optimize out the initialization
of local arrays which could be used as semihosting arguments.
This resulted in garbage values being passed as semihosting call
arguments.

Additionally this commit changes the approach for placing values into
specific register. Instead of clobbers, local register variables are
used. This results in simpler generated code, since the compiler is
able to place values directly into the registers used for semihosting
arguments, avoiding additional moves.
This commit is contained in:
Ivan Grokhotkov 2022-01-20 19:18:06 +01:00
parent 09f5c1d32e
commit aeed91b589

View File

@ -27,28 +27,32 @@ extern "C" {
*/ */
static inline long semihosting_call(long id, long *data, int *out_errno) // NOLINT(readability-non-const-parameter) static inline long semihosting_call(long id, long *data, int *out_errno) // NOLINT(readability-non-const-parameter)
{ {
long host_ret; /* GCC doesn't allow using specific register names in constraints for Xtensa.
long host_errno; * For this case, GCC extended inline assembly manual says the following:
* If you must use a specific register, but your Machine Constraints do not provide
* sufficient control to select the specific register you want, local register variables
* may provide a solution.
* Using local register variables results in simpler generated code than
* the previous implementation which listed a2-a6 as clobbered registers.
*/
register long a2 asm ("a2") = id;
register long a3 asm ("a3") = (long) data[0];
register long a4 asm ("a4") = (long) data[1];
register long a5 asm ("a5") = (long) data[2];
register long a6 asm ("a6") = (long) data[3];
/* The break instruction operands should be (1, 14) according to the ISA manual. /* The break instruction operands should be (1, 14) according to the ISA manual.
* We keep (1, 1) for compatibility, until OpenOCD is updated to support both * We keep (1, 1) for compatibility, until OpenOCD is updated to support both
* conventions. * conventions.
*/ */
__asm__ __volatile__ ( __asm__ __volatile__ (
"mov a2, %[sys_nr]\n" \ "break 1, 1\n"
"mov a3, %[arg1]\n" \ : "+r"(a2), "+r"(a3)
"mov a4, %[arg2]\n" \ : "r"(a4), "r"(a5), "r"(a6)
"mov a5, %[arg3]\n" \ : "memory");
"mov a6, %[arg4]\n" \
"break 1, 1\n" \ long host_ret = a2;
"mov %[host_ret], a2\n" \ long host_errno = a3;
"mov %[host_errno], a3\n" \
:[host_ret]"=r"(host_ret), [host_errno]"=r"(host_errno)
:[sys_nr]"r"(id),
[arg1]"r"(data[0]),
[arg2]"r"(data[1]),
[arg3]"r"(data[2]),
[arg4]"r"(data[3])
:"a2", "a3", "a4", "a5", "a6");
if (host_ret < 0) { if (host_ret < 0) {
*out_errno = host_errno; *out_errno = host_errno;
} }