2016-11-16 66 views
5

的代碼如下(C++ 11碼與G ++編譯 - 在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檢查存儲器佈局對象「OBJ_A」的(首先,我設置「中設置的打印對象」,「漂亮上設置打印」,「關於設置打印VTBL」,「設置打印ASM-還原函數的」在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 

我們可以看到,有兩個 「虛擬的thunk到XXX」,即 「0x400b8f」 和 「0x400be1」。我同意這兩個地址。

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

我的問題是:什麼 「增加-0x18(%R10),%RDI」 和 「添加-0x20(%R10),%RDI」 究竟意味着什麼?爲什麼是-24(-0x18)和-32(-0x20)? (我認爲他們應該都是-16)

+1

我想你會通過查看功能實現的asm得到答案 – Rerito

+0

嗨Rerito,謝謝你的回覆。我檢查了兩個虛函數實現的asm代碼,我沒有任何答案。實際上,我真正想知道的是如何在執行該函數之前更改此指針。 – Jason

+0

哦,我知道。這裏需要以間接方式獲得偏移量。 「vtbl - 0x18」指出虛擬功能表中的偏移值。然後通過添加偏移來糾正「這個」。 – Jason

回答

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

在用於 「虛擬形實轉換到A ::顯示()」 彙編代碼,%RDI保存 「這個」 值。 「mov(%rdi),%r​​10」表示將「vptr」值(其地址是「this」)移動到r10寄存器。 「加-0x18(%r10),%rdi」表示將地址爲「vptr-24」的值(即虛表中的0xfffffffffffffff)加到「this」。所以「這個」值可以作爲A的對象的地址糾正。