Cross compile Linux for ARM using LLVM/clang on Arch Linux

The LLVMLinux team made quite some progress in enabling LLVM/clang to build the Linux kernel. There has also been a talk at the Collaboration Summit 2015 in Santa Rosa (slides). So I thought, give it a try and compile a kernel for my ARM based board of choice. The upstream Linux kernel is not yet ready to be built using LLVM/clang, some patches are still required. Therefor I used the kernel from the LLVMLinux git server.

The nice thing about LLVM/clang is that it supports multiple targets. The binaries provided by the Arch repositories support several ARM targets:

$ pacman -S clang
$ llc --version
 LLVM version 3.5.1
 Optimized build.
 Built Jan 14 2015 (03:18:15).
 Default target: x86_64-unknown-linux-gnu
 Host CPU: core-avx-i

 Registered Targets:
 aarch64 - AArch64 (little endian)
 aarch64_be - AArch64 (big endian)
 arm - ARM
 arm64 - AArch64 (little endian)
 arm64_be - AArch64 (big endian)
 armeb - ARM (big endian)

There is no need to compile a cross compile version of LLVM/clang! Neat! However, as a prerequisite a GNU GCC cross compiler toolchain is still required: The current state of affairs still requires GCC binaries, for instance the GNU linker or assembler (at least for ARM). For a quick test, I used Linaro’s toolchain (in my case the 2014.09 release based on GCC 4.9.2). To make sure clang picks up the assembler, create a symlink to clang within your GCC toolchain:

$ tar xvJf ~/Downloads/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux.tar.xz
$ ln -s /usr/bin/clang ~/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/clang
$ git clone git:// -b llvmlinux-latest

After adding the toolchain to my path environment variable, I could successfully build the Linux kernel

$ export PATH=~/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/:$PATH
$ make ARCH=arm multi_v7_defconfig
$ make -j 4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- HOSTCC=clang CC=clang

The build time was not really faster on my Laptop. But what I find more interesting is the fact that LLVM/clang reports more warnings and its error and warning output is much more readable:

LLVM/clang output
LLVM/clang output

And, it actually booted!

[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 3.19.0-rc4-00183-g230b22d (ags@trochilidae) (clang version 3.5.1 (tags/RELEASE_351/final)) #3 SMP Tue Mar 3 00:12:04 CET 2015
[ 0.000000] CPU: ARMv7 Processor [410fc051] revision 1 (ARMv7), cr=10c5387d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] Machine model: Toradex Colibri VF61 on Colibri Evaluation Board


Wrong assembler

/usr/bin/as: unrecognized option '-mfloat-abi=soft'
clang: error: assembler command failed with exit code 1 (use -v to see invocation)

To compile the kernel, clang does not use its internal assembler but uses the GNU assembler (by using the -no-integrated-as option). In this case the build system picked your hosts assembler (x86_64) instead of the one provided by the cross compiler toolchain. The simplest way to work around this is creating a symlink to clang in the cross compiler toolchains directory:

$ ln -s /usr/bin/clang ~/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/clang

Unsupported ARM assembly

/tmp/traps-3da78a.s: Assembler messages:
/tmp/traps-3da78a.s:407: Error: selected processor does not support ARM mode `wfe'
/tmp/traps-3da78a.s:647: Error: selected processor does not support ARM mode `sev'
clang: error: assembler command failed with exit code 1 (use -v to see invocation)
scripts/ recipe for target 'arch/arm/kernel/traps.o' failed

This happend to me whent trying to build for ARMv6 architecture too. After revising the kernel configuration (removing CONFIG_ARCH_MULTI_V6) I could successfully build the kernel.

Non-relocatable link

error: multiple SHT_ARM_EXIDX sections .ARM.exidx.init.text and .ARM.exidx.ref.text in a non-relocatable link

This is actually not related to the LLVM/clang build itself. It happened to me when using the default cross compiler toolchain from my Ångström distribution build. This toolchain uses the gold linker by default, which does not work with the Linux kernel, the standard BFD linker is required. You can either append the Linker explicitly or symlink the correct assembler.

$ make ... LD=${CROSS_COMPILE}ld.bfd
- or -
$ cd path/to/toolchain/bin/
$ ln -sf arm-linux-gnueabihf-ld.bfd arm-linux-gnueabihf-ld

The latter might break your OpenEmbedded/Ångström builds and is hence not recommended if you use the toolchain located in your OpenEmbedded sysroots…

Leave a Reply

Your email address will not be published. Required fields are marked *