从源码开始部署 SVF 并且让配套的 LLVM 包含 gold 插件

gold 插件可以将一个复杂的项目打包,得到单个 bitcode 文件,然后便于使用 SVF 工具分析。但是,按照 SVF 仓库首页的部署教程操作,并不能得到装有 gold 插件的 LLVM 。仓库的 wiki 里有一些资料,但是时间略久远了。因此,有必要写一份新的操作指南,引导大家进行部署。

0. 前置资料

我参考了下面的几份资料,总结出了全部的操作流程

官方文档:SVF 官方部署文档
LLVM gold 插件安装指南1:Build whole programs into LLVM IR
LLVM gold 插件安装指南2:安装带有 gold-plugin 的 LLVM
LLVM gold 插件安装指南3:LLVM 官网文档
LLVM gold 插件安装指南4:LLVM gold插件安装步骤

1. 安装必要的前置工具

除了官方文档要求的工具,还要安装 gold 插件所在的 binutils 。

1.1 安装官方部署文档要求的工具

先别急着输入下面这行代码,CMake 需要特别关注一下。

sudo apt install cmake make gcc g++ libtinfo5 libz-dev libzstd-dev zip wget libncurses5-dev

我用的 Linux 发行版是 Mint,库里面的 CMake 版本太低了。如果 apt 方式安装的 CMake 版本达不到要求( ≥ 3.23 \ge3.23 3.23 ),那么在用 apt 安装工具时要把 cmake 去掉。

sudo apt install make gcc g++ libtinfo5 libz-dev libzstd-dev zip wget libncurses5-dev

我使用软链接安装了更新的版本,可以直接参考我的上一篇文章。

点这里:在 Linux 下卸载手动安装的 CMake,并以软链接的方式重装

1.2 安装 gold 插件所在的包

根据 gold 插件安装指南1,首先要安装一些前置工具

# some necessary pre-requisite
sudo apt install bison flex libncurses5-dev texinfo

我在桌面上创建了一个文件夹叫 tools ,在这个文件夹下执行以下代码,得到了 binutils 文件夹以及 binutils_build 文件夹。第一个文件夹装有 bintuils-gdb 的 trunk 版源码,第二个文件夹用于存放等会构建出来的文件,以免混在源代码目录下。

# get the trunk version of binutils
git clone --depth 1 git://sourceware.org/git/binutils-gdb.git binutils
# create a build directory
mkdir binutils_build

tools文件夹

我选择把 bintuils装在 /opt 下,在这里先新建一个文件夹 binutils ,等会装在这里

cd /opt
sudo mkdir binutils

然后就是进行配置和编译了,注意 configuration 这一步的 --prefix 不要无脑照抄我的,一定要改成自己选择的安装目录

# 返回 build 文件夹
cd ~/Desktop/tools/binutils_build
# configuration
../binutils/configure --enable-gold --enable-plugins --disable-werror --prefix=/opt/binutils
# 可能报错
# configure: error: Building GDB requires GMP 4.2+, and MPFR 3.1.0+.
# Try the --with-gmp and/or --with-mpfr options to specify
# their locations.  If you obtained GMP and/or MPFR from a vendor
# distribution package, make sure that you have installed both the libraries
# and the header files.  They may be located in separate packages.
# 执行下面这个,然后重新执行 configuration 这一步
sudo apt install libgmp-dev libmpfr-dev
# build/compile
make -j4
make install

把 binutils 加到环境变量里,这里也不要无脑照抄,而是改成自己安装路径下的 bin 文件夹

vim ~/.bashrc
# 把路径改成自己选择的↓↓↓
export PATH="/opt/binutils/bin:$PATH"
# 把路径改成自己选择的↑↑↑
source ~/.bashrc

2. 部署 SVF

首先把 SVF 的仓库克隆到本地

git clone https://github.com/SVF-tools/SVF.git
cd SVF/

官方文档叫你直接在这一步执行 source ./build.sh ,但这样是不行的。我们把 build.sh 用文本编辑器打开,发现前面都是在定义变量和函数,而后面真正的部署方式还是下载二进制文件进行安装。要想使用 gold 插件必须编译安装,因此必须对构建脚本进行修改。

官方其实提供了从源码开始构建的函数 build_z3_from_sourcebuild_llvm_from_source ,只是这两个函数并没有被使用,好在这样可以减小我们的工作量。

下面这部分代码用于设置系统相关变量的值,先找到它,大概在第146行(不排除以后会变)

########
# Set OS-specific values, mainly URLs to download binaries from.
# M1 Macs give back arm64, some Linuxes can give aarch64 for arm architecture
#######
if [[ $sysOS == "Darwin" ]]; then
    check_and_install_brew
    if [[ "$arch" == "arm64" ]]; then
        OSDisplayName="macOS arm64"
    else
        OSDisplayName="macOS x86"
    fi
