C++编译器检索VTABLE的具体方法不同
来源:互联网 发布:专业java就业培训 编辑:程序博客网 时间:2024/06/06 14:11
以前没太注意过这个问题,只知道C++代码调用某个虚函数时要到虚函数表里去查找,然后执行特定的函数。这两天跟别人调程序时发现,VC和gcc对这个检索操作的实现方法是不一样的:
早期的gcc(2001年5月前?)使用的是一个比较直观的查表方法。gcc中指向成员函数的指针其实是一个结构,类似于最早期的cfront编译器:
struct
{
??? short __delta;
??? short __index;
??? union
??? {
??????? void * __pfn;
??????? short _delta2;
??? } _pfn_or_delta2;
};
如果指向非虚成员函数,__pfn中就保存了内存中实际的函数指针。如果指向虚成员函数,__pfn无效,__index为该函数在虚函数表中的索引。调用虚函数时,根据虚函数表的地址和索引查到特定函数地址。
后续版本的gcc在不断改进这种虚函数表的检索方法(实际上后续的gcc对C++ ABI的改动比较多),现在的gcc 3.3.3的源码里,gcc/cp/cp-tree.h等文件包含了相关代码。不过现在的实现代码比较复杂,我还没有彻底看明白。
而VC的实现与此大不相同。VC为一棵继承树上的每个虚函数生成一个vcall代码(可以被看成一个小的中介函数),根据每个虚函数在虚函数表中的偏移不同,每个vcall调用时为eax增加的偏移量不同。这实际上是一种快速的查表机制,而且不用传虚函数表的index就可以调用到特定函数了。
`vcall':
00401010? mov???????? eax,dword ptr [ecx]
00401012? jmp???????? dword ptr [eax]
`vcall':
00401020? mov???????? eax,dword ptr [ecx]
00401022? jmp???????? dword ptr [eax+4]
`vcall':
00401030? mov???????? eax,dword ptr [ecx]
00401032? jmp???????? dword ptr [eax+8]
`vcall':
00401040? mov???????? eax,dword ptr [ecx]
00401042? jmp???????? dword ptr [eax+0Ch]
调用时,对同名虚函数(无论该函数在属于一个类),使用的都是同一个vcall,但调用不同类的虚函数时,传入vcall的虚函数表起始地址不同(下面C2类是C1类的派生类,f1和f2是虚函数)。
& C1::f1 - offset `vcall' (401010h)
& C1::f2 - offset `vcall' (401020h)
& C2::f1 - offset `vcall' (401010h)
& C2::f2 - offset `vcall' (401020h)
- C++编译器检索VTABLE的具体方法不同
- C++编译器检索VTABLE的具体方法不同
- C++编译器检索VTABLE的具体方法不同
- lucene检索的具体实现
- [ --> C Language<-- ] 不同的C编译器差别够大的
- 不同的编译器:GCC G++ C C++的区别
- 【转】不同的编译器:GCC G++ C C++的区别
- 不同的编译器:GCC G++ C C++的区别
- 不同的编译器:GCC G++ C C++的区别
- 编译器 不同的宏
- C语言各种编译器的清屏方法
- sql中全文检索的具体细节
- 同一段代码,不同C编译器,输出结果真的会不同啊!!!
- gcc编译器的具体处理过程
- 不同编译器的故事一
- 不同编译器的类型字节
- obective-c产生不同的随机数 方法
- Hibernate的检索方法
- VC编译优化设置
- WINX调查:您使用什么C++开发平台?
- 应用程序框架设计(2):SW系统的窗口类
- 关于VC中的时间函数讨论
- 再论C++之垃圾回收(GC)
- C++编译器检索VTABLE的具体方法不同
- VC应用程序框架
- 应用程序框架设计(1):SW系统简介
- 垃圾收集机制(Garbage Collection)批判
- 钩子技术介绍及函数使用
- 在Win2K/XP/2K3中 模拟实现VISITA效果对话框
- 内存池(MemPool)技术详解
- WINX的消息分派机制(终结篇)
- MFC的子类化技术