资讯动态

虚函数表vtable揭秘:C++虚函数在LLVM IR底层实现的完整指南

发布时间:2026/8/23 11:06:38 来源:尧图企业网站定制
虚函数表vtable揭秘C虚函数在LLVM IR底层实现的完整指南【免费下载链接】mapping-high-level-constructs-to-llvm-irA guide that explains how high level programming language constructs are mapped to the LLVM intermediate language.项目地址: https://gitcode.com/gh_mirrors/ma/mapping-high-level-constructs-to-llvm-ir 本指南基于开源教程mapping-high-level-constructs-to-llvm-ir编写。该项目是一本专门讲解高层语言构造如何映射到 LLVM 中间表示LLVM IR的电子书覆盖类、虚函数表vtable、继承、异常处理等主题是了解编译器内部运作的宝藏资料。虚函数vtable为什么值得新手关注C 的虚函数virtual function是多态的基石但它真正的魔法发生在编译后编译器为每个含虚函数的类生成一张虚函数表vtable把运行时该调用哪个函数的问题变成了一张函数指针地址表的查询。而 LLVM IR 正是窥探这张表长什么样的最佳窗口——因为编译器在生成机器码之前会先把 C 翻译成 LLVM IR。看懂 vtable 在 LLVM IR 中的表示你就掌握了 C 多态的底层真相。vtable在LLVM IR中的本质一张函数指针表书中有句话说得极简虚函数不过是编译器控制的函数指针。以一个含虚函数的Foo类为例编译器会做三件事对应资料object-oriented-constructs/virtual-methods.rst定义 vtable 类型一个只包含若干指向函数的指针的结构体把 vtable 指针放进类本身类的内存布局变成{ vtable指针, 成员变量... }即 LLVM IR 中的%Foo type { %Foo_vtable_type*, i32 }生成 vtable 数据一个全局变量把每个虚函数的地址按顺序填进去。class Foo { public: virtual int GetLengthTimesTwo() const { return _length * 2; } private: int _length; };%Foo_vtable_type type { i32(%Foo*)* } ; vtable一张函数指针表 %Foo type { %Foo_vtable_type*, i32 } ; 类对象 vtable指针 数据 Foo_vtable_data global %Foo_vtable_type { ; 表里填的是函数地址 i32(%Foo*)* Foo_GetLengthTimesTwo } 换句话说对象内部第一个字段就是 vtable 指针虚函数调用 解引用 vtable → 按下标取出函数指针 → 间接调用。一次虚函数调用的底层执行流程这是全文最精华的部分。main函数中对foo.GetLengthTimesTwo()的虚函数调用在 LLVM IR 中被翻译成四步完整代码见object-oriented-constructs/listings/listing_4.ll步骤LLVM IR 指令做了什么① 定位getelementptr ... i32 0取对象起始处的vtable 指针字段② 取表load %Foo_vtable_type*, ...读出 vtable 的地址③ 索引getelementptr ... i32 0, i32 0按下标 0找到第 0 个虚函数槽位④ 调用load i32(%Foo*)* ...call %4(...)取出函数地址间接调用call %4对比一下普通函数调用普通成员函数编译后是直接调用call void Foo_SetLength(...)地址编译期就确定了而虚函数是call %4(...)——被调用的目标是一个变量只能运行时决定。这正是多态的实现原理。对象如何获得自己的vtable指针对象创建时编译器会生成一个默认构造函数来初始化 vtable 指针见object-oriented-constructs/listings/listing_5.lldefine void Foo_Create_Default(%Foo* %this) nounwind { %1 getelementptr %Foo, %Foo* %this, i32 0, i32 0 store %Foo_vtable_type* Foo_vtable_data, %Foo_vtable_type** %1 ; 把vtable指针存进对象 ... }每当new Foo()或栈上创建Foo foo;这段初始化逻辑都会执行保证对象一出生就知道自己的 vtable 在哪。单继承、多继承与vtable的内存布局虚函数表必须和内存布局配合使用书中还讲了三类继承在 LLVM IR 中的映射单继承object-oriented-constructs/single-inheritance.rst基类的成员包括 vtable 指针按声明顺序平铺在派生类前面派生类指针转基类指针只需bitcast类型转换偏移量为 0。多继承object-oriented-constructs/multiple-inheritance.rst多个基类依次排布向上转换时可能需要调整指针偏移。虚继承object-oriented-constructs/virtual-inheritance.rst相同的虚基类被合并为一份避免菱形继承产生两份数据。接口interface 纯虚函数vtable的特例书中对接口的定义一句话就能说完接口就是一个没有数据成员、所有方法都是纯虚函数的基类object-oriented-constructs/interfaces.rst。因此接口在 LLVM IR 中的映射方式与虚函数完全相同——一张纯虚函数地址组成的 vtable。这也是为什么 C 的interface风格设计与 Java/C# 的 interface 在底层殊途同归。Rust的动态分派vtable的另一番模样 一个有趣的延伸书中还专门分析了 Rust。Rust 虽然没有 C 意义上的虚函数但它的dyn Trait特性对象trait object底层同样是 vtable只是表的内容更丰富vtable.button private unnamed_addr constant { void (%Button*)*, i64, i64, void (%Button*)* } { void (%Button*)* core::ptr::drop_in_placetest::Button, ; 析构函数 i64 32, ; 对象大小 i64 8, ; 对齐 void (%Button*)* test::Button as test::Draw::draw ; 方法地址 }可以看到 Rust 的 vtable 里除了方法指针还多存了析构函数指针、对象大小和对齐值方便运行时处理Boxdyn Trait这类动态大小对象。两种语言在动态分派这一层的实现惊人地相似。如何获取并本地构建这份完整指南如果不想 clone 仓库也可以直接在线阅读。想本地构建流程如下git clone https://gitcode.com/gh_mirrors/ma/mapping-high-level-constructs-to-llvm-ir llvm-ir cd llvm-ir sudo apt install -y build-essential python3-pip python3-sphinx python3-sphinx-rtd-theme make html构建完成后在_build/html目录用浏览器打开即可得到完整电子书。延伸阅读项目内路径类的基础映射object-oriented-constructs/classes.rst虚函数vtable核心章节object-oriented-constructs/virtual-methods.rst配套 LLVM IR 示例object-oriented-constructs/listings/listing_4.ll、object-oriented-constructs/listings/listing_5.ll控制流与 φ 节点control-structures/ssa-phi.rst总结看懂 vtable 在 LLVM IR 中的表示只需记住三句话对象里第一个字段是 vtable 指针类类型在 LLVM IR 中就是{ vtable指针, 数据... }vtable 是全局的函数指针表虚函数按声明顺序占槽虚函数调用 取 vtable → 按下标索引 → 间接调用四步 IR 指令完成。掌握这套映射后无论是 C 多态、Rust trait 对象还是编译器生成的异常处理、接口实现你都能透过 LLVM IR 看清它们的真实面目。【免费下载链接】mapping-high-level-constructs-to-llvm-irA guide that explains how high level programming language constructs are mapped to the LLVM intermediate language.项目地址: https://gitcode.com/gh_mirrors/ma/mapping-high-level-constructs-to-llvm-ir创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价