elif [[ $sysOS == "Linux" ]]; then
    if [[ "$arch" == "aarch64" ]]; then
        urlLLVM="$UbuntuArmLLVM"
        urlZ3="$UbuntuZ3Arm"
        OSDisplayName="Ubuntu arm64"
    else
        urlLLVM="$UbuntuLLVM"
        urlZ3="$UbuntuZ3"
        OSDisplayName="Ubuntu x86"
    fi
else
    echo "Builds outside Ubuntu and macOS are not supported."
fi

紧接着的两部分代码分别用于以二进制的方式安装 LLVM 和 Z3 ,我们是用不到了。所以我们可以确定调用源码构建函数的位置就是设置系统相关变量值那部分代码的后面,也就是二进制构建 LLVM 和 Z3 代码的前面,把下面的命令加到脚本中。

build_llvm_from_source
export LLVM_DIR="$SVFHOME/$LLVMHome"
build_z3_from_source
export Z3_DIR="$SVFHOME/$Z3Home"

那么二进制构建 LLVM 和 Z3 的代码需要删除吗?其实并不需要,因为 这两部分代码的开头是 if [[ ! -d "$LLVM_DIR" ]]; then 以及 if [[ ! -d "$Z3_DIR" ]]; then ,我们已经导出过相应的环境变量了,所以二进制构建的命令并不会被执行,我们也就不用管了。

build_llvm_from_source 函数也是要修改的,原来的 cmake 命令并没有启用 gold 插件,也没有使用 Ninja 加快编译,所以要把它改成下面这样。注意,不是直接执行下面这行命令,而是把脚本里函数体中的语句改掉。 -DLLVM_BINUTILS_INCDIR 不要照抄我的,而是要改成自己安装目录下的 include 文件夹。另外,在 -DLLVM_ENABLE_PROJECTS 中,推荐加上 lld

cmake -G Ninja -DLIBCXX_ENABLE_SHARED=OFF -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/opt/binutils/include -DCMAKE_INSTALL_PREFIX="$SVFHOME/$LLVMHome" -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb;compiler-rt;mlir;pstl" ../llvm-source/*/llvm

-DLLVM_ENABLE_PROJECTS 选项在配置 LLVM 项目时用于指定要额外构建的 LLVM 子项目。这些子项目可以根据需要进行选择和组合。以下是一些可选的 LLVM 子项目:boltclangclang-tools-extracompiler-rtcross-project-testslibclibclclldlldbmliropenmppollypstlflang

  • clang:C、C++、Objective-C 和 Objective-C++ 的前端编译器。
  • clang-tools-extra:提供额外的 Clang 工具,如 clang-tidy、clang-format 等,用于代码分析和格式化。
  • lldb:LLDB 调试器,一个基于 LLVM 的多平台调试器。
  • lld:LLVM 的链接器,支持多种平台和格式。
  • polly:Polly 是一个自动并行化和向量化编译器,它可以集成到 Clang 中。
  • cross-project-tests:跨项目测试,用于测试 LLVM 生态系统中不同组件之间的交互。
  • bolt:一个针对 x86 架构的二进制优化工具,可以优化程序的执行时间和性能。
  • compiler-rt:编译器运行时库,提供了一系列底层运行时支持,如数学函数、原子操作等。
  • libclibclclibcxxlibcxxabilibunwind :这些是 LLVM 项目中的标准库和运行时库,提供了 C、C++ 和其他语言的运行时支持。
  • mlir:MLIR(Multi-Level Intermediate Representation)是 LLVM 项目中的一个新中间表示(IR),旨在支持多种编译器和工具链的优化和转换。
  • openmp:OpenMP 运行时库,支持 OpenMP API 的实现,用于并行编程。
  • pstl:Parallel STL,一个并行版本的 C++ 标准模板库(STL),利用多线程来加速数据处理。
  • flang:Fortran 前端编译器,支持 Fortran 语言的编译。

请注意,以上列表并不是全部可选的子项目,LLVM 项目还在不断发展中,新的子项目可能会被添加进来。在配置 LLVM 时,你可以根据需要选择这些子项目中的一个或多个进行构建。

例如,如果你想要构建 LLVM、Clang 和 LLD,你可以在 CMake 配置命令中使用 -DLLVM_ENABLE_PROJECTS=“clang;lld”。如果你想要构建更多的子项目,只需要在分号分隔的列表中添加它们即可。

此外,还需要注意的是,一些子项目可能依赖于其他特定的库或工具链,因此在构建之前需要确保这些依赖项已经正确安装和配置。同时,构建整个 LLVM 项目可能需要大量的计算资源和时间,因此建议在性能较好的计算机上进行。

还要装一下 Python ,我推荐使用 miniconda ,参考这篇文章就可以了。

Ubuntu快速安装miniconda

有一个注意事项,Python 3.12 删除了构建 z3 必须要用到的 distutils 库,Ubuntu 24.04 和 Mint 22 系统自带 3.12 版本的 Python ,既无法装上 distutils 库,也因与系统耦合而无法卸载。如果 Python 版本是 3.12 ,请创建一个 Python 3.8 的环境,然后激活它。为了防止构建 z3 时调用系统自带的 Python ,最好在 build.sh 中构建 z3 的部分手动指定 Python 3.8 的路径。

conda activate py38
which python # 确认是不是 Python 3.8 的路径
# 位于 build_z3_from_source 函数,大约在第97行,参考下面的内容进行修改
cmake -DCMAKE_INSTALL_PREFIX="$SVFHOME/$Z3Home" -DZ3_BUILD_LIBZ3_SHARED=false -DPYTHON_EXECUTABLE=/opt/miniconda3/envs/py38/bin/python ../z3-source/*

现在可以运行脚本了,请注意,这一步对内存是有要求的!之前我只给虚拟机划了2GB的内存,最后一定会出现死机的情况,在把内存划到16GB以后就顺利完成了部署。这一步的花费时间会很长很长,自己挑选合适的时间来做。如果中断了,照着原始的仓库把多出来的文件和文件夹都删掉,然后重新运行脚本即可。

sudo apt install ninja-build # 安装ninja
source ./build.sh

完成后,输入下面的命令测试是否成功。不要急着把 shell 关掉了,后面还要用

wpa -h

再去看看gold插件,已经装上了

终于把你装上了

3. 编辑环境变量

source ./build.sh 只能对当前的 shell 生效,一旦换一个 shell 就不能使用 SVF 相关的命令了。可以自己打开一个新的 shell,再输入 wpa -h 试试,会提示“未找到命令”。

3.1 新的做法

官方给了设置环境变量的脚本,直接在 .bashrc 里加上运行该脚本的命令即可

vim ~/.bashrc
# 在合适的位置添加↓↓↓
if [ -f ~/Desktop/SVF/setup.sh ]; then  
    source ~/Desktop/SVF/setup.sh Release
fi  
# 在合适的位置添加↑↑↑

3.2 旧的做法

我没有添加 LD_LIBRARY_PATHDYLD_LIBRARY_PATH 这两个环境变量,但是脚本里有。

3.2.1 添加3个环境变量

在整个部署过程的最后,shell 会显示3个相关的路径,可以把它们加进环境变量里。不要照抄我这里的路径,一定要使用自己部署时的路径!

vim ~/.bashrc
# 在最后加上这三行
export SVF_DIR=/home/a/Desktop/SVF
export LLVM_DIR=/home/a/Desktop/SVF/llvm-16.0.0.obj
export Z3_DIR=/home/a/Desktop/SVF/z3.obj

3.2.2 修改 $PATH 环境变量

在部署好 SVF 的 shell 里执行 env ,查看当前 shell 的环境变量。我在做这一步的时候还没装 binutils ,所以 $PATH 里没有相关的路径,大家如果一步一步跟到这里,应该是有的

PATH=/home/a/Desktop/SVF/Release-build/bin:/home/a/Desktop/SVF/llvm-16.0.0.obj/bin:/home/a/Desktop/SVF/z3.obj/bin:/usr/local/binutils/bin:/home/a/miniconda3/bin:/home/a/miniconda3/condabin:/home/a/Desktop/SVF/Release-build/bin:/home/a/Desktop/SVF/llvm-16.0.0.obj/bin:/home/a/Desktop/SVF/z3.obj/bin:/usr/local/binutils:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

再打开一个 shell 执行 env ,查看系统的环境变量

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

可以看到,系统的 $PATH 变量里还没有部署 SVF 时产生的新值,因此要将它们加进去。加的时候自己检查一下有没有重复的,有的话就删掉。当然,也可以像之前的 binutils 一样使用 export

vim ~/.bashrc
export PATH="/home/a/Desktop/SVF/Release-build/bin:/home/a/Desktop/SVF/llvm-16.0.0.obj/bin:/home/a/Desktop/SVF/z3.obj/bin:$PATH"
source ~/.bashrc

这时候再新开一个 shell ,执行 wpa -h ,应该可以正常使用。

4. 使用 sed 进行测试

选中一个位置,创建测试目录和 build 子目录

cd ~/Desktop
mkdir sed-4.9
cd sed-4.9/
mkdir build

下载 sed 的源码并解压,下载网址

wget https://mirrors.nju.edu.cn/gnu/sed/sed-4.9.tar.xz
tar -Jxvf sed-4.9.tar.xz
mv sed-4.9 source

配置并构建

cd build
../source/configure CC=clang CFLAGS='-flto' LDFLAGS='-flto -fuse-ld=gold -Wl,-plugin-opt=save-temps' RANLIB=llvm-ranlib
make

分析

cd sed # 可执行文件在 `sed` 目录下
wpa -ander a.out.0.0.preopt.bc

分析结果

分析结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值