On 2020-02-27 23:08, J.W. Jagersma wrote: > Is there some way to convince gcc to generate unwind tables for asm > statements? As an example: > > ``` > $ cat throw-asm.cpp > void throw_exc() > { > throw 0; > } > > int main() > { > try > { > asm("call %0" :: "i" (throw_exc)); > } > catch(...) { } > return 0; > } > > $ g++ -fnon-call-exceptions -fasynchronous-unwind-tables -masm=intel throw-asm.cpp -o throw-asm && ./throw-asm > terminate called after throwing an instance of 'int' > Aborted (core dumped) > ``` > > Compiling with -S reveals that main() has no unwind table at all. > If you add something before and after the asm statement, eg. function > calls, then it generates unwind tables and it's sometimes possible to > catch the exception, but there's a lot of randomness involved (due to > instruction reordering). > Much of my code depends on non-call exceptions and I really need the > unwind tables to cover asm code too. A better example maybe: ``` $ cat throw.cpp #include <iostream> void throw_exc() { asm (".cfi_signal_frame"); throw 0; } [[gnu::noinline]] void f() { asm (""); } int main() { try { asm ("call %0" :: "i" (throw_exc)); f(); } catch (...) { } std::cout << "caught 1st\n"; try { asm ("call %0" :: "i" (throw_exc)); asm ("nop"); f(); } catch (...) { } std::cout << "caught 2nd\n"; return 0; } $ g++ -fnon-call-exceptions -fasynchronous-unwind-tables -masm=intel throw.cpp -o throw && ./throw caught 1st terminate called after throwing an instance of 'int' Aborted (core dumped) ``` The first exception is caught because it is thrown at the instruction boundary between the asm and the call to f(). From the perspective of the unwinder, the exception originated from f(). The second exception ends up between the 'call' and 'nop' asms which have no unwind information. Compiling with -S shows that the asm statements are now covered by an entry in the unwind table (with the call to ostream::operator<<), but its 'action' and 'landingpad' fields are zero: ``` .LEHE4: .L8: lea rsi, .LC0[rip] lea rdi, _ZSt4cout[rip] .LEHB5: call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT #APP # 23 "throw.cpp" 1 call OFFSET FLAT:_Z9throw_excv # 0 "" 2 # 24 "throw.cpp" 1 nop # 0 "" 2 .LEHE5: .LEHB6: #NO_APP call _Z1fv .LEHE6: <...> .uleb128 .LEHB4-.LFB1523 .uleb128 .LEHE4-.LEHB4 .uleb128 .L11-.LFB1523 .uleb128 0x1 .uleb128 .LEHB5-.LFB1523 .uleb128 .LEHE5-.LEHB5 .uleb128 0 .uleb128 0 .uleb128 .LEHB6-.LFB1523 .uleb128 .LEHE6-.LEHB6 .uleb128 .L12-.LFB1523 .uleb128 0x1 ``` It seems clang does fill out these fields for asm statements in the lsda table. But I can't use clang here. I looked around in the gcc source but I'm having difficulty finding anything. I tried changing insn_could_throw_p (except.c) to unconditionally return true, but that didn't do anything. In may_trap_p_1 (rtlanal.c) there are cases for ASM_INPUT and ASM_OPERAND which to me suggests that it should be possible for asm statements to trap (and throw), at the very least so if the asm involves a volatile memory access. Let's try that: ``` $ cat unwind-asm.cpp int main() { int a = 1; int b; int* volatile p = &a; try { asm ("mov %0, %1" : "=r" (b) : "m" (*p)); } catch (...) { b = 0; } return b; } $ g++-9 -masm=intel -fnon-call-exceptions -fasynchronous-unwind-tables unwind-asm.cpp -S $ cat unwind-asm.s .file "unwind-asm.cpp" .intel_syntax noprefix .text .globl main .type main, @function main: .LFB0: .cfi_startproc push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 sub rsp, 32 mov rax, QWORD PTR fs:40 mov QWORD PTR -8[rbp], rax xor eax, eax mov DWORD PTR -24[rbp], 1 lea rax, -24[rbp] mov QWORD PTR -16[rbp], rax mov rax, QWORD PTR -16[rbp] #APP # 7 "unwind-asm.cpp" 1 mov eax, DWORD PTR [rax] # 0 "" 2 #NO_APP mov DWORD PTR -20[rbp], eax mov eax, DWORD PTR -20[rbp] mov rdx, QWORD PTR -8[rbp] xor rdx, QWORD PTR fs:40 je .L3 call __stack_chk_fail@PLT .L3: leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 9.2.1-17ubuntu1~18.04.1) 9.2.1 20191102" .section .note.GNU-stack,"",@progbits ``` Again, there is no unwind information at all.