`
阿尔萨斯
  • 浏览: 4170142 次
社区版块
存档分类
最新评论

C++编译器检索VTABLE的具体方法不同

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>

以前没太注意过这个问题,只知道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)




分享到:
评论

相关推荐

    vtable 虚函数表

    vtable 虚函数表 更加有效的理解虚函数

    C++程序设计彻底研究(是code不是书)

    本书包含所有重要的有关C++程序设计的知识,除了入门的基础知识之外,对较深入的内容也作了讲解,例如对VPTR和VTABLE都有精彩的说明。本书提供了极佳的学习步调和连贯的先后次序,叙述方式主线明显,使读者不会为...

    C++中虚函数的实现机制

    介绍了C++编程语言中的虚函数及其在进行面向对象程序设计中重要性,并且详细阐述了它在编译器底层虚函数的实现机制.它通过一个vptr和vtable在运行时进行动态绑定,从而能够根据对象类型的不同调用不同的 虚函数;并...

    C++100天经典实战系(含大量案例源码及通俗讲解教程,effective_c++、STL、综合能力全面提升)

    友元函数与友元类、引用与指针那些事、深入浅出C++虚函数的vptr与vtable、宏那些事、范围解析运算符那些事、从初级到高级的enum那些事、纯虚函数和抽象类、volatile、virtual、using、union、this、struct_class、...

    C++编程思想习题

    8.3内联函数和编译器 8.3.1局限性 8.3.2赋值顺序 8.3.3在构造函数和析构函数里隐藏行为 8.4减少混乱 8.5预处理器的特点 8.6改进的错误检查 8.7小结 8.8练习 第9章 命名控制 9.1来自C语言中的静态成员 9.1.1函数内部...

    C语言和C++的重要知识点提炼.rar

    当编译器发现基类当中有虚函数存在时,就会为每个含有虚函数的类创建一个虚函数表(vtable),该表是一个一维数组,存放的是虚函数的地址,子类中如果没有虚函数也会从基类中继承虚函数表,虚表创建之后还会创建一个...

    CPP-function.rar_CPPFunction_doc_vtable

    C++ 虚函数表解析。C++中的虚函数的作用主要是实现了多态的机制。.doc文件。教程

    C++ 虚函数表详解

    很好的虚函数表解析, 代码,图,文并茂,对多态的理解会非常深刻

    vtable.rar

    c/c++ 简单回调实例,回调函数本质上提供了一种与常规的上层调用下层代码相反的模式,使得底层代码也有机会反调高层的代码,这大大提升了代码的能力。简单明了。

    HotSpot实战高清版本

    Cache、Perf Data、Crash 分析方法、转储分析方法、 垃圾收集器的设计演进、CMS 和 G1 收集器、栈、JVM 对硬件寄存器的利用、栈顶缓存技术、解释器、字节 码表、转发表、Stubs、Code Cache、Code 生成器、JIT 编译器...

    parrt-vtable:vtable 项目的入门套件

    vtable 项目的入门套件 见。

    ObjectiveK:C语言源代码编译器的源代码,用于具有vtable,类别和重要缩进的简单面向对象语言

    一种简单的实验性编程语言,实现为预处理器,可获取ObjectiveK源代码并从中生成C源代码。ObjectiveK的设计目标提供面向对象的编码机制,但通过使用vtables可以更快使用类似于C的语法,但更喜欢使用清晰的标识符而...

    简述C++中虚拟函数的内存分配机制

    就要生成一张虚函数表,即vtable。而在类的对象地址空间中存储一个该虚函数表的入口, 占4个字节,这个入口地址是在构造对象是由编译器写入的。 有如下C++程序: //#include #include using namespace std; class ...

    构造函数不能声明为虚函数的原因及分析

    1. 从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有...

    在什么情况下,Java比C++慢很多?

    在Java中,所有的对象都有一个vtable指针,而C++中使用POD结构没有额外开销。此外,所有的Java对象是可以被锁定的。其实现依赖于JVM,这可能需要在对象中增加额外的字段。大对象 == 缓存更少的对象 == 更慢。

    HotSpot实战

    Klass对象表示系统、链接、运行时数据区、方法区、常量池和常量池Cache、...编译器、编译原理、JVM指令集实现、函数的分发机制、VTABLE和ITABLE、异常表、虚拟机监控工具(如jinfo、jstack、jhat、jmap等)的实现原理和...

    Ghidra-Cpp-Class-Analyzer:Ghidra C++ 类和运行时类型信息分析器

    Ghidra C++ 类和运行时类型信息分析器 API 文档 完整构建和链接的文档版本可在。 建造 在您选择的终端中运行以下命令。 gradle buildExtension 完成后,输出将位于 dist 文件夹中。 安装 将存档解压缩到您选择的...

    natsu-clr:il2cpp编译器和运行时与.Net Core兼容

    编译时vtable和变量初始值设定项 没有完整程序的汇编级编译 特性 .Net Core 3.0兼容 极小内存占用 可移植性强 很容易和C ++互操作 编译期虚表和变量初始化 程序集等级编译,不需要整个程序全部编译 支持的CLR功能 ...

    vtable_hook:挂钩 vtables

    vtable_hook 挂钩 vtables 从 2015 年 1 月开始 -

Global site tag (gtag.js) - Google Analytics