From 1d9921cbdc732e1a7fc66b9c24a6dfa9625bd4c0 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 6 Jun 2020 05:06:04 -0700 Subject: xtensa: libgcc: fix PR target/95571 Rewrite uw_install_context without function calls to avoid register spilling in _Unwind_RaiseException during return context installation. 2020-06-08 Max Filippov gcc/testsuite/ * g++.target/xtensa/pr95571.C: New test. * g++.target/xtensa/xtensa.exp: New testsuite. libgcc/ * config/xtensa/unwind-dw2-xtensa.c (uw_install_context): Merge with uw_install_context_1. --- libgcc/config/xtensa/unwind-dw2-xtensa.c | 46 +++++++++++++++----------------- 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'libgcc') diff --git a/libgcc/config/xtensa/unwind-dw2-xtensa.c b/libgcc/config/xtensa/unwind-dw2-xtensa.c index 056182a..8a6a44a 100644 --- a/libgcc/config/xtensa/unwind-dw2-xtensa.c +++ b/libgcc/config/xtensa/unwind-dw2-xtensa.c @@ -481,37 +481,35 @@ uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa, /* Install TARGET into CURRENT so that we can return to it. This is a macro because __builtin_eh_return must be invoked in the context of - our caller. */ + our caller, and also because spilling registers of the caller before + the context installation may result in reload of wrong register values + after the context installation due to the change of the stack pointer + in the base save area. This spilling may be caused by an interrupt + handler on baremetal host. */ -#define uw_install_context(CURRENT, TARGET, FRAMES) \ +#define uw_install_context(CURRENT, TARGET, FRAMES) \ do \ { \ - long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ - __builtin_eh_return (offset, handler); \ + long i; \ + \ + /* The eh_return insn assumes a window size of 8, so don't bother \ + copying the save areas for registers a8-a15 since they won't be \ + reloaded. */ \ + for (i = 0; i < 2; ++i) \ + { \ + _Unwind_Word *c = (CURRENT)->reg[i]; \ + _Unwind_Word *t = (TARGET)->reg[i]; \ + int j; \ + \ + if (t && c && t != c) \ + for (j = 0; j < 4; ++j) \ + *c++ = *t++; \ + } \ + __builtin_eh_return (0, handler); \ } \ while (0) -static long -uw_install_context_1 (struct _Unwind_Context *current, - struct _Unwind_Context *target) -{ - long i; - - /* The eh_return insn assumes a window size of 8, so don't bother copying - the save areas for registers a8-a15 since they won't be reloaded. */ - for (i = 0; i < 2; ++i) - { - void *c = current->reg[i]; - void *t = target->reg[i]; - - if (t && c && t != c) - memcpy (c, t, 4 * sizeof (_Unwind_Word)); - } - - return 0; -} - static inline _Unwind_Ptr uw_identify_context (struct _Unwind_Context *context) { -- cgit v1.1