Re: unwind tables for asm blocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux