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

原创 2004年04月21日 18:14:00

以前没太注意过这个问题,只知道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++代码调用某个虚函数时要到虚函数表里去查找,然后执行特定的函数。这两天跟别人调程序时发现,VC和gcc对这个检索操作的实现方法是不一样的:早期的gcc(2001年...
  • hejishan
  • hejishan
  • 2008年04月01日 17:03
  • 135

C++ 中的vptr与vtable

// test.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #include using namespace ...
  • chjjunking
  • chjjunking
  • 2014年03月28日 11:03
  • 2589

查看C++类的虚表(vtable)结构

假定源文件如下: #include #include class IA { public: virtual ~IA() {} virtual void PrintA() = 0; virtua...
  • CaspianSea
  • CaspianSea
  • 2015年07月22日 09:01
  • 1570

C++动态绑定和虚函数表vtable (动态实现原理)

关于C++内部如何实现多态,对程序员来说即使不知道也没关系,但是如果你想加深对多态的理解,写出优秀的代码,那么这一节就具有重要的意义。 我们知道,函数调用实际上是执行函数体中的代码。函数体是内存中的一...
  • zhanghow
  • zhanghow
  • 2016年12月12日 21:38
  • 782

C++中的 虚表(vtable)和虚指针(vptr)

1、每个c++类都有一个vtable,每个类对象都有个vtable的vptr; 2、在vc中,类的继承是在基类后面追加数据的形式进行继承的。 测试代码如下(在32位系统下的vs2008环境...
  • u013617648
  • u013617648
  • 2015年06月21日 19:52
  • 1740

c++多态性——vptr和vtable

多态性 (polymorphism) 是面向对象编程的基本特征之一。而在 C++ 中,多态性通过虚函数 (virtual function) 来实现。我们来看一段简单的代码:   #include ...
  • rongwenbin
  • rongwenbin
  • 2014年02月19日 16:43
  • 747

[C++] Undefined reference to vtable

链接器linker需要将虚函数表vtable 放入某个object file,但是linker无法找到正确的object文件。这个错误常见于刚刚创建一系列有继承关系的class的时候,这个时候很容易忘...
  • wwwsq
  • wwwsq
  • 2006年09月20日 10:27
  • 6874

我对C++ VTable 的理解

我们知道C++支持的虚函数是通过为每个类提供一个虚函数来实现的,它的内存状态究竟是怎样的呢?首先我们实现两个拥有虚函数的类:ClassA和ClassB,其中ClassB是ClassA的派生类,具体实现...
  • theCFan
  • theCFan
  • 2005年04月24日 11:35
  • 7871

C++:undefined reference to vtable 原因与解决办法 [转]

最近在写一套基础类库用于SG解包blob字段统计,在写完了所有程序编译时遇到一个郁闷无比的错误:  MailBox.o(.text+0x124): In function `CMailBox::CM...
  • ai2000ai
  • ai2000ai
  • 2015年08月06日 15:43
  • 1802

VPTR和VTABLE和构造函数与继承

C++中类的成员函数默认情况下是non-virtual,即被调用时为静态绑定。          至少包含一个virtual成员函数的类,都有一个VTABLE——虚函数映射表,表中的每项对应类中一...
  • xiatianhappy
  • xiatianhappy
  • 2016年04月17日 20:01
  • 531
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++编译器检索VTABLE的具体方法不同
举报原因:
原因补充:

(最多只允许输入30个字)