将Linux内核模块编译为LLVM .bc位码

10

背景

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

到目前为止,我能够使用下面显示的 Makefile 编译实际模块:

make CC=clang CFLAGS=-emit-llvm drivers/gpu/drm/radeon/

但是这并没有真正生成任何 llvm 位码 - 我需要 .bc 文件才能使用 opt 运行我的过程。

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

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

既然可以工作,我获取了 GNU make 操作的详细输出,将 gcc 更改为 clang 并运行它来创建 .bc 文件,这也起作用:

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

唯一的问题是我只能一次处理内核模块中的一个 C 文件。而且这种方法非常繁琐...

主要问题

这就带我来到我的主要问题:如何使用内核的 Makefile 发出 llvm .bc 位码文件?

或者,如果必须对每个文件单独进行 .bc 位码创建,则如何在最后将它们全部链接在一起,以便我可以运行 LLVM opt 过程,对内核模块中所有 .bc 文件的聚合进行处理?


1
请问您能否将使用clang和-emit-llvm编译的输出粘贴一下?您是否尝试查看.o文件并检查它们是否实际上是llvm位代码? - Christophe Augier
如果你最终需要遵循多个 .bc 文件的方法,那么你可能想要查看 http://llvm.org/docs/CommandGuide/llvm-link.html - user335938
2个回答

2
从Clang中以位码形式获取LLVM IR的最佳方法是使用-flto命令行标志进行LTO。
如果您有多个翻译单元,可以使用llvm-lto工具将它们组合在一起,"链接"位码文件。通常它会生成代码,但您可以使用-save-merged-module标志获得合并的LLVM IR模块。
但是这些都不是真正支持的接口。如果这是一个非常有用的工作流程,您应该与LLVM开发人员讨论支持类似于ld的-r的东西。

1
我使用clang来对ext2模块进行插桩。有三件事情需要做: 1)将.c文件转换为.bc文件 2)在.bc文件上运行优化器,并创建ext2-opt.o文件 3)从ext2-opt.o文件创建ext2-instrumented.ko文件。
除此之外,您还需要使用clang编译的Linux版本。我可以在禁用了一些模块后,使用clang版本3.8.1编译Linux 4.17。您可以在这里获取它。
现在,让我们进入第一步-如您所说,以详细模式运行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系统很难理解,甚至更难进行修改。我建议使用这个两个文件夹的技巧(第一个文件夹用于创建.bc文件,第二个文件夹用于创建.o和.ko文件)。总之,以下是我在ext2_instrumented文件夹中得到的makefile:
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接