到达放松处理程序

时间:2018-01-14 11:15:49

标签: c++ assembly x86-64 stack-unwinding

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

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开始)似乎无法访问。

1 个答案:

答案 0 :(得分:3)

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

  1. 在异常抛出点,__cxa_throw被调用。这有点像longjmp(),因为函数被调用但永远不会返回。该功能执行两个主要任务
    • 它向上调用堆栈寻找捕获。如果找不到,std::terminate会被调用。
    • 如果确实找到了一个catch块,那么它会调用当前函数和catch块之间的所有unwind处理程序,然后调用catch块。
  2. 返回我原来的机器代码(在编译器资源管理器中关闭过滤)。哈希之后我的评论。

        # 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处理函数可以从堆栈中的地址和此表中的偏移量计算出展开处理程序块的位置。