生成BC文件
BC(BitCode)文件是使用LLVM(Low Level Virtual Machine)编译源代码生成中间文件(IR)的二进制表示,包含了程序编译的中间代码,比源代码文件更加紧凑和高效。DevKit基于LLVM框架,利用BC文件,提高程序的分析效率与分析准确度。
LLVM是一种开源编译器基础设施,它提供了一个通用的编译器框架和工具链,可以用于构建各种编程语言的编译器、解释器、调试器、代码优化器等。
前提条件
用于生成BC文件的项目需要确保可以在本地使用LLVM(C/C++编译器使用clang、clang++,Fortran编译器使用flang)编译通过并生成动态库(.so)文件或者可执行文件。
clang是一个C、C++、Objective-C和Objective-C++编程语言的开源编译器前端。
方法二
借助第三方工具gllvm生成BC文件,gllvm是一个基于LLVM的编译器工具链,用于将C/C++代码编译为BC文件,利用gllvm可以简化BC文件的生成流程。
生成BC文件之前请确保系统当前环境满足待测试程序的构建条件。
- 将DevKit自带的clang编译器和编译后gllvm工具设置到环境变量中:
1 2 3
export PATH=/path/DevKit/devkitplugins/affinity/tools/weakconsistency/staticcodeanalyzer/llvm-tools/bin:$PATH export PATH=/path/DevKit/devkitplugins/affinity/tools/weakconsistency/staticcodeanalyzer/gllvm-tools:$PATH export LD_LIBRARY_PATH=/path/DevKit/devkitplugins/affinity/tools/weakconsistency/staticcodeanalyzer/llvm-tools/lib:$LD_LIBRARY_PATH
- /path:表示DevKit安装目录,请用户根据实际路径进行替换。
- 若系统中libstdc++版本低于/home/devkit/lib中版本,则需要设置以下环境变量。
export LD_LIBRARY_PATH=/home/devkit/lib:$LD_LIBRARY_PATH
- 设置gllvm对clang和flang的依赖:
1 2 3 4
export LLVM_CC_NAME="clang" export LLVM_CXX_NAME="clang++" export LLVM_FC_NAME="flang" export LLVM_LINK_NAME="llvm-link"
- 优化等级:将待测试工程的所有优化等级都修改为“-O0”。
- 构建:将C编译器指定为gclang,C++编译器修改为gclang++,Fortran编译器修改为gflang,同时增加编译选项“-g -fno-inline-functions”,此操作不唯一,与待测试工程的构建工具和参数相关;其他构建步骤不变;可参考以下构建用例:
- 对于使用脚本构建,但未指定输入参数的工程,以jemalloc为例,可使用如下命令指定编译器类型:
[root@localhost jemalloc-5.2.1]# CC="gclang" CXX="gclang++" CFLAGS="-g -fno-inline-functions" CXXFLAGS="-g -fno-inline-functions" ./autogen.sh autoconf ./configure --enable-autogen checking for xsltproc.. /usr/bin/xsltproc checking for gcc.. gclang
- 对于使用脚本构建,但指定输入参数的工程,以incubator-brpc为例,可根据incubator-brpc的参数要求,使用如下命令指定编译器类型:
[root@localhost incubator-brpc-0.9.6]# sh config_brpc.sh --headers=/usr/include --libs=/usr/lib64 --cc="gclang" --cxx="gclang++" CFLAGS="-g -fno-inline-functions" CXXFLAGS="-g -fno-inline-functions" objcopy: st4rvLWw: Failed to find link section for section 8 objcopy: st4rvLWw: Failed to find link section for section 8
- 对于使用configure构建的工程,以sqlite为例,可使用如下命令指定编译器类型:
[root@localhost sqlite-version-3.32.1]# CC="gclang" CXX="gclang++" ./configure CFLAGS="-g -fno-inline-functions" CXXFLAGS="-g -fno-inline-functions" checking build system type... aarch64-unknown-Linux-gnu checking host system type... aarch64-unknown-linux-gnu checking for gcc... gclang
- 对于在配置文件中指定了编译器类型的工程,需修改配置文件,以bwa为例,使用make构建工具,需将Makefile第一行CC指定为gclang后再执行构建命令。
#CC= gcc CC= gclang
bwa:
[root@localhost bwa-0.7.17]# make CFLAGS="-g -fno-inline-functions" CXXFLAGS="-g -fno-inline-functions" gclang -c -g -fno-inline-functions -DHAVE_PTHREAD -DUSE_MALLOC_WRAPPERS utils.c -o utils.o objcopy: stKUUevi: Failed to find link section for section 15 objcopy: stKUUevi: Failed to find link section for section 15 gclang -c -g -fno-inline-functions -DHAVE_PTHREAD -DUSE_MALLOC_WRAPPERS kthread.c -o kthread.o objcopy: stzqwREn: Failed to find link section for section 14
- 对于使用脚本构建,但未指定输入参数的工程,以jemalloc为例,可使用如下命令指定编译器类型:
- 生成BC文件:构建完成后,生成动态库(.so)文件或者可执行文件,使用gllvm的get-bc工具生成BC文件。以jemalloc为例:
[root@localhost lib]# ls libjemalloc.a libjemalloc_pic.a libjemalloc.so libjemalloc.so.2 [root@localhost lib]# get-bc libjemalloc.so.2 Bitcode file extracted to: libjemalloc.so.2.bc. [root@localhost lib]# ls libjemalloc.a libjemalloc_pic.a libjemalloc.so libjemalloc.so.2 libjemalloc.so.2.bc [root@localhost lib]#
- 打包BC文件。
- 创建目录。
mkdir bcfile
- 将bc文件拷贝到目录中。
cp libjemalloc.so.2.bc bcfile/
- 将bc文件打包。
tar -czvf bcfile.tar.gz bcfile
- 创建目录。
方法三
使用工程构建工具生成BC文件,如make,cmake等。如果软件使用该方法,需修改相关的配置文件,如makefile。
- 替换编译命令:若构建文件中有gcc、g++、gfortran或ld,需要替换成对应的clang、clang++、flang或llvm-link。
- 调整编译选项:修改优化等级“-O0”,增加“-flto -g -fno-inline-functions”。
完成上述操作后,即可通过构建获得BC文件。
- 在构建项目之前,需将gcc编译器替换成llvm相关的工具。
- 构建时务必替换或增加指定的编译选项,防止部分指令信息缺失,从而影响分析结果准确性。
- 将最终生成的目标文件修改为BC文件。
- 使用make工具完成项目构建。
[root@localhost test]# ls main.c Makefile test.c
- 修改编译命令并替换编译选项。原始的makefile文件和修改后的makefile文件如下所示:
原始的makefile文件:
objects=main.o test.o exe=case CFLAGS = -O2 -DAM_CPU_NUMBER=96 -DMAX_PARALLEL_NUMBER=1 all: $(objects) main.o: ./main.c gcc $(CFLAGS) -c $< -o main.o test.o: ./test.c gcc $(CFLAGS) -c $< -o test.o all: $(exe) case: main.o test.o gcc -lpthread main.o test.o -o case clean: rm -f *.o
修改后的makefile文件:
objects=main.o test.o exe=case.bc CFLAGS = -O0 -flto -g -fno-inline-functions -DAM_CPU_NUMBER=96 -DMAX_PARALLEL_NUMBER=1 all: $(objects) main.o: ./main.c clang $(CFLAGS) -c $< -o main.o test.o: ./test.c clang $(CFLAGS) -c $< -o test.o all: $(exe) case.bc: main.o test.o llvm-link main.o test.o -o case.bc clean: rm -f *.o
修改后的makefile文件,将编译工具修改为clang,链接生成目标文件的工具改为llvm-link。
- 完成项目构建。
[root@localhost test]# make clang -O0 -flto -g fno-inline-functions -DAM_CPU_NUNBER=96 -DMAX_PARALLEL_NUMBER=1 -c main.c -o main.o clang -O0 -flto -g fno-inline-functions -DAM_CPU_NUNBER=96 -DMAX_PARALLEL_NUMBER=1 -c test.c -o test.o llvm-link main.o test.o -o case.bc [root@localhost test]# ls case.bc main.c main.o Makefile test.c test.o
- 打包BC文件。
- 创建目录。
mkdir bcfile
- 将bc文件拷贝到目录中。
cp case.bc bcfile/
- 将bc文件打包。
tar -czvf bcfile.tar.gz bcfile
- 创建目录。
父主题: 常用操作