运行时的Vtable修改

13

对于使用虚函数表(vtable)的编译器实现,是否存在虚函数表在运行时更改的情况? 或者 vtable 只在编译时填充,运行时不执行任何修改操作?


2
你认为哪些运行时修改会有用/可能? - Lightness Races in Orbit
2
如果这只是一个普通的C++程序,那么不需要这样做,这很愚蠢。但是,如果他现在或将来需要编写类似虚拟机或解释器/JIT编译器之类的东西,那么我不会轻易地忽略他的问题。@Cheersandhth.-Alf - David Haim
这很重要,设计一个线程安全的方案非常困难,因此往往不会去做。 - Martin James
1
最明显的情况是类的构造函数。它使用另一个虚函数表运行,防止虚函数成为虚函数,实现所需的C++行为。在构造函数结束时与常规函数表交换。我们不允许谈论这样的实现细节。 - Hans Passant
https://defuse.ca/exploiting-cpp-vtables.htm和http://kaisar-haque.blogspot.ru/2008/07/c-accessing-virtual-table.html提供了一些有趣的见解,尽管你必须具备一定的C++技能、勇气和最重要的是理由才能做这些事情。此外,即将推出的JIT C++编译器jyt.io可能也会相关。 - strangeqargo
显示剩余2条评论
2个回答

8

我不知道任何使用运行时更改虚拟表的多态实现的C++ ABI。

无论如何,这样做并没有太大用处,因为虚拟表通常描述代码的一个属性(成员函数与类层次结构中其他函数之间的关系),而C++代码在运行时不会改变。

而且因为这样做没有什么用处,所以它会很浪费。


虚函数表(vtable)是放在可执行映像的代码段还是数据段? - Karolis Milieška
2
@KarolisMilieška:在哪种实现下?你为什么需要知道呢? - Lightness Races in Orbit
具体来说:ARM Keil,但这同样适用于gcc arm。1. 我只是好奇,2. 我处理嵌入式系统,有时需要知道在哪里放置某些部分。 - Karolis Milieška

3
简短的回答是不行。
稍微长一点(也可能是具体实现)的答案是:在派生多态类的构造函数和析构函数执行期间,对象指向实际虚函数表的指针会发生变化,因此在派生类中重写的方法在基类的构造函数/析构函数中不会被执行,而此时派生类尚未构造完成/已经被析构。
如果您想让对象在运行时更改类,则有几个选项:
  1. Objective-C(++)
  2. 手动编写调度机制
  3. Python/JavaScript等
  4. (最好的选择)重新考虑您的设计。

1
不是 vtable 改变了,而是正在销毁的对象的 vptr 成员改变了! - Kerrek SB
另外,std::function 可以在运行时重新分配,因此这是另一种选择。 - David Haim
@KerrekSB 已修复,虽然我相信有更好的措辞。 - Richard Hodges
1
@DavidHaim 我认为这将属于“自己动手”的范畴,因为他正在谈论在运行时更改整个对象类的行为 - 需要在更改周围放置互斥锁,并且需要一些机制来保护实际执行的函数(可能是复制std :: function或持有其shared_ptr?) - Richard Hodges
1
@RichardHodges,我完全同意你的观点。我只是想提一下函数对象,这样“调度机制”就不会总是指JIT编译或者干扰汇编代码之类的东西了。 - David Haim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接