【问题标题】:Duplicate Destructors in Assembler Output for C++C++ 汇编器输出中的重复析构函数
【发布时间】:2014-08-20 21:44:03
【问题描述】:

我目前正在尝试了解 G++ 如何从一个小的示例 C++ 程序生成程序集。因此,我正在测试以下程序并进行了各种优化:

#define noinline __attribute__ ((noinline))

class Test_Base {
public:
    noinline Test_Base() {}
    virtual noinline ~Test_Base() {}
    void noinline method() { v_method(); }
private:
    virtual void v_method()=0;
};

class Test1
   : public Test_Base
{
public:
    noinline Test1() {}
    noinline ~Test1() {}
private:
    void noinline v_method() {}
};

class Test2
   : public Test_Base
{
public:
    noinline Test2() {}
    ~Test2() {}
private:
    void noinline v_method() {}
};

int main() {
    volatile int x = 0;
    Test_Base * b;
    Test1 t1;
    Test2 t2;
    if( x )
        b = &t1;
    else
        b = &t2;
    b->method();
    return 0;
}

但是查看这段代码(使用 -Os 为 ARMv7 平台编译),我发现构造函数和析构函数的所有定义都被包含了多次。以下是 Test1 的符号表的相关部分:

00008730  w    F .text  00000004              Test1::v_method()
000088d8  w    O .rodata        00000014              vtable for Test1
000087d0  w    F .text  00000020              Test1::Test1()
00008774  w    F .text  0000001c              Test1::~Test1()
00008710  w    F .text  00000020              Test1::~Test1()
000088a4  w    O .rodata        00000007              typeinfo name for Test1
00008898  w    O .rodata        0000000c              typeinfo for Test1
000087d0  w    F .text  00000020              Test1::Test1()
00008710  w    F .text  00000020              Test1::~Test1()

所以我有一个构造函数和两个析构函数(最后两个调用只是重复,位置与以前相同)。查看程序集,我观察到以下内容:

首先是构造函数

000087d0 <Test1::Test1()>:
    87d0:       e92d4010        push    {r4, lr}
    87d4:       e1a04000        mov     r4, r0
    87d8:       ebfffff3        bl      87ac <Test_Base::Test_Base()>
    87dc:       e1a00004        mov     r0, r4
    87e0:       e59f3004        ldr     r3, [pc, #4]    ; 87ec <Test1::Test1()+0x1c>
    87e4:       e5843000        str     r3, [r4]
    87e8:       e8bd8010        pop     {r4, pc}
    87ec:       000088e0        .word   0x000088e0

我想这就是我告诉它做的事情。

现在是 0x8710 处的析构函数:

00008710 <Test1::~Test1()>:
    8710:       e59f3014        ldr     r3, [pc, #20]   ; 872c <Test1::~Test1()+0x1c>
    8714:       e92d4010        push    {r4, lr}
    8718:       e1a04000        mov     r4, r0
    871c:       e5803000        str     r3, [r0]
    8720:       ebfffff6        bl      8700 <Test_Base::~Test_Base()>
    8724:       e1a00004        mov     r0, r4
    8728:       e8bd8010        pop     {r4, pc}
    872c:       000088e0        .word   0x000088e0

这里没有什么可疑的地方。

现在是 0x8774 处的析构函数:

00008774 <Test1::~Test1()>:
    8774:       e92d4010        push    {r4, lr}
    8778:       e1a04000        mov     r4, r0
    877c:       ebffffe3        bl      8710 <Test1::~Test1()>
    8780:       e1a00004        mov     r0, r4
    8784:       ebffff69        bl      8530 <_init+0x44>
    8788:       e1a00004        mov     r0, r4
    878c:       e8bd8010        pop     {r4, pc}

由于我对 ABI 并不十分熟悉,因此我无法真正说出它的作用。我猜它与静态初始化有关。

这个额外的析构函数的目的是什么?

如果我为 x86_64 编译相同的,我也会得到重复的析构函数,所以这似乎不是系统特定的。

【问题讨论】:

    标签: c++ gcc assembly arm code-generation


    【解决方案1】:

    第一个是非虚​​拟析构函数,用于在编译时知道动态类型时销毁自动或静态对象。

    第二个是用于多态删除的虚拟“thunk”。它调用非虚析构函数销毁对象,然后调用operator delete释放内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-26
      • 2012-12-29
      • 2020-11-27
      • 2013-04-03
      • 1970-01-01
      • 2021-07-27
      • 2016-08-14
      相关资源
      最近更新 更多