10

背景

我正在尝试在 Linux 内核中编译某些驱动程序:drm ( drivers/gpu/drm/drm_drv.o) 和 radeon ( drivers/gpu/drm/radeon/) gpu 驱动程序。我将 LLVM 用于静态分析(跟踪copy_to/from_user()调用中使用的参数)。

到目前为止,我可以使用 Makefile 编译实际的模块,如下所示:

使 CC=clang CFLAGS=-emit-llvm 驱动程序/gpu/drm/radeon/

但这实际上并没有发出任何 llvm 位码——我需要这些.bc文件来运行我的通行证opt

.bc我只知道直接使用 clang 时如何生成文件(如下所示),但不知道使用 Makefile ......

clang -emit-llvm hello.c -c -o hello.bc

由于这行得通,我抓住了 GNU make 操作的详细输出,更改gccclang,然后运行它来创建.bc文件,该文件也有效:

clang -emit-llvm [[吨 CFLAGS]] -c -o drm_drv.bc drivers/gpu/drm/drm_drv.c

唯一的问题是我一次只能处理内核模块中的一个 C 文件。做这种方法也很乏味......

主要问题

这让我想到了我的主要问题:您将如何.bc使用内核的 Makefiles 发出 llvm 位码文件?

或者,如果.bc必须在每个文件的基础上创建位码,那么最后我将如何将它们链接在一起,以便我可以在内核模块中opt的所有文件的聚合上运行 LLVM 传递?.bc

4

2 回答 2

2

从 Clang 中获取位码形式的 LLVM IR 的最佳方法是使用-flto命令行标志执行 LTO。

如果您有多个翻译单元,您可以使用该工具将它们组合在一起llvm-lto以“链接”位码文件。通常它会生成代码,但您可以让它删除带有-save-merged-module标志的合并 LLVM IR 模块。

但这都不是真正受支持的接口。如果这是一个非常有用的工作流程,您应该与 LLVM 开发人员讨论支持更类似于 ld 的东西-r

于 2016-05-31T05:27:54.293 回答
0

我使用 clang 来检测 ext2 模块。您需要做 3 件事:1) 将 .c 转换为 .bc 2) 在 .bc 文件上运行优化器,并创建 ext2-opt.o 文件 3) 从 ext2- 创建 ext2-instrumented.ko 文件opt.o 文件。

除此之外,您还需要使用 clang 编译的 linux 版本。在禁用几个模块后,我可以使用 clang 版本 3.8.1 编译 linux 4.17。你可以在这里得到它

现在,让我们进入第 1 步 - 如您所说,以详细模式运行 Make

make V=1 M=fs/ext2

并获取 Makefile 吐出的所有选项。默认编译器将是 gcc。将 gcc 替换为 clang,添加 --emit-llvm 命令,并将 .o 替换为 .bc。我机器上生成的编译命令如下所示:

cd ../../ && clang -emit-llvm -Wp,-MD,fs/ext2/.all.o.d  -nostdinc -isystem /usr/local/bin/../lib/clang/3.8.1/include -I./arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated  -Iinclude -I./arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -Qunused-arguments -Wno-unknown-warning-option -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -no-integrated-as -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -O2 -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-variable -Wno-format-invalid-specifier -Wno-gnu -Wno-asm-operand-widths -Wno-initializer-overrides -fno-builtin -Wno-tautological-compare -mno-global-merge -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -Wno-initializer-overrides -Wno-unused-value -Wno-format -Wno-unknown-warning-option -Wno-sign-compare -Wno-format-zero-length -Wno-uninitialized  -DMODULE  -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(all)"  -D"KBUILD_MODNAME=KBUILD_STR(ext2)" -mcmodel=kernel -c -o fs/ext2_instrumented/all.bc fs/ext2/all.c && cd -

这将为您创建一个 .bc 文件。请注意,我已将生成的 .bc 代码目录更改为 ext2_instrumented,即我的 bc 文件不是在 fs/ext2 中创建的,而是在另一个名为 fs/ext2_instrumented 的文件夹中创建的。这是我的工作文件夹。我希望这个文件夹没有任何 .c 文件,只有 .bc 文件。我需要这个,因为默认的 KBuild 系统会在文件夹中查找 .c 文件。稍后再谈。

第 2 步:使用 opt 命令对生成的 ext2-instrumented.bc 文件运行所有优化过程,如下所示:

opt -load $(DIR)/build/FSlice.so -constprop -sccp -mergereturn -sink -licm -reg2mem all.bc -o all.inst.bc llvm-link -o all.inst2.bc $(DIR)/ build/libFSlice.bc all.inst.bc clang -mcmodel=kernel -c all.inst2.bc -o all.o

这将生成一个 .o 文件,我们现在将在下一步将其编译为 .ko 文件:

第 3 步:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) ext2instrumented.ko

Kbuild 系统很难理解,甚至更难修改。我建议使用这 2 个文件夹 hack(第一个文件夹创建 .bc 文件,第二个文件夹创建 .o 和 .ko 文件)。总而言之,这是我在 ext2_instrumented 文件夹中生成的生成文件:

DIR=/home/fslice/fslice

obj-m += ext2instrumented.o

ext2instrumented-objs := all.o

all:
        cd ../../ && clang -emit-llvm -Wp,-MD,fs/ext2/.all.o.d  -nostdinc -isystem /usr/local/bin/../lib/clang/3.8.1/include -I./arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated  -Iinclude -I./arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -Qunused-arguments -Wno-unknown-warning-option -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -no-integrated-as -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -O2 -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-variable -Wno-format-invalid-specifier -Wno-gnu -Wno-asm-operand-widths -Wno-initializer-overrides -fno-builtin -Wno-tautological-compare -mno-global-merge -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -Wno-initializer-overrides -Wno-unused-value -Wno-format -Wno-unknown-warning-option -Wno-sign-compare -Wno-format-zero-length -Wno-uninitialized  -DMODULE  -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(all)"  -D"KBUILD_MODNAME=KBUILD_STR(ext2)" -mcmodel=kernel -c -o fs/ext2_instrumented/all.bc fs/ext2/all.c && cd -
        opt -load $(DIR)/build/FSlice.so -constprop -sccp -mergereturn -sink -licm -reg2mem all.bc -o all.inst.bc
        llvm-link -o all.inst2.bc $(DIR)/build/libFSlice.bc all.inst.bc
        clang -mcmodel=kernel -c all.inst2.bc -o all.o
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) ext2instrumented.ko

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
        rm -rf *.bc
于 2016-10-09T18:27:41.610 回答