* unwind tables for asm blocks @ 2020-02-28 10:56 J.W. Jagersma 2020-02-28 20:58 ` J.W. Jagersma 2020-02-28 21:32 ` Florian Weimer 0 siblings, 2 replies; 7+ messages in thread From: J.W. Jagersma @ 2020-02-28 10:56 UTC (permalink / raw) To: gcc-help 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. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: unwind tables for asm blocks 2020-02-28 10:56 unwind tables for asm blocks J.W. Jagersma @ 2020-02-28 20:58 ` J.W. Jagersma 2020-02-28 21:32 ` Florian Weimer 1 sibling, 0 replies; 7+ messages in thread From: J.W. Jagersma @ 2020-02-28 20:58 UTC (permalink / raw) To: gcc-help 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. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: unwind tables for asm blocks 2020-02-28 10:56 unwind tables for asm blocks J.W. Jagersma 2020-02-28 20:58 ` J.W. Jagersma @ 2020-02-28 21:32 ` Florian Weimer 2020-02-28 22:03 ` J.W. Jagersma 1 sibling, 1 reply; 7+ messages in thread From: Florian Weimer @ 2020-02-28 21:32 UTC (permalink / raw) To: J.W. Jagersma; +Cc: gcc-help * J. W. Jagersma: > asm("call %0" :: "i" (throw_exc)); Calling functions from inline assembly is typically invalid for many other reasons. For example, on x86-64, there is no way to express that the red zone is clobbered. What is the actual issue you are trying to solve? Thanks, Florian ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: unwind tables for asm blocks 2020-02-28 21:32 ` Florian Weimer @ 2020-02-28 22:03 ` J.W. Jagersma 2020-02-28 22:24 ` Florian Weimer 0 siblings, 1 reply; 7+ messages in thread From: J.W. Jagersma @ 2020-02-28 22:03 UTC (permalink / raw) To: Florian Weimer; +Cc: gcc-help On 2020-02-28 22:04, Florian Weimer wrote: > * J. W. Jagersma: > >> asm("call %0" :: "i" (throw_exc)); > > Calling functions from inline assembly is typically invalid for many > other reasons. For example, on x86-64, there is no way to express that > the red zone is clobbered. > > What is the actual issue you are trying to solve? > > Thanks, > Florian > The call instruction is just a practical example. The problem I want to address is that no exception handling information is generated at all for asm statements. Other operations, eg. memory access, division, etc could trap and throw an exception. The unwind tables should cover this. There is a comment in stmt_could_throw_p (tree-eh.c) that states: /* The only statements that can throw an exception are assignments, conditionals, calls, resx, and asms. */ Which leads me to believe that the current behaviour is a bug. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: unwind tables for asm blocks 2020-02-28 22:03 ` J.W. Jagersma @ 2020-02-28 22:24 ` Florian Weimer 2020-02-28 22:32 ` J.W. Jagersma 0 siblings, 1 reply; 7+ messages in thread From: Florian Weimer @ 2020-02-28 22:24 UTC (permalink / raw) To: J.W. Jagersma; +Cc: gcc-help * J. W. Jagersma: > The call instruction is just a practical example. The problem I want to > address is that no exception handling information is generated at all > for asm statements. Other operations, eg. memory access, division, etc > could trap and throw an exception. The unwind tables should cover this. I think permitted uses of asm cannot do anything that would make the tables invalid, at least for DWARF unwinding information. DWARF does not need to annotate any instruction that might throw (which would be every instruction in case of asynchronous unwind tables). Thanks, Florian ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: unwind tables for asm blocks 2020-02-28 22:24 ` Florian Weimer @ 2020-02-28 22:32 ` J.W. Jagersma 2020-02-29 14:36 ` Florian Weimer 0 siblings, 1 reply; 7+ messages in thread From: J.W. Jagersma @ 2020-02-28 22:32 UTC (permalink / raw) To: Florian Weimer; +Cc: gcc-help On 2020-02-28 22:32, Florian Weimer wrote: > * J. W. Jagersma: > >> The call instruction is just a practical example. The problem I want to >> address is that no exception handling information is generated at all >> for asm statements. Other operations, eg. memory access, division, etc >> could trap and throw an exception. The unwind tables should cover this. > > I think permitted uses of asm cannot do anything that would make the > tables invalid, at least for DWARF unwinding information. I don't see how a trapping instruction in asm would invalidate the unwind table. An explicit call, maybe, but as I said that was only an example. The problem is that there is no unwind table at all. > DWARF does not need to annotate any instruction that might throw (which > would be every instruction in case of asynchronous unwind tables). But it should, if the instruction appears in a try block. Without that it is impossible to catch the exception. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: unwind tables for asm blocks 2020-02-28 22:32 ` J.W. Jagersma @ 2020-02-29 14:36 ` Florian Weimer 0 siblings, 0 replies; 7+ messages in thread From: Florian Weimer @ 2020-02-29 14:36 UTC (permalink / raw) To: J.W. Jagersma; +Cc: gcc-help * J. W. Jagersma: > On 2020-02-28 22:32, Florian Weimer wrote: >> * J. W. Jagersma: >> >>> The call instruction is just a practical example. The problem I want to >>> address is that no exception handling information is generated at all >>> for asm statements. Other operations, eg. memory access, division, etc >>> could trap and throw an exception. The unwind tables should cover this. >> >> I think permitted uses of asm cannot do anything that would make the >> tables invalid, at least for DWARF unwinding information. > > I don't see how a trapping instruction in asm would invalidate the > unwind table. An explicit call, maybe, but as I said that was only an > example. The problem is that there is no unwind table at all. > >> DWARF does not need to annotate any instruction that might throw (which >> would be every instruction in case of asynchronous unwind tables). > > But it should, if the instruction appears in a try block. Without that > it is impossible to catch the exception. I don't think this is true. DWARF unwind information is range-based, after all. The asm statement will be covered by the unwinding information for the surrounding code. Thanks, Florian ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2020-02-29 4:49 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-02-28 10:56 unwind tables for asm blocks J.W. Jagersma 2020-02-28 20:58 ` J.W. Jagersma 2020-02-28 21:32 ` Florian Weimer 2020-02-28 22:03 ` J.W. Jagersma 2020-02-28 22:24 ` Florian Weimer 2020-02-28 22:32 ` J.W. Jagersma 2020-02-29 14:36 ` Florian Weimer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).