Clang AST可以获取虚函数表吗?

问题描述 投票:0回答:1

我尝试使用 CXXRecordDecl 打印虚函数,但它们是按声明顺序排列的,这可能不是 vtable 中的实际顺序。

示例代码

namespace test
{

class Foo {

 public:
    virtual void v_func() {}
    virtual void v_func2() {}
    virtual ~Foo() = default;
};

class Bar : public Foo {
    public:
    virtual void v_func2() {}
    virtual void v_func() {}
    virtual ~Bar() = default;
};

} // namespace test



int main() {
    test::Foo *foo = new test::Bar();
    test::Bar *bar = new test::Bar();
    delete foo;
    delete bar;
    return 0;
}

gdb打印的虚函数表如下:

(gdb) info vtbl foo
vtable for 'test::Foo' @ 0x65a450 (subobject @ 0x101a008):
[0]: 0x404402 <test::Bar::v_func()>
[1]: 0x4043f4 <test::Bar::v_func2(int, test::tmp)>
(gdb) info vtbl bar
vtable for 'test::Bar' @ 0x65a450 (subobject @ 0x101a010):
[0]: 0x404402 <test::Bar::v_func()>
[1]: 0x4043f4 <test::Bar::v_func2(int, test::tmp)>

遍历CXXRecordDecl的方法,只能按照函数声明的顺序打印

// CXXRecordDecl *cxx_record
// Dump out all the virtual methods
for (CXXRecordDecl::method_iterator first = cxx_record->method_begin();
      first != cxx_record->method_end(); ++first) {
  if (!first->isVirtual()) {
    continue;
  }
  llvm::outs() << first->getQualifiedNameAsString() << " " << first->getType().getAsString() << "\n";
}

出:

v_func void (void)
v_func2 void (int, class test::tmp)
~Foo void (void) noexcept
v_func2 void (int, class test::tmp)
v_func void (void)
~Bar void (void) noexcept

我检查了 CXXRecordDecl 的文档,没有发现任何与 vtables 相关的东西

clang clang++ clang-ast-matchers
1个回答
0
投票

当您查看 Clang AST 时,例如在

CXXRecordDecl
中,您会看到编译器“前端”中可用的信息,其中包括输入语法、静态类型以及在中指定的其他内容C++ 语言标准。

但是,C++ 标准根本不需要存在虚函数表(“vtables”)本身(原则上,虚拟调度可以通过一些完全不同的机制来完成),更不用说它们的顺序了。相反,vtables 是 Application Binary Interface (ABI) 的一个特性,它指定了如何在机器代码数据结构级别实现各种语言特性。 ABI 取决于处理器架构。

一个常用的 C++ ABI,即使在 x86_64 上,也是 Itanium C++ ABI。引用其关于 vtable 组件的部分

虚表中虚函数指针的顺序就是类中对应成员函数的声明顺序

因此,如果您对使用该 ABI 的平台的 vtable 顺序感兴趣,您在 Clang AST 中看到的顺序就是该顺序(尽管您需要阅读完整文档,而不仅仅是我引用的部分,以获取完整的故事)。

如果你想挂钩进程

clang

 特别是用来生成 vtables,看看它的 
VTableBuilder
 类。该类是
clang
“后端”的一部分,即生成机器代码的部分,这意味着您必须使用代码生成器(而不仅仅是解析器)才能使用它。

© www.soinside.com 2019 - 2024. All rights reserved.