当我尝试访问从虚拟基类继承的派生类对象的内存布局时,出了点问题。
编程环境:GNU / Linux 3.19.0-32-generic,x86_64
编译:gcc 4.8.4
400c12
Derived::f()
400c3c
segment fault
当我运行代码时,我得到了“段错误”:
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
所以我反汇编了可执行文件 我找到了函数&lt; _ZTv0_n24_N7Derived1fEv&gt;在0x400c3c:
> c++filt _ZTv0_n24_N7Derived1fEv
virtual thunk to Derived::f()
在终端中解码符号:
/*
skeleton code - it won't be this exactly but will
look like this.
*/
EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
unsigned char ** outbuffer,
unsigned long * outsize))
{
int width, height;
unsigned char *rgba;
getimagesize(cinfo, &width, & height);
rgba = malloc(width * height * 4);
decompress(cinfo, rgba);
*outbuffer = rgba;
*outsize = width * height *4;
}
然后什么是Derived :: f()的虚拟thunk?它为什么存在?
答案 0 :(得分:9)
某个函数的虚拟thunk是一个辅助函数,它在调用实际函数之前修复了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:现在还应该清楚为什么在_ZTv0_n24_N7Derived1fEv
指针上调用d
会崩溃。只有在指向this
对象内部的Derived
指针指向可以像Base
对象一样使用的部分时,该函数才有效。
答案 1 :(得分:0)
问题中有一个不清楚的地方。 在“虚拟thunk到Derived :: f()”中,我认为“添加-0x18(%r10),%rdi”无法修复此指针,因为Derive对象的开头与其子对象(Base)之间的偏移量不是24(0x18)。