Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

virtual base offset in virtual function table for virtual inheritance

The codes are as follows (C++11 codes compiled with G++-5.4 on Ubuntu 16.04):

#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;
}

I try to use GDB to check memory layout of object "obj_a" (firstly, I set "set print object on", "set print pretty on", "set print vtbl on", "set print asm-demangle on" in 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

We can know that the offset between the beginning of obj_a and its virtual base subobject is 16B (virtual base offset). And then I check A's virtual function table pointed by 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

As we can see, there are two "virtual thunk to xxx", namely "0x400b8f " and "0x400be1 ". I peer into these two addresses.

(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()>

My questions are: what do "add -0x18(%r10),%rdi" and "add -0x20(%r10),%rdi" really mean? why are -24 (-0x18) and -32 (-0x20)? (I think they should all be -16)

like image 347
Jason Avatar asked Nov 16 '16 08:11

Jason


1 Answers

Thank Rerito, sorry about that.

My problem lies that I am not familiar with assembly code.

(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()>

In the assembly code for "virtual thunk to A::show()", %rdi saves "this" value. "mov (%rdi),%r10" means moving "vptr" value (its address is the "this") to r10 register. "add -0x18(%r10),%rdi" means that adding the value whose address is "vptr - 24" (i.e. 0xfffffffffffffff0 in the virtual table) to "this". So "this" value can be corrected as address of A's object.

like image 119
Jason Avatar answered Sep 20 '22 16:09

Jason