public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* 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).