Generate Linux Kernel LLVM Bitcode with Custom Optimization
In Compile Linux Kernel to LLVM Bitcode we use wllvm to generate the LLVM bitcode of Linux kernel. when analyzing the kernel, we sometimes need to disable some optimization passes. However, it’s hard to do with clang. First compiling it to -O0 IR and then applying some optimization passes on it seems easier.
The optimization level of the LLVM IR is -O2 by default. If we need an -O0 LLVM IR, we need to modify the kernel compilation flag.
1
make KCFLAG='-O0' CC=wllvm
However, it doesn’t work because some kernel code cannot be compiled with -O0.
Fortunately, we have another way to get our -O0 LLVM IR.
When wllvm generates LLVM bitcode (.filename.o.bc) for a C file, it also generates the command to compile the file in .filename.o.cmd. We can get the command by:
path='/path/to/our/output' awk_cmd='{ s = ""; ofile = 0; for (i = 3; i <= NF; i++) { if (ofile == 1) { s = s "'"$path"'" " "; ofile = 0; } else { if ($i == "-o") ofile = 1; s = s $i " "; } } print s }' cmd_line=`head -n 1 $1 | awk "$awk_cmd"`
The output file path will be replaced by the path we provide.
This command generates native code. To get LLVM bitcode, we need to add -emit-llvm. To disable optimization, we need to add -mllvm -disable-llvm-optzns.
After generating -O0 bitcode, we can optimize it with any passes we want. Finally link all bitcodes we generate and we get a kernel bitcode with custom optimization.
cat"$manifest" | whileread o_bc_name; do basename=`basename"${o_bc_name%.o.bc}"` # basename="${basename#.}" dir="${o_bc_name%/*}" basepath="${dir}/${basename}" if [ -z "$dir" ] && [ -z "$basename" ] then continue fi cmd_path="${basepath}.o.cmd" if [ ! -r "${cmd_path}" ] then echo"${cmd_path} not found" continue fi