什么是从虚拟基类继承的虚函数的"virtual thunk"?
What is a "virtual thunk" to a virtual function that inherits from a virtual base class?
当我试图访问从虚拟基类继承的派生类对象的内存布局时,出现了问题。
编程环境:GNU/Linux 3.19.0-32-generic, x86_64
编译器:gcc 4.8.4
//virtual base class
class Base {
public :
virtual void f() {
cout << "Base::f()" << endl;
}
private:
long x;
};
//derived class
class Derived : public virtual Base {
public:
virtual void f() {
cout << "Derived::f()" << endl;
}
private:
long y;
};
int main() {
typedef void (*FUNC)(void);
Derived d;
//In my machine, sizeof(long) == sizeof(pointers). My code below is neither portable nor concise. You can just read the annotation.
//dereference the first element of the first virtual function table(equals to *(vptr1->slot[0]))
cout << hex << *((long*)*((long*)(&d) + 0) + 0) << endl;
((FUNC)*((long*)*((long*)(&d) + 0) + 0))();//invoke Derived::f()
//dereference the first element of the second virtual function table(equals to *(vptr2->slot[0]))
cout << hex << *((long*)*((long*)(&d) + 2) + 0) << endl;
((FUNC)*((long*)*((long*)(&d) + 2) + 0))();//maybe Derived::f()?
return 0;
}
当我运行代码时,我得到了"段错误":
400c12
Derived::f()
400c3c
segment fault
所以我反汇编了可执行文件。
我在0x400c3c:
0000000000400c3c <_ZTv0_n24_N7Derived1fEv>:
400c3c: 4c 8b 17 mov (%rdi),%r10
400c3f: 49 03 7a e8 add -0x18(%r10),%rdi
400c43: eb cd jmp 400c12 <_ZN7Derived1fEv>
400c45: 90 nop
在我的终端中删除符号:
> c++filt _ZTv0_n24_N7Derived1fEv
virtual thunk to Derived::f()
那么,派生::f()的虚函数是什么?它为什么在那里?
某个函数的虚库是在调用实际函数之前修复this
参数的辅助函数。看这个例子:
Derived *d = new Derived();
// d now points to some address, e.g. 0x6eac40
d->f(); // This calls _ZN7Derived1fEv (Derived::f() directly)
Base *b = d;
// b now points to some other address (!), e.g. 0x6eac50
b->f(); // This calls _ZTv0_n24_N7Derived1fEv (the virtual thunk
// of Derived::f()), which subtracts some amount from `this`
// and then jumps to the _ZN7Derived1fEv (Derived::f())
内存中的Base
对象看起来像这样:
* Pointer to part of Base vtable with Base's virtual functions.
This vtable contains Base::f()
* Data of Base class (variable `x`)
内存中的Derived
对象看起来像这样:
|> * Pointer to part of Derived vtable with Derived's virtual functions.
|> This vtable contains the Derived::f()
|>
|> |> * Pointer to part of Derived vtable with the same layout as Base vtable.
|> |> This vtable contains the thunk of Derived::f()
|> |>
|> |> * Data of Base class (variable `x`)
| |>
| |> * Data of Derived class (variable `y`)
| |
| This is complete Derived object.
| The `d` pointer points at the beginning of this.
|
This is the part of Derived object that can act as a Base object.
The `b` pointer points at beginning of this.
PS:现在也应该清楚为什么在d
指针上调用_ZTv0_n24_N7Derived1fEv
会崩溃。该函数只有在给定this
指针时才能工作,该指针指向Derived
对象内部-指向它的一部分,可以像Base
对象一样使用。
这个问题有一个不清楚的地方。在"virtual think to Derived::f()"中,我认为"add -0x18(%r10),%rdi"无法修复此指针,因为派生对象的开始与其子对象(Base)之间的偏移量不是24 (0x18)。
相关文章:
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 如何进行故障排除:未定义对"非虚拟 thunk to ..."的引用
- 在基类中调用的 VIrtual 基函数,C++
- C++类:virtual和override,或者两者都没有
- g++ [[noreturn]] on a virtual method
- "virtual"对C++析构函数有何影响?
- 多重继承:跳过'virtual'关键字并拒绝菱形层次结构的使用?
- 错误"pure virtual method called",当此方法已被覆盖时
- 为什么C++尝试/捕获没有捕获"pure virtual call"异常?
- 防止 CRTP 特征码在"pure virtual"调用中堆栈溢出
- Protobuf 生成的C++类无法针对 iOS 进行编译,并显示错误"Only virtual member functions can be marked 'final'"
- 为什么必须将"virtual"放入基类中,而不是仅在子类中使用"override"?在C++
- 为什么需要虚拟thunk
- 使用 -march 编译会导致线程说"pure virtual method called"
- "Prototype pattern"和"Virtual constructor"是相同的模式吗?
- 为什么Virtual继承2类会增加对象大小
- C vtable在多个继承中,指向thunk方法的指针
- 什么是从虚拟基类继承的虚函数的"virtual thunk"?
- "non-virtual thunk to <method name>" ,引用自:Vtable <classname>for in <objectfile.o>