在llvm中识别虚拟呼叫站点

时间:2017-04-24 20:00:45

标签: c++ llvm llvm-clang llvm-ir

我需要在LLVM传递中识别虚函数调用站点,以及识别可能在运行时调用的候选函数。

class B
{
   virtual void F() { // do something }
};

class D : public B
{
 void F() { // do something else }
};

B* d = new D();
d->F();

例如,对于给定的层次结构和F的调用,将B :: F和D :: F都标识为可能的候选者。

在寻找解决方案时,我遇到了Clang CFI(控制流集成),他们说他们通过检查虚拟表指针是否在一组候选虚拟表指针中来识别虚拟表指针是否有效。因此,我假设有一种方法可以获取有关继承层次结构的信息。但我无法找到任何如何在llvm中完成这项工作。

那么有人知道如何做到这一点吗?

1 个答案:

答案 0 :(得分:1)

在llvm开发人员的帮助下,我找到了解决问题的方法,并考虑在此处分享,以防有人需要它。

在llvm中有一个转换传递-wholeprogramdevirt,它正在做我想要达到的目标。它标识模块中的虚拟呼叫站点和候选被叫者,然后尝试在可能的情况下对这些呼叫进行虚拟化。例如,如果虚拟函数仅在一个层次结构中实现,则对该函数的间接调用将替换为已实现函数的直接调用。

class B
{
virtual void F() { // do something }
};

class D : public B {};

B* d = new D();
d->F();

因此,对于这种情况,F的间接调用将被直接调用B :: F替换。 WholeProgramDevirt传递使用类型元数据和llvm类型检查内部函数来识别虚拟呼叫站点和候选被调用者。

首先,您需要启用带有clang -fwhole-program-vtables标志的bitcode。这将为虚拟呼叫站点生成相应的内部功能。这些内在函数是llvm.type.test,llvm.checked.load和llvm.assume。然后使用这些内在函数整个程序,devirtualizer找到虚拟调用站点,并为每个候选callees找到它们。

对于我的情况,我不需要进行转换,因此我将其作为分析过程实现并收集结果以供进一步使用。