I'm showing my ignorance here, but couldn't find an example of something similar on another RISCy target, so here goes...
My latest round of testing showed these failures for MIPS16: FAIL: 21_strings/basic_string/numeric_conversions/char/stod.cc execution test FAIL: 21_strings/basic_string/numeric_conversions/char/stof.cc execution test FAIL: 21_strings/basic_string/numeric_conversions/char/stold.cc execution test FAIL: 21_strings/basic_string/numeric_conversions/wchar_t/stod.cc execution test FAIL: 21_strings/basic_string/numeric_conversions/wchar_t/stof.cc execution test FAIL: 21_strings/basic_string/numeric_conversions/wchar_t/stold.cc execution test I've no idea why they're suddenly showing up now, since the problem has been around forever. A depressingly trivial testcase is: #include <stdexcept> double foo (void) { throw std::out_of_range ("foo"); } double (*volatile foo_ptr) (void) = foo; int main (void) { try { foo_ptr (); } catch (...) {} return 0; } which triggers: terminate called after throwing an instance of 'std::out_of_range' what(): foo Aborted The call to foo_ptr goes through a stub that moves the return value of the real foo from floating-point to general registers. Rather than create a frame and save the return address on the stack, the stub instead stores it in _call-saved_ register $18. The MIPS16 caller is aware of this special exception and makes sure to save $18 itself where necessary. (I don't know whether this was supposed to be a time or a space saving, but there will obviously be cases where it makes code bigger.) libgcc has stubs for indirect calls, while gcc generates wrappers for direct calls. The latter are only pulled in when needed. The first (predictable) problem is that these stubs lack cfi info. I first tried to fix this for libgcc by adding the cfi markup below: #define CALL_STUB_RET(NAME, CODE, MODE) \ STARTFN (NAME); \ .cfi_startproc; \ move $18,$31; \ .cfi_register 31,18; \ STUB_ARGS_##CODE; \ .set noreorder; \ jalr $2; \ move $25,$2; \ .set reorder; \ MOVE_##MODE##_RET (f, $18); \ .cfi_endproc; \ ENDFN (NAME) This fixes gdb backtraces from a stripped executable, but libgcc's unwinder seems to get confused by having a stub in the middle of the trace that (a) isn't a signal handler and (b) has no frame of its own. The CFA at the point of the call to the stub (i.e. the point that is trying to catch the exception) is the same as the CFA at the call in the stub itself. We then trip: /* Don't let us unwind past the handler context. */ gcc_assert (!match_handler); in _Unwind_RaiseException_Phase2. What's the right thing to do here? Thanks, Richard