As we’re exploring bringing up a C/C++ runtime on our system, I’d like to share a very helpful resource for those using clang/llvm: compiler-rt.
Compiler-rt is an LLVM project that provides implementations of various builtin functions for a variety of architectures. This saves us a lot of heavy lifting when bringing up a new platform, as we can link compiler-rt instead of re-implementing these functions.
While most useful as a complete library, compiler-rt is also a useful source code resource if you need to implement these builtins with a different toolchain. Simply import the required builtin source into your project.
I’ll let the compiler-rt project describe the builtins they provide:
builtins – a simple library that provides an implementation of the low-level target-specific hooks required by code generation and other runtime components. For example, when compiling for a 32-bit target, converting a double to a 64-bit unsigned integer is compiling into a runtime call to the
__fixunsdfdifunction. The builtins library provides optimized implementations of this and other low-level routines, either in target-independent C form, or as a heavily-optimized assembly.builtins provides full support for the libgcc interfaces on supported targets and high performance hand tuned implementations of commonly used functions like
__floatundidfin assembly that are dramatically faster than the libgcc implementations. It should be very easy to bring builtins to support a new target by adding the new routines needed by that target.
Table of Contents:
- Prerequisites
- Getting compiler-rt
- Building compiler-rt
- Using compiler-rt in Your Project
- Embedded Artistry compiler-rt
- Further Reading
Prerequisites
You will need the llvm-config binary on your platform. This binary is provided when you install llvm.
If you’re using OSX, note that Apple does not provide llvm-config with Xcode, so you will need to install mainline llvm to get this binary. See my notes on installing clang/llvm on OSX.
Getting compiler-rt
You can checkout the compiler-rt source with svn:
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
If you prefer git, check out the github mirror:
git clone git@github.com:llvm-mirror/compiler-rt.git
I’ll leave the folder structure descriptions to the compiler-rt team:
include/contains headers that can be included in user programs (for example, users may directly call certain function from sanitizer runtimes).lib/contains libraries implementations.lib/builtinsis a generic portable implementation of builtins routines.lib/builtins/(arch)has optimized versions of some routines for the supported architectures.test/contains test suites for compiler-rt runtimes.
The lib/builtins/ folder contains the source for the various builtin functions. You can use these items piecemeal in your repository. This is useful if you just need to port specific functions or don’t want to deal with installing clang or compiling compiler-rt.
Building compiler-rt
For those who are interested in the compiler-rt builtins library, let’s continue our journey.
Once you have llvm-config on your system, you can build compiler-rt with the following commands:
mkdir build
cd build
cmake ../compiler-rt -DLLVM_CONFIG_PATH=/path/to/llvm-config
make
The build diectory is important – it’s where cmake will place the resulting files.
For those following with homebrew, you could use this command:
cmake ../compiler-rt -DLLVM_CONFIG_PATH=$(brew --prefix llvm)/bin/llvm-config
make
If you don’t have llvm-config, you can still build the project. For cross-compiling, follow the instructions here to configure your CMake build directory.
By default, make will build everything. If you want to build a limited subset, you can run make help and pick the specific items you want to build.
If you want to install libraries, run this additional command:
make install
I usually do not run the make install step.
Finding the Right Library
After your build is completed, change to the lib/builtin directory in your build folder. There you will likely see a massive list of files. Here’s my example output from compiling with Apple Clang on OSX:
libclang_rt.builtins_arm64_ios.a
libclang_rt.builtins_armv7_ios.a
libclang_rt.builtins_armv7k_ios.a
libclang_rt.builtins_armv7s_ios.a
libclang_rt.builtins_i386_10.4.a
libclang_rt.builtins_i386_iossim.a
libclang_rt.builtins_i386_osx.a
libclang_rt.builtins_x86_64_10.4.a
libclang_rt.builtins_x86_64_iossim.a
libclang_rt.builtins_x86_64_osx.a
libclang_rt.builtins_x86_64h_osx.a
libclang_rt.cc_kext_arm64_ios.a
libclang_rt.cc_kext_armv7_ios.a
libclang_rt.cc_kext_armv7k_ios.a
libclang_rt.cc_kext_armv7s_ios.a
libclang_rt.cc_kext_i386_osx.a
libclang_rt.cc_kext_x86_64_osx.a
libclang_rt.cc_kext_x86_64h_osx.a
libclang_rt.hard_pic_armv7_macho_embedded.a
libclang_rt.hard_pic_armv7em_macho_embedded.a
libclang_rt.hard_pic_i386_macho_embedded.a
libclang_rt.hard_pic_x86_64_macho_embedded.a
libclang_rt.hard_static_armv7_macho_embedded.a
libclang_rt.hard_static_armv7em_macho_embedded.a
libclang_rt.hard_static_i386_macho_embedded.a
libclang_rt.hard_static_x86_64_macho_embedded.a
libclang_rt.soft_pic_armv6m_macho_embedded.a
libclang_rt.soft_pic_armv7_macho_embedded.a
libclang_rt.soft_pic_armv7em_macho_embedded.a
libclang_rt.soft_pic_armv7m_macho_embedded.a
libclang_rt.soft_static_armv6m_macho_embedded.a
libclang_rt.soft_static_armv7_macho_embedded.a
libclang_rt.soft_static_armv7em_macho_embedded.a
libclang_rt.soft_static_armv7m_macho_embedded.a
You only need one of these for your system, likely. Which one do you pick?
Here’s a quick decoder:
- hard vs soft: this is floating point. Is your platform configured to support hard or soft floating point operations?
- static vs pic: is the code compiled as a static library, or are you compiling with position-independent-code? (PIC)
- i386 vs armv7x: this will be dependent upon your platform’s processor. You need to pick the instruction set to match.
- The last portion of the name is the library format.
Generally, I end up picking this library for my purposes if I am compiling and linking on OSX:
libclang_rt.hard_pic_armv7_macho_embedded.a
Note the “macho embedded” format – this requires special parsing to use with your embedded system. We will investigate MACHO files further in a future article.
Using compiler-rt in your project
Since compiler-rt builtin libraries do not regularly need updates, I recommend pre-compiling compiler-rt into a library file that can be linked against in your project. It may be worth it to build compiler-rt on your build machine so you have a known source to retrieve updates from.
Once you have built compiler-rt, you can copy the desired library to your project’s repository.
You will need to add the -L linker flag to get the location into the library search path. The -l linker flag can be used to include the library itself: -lcompiler_rt.
If you built compiler-rt on OSX, you ended up with a bunch of macho libraries. The macho format will require additional handling that will be described in a future article.
Embedded Artistry compiler-rt
We use Meson for our projects. We have a compiler-rt project that builds with Meson which will build for your native system. Cross-compilation for ARM is also supported using cross-files.
The Embedded Artistry compiler-rt produces static libraries only, because that’s what we use on our embedded systems.
To build for your host machine, simply run make (after installing Meson):
make
For cross-compilation, you will need to supply a cross-compilation file when creating the build results directory. Some samples are provided in the build/cross folder, and you can create your own as needed.
meson buildresults --cross-file=build/cross/gcc/arm/nrf52840.txt
Change into the buildresults directory and build:
cd buildresults
ninja
In both cases, the static libraries will be in buildresults. If you enabled a cross-compilation build, a native llibrary and cross-compiled library will present.

I could need some help on this.
I seem to be doing something wrong as when I compile it, i only get x86_64 libs. Do i need a special llvm-config? How can i get one of those?
By the way I am trying on a Debian system.
Hi Christoph,
You need to set up Cmake to cross compile. Try these instructions, substituting the architecture for your actual target: https://llvm.org/docs/HowToCrossCompileBuiltinsOnArm.html.
Please let me know if that solves your problem.
Can you tell me your full cmake options? I can only get x86_64 as well. I failed to adopted cmake options in https://llvm.org/docs/HowToCrossCompileBuiltinsOnArm.html
I’m getting some CMake build failures due to missing includes, I’ll unwind that when I have some more time. I’ve been using the Meson port of compiler-rt for my projects to build for ARM.
For reference, can you share the CMake flags you tried? Are you sure that the compiler you’re using actually builds for ARM? For example, I see this kind of output with CMake:
-- Got ld supported ARCHES: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em -- Toolchain supported arches: armv6;armv7;armv7s;arm64;arm64e;arm64_32;i386;x86_64;x86_64h;armv6m;armv7k;armv7m;armv7emCMake options:
cmake -G Ninja ../compiler-rt -DBAREMETAL_ARMV6M_SYSROOT=${ARMEABI5GCC} -DBAREMETAL_ARMV7M_SYSROOT=${ARMEABI5GCC} -DBAREMETAL_ARMV7EM_SYSROOT=${ARMEABI5GCC} -DCMAKE_BUILD_TYPE=Release -C /home/llvm-project/clang/cmake/caches/BaremetalARM.cmake /home/llvm-project/compiler-rt/
where $ARMEABI5GCC is /home/gcc-arm-none-eabi-5_4-2016q3/
please help me delete the former reply since it’s a mess