EuroLLVM 2024 参会报告
EuroLLVM 是一个专注于 LLVM Foundation 旗下项目的开发者会议,这些项目位于 LLVM GitHub 单仓库中,例如 Clang 以及最近因机器学习研究而兴起的 MLIR 框架。Trail of Bits 在编译器工程和 LLVM 相关领域有着悠久历史,此次派遣了一批编译器专家参会,并展示了两个项目:基于 MLIR 的 C/C++ 编译器 VAST,以及针对 MLIR 的新型指向分析方法 PoTATo。本博客文章分享了我们从为期两天的开发者会议(包括一天会前研讨会)中的收获和体验。
安全意识
与往年相比,一个显著的变化是对安全性的日益关注。LLVM 社区内部似乎有一股不断增强的驱动力,旨在提升整个软件生态系统的安全性。这代表了编译器社区中一个相对较新的发展,LLVM 领导层积极寻求该主题的专业知识。
开幕主题演讲引入了安全主题,断言其已成为编译器的第三大支柱,与优化和翻译并列。ARM 的 Kristof Beyls 发表了主题演讲,简要回顾了编译器关注点和角色的演变历史。他强调,安全性现在是与正确性和性能并列的主要关注点。
主题演讲的技术部分提出了一个有趣的问题:是否有人验证安全缓解措施是否正确应用,或者是否应用了?为了回答这个问题,Kristof 使用 BOLT 实现了一个静态二进制分析工具。他选择验证的缓解措施是 -fstack-clash-protection 和 -mbranch-protection=standard,特别是其 pac-ret 机制。
基于 BOLT 的扫描器评估是在 Fedora 39 AArch64-linux 发行版中的库上进行的,包括大约 3,000 个已安装的软件包。对于 pac-ret,分析揭示了 250 万条返回指令,其中 46,000 条缺乏适当的保护。扫描使用 -fstack-clash-protection 的 1,920 个库,识别出 39 个可能易受攻击,尽管其中一些可能是误报。
关于选择 BOLT 而非逆向工程领域的工具(如 IDA、Ghidra 或 Angr)的偏好引发了一场有趣的讨论。区别在于 BOLT 适用于批量处理二进制文件,而 IDA 或 Ghidra 则侧重于用户交互性。此外,BOLT 的优势在于它支持最新的目标架构变化,因为它是编译管道的一部分,而逆向工程工具往往滞后,特别是在更小众的指令方面。
有关更多细节,Kristof 在 LLVM discourse 上的 RFC 提供了额外信息。
对于对编译器加固感兴趣的人,OpenSSF 指南提供了全面的概述。此外,对于编译器工程师更深入的安全讨论,我们建议阅读《低级软件安全》在线书籍。它仍在进行中,欢迎对指南做出贡献。
关于程序分析和调试的一个值得注意的演讲是《Clang 静态分析器的增量符号执行》,讨论了 Clang 静态分析器如何现在可以缓存结果。这一创新有助于在代码库变更时保持诊断信息的相关性,并最小化调用分析器的需求。另一个亮点是《Mojo 调试:扩展 MLIR 和 LLDB》,探讨了 LLDB 的新发展,允许其在 Clang 环境之外使用。该演讲还涵盖了从 Modular 仓库上游化调试方言的潜力。
MLIR 不仅仅是机器学习
MLIR 是一个编译器基础设施项目,因机器学习(ML)热潮而受到关注。然而,MLIR 中的 ML 代表多级(Multi-Level),该项目远不止于张量处理。以 RISC-V 工作闻名的 SiFive 在电路设计等应用中使用了它。使用 MLIR 的通用语言编译器也在涌现,例如用于 JavaScript 的 JSIR Dialect、作为 Python 超集的 Mojo、ClangIR,以及我们自己的用于 C/C++ 的 VAST。
本次开发者会议的 MLIR 主题可以总结为“弄清楚如何在共享管道中充分利用 LLVM 和 MLIR”。许多演讲者展示的工作以某种方式得出结论,认为许多性能优化在 MLIR 中做得更好,得益于其更好的抽象。然后 LLVM 主要负责生成目标机器代码。
在回顾了 MLIR 相对于 LLVM 的所有慢速方面后,Jeff Niu(Modular)评论说,在 Mojo 编译器中,大部分运行时仍然花费在 LLVM 中。原因很简单:当代码编译到 LLVM 时,有更多的输入需要处理。
慕尼黑工业大学的一个团队甚至选择完全跳过 LLVM IR,直接生成机器 IR(MIR),在即时(JIT)编译工作负载中实现了约 20% 的性能提升。
对 MLIR 内部机制感兴趣的人一定要观看第二次会议主题演讲《MLIR 中的高效惯用法》。该主题演讲深入探讨了不同 MLIR 原语和模式的性能比较。它让开发者对执行操作(如获取属性、迭代或变异 IR)的成本有了良好的直觉。在类似主题上,《接口实现深度探讨》演讲更深入地了解了 MLIR 通用性的基石。这些接口使方言能够表达常见概念,如副作用、符号和控制流交互。该演讲阐明了它们的实现细节以及在追求通用性时产生的相关开销。
基于区域的分析
我们注意到的另一个有趣趋势是,几个独立团队发现,传统上使用基于基本块的控制流图定义的分析,在使用基于区域的控制流表示时,可能会获得更好的运行时性能。这一改进主要是因为分析不需要重建循环信息,整体表示更小,因此分析更快。 presented 的主要例子是在 Mojo 编译器内部完成的数据流分析。
对于像 Mojo 这样的情况,从源代码开始并编译基于 MLIR 的管道,切换到基于区域的控制流进行分析只是在管道中更早进行分析的问题。其他用户则不那么幸运,需要从传统的控制流图构建区域。如果你是这样的人,你并不孤单。高性能计算行业的团队一直在寻找从循环中挤出更多性能的方法,将循环明确表示为区域而不是在图中寻找它们,使许多事情变得更容易。这就是为什么 MLIR 现在有一个传递(pass)来将控制流图提升为基于区域的控制流。听起来熟悉吗?在底层,我们的 LLVM 到 C 反编译器 Rellic 做了非常类似的事情。
然而,使用区域进行控制流并非一切顺利。区域需要具有单入口和单出口。然而,许多编程语言允许在循环体内使用 break 和 continue 等结构。这些被视为异常入口或出口。幸运的是,随着关于区域的讨论如此之多,核心 MLIR 开发者已经注意到,并正在酝酿一个主要新功能来解决这个问题。正如在 MLIR 研讨会上所展示的,新设计的基于区域的控制流将允许指定 continue 或 break 等结构的语义。想法很简单:这些操作将产生终止信号,并将控制流转发到捕获该信号的某个父区域。不幸的是,这仍然不允许我们在高级表示中表示 goto,因为信令机制只允许用户将控制流传递给父区域。
C/C++ 继任者语言
会议最后一个主要主题是,鉴于最近的发展,C/C++ 的继任者语言。其中一个努力是 Carbon,它有一个专门的专题讨论。专题讨论的问题范围从技术问题(如如何支持重构工具)到更管理性的问题(如 Carbon 如何避免过度受 Google 需求的影响,Google 目前是该项目的主要支持者)。有关专题讨论的更全面总结,请查看 Alex Bradbury 的这篇优秀博客文章。
其他 C++ 的挑战者也得到了提及——特别是 Rust 和 Swift。这两种语言都认识到 C++ 在软件生态系统中的权威,并有自己的 C++ 互操作性故事。在 Carbon 专题讨论中提到了 Google 的 Crubit for Rust,而 Apple 的 Egor Zhdan 就互操作性进行了单独演讲。
我们的贡献
我们自己的 Henrich Lauko 就 VAST(我们基于 MLIR 的 C/C++ 编译器)的一个新功能进行了演讲:IR 塔(Tower of IRs)。这里的总体思路是,VAST 是一个基于 MLIR 的 C/C++ 编译器 IR 项目,提供多层抽象。VAST 的用户可以为他们的分析或转换用例选择合适的抽象。然而,有许多有价值的基于 LLVM 的工具,如果我们不能将它们与我们的高级 MLIR 表示一起使用,那将是不幸的。这正是我们开发 IR 塔的原因。它使用户能够将低级分析与高级抽象桥接起来。
IR 塔引入了一种机制,允许用户在转换之间和之后拍摄 IR 快照,并将它们链接在一起,创建来源链。这样,当一段代码发生变化时,总有一条引用链回到原始输入。敏锐的读者已经会心一笑。
Henrich 展示的演示用例是通过使用塔将输入 C 源代码一直向下带到 LLVM,执行依赖分析,并通过塔中的来源链接将分析结果一直翻译回 C,从而在 MLIR 中重新利用 LLVM 分析。
与 Henrich 一起,Robert Konicar 以 PoTATo 的形式展示了他学生工作的丰硕成果。该项目实现了一个简单的 MLIR 方言,专门用于实现指向分析。想法是将内存操作从源方言翻译到 PoTATo 方言,进行一些基本优化,然后运行你选择的指向分析,产生别名集。为了将相关信息带回原始代码,当然可以使用 VAST IR 塔。Robert 在海报上展示的结果很有希望:在指向分析之前应用基本复制传播显著减少了问题规模。
AI 走廊谈话
除了参加官方演讲和研讨会外,Trail of Bits 的代表在休息时间和宴会上花了很多时间与人交谈。许多这些对话的潜流是各种形式的 AI 和机器学习。因为 EuroLLVM 专注于语言、编译器和硬件运行时,对话通常采取“我们如何最好地服务这种新计算范式?”的形式。硬件人员对如何为专用加速器生成代码感兴趣;编译器人群以各种可想象的方式优化线性代数;而语言则尽力满足数据科学家的需求。
关于反向项目的讨论——即“机器学习如何帮助 LLVM 人群?”——则少之又少。这些项目通常研究在 LLVM 相关领域收集的各种数据,以便使用机器学习方法理解它们。从我们所见,像 LLM 和 GAN 这样的东西并没有以任何方式被真正提及。似乎是一个新想法的机会!