Compile Linux Kernel to LLVM Bitcode
Tools
- wllvm 1.2.7
- clang 9.0.1
- LLVM 9.0.1
- linux 5.3.6
Compile Kernel with WLLVM
1 | make CC=wllvm defconfig |
Extract Bitcode
1 | extract-bc vmlinux |
Then vmlinux.bc is the bitcode.
Cross-compile
1 | BINUTILS_TARGET_PREFIX=aarch64-linux-gnu make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- HOSTCC=clang CC=wllvm defconfig |
Then, extract bitcode from vmlinux
.
1 | extract-bc vmlinux |
Problems
symbol multiply defined during bitcode extraction
When extracting bitcode from vmlinux (arm64), an error occurs:
error: Linking globals named ‘sort’: symbol multiply defined!
Get all .bc
file names by
1 | extract-bc -m vmlinux |
and it generates vmlinux.llvm.manifest
, which is something like:
/home/xx/dev/linux-5.3.6-arm-llvm/init/.main.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/init/.version.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/init/.do_mounts.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/init/.do_mounts_initrd.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/init/.initramfs.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/init/.calibrate.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/init/.init_task.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/arch/arm64/kernel/.debug-monitors.o.bc
/home/xx/dev/linux-5.3.6-arm-llvm/arch/arm64/kernel/.irq.o.bc
And then use a script to find all code that defines function sort
:
1 | !/bin/sh |
We find that sort
has been defined in both lib/.sort.o.bc
and drivers/firmware/efi/libstub/.lib-sort.o.bc
.
Read drivers/firmware/efi/libstub/Makefile
and find that it first compiles all c files in lib/
to lib-*.o by
1 | $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE |
and then use objcopy
to add __efistub_
prefix to them.
1 | $(obj)/%.stub.o: $(obj)/%.o FORCE |
However, it doesn’t change the corresponding .bc
, so error occurs.
If we don’t care about efi, simply remove drivers/firmware/efi/libstub/.*.o.bc
in vmlinux.llvm.manifest
and then
1 | llvm-link -o vmlinux.bc `cat vmlinux.llvm.manifest` |
can solve this problem.