一般面试C ,都会很无聊的问到虚拟函数的实现机制,接着就会问到vtable放在哪里 – 实现细节中的细节,我个人觉得这个除了卖弄没啥大意义,但面试嘛,一般就这吊样。
写个小程序:
代码语言:javascript复制#include <iostream>
using namespace std;
// .data - read-write data
int rwdata = 100;
// .rodata - read-only data
const char* rodata = "hello, world";
// .bss - non-initialized data
int bssdata;
// .text
void text_code()
{
cout << "text_code" << endl;
}
class VTableTest
{
public:
virtual void virtualfunc()
{
cout << "virtualfunc" << endl;
}
};
int main()
{
cout << ".data: " << &rwdata << endl;
cout << ".rodata: " << reinterpret_cast<const void*>(rodata) << endl;
cout << ".bss: " << &bssdata << endl;
cout << ".text-normal-function: " << reinterpret_cast<void*>(text_code) << endl;
VTableTest* pV = new VTableTest();
long* pVlong = reinterpret_cast<long*>(pV);
void* vptr = reinterpret_cast<void*>(*pVlong);
cout << ".rodata-vtable: " << vptr << endl;
}
编译运行:
代码语言:javascript复制$ segment
.data: 0x804a030
.rodata: 0x80489d0
.bss: 0x804a114
.text-normal-function: 0x80486e4
.rodata-vtable: 0x8048a40
查询各个段的地址范围:
代码语言:javascript复制$ readelf -S segment
There are 29 section headers, starting at offset 0x115c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000034 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481e0 0001e0 0000f0 10 A 6 1 4
[ 6] .dynstr STRTAB 080482d0 0002d0 00018e 00 A 0 0 1
[ 7] .gnu.version VERSYM 0804845e 00045e 00001e 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0804847c 00047c 000060 00 A 6 2 4
[ 9] .rel.dyn REL 080484dc 0004dc 000018 08 A 5 0 4
[10] .rel.plt REL 080484f4 0004f4 000050 08 A 5 12 4
[11] .init PROGBITS 08048544 000544 00002e 00 AX 0 0 4
[12] .plt PROGBITS 08048580 000580 0000b0 04 AX 0 0 16
[13] .text PROGBITS 08048630 000630 00037c 00 AX 0 0 16
[14] .fini PROGBITS 080489ac 0009ac 00001a 00 AX 0 0 4
[15] .rodata PROGBITS 080489c8 0009c8 000094 00 A 0 0 8
[16] .eh_frame_hdr PROGBITS 08048a5c 000a5c 00005c 00 A 0 0 4
[17] .eh_frame PROGBITS 08048ab8 000ab8 000168 00 A 0 0 4
[18] .init_array INIT_ARRAY 08049ef8 000ef8 000004 00 WA 0 0 4
[19] .ctors PROGBITS 08049efc 000efc 000008 00 WA 0 0 4
[20] .dtors PROGBITS 08049f04 000f04 000008 00 WA 0 0 4
[21] .jcr PROGBITS 08049f0c 000f0c 000004 00 WA 0 0 4
[22] .dynamic DYNAMIC 08049f10 000f10 0000e0 08 WA 6 0 4
[23] .got PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4
[24] .got.plt PROGBITS 08049ff4 000ff4 000034 04 WA 0 0 4
[25] .data PROGBITS 0804a028 001028 000010 00 WA 0 0 4
[26] .bss NOBITS 0804a040 001038 0000dc 00 WA 0 0 32
[27] .comment PROGBITS 00000000 001038 00002a 01 MS 0 0 1
[28] .shstrtab STRTAB 00000000 001062 0000f8 00 0 0 1
值得注意的是,vtable是作为readonly的data被放在.rodata段,而不是大家所认为的.text段(代码段)