travitch/whole-program-llvm

GitHub: travitch/whole-program-llvm

一套基于 Python 的编译器封装工具,用于从未经修改的 C/C++ 源码构建完整的全程序 LLVM bitcode 文件,解决传统 LTO 在静态库场景下的局限性。

Stars: 737 | Forks: 134

![WLLVM](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/917c0506b1213844.png)Whole Program LLVM [![许可证: MIT](https://img.shields.io/badge/License-MIT-blueviolet.svg)](https://opensource.org/licenses/MIT) [![PyPI 版本](https://badge.fury.io/py/wllvm.svg)](https://badge.fury.io/py/wllvm) [![构建状态](https://travis-ci.org/SRI-CSL/whole-program-llvm.svg?branch=master)](https://travis-ci.org/SRI-CSL/whole-program-llvm) [![PyPI 统计](https://img.shields.io/pypi/dm/wllvm.svg)](https://pypistats.org/packages/wllvm) ## 介绍 本项目 WLLVM 提供了一系列工具,用于从未经修改的 C 或 C++ 源码包构建全程序(或全库)LLVM bitcode 文件。它目前可在 `*nix` 平台上运行,例如 Linux、FreeBSD 和 Mac OS X。 WLLVM 提供了基于 Python 的编译器封装,分两步工作。封装器首先像往常一样调用编译器。然后,对于每个目标文件,它们调用 bitcode 编译器生成 LLVM bitcode。封装器还会将生成的 bitcode 文件的位置存储在目标文件的专用段中。当目标文件链接在一起时,专用段的内容会被连接起来(因此我们不会丢失任何组成部分 bitcode 文件的位置)。构建完成后,可以使用 WLLVM 实用程序读取专用段的内容,并将所有 bitcode 链接成一个单独的全程序 bitcode 文件。该实用程序适用于可执行文件和原生库。 这种两阶段构建过程对于在任何构建系统中直接替代 gcc 或 g++ 是必要的。在 gcc 中使用 LTO 框架和 gold 链接器插件在许多情况下都有效,但在构建中存在静态库时会失败。WLLVM 的方法具有生成可运行二进制文件的显著优势,以防构建过程的某些部分需要这样做。 WLLVM 可与 clang 或 gcc dragonegg 插件一起使用。如果您对 dragonegg 支持不感兴趣,并且速度对您来说是个问题,您可能想尝试 [gllvm。](https://github.com/SRI-CSL/gllvm) ## 安装 截至 2016 年 8 月,WLLVM 现已是一个 pip 包。您只需执行: ``` pip install wllvm ``` 或 ``` sudo pip install wllvm ``` 具体取决于您机器的权限。 # 教程 如果您想开发或使用开发版本: ``` git clone https://github.com/travitch/whole-program-llvm cd whole-program-llvm ``` 现在您需要安装 WLLVM。您可以选择在系统上全局安装并使用开发模式: ``` sudo pip install -e . ``` 或者将 WLLVM 安装到虚拟 Python 环境中并使用开发模式,以避免全局安装: ``` virtualenv venv source venv/bin/activate pip install -e . ``` ## 使用 WLLVM 包含四个 Python 可执行文件:用于编译 C 代码的 `wllvm` 和用于编译 C++ 的 `wllvm++`,用于从构建产物(目标文件、可执行文件、库或归档文件)中提取 bitcode 的辅助工具 `extract-bc`,以及用于检测配置疏忽的健全性检查器 `wllvm-sanity-checker`。 必须设置三个环境变量才能使用这些封装器: * `LLVM_COMPILER` 应设置为 `dragonegg` 或 `clang`。 * `LLVM_GCC_PREFIX` 应设置为应与 dragonegg 一起使用的 gcc 版本的前缀。如果没有前缀,可以留空。如果 `$LLVM_COMPILER == clang`,则不使用此变量。 * `LLVM_DRAGONEGG_PLUGIN` 应是 dragonegg 插件的完整路径。如果 `$LLVM_COMPILER == clang`,则不使用此变量。 设置好环境后,只需分别使用 `wllvm` 和 `wllvm++` 作为您的 C 和 C++ 编译器。 除了上述环境变量外,还可以选择使用以下变量: * 如果您的 clang 编译器不叫 `clang` 而是像 `clang-3.7` 这样的名称,可以设置 `LLVM_CC_NAME`。类似地,可以使用 `LLVM_CXX_NAME` 来描述 C++ 编译器的名称。请注意,在这类情况下,环境变量 `LLVM_COMPILER` 仍应设置为 `clang`,而不是 `clang-3.7` 等。 我们还会以类似的方式关注环境变量 `LLVM_LINK_NAME` 和 `LLVM_AR_NAME`,因为它们在各种 Linux 发行版中也会被加上后缀。 * `LLVM_COMPILER_PATH` 可以设置为包含编译器和其他要使用的 LLVM 工具(如 `llvm-link`)的文件夹的绝对路径。 这可以防止在您的 PATH 环境变量中搜索编译器。 如果您的系统上有不同版本的 clang,并且您希望轻松切换编译器而无需修改 PATH 变量,这将非常有用。 例如 `LLVM_COMPILER_PATH=/home/user/llvm_and_clang/Debug+Asserts/bin`。 * `WLLVM_CONFIGURE_ONLY` 可以设置为任何值。如果设置了它,`wllvm` 和 `wllvm++` 的行为就像普通的 C 或 C++ 编译器。它们不会产生 bitcode。设置 `WLLVM_CONFIGURE_ONLY` 可以防止因意外生成隐藏的 bitcode 文件而导致的配置错误。有时在配置构建时需要这样做。 ## 使用 clang 构建 bitcode 模块 ``` export LLVM_COMPILER=clang tar xf pkg-config-0.26.tar.gz cd pkg-config-0.26 CC=wllvm ./configure make ``` 这应该生成可执行文件 `pkg-config`。要提取 bitcode: ``` extract-bc pkg-config ``` 这将生成 bitcode 模块 `pkg-config.bc`。 ## 教程 关于在 vagrant Ubuntu 14.04 中构建 apache 的更详细的说明可以在 [这里找到,](doc/tutorial.md) 针对 Ubuntu 16.04 的在 [这里。](doc/tutorial-ubuntu-16.04.md) ## 使用 dragonegg 构建 bitcode 模块 ``` export LLVM_COMPILER=dragonegg export LLVM_GCC_PREFIX=llvm- export LLVM_DRAGONEGG_PLUGIN=/unsup/llvm-2.9/lib/dragonegg.so tar xf pkg-config-0.26.tar.gz cd pkg-config-0.26 CC=wllvm ./configure make ``` 同样,这应该生成可执行文件 `pkg-config`。要提取 bitcode: ``` extract-bc pkg-config ``` 这将生成 bitcode 模块 `pkg-config.bc`。 ## 构建 bitcode 归档 ``` export LLVM_COMPILER=clang tar -xvf bullet-2.81-rev2613.tgz mkdir bullet-bin cd bullet-bin CC=wllvm CXX=wllvm++ cmake ../bullet-2.81-rev2613/ make # 生成 src/LinearMath/libLinearMath.bca extract-bc src/LinearMath/libLinearMath.a ``` 请注意,默认情况下,从归档中提取 bitcode 会生成 bitcode 的归档。您也可以直接将 bitcode 提取到模块中。 ``` extract-bc -b src/LinearMath/libLinearMath.a ``` 生成 `src/LinearMath/libLinearMath.a.bc`。 ## 构建操作系统 要了解如何从头开始构建 freeBSD 10.0,请查看此 [指南。](doc/tutorial-freeBSD.md) ## 配置而不构建 bitcode 有时需要禁用 bitcode 的生成。 通常这是在配置期间,此时生成意外文件可能会使配置脚本混淆。为此,我们有一个标志 `WLLVM_CONFIGURE_ONLY`,可以按以下方式使用: ``` WLLVM_CONFIGURE_ONLY=1 CC=wllvm ./configure CC=wllvm make ``` ## 构建 bitcode 归档然后提取 bitcode ``` export LLVM_COMPILER=clang tar xvfz jansson-2.7.tar.gz cd jansson-2.7 CC=wllvm ./configure make mkdir bitcode cp src/.libs/libjansson.a bitcode cd bitcode extract-bc libjansson.a llvm-ar x libjansson.bca ls -la ``` ## 在存储中保留 bitcode 文件 有时保留构建中生成的 bitcode 文件很有用,无论是为了防止删除还是为了稍后检索。如果环境变量 `WLLVM_BC_STORE` 设置为现有目录的绝对路径,那么 WLLVM 会将生成的 bitcode 文件复制到该目录中。 复制的 bitcode 文件的名称是原始 bitcode 文件路径的哈希值。为了方便起见,当同时使用 `extract-bc` 的清单功能和存储时,清单将包含原始路径和存储路径。 ## 交叉编译 为了支持交叉编译,WLLVM 支持 clang 使用的 `-target` 三元组。 更多信息可以在 [这里找到。](https://clang.llvm.org/docs/CrossCompilation.html#target-triple) 此外,WLLVM 利用 `objcopy` 进行一些繁重的工作。进行交叉编译时,必须确保为目标架构使用适当的 `objcopy`。`BINUTILS_TARGET_PREFIX` 环境变量可用于设置所选的 objcopy,例如 `arm-linux-gnueabihf`。 ## LTO 支持 在某些情况下,可能希望在生成 bitcode 的步骤中将某些标志传递给 clang。这可以通过将 `LLVM_BITCODE_GENERATION_FLAGS` 环境变量设置为所需的标志来实现,例如 `"-flto -fwhole-program-vtables"`。 ## 调试 WLLVM 工具可以显示不同级别的输出以辅助调试。 要显示此输出,请将 `WLLVM_OUTPUT_LEVEL` 环境变量设置为以下级别之一: * `ERROR` * `WARNING` * `INFO` * `DEBUG` 例如: ``` export WLLVM_OUTPUT_LEVEL=DEBUG ``` 输出将定向到标准错误流,除非您通过 `WLLVM_OUTPUT_FILE` 环境变量指定日志文件的路径。 例如: ``` export WLLVM_OUTPUT_FILE=/tmp/wllvm.log ``` ## 健全性检查 环境变量太多?尝试做一个健全性检查: ``` wllvm-sanity-checker ``` 它可能会指出问题所在。 ## 许可证 WLLVM 在 MIT 许可证下发布。有关 [详细信息,](LICENSE) 请参阅 `LICENSE` 文件。
标签:C/C++, Cutter, LLVM, pocsuite3, Python, WLLVM, 中间表示, 事务性I/O, 代码构建工具, 全程序分析, 可配置连接, 字节码生成, 无后门, 程序分析, 编译器包装器, 软件测试, 逆向工具, 逆向工程辅助, 静态分析工具