travitch/whole-program-llvm
GitHub: travitch/whole-program-llvm
一套基于 Python 的编译器封装工具,用于从未经修改的 C/C++ 源码构建完整的全程序 LLVM bitcode 文件,解决传统 LTO 在静态库场景下的局限性。
Stars: 737 | Forks: 134
Whole Program LLVM
[](https://opensource.org/licenses/MIT)
[](https://badge.fury.io/py/wllvm)
[](https://travis-ci.org/SRI-CSL/whole-program-llvm)
[](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, 代码构建工具, 全程序分析, 可配置连接, 字节码生成, 无后门, 程序分析, 编译器包装器, 软件测试, 逆向工具, 逆向工程辅助, 静态分析工具