虚拟继承中的虚拟基本偏移量

时间:2016-11-16 08:43:07

标签: c++ c++11 virtual-inheritance

代码如下(使用G ++编译的C ++ 11代码 - 在Ubuntu 16.04上为5.4):

#include <iostream>

using namespace std;



class Base
{
    public:
        virtual void show()
        {
            cout << "Base" << endl;
        }

        virtual void func()
        {
            cout << "func in Base" << endl;
        }

    protected:
        int base = 15;
};

class A: public virtual Base
{
    public:
        void show() override
        {
            cout << this << endl;
            cout << 'A' << endl;
        }

        void func() override
        {
            cout << this << endl;
            cout << "func in A" << endl;
        }

    protected:
        int a = 31;
};



int main(int argc, const char *argv[])
{
    A obj_a;

    return 0;
}

我尝试使用GDB来检查对象的内存布局&#34; obj_a&#34; (首先,我设置&#34;将打印对象设置为&#34;,&#34;将打印设置为&#34;,&#34;将打印vtbl设置为&#34;,&#34;设置打印asm-demangle在&#34;在GDB中):

(gdb) p sizeof(obj_a)
$1 = 32
(gdb) x/8aw &obj_a
0x7fffffffe320: 0x400d20 <vtable for A+24>  0x0 0x1f    0x0
0x7fffffffe330: 0x400d50 <vtable for A+72>  0x0 0xf 0x0

我们可以知道obj_a的开头与其虚拟基础子对象之间的偏移量是16B(虚拟基本偏移量)。然后我检查A 0x400d08 (0x400d20 - 24)指向的虚拟功能表:

(gdb) x/14ag 0x400d08
0x400d08 <vtable for A>:    0x10    0x0
0x400d18 <vtable for A+16>: 0x400d90 <typeinfo for A>   0x400b46 <A::show()>
0x400d28 <vtable for A+32>: 0x400b98 <A::func()>    0xfffffffffffffff0
0x400d38 <vtable for A+48>: 0xfffffffffffffff0  0xfffffffffffffff0
0x400d48 <vtable for A+64>: 0x400d90 <typeinfo for A>   0x400b8f <virtual thunk to A::show()>
0x400d58 <vtable for A+80>: 0x400be1 <virtual thunk to A::func()>          0x400d20 <vtable for A+24>
0x400d68 <VTT for A+8>: 0x400d50 <vtable for A+72>  0x0

正如我们所看到的,有两个&#34;虚拟thunk到xxx&#34;,即&#34; 0x400b8f&#34;和&#34; 0x400be1&#34;。我查看了这两个地址。

(gdb) x/3i 0x400b8f
0x400b8f <virtual thunk to A::show()>:  mov    (%rdi),%r10
0x400b92 <virtual thunk to A::show()+3>:    add    -0x18(%r10),%rdi
0x400b96 <virtual thunk to A::show()+7>:    jmp    0x400b46 <A::show()>
(gdb) x/3i 0x400be1
0x400be1 <virtual thunk to A::func()>:  mov    (%rdi),%r10
0x400be4 <virtual thunk to A::func()+3>:    add    -0x20(%r10),%rdi
0x400be8 <virtual thunk to A::func()+7>:    jmp    0x400b98 <A::func()>

我的问题是:&#34;添加-0x18(%r10),%rdi&#34;和&#34;添加-0x20(%r10),%rdi&#34;实际意思?为什么是-24(-0x18)和-32(-0x20)? (我认为他们都应该是-16)

1 个答案:

答案 0 :(得分:1)

感谢Rerito,对不起。

我的问题在于我不熟悉汇编代码。

(gdb) x/3i 0x400b8f
0x400b8f <virtual thunk to A::show()>:  mov    (%rdi),%r10
0x400b92 <virtual thunk to A::show()+3>:    add    -0x18(%r10),%rdi
0x400b96 <virtual thunk to A::show()+7>:    jmp    0x400b46 <A::show()>

在“虚拟thunk到A :: show()”的汇编代码中,%rdi保存“this”值。 “mov(%rdi),%r​​10”表示将“vptr”值(其地址为“this”)移动到r10寄存器。 “add -0x18(%r10),%rdi”表示将地址为“vptr-24”的值(即虚拟表中的0xfffffffffffffff0)添加到“this”。因此,“this”值可以更正为A对象的地址。