1=================================================================== 2How to Cross Compile Compiler-rt Builtins For Arm 3=================================================================== 4 5Introduction 6============ 7 8This document contains information about building and testing the builtins part 9of compiler-rt for an Arm target, from an x86_64 Linux machine. 10 11While this document concentrates on Arm and Linux the general principles should 12apply to other targets supported by compiler-rt. Further contributions for other 13targets are welcome. 14 15The instructions in this document depend on libraries and programs external to 16LLVM, there are many ways to install and configure these dependencies so you 17may need to adapt the instructions here to fit your own local situation. 18 19Prerequisites 20============= 21 22In this use case we'll be using cmake on a Debian-based Linux system, 23cross-compiling from an x86_64 host to a hard-float Armv7-A target. We'll be 24using as many of the LLVM tools as we can, but it is possible to use GNU 25equivalents. 26 27 * ``A build of LLVM/clang for the llvm-tools and llvm-config`` 28 * ``A clang executable with support for the ARM target`` 29 * ``compiler-rt sources`` 30 * ``The qemu-arm user mode emulator`` 31 * ``An arm-linux-gnueabihf sysroot`` 32 33In this example we will be using ninja. 34 35See https://compiler-rt.llvm.org/ for more information about the dependencies 36on clang and LLVM. 37 38See https://llvm.org/docs/GettingStarted.html for information about obtaining 39the source for LLVM and compiler-rt. Note that the getting started guide 40places compiler-rt in the projects subdirectory, but this is not essential and 41if you are using the BaremetalARM.cmake cache for v6-M, v7-M and v7-EM then 42compiler-rt must be placed in the runtimes directory. 43 44``qemu-arm`` should be available as a package for your Linux distribution. 45 46The most complicated of the prerequisites to satisfy is the arm-linux-gnueabihf 47sysroot. In theory it is possible to use the Linux distributions multiarch 48support to fulfill the dependencies for building but unfortunately due to 49/usr/local/include being added some host includes are selected. The easiest way 50to supply a sysroot is to download the arm-linux-gnueabihf toolchain. This can 51be found at: 52* https://developer.arm.com/open-source/gnu-toolchain/gnu-a/downloads for gcc 8 and above 53* https://releases.linaro.org/components/toolchain/binaries/ for gcc 4.9 to 7.3 54 55Building compiler-rt builtins for Arm 56===================================== 57We will be doing a standalone build of compiler-rt using the following cmake 58options. 59 60* ``path/to/compiler-rt`` 61* ``-G Ninja`` 62* ``-DCOMPILER_RT_BUILD_BUILTINS=ON`` 63* ``-DCOMPILER_RT_BUILD_SANITIZERS=OFF`` 64* ``-DCOMPILER_RT_BUILD_XRAY=OFF`` 65* ``-DCOMPILER_RT_BUILD_LIBFUZZER=OFF`` 66* ``-DCOMPILER_RT_BUILD_PROFILE=OFF`` 67* ``-DCMAKE_C_COMPILER=/path/to/clang`` 68* ``-DCMAKE_AR=/path/to/llvm-ar`` 69* ``-DCMAKE_NM=/path/to/llvm-nm`` 70* ``-DCMAKE_RANLIB=/path/to/llvm-ranlib`` 71* ``-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld"`` 72* ``-DCMAKE_C_COMPILER_TARGET="arm-linux-gnueabihf"`` 73* ``-DCMAKE_ASM_COMPILER_TARGET="arm-linux-gnueabihf"`` 74* ``-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON`` 75* ``-DLLVM_CONFIG_PATH=/path/to/llvm-config`` 76* ``-DCMAKE_C_FLAGS="build-c-flags"`` 77* ``-DCMAKE_ASM_FLAGS="build-c-flags"`` 78 79The ``build-c-flags`` need to be sufficient to pass the C-make compiler check, 80compile compiler-rt, and if you are running the tests, compile and link the 81tests. When cross-compiling with clang we will need to pass sufficient 82information to generate code for the Arm architecture we are targeting. We will 83need to select the Arm target, select the Armv7-A architecture and choose 84between using Arm or Thumb. 85instructions. For example: 86 87* ``--target=arm-linux-gnueabihf`` 88* ``-march=armv7a`` 89* ``-mthumb`` 90 91When using a GCC arm-linux-gnueabihf toolchain the following flags are 92needed to pick up the includes and libraries: 93 94* ``--gcc-toolchain=/path/to/dir/toolchain`` 95* ``--sysroot=/path/to/toolchain/arm-linux-gnueabihf/libc`` 96 97In this example we will be adding all of the command line options to both 98``CMAKE_C_FLAGS`` and ``CMAKE_ASM_FLAGS``. There are cmake flags to pass some of 99these options individually which can be used to simplify the ``build-c-flags``: 100 101* ``-DCMAKE_C_COMPILER_TARGET="arm-linux-gnueabihf"`` 102* ``-DCMAKE_ASM_COMPILER_TARGET="arm-linux-gnueabihf"`` 103* ``-DCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN=/path/to/dir/toolchain`` 104* ``-DCMAKE_SYSROOT=/path/to/dir/toolchain/arm-linux-gnueabihf/libc`` 105 106Once cmake has completed the builtins can be built with ``ninja builtins`` 107 108Testing compiler-rt builtins using qemu-arm 109=========================================== 110To test the builtins library we need to add a few more cmake flags to enable 111testing and set up the compiler and flags for test case. We must also tell 112cmake that we wish to run the tests on ``qemu-arm``. 113 114* ``-DCOMPILER_RT_EMULATOR="qemu-arm -L /path/to/armhf/sysroot`` 115* ``-DCOMPILER_RT_INCLUDE_TESTS=ON`` 116* ``-DCOMPILER_RT_TEST_COMPILER="/path/to/clang"`` 117* ``-DCOMPILER_RT_TEST_COMPILER_CFLAGS="test-c-flags"`` 118 119The ``/path/to/armhf/sysroot`` should be the same as the one passed to 120``--sysroot`` in the "build-c-flags". 121 122The "test-c-flags" need to include the target, architecture, gcc-toolchain, 123sysroot and arm/thumb state. The additional cmake defines such as 124``CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN`` do not apply when building the tests. If 125you have put all of these in "build-c-flags" then these can be repeated. If you 126wish to use lld to link the tests then add ``"-fuse-ld=lld``. 127 128Once cmake has completed the tests can be built and run using 129``ninja check-builtins`` 130 131Troubleshooting 132=============== 133 134The cmake try compile stage fails 135--------------------------------- 136At an early stage cmake will attempt to compile and link a simple C program to 137test if the toolchain is working. 138 139This stage can often fail at link time if the ``--sysroot`` and 140``--gcc-toolchain`` options are not passed to the compiler. Check the 141``CMAKE_C_FLAGS`` and ``CMAKE_C_COMPILER_TARGET`` flags. 142 143It can be useful to build a simple example outside of cmake with your toolchain 144to make sure it is working. For example: ``clang --target=arm-linux-gnueabi -march=armv7a --gcc-toolchain=/path/to/gcc-toolchain --sysroot=/path/to/gcc-toolchain/arm-linux-gnueabihf/libc helloworld.c`` 145 146Clang uses the host header files 147-------------------------------- 148On debian based systems it is possible to install multiarch support for 149arm-linux-gnueabi and arm-linux-gnueabihf. In many cases clang can successfully 150use this multiarch support when -gcc-toolchain and --sysroot are not supplied. 151Unfortunately clang adds ``/usr/local/include`` before 152``/usr/include/arm-linux-gnueabihf`` leading to errors when compiling the hosts 153header files. 154 155The multiarch support is not sufficient to build the builtins you will need to 156use a separate arm-linux-gnueabihf toolchain. 157 158No target passed to clang 159------------------------- 160If clang is not given a target it will typically use the host target, this will 161not understand the Arm assembly language files resulting in error messages such 162as ``error: unknown directive .syntax unified``. 163 164You can check the clang invocation in the error message to see if there is no 165``--target`` or if it is set incorrectly. The cause is usually 166``CMAKE_ASM_FLAGS`` not containing ``--target`` or ``CMAKE_ASM_COMPILER_TARGET`` not being present. 167 168Arm architecture not given 169-------------------------- 170The ``--target=arm-linux-gnueabihf`` will default to arm architecture v4t which 171cannot assemble the barrier instructions used in the synch_and_fetch source 172files. 173 174The cause is usually a missing ``-march=armv7a`` from the ``CMAKE_ASM_FLAGS``. 175 176Compiler-rt builds but the tests fail to build 177---------------------------------------------- 178The flags used to build the tests are not the same as those used to build the 179builtins. The c flags are provided by ``COMPILER_RT_TEST_COMPILE_CFLAGS`` and 180the ``CMAKE_C_COMPILER_TARGET``, ``CMAKE_ASM_COMPILER_TARGET``, 181``CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN`` and ``CMAKE_SYSROOT`` flags are not 182applied. 183 184Make sure that ``COMPILER_RT_TEST_COMPILE_CFLAGS`` contains all the necessary 185information. 186 187 188Modifications for other Targets 189=============================== 190 191Arm Soft-Float Target 192--------------------- 193The instructions for the Arm hard-float target can be used for the soft-float 194target by substituting soft-float equivalents for the sysroot and target. The 195target to use is: 196 197* ``-DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabi`` 198 199Depending on whether you want to use floating point instructions or not you 200may need extra c-flags such as ``-mfloat-abi=softfp`` for use of floating-point 201instructions, and ``-mfloat-abi=soft -mfpu=none`` for software floating-point 202emulation. 203 204You will need to use an arm-linux-gnueabi GNU toolchain for soft-float. 205 206AArch64 Target 207-------------- 208The instructions for Arm can be used for AArch64 by substituting AArch64 209equivalents for the sysroot, emulator and target. 210 211* ``-DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu`` 212* ``-DCOMPILER_RT_EMULATOR="qemu-aarch64 -L /path/to/aarch64/sysroot`` 213 214The CMAKE_C_FLAGS and COMPILER_RT_TEST_COMPILER_CFLAGS may also need: 215``"--sysroot=/path/to/aarch64/sysroot --gcc-toolchain=/path/to/gcc-toolchain"`` 216 217Armv6-m, Armv7-m and Armv7E-M targets 218------------------------------------- 219To build and test the libraries using a similar method to Armv7-A is possible 220but more difficult. The main problems are: 221 222* There isn't a ``qemu-arm`` user-mode emulator for bare-metal systems. The ``qemu-system-arm`` can be used but this is significantly more difficult to setup. 223* The targets to compile compiler-rt have the suffix -none-eabi. This uses the BareMetal driver in clang and by default won't find the libraries needed to pass the cmake compiler check. 224 225As the Armv6-M, Armv7-M and Armv7E-M builds of compiler-rt only use instructions 226that are supported on Armv7-A we can still get most of the value of running the 227tests using the same ``qemu-arm`` that we used for Armv7-A by building and 228running the test cases for Armv7-A but using the builtins compiled for 229Armv6-M, Armv7-M or Armv7E-M. This will test that the builtins can be linked 230into a binary and execute the tests correctly but it will not catch if the 231builtins use instructions that are supported on Armv7-A but not Armv6-M, 232Armv7-M and Armv7E-M. 233 234To get the cmake compile test to pass you will need to pass the libraries 235needed to successfully link the cmake test via ``CMAKE_CFLAGS``. It is 236strongly recommended that you use version 3.6 or above of cmake so you can use 237``CMAKE_TRY_COMPILE_TARGET=STATIC_LIBRARY`` to skip the link step. 238 239* ``-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY`` 240* ``-DCOMPILER_RT_OS_DIR="baremetal"`` 241* ``-DCOMPILER_RT_BUILD_BUILTINS=ON`` 242* ``-DCOMPILER_RT_BUILD_SANITIZERS=OFF`` 243* ``-DCOMPILER_RT_BUILD_XRAY=OFF`` 244* ``-DCOMPILER_RT_BUILD_LIBFUZZER=OFF`` 245* ``-DCOMPILER_RT_BUILD_PROFILE=OFF`` 246* ``-DCMAKE_C_COMPILER=${host_install_dir}/bin/clang`` 247* ``-DCMAKE_C_COMPILER_TARGET="your *-none-eabi target"`` 248* ``-DCMAKE_ASM_COMPILER_TARGET="your *-none-eabi target"`` 249* ``-DCMAKE_AR=/path/to/llvm-ar`` 250* ``-DCMAKE_NM=/path/to/llvm-nm`` 251* ``-DCMAKE_RANLIB=/path/to/llvm-ranlib`` 252* ``-DCOMPILER_RT_BAREMETAL_BUILD=ON`` 253* ``-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON`` 254* ``-DLLVM_CONFIG_PATH=/path/to/llvm-config`` 255* ``-DCMAKE_C_FLAGS="build-c-flags"`` 256* ``-DCMAKE_ASM_FLAGS="build-c-flags"`` 257* ``-DCOMPILER_RT_EMULATOR="qemu-arm -L /path/to/armv7-A/sysroot"`` 258* ``-DCOMPILER_RT_INCLUDE_TESTS=ON`` 259* ``-DCOMPILER_RT_TEST_COMPILER="/path/to/clang"`` 260* ``-DCOMPILER_RT_TEST_COMPILER_CFLAGS="test-c-flags"`` 261 262The Armv6-M builtins will use the soft-float ABI. When compiling the tests for 263Armv7-A we must include ``"-mthumb -mfloat-abi=soft -mfpu=none"`` in the 264test-c-flags. We must use an Armv7-A soft-float abi sysroot for ``qemu-arm``. 265 266Depending on the linker used for the test cases you may encounter BuildAttribute 267mismatches between the M-profile objects from compiler-rt and the A-profile 268objects from the test. The lld linker does not check the profile 269BuildAttribute so it can be used to link the tests by adding -fuse-ld=lld to the 270``COMPILER_RT_TEST_COMPILER_CFLAGS``. 271 272Alternative using a cmake cache 273------------------------------- 274If you wish to build, but not test compiler-rt for Armv6-M, Armv7-M or Armv7E-M 275the easiest way is to use the BaremetalARM.cmake recipe in clang/cmake/caches. 276 277You will need a bare metal sysroot such as that provided by the GNU ARM 278Embedded toolchain. 279 280The libraries can be built with the cmake options: 281 282* ``-DBAREMETAL_ARMV6M_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi`` 283* ``-DBAREMETAL_ARMV7M_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi`` 284* ``-DBAREMETAL_ARMV7EM_SYSROOT=/path/to/bare/metal/toolchain/arm-none-eabi`` 285* ``-C /path/to/llvm/source/tools/clang/cmake/caches/BaremetalARM.cmake`` 286* ``/path/to/llvm`` 287 288**Note** that for the recipe to work the compiler-rt source must be checked out 289into the directory llvm/runtimes. You will also need clang and lld checked out. 290 291