到达放松处理程序

Reaching unwind handlers

本文关键字:处理 程序      更新时间:2023-10-16

>知道为什么代码看起来像这样吗

list<Foo> fooList;
processList(&fooList);

生成以下机器代码

    lea     rax, [rbp-48]
    mov     rdi, rax
    call    processList(std::__cxx11::list<Foo, std::allocator<Foo> >*)
    lea     rax, [rbp-48]
    mov     rdi, rax
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    jmp     .L11
    mov     rbx, rax
    lea     rax, [rbp-48]
    mov     rdi, rax
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    mov     rax, rbx
    mov     rdi, rax
    call    _Unwind_Resume
.L11:
    add     rsp, 40
    pop     rbx
    pop     rbp
    ret

特别是,在无条件jmp .L11之后,我没有看到任何通向该线的路径

(这是GCC 6.2,没有优化,在编译器资源管理器上生成(

为了进行比较,clang 5.0.0 产生

    call    processList(std::__cxx11::list<Foo, std::allocator<Foo> >*)
    jmp     .LBB5_1
.LBB5_1:
    lea     rdi, [rbp - 24]
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    add     rsp, 48
    pop     rbp
    ret
    lea     rdi, [rbp - 24]
    mov     ecx, edx
    mov     qword ptr [rbp - 32], rax
    mov     dword ptr [rbp - 36], ecx
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    mov     rdi, qword ptr [rbp - 32]
    call    _Unwind_Resume
同样,有一个

无条件跳转到返回块,以及似乎无法访问的平仓块(从第二个lea rdi开始(。

在对C++异常机制进行一些研究后,我的结论是该过程如下:

  1. 在异常引发时,__cxa_throw被调用。这有点像longjmp()函数被调用但永远不会返回。该函数执行两个主要任务
    • 它在调用堆栈中向上走来寻找捕获。如果找不到,std::terminate就会被调用。
    • 如果它确实找到了一个 catch 块,那么它会调用当前函数和 catch 块之间的所有展开处理程序,然后调用 catch 块。

回到我的原始机器代码(在编译器资源管理器中关闭过滤(。哈希之后的评论。

    # this is the normative path
    call    std::list<Handle, std::allocator<Handle> >::~list()
    # unconditional jump around the unwind handler
    jmp     .L11
.L10:
    # unwind handler code, calls the local variable destructor
    mov     rbx, rax
    .loc 2 30 0
    lea     rax, [rbp-32]
    mov     rdi, rax
    call    std::list<Handle, std::allocator<Foo> >::~list()
    mov     rax, rbx
    mov     rdi, rax
.LEHB1:
    # carry on unwinding
    call    _Unwind_Resume
.L11:

然后是异常表

   .section        .gcc_except_table,"a",@progbits
.LLSDA1386:
    .byte   0xff
    .byte   0xff
    .byte   0x1
    .uleb128 .LLSDACSE1386-.LLSDACSB1386
.LLSDACSB1386:
    # entry for unwind handler
    .uleb128 .LEHB0-.LFB1386
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L10-.LFB1386
    .uleb128 0
    .uleb128 .LEHB1-.LFB1386
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0

我猜 unwind 处理程序函数可以根据堆栈上的地址和此表中的偏移量计算出展开处理程序块的位置。