Migrating from Arm GNU Toolchain
March 6, 2025 · View on GitHub
Overview
Arm GNU Toolchain is the GNU Toolchain for the Arm® architecture released by Arm and traditionally used for embedded development.
Generally the LLVM toolchain tries to be a drop in replacement for the GNU toolchain, however there may be some missing features or small incompatibilities.
Some known differences and migration strategies are summarized below.
Benefits
Using multiple toolchains to build a project benefits from different checks and warnings present in different compilers to catch more issues, particularly C and C++ standards compliance, during build time.
Arm Toolchain for Embedded provides support for multiple sanitizers and memory safety features to also catch typical issues at runtime during testing, see the Clang documentation and samples.
Arm Toolchain for Embedded provides superior performance when targeting the Armv8-M or later architecture, including the Arm® Helium™ technology (M-Profile Vector Extension, MVE).
Key toolchain components
| Component | GNU toolchain (arm-none-eabi-) | LLVM toolchain |
|---|---|---|
| C, C++ compiler | gcc, g++ | clang, clang++ |
| Assembler | as | clang integrated assembler |
| Linker | ld | lld |
| Binutils | objdump, readelf, ... | llvm-objdump, llvm-readelf, ... |
| Compiler runtime library | libgcc | compiler-rt |
| Unwinder | libgcc | libunwind |
| C standard library | newlib, newlib-nano | picolibc (or newlib/newlib-nano as overlay) |
| C++ ABI library | libsupc++.a | libc++abi |
| C++ standard library | libstdc++ | libc++ |
Toolchain identification
Toolchain version macros:
| Version number | GNU macro | LLVM macro |
|---|---|---|
| Major | __GNUC__ | __clang_major__ |
| Minor | __GNUC_MINOR__ | __clang_minor__ |
| Patch level | __GNUC_PATCHLEVEL__ | __clang_patchlevel__ |
Note that clang defines GNU macros for compatibility too:
__GNUC__ equal to 4, __GNUC_MINOR__ equal to 2,
and __GNUC_PATCHLEVEL__ equal to 1.
C and C++ language extensions
Clang supports the majority of GNU C and C++ extensions as described in Clang Language Extensions.
The following feature checking macros can be used to test whether a particular feature is supported:
Assembly language
clang should be used instead of arm-none-eabi-as to compile assembly
(.s and .S) files.
There are minor differences in the assembly syntax between GNU and LLVM compilers, however most of the time it is possible to write code that is accepted by both.
For example, GNU and LLVM compilers differ in:
- Use of
.Nand.Wsuffixes for Thumb instructions. - Use of
Ssuffix for flag setting instructions.
Multilib support
LLVM toolchain for Arm provides multilib support similar to the GNU toolchain, see Using the toolchain section in the README, however uses different command line options to control selection of semihosting.
| Use case | GNU options | LLVM options |
|---|---|---|
| No semihosting | --specs=nosys.specs | |
| Semihosting | --specs=rdimon.specs | -nostartfiles -lcrt0-semihost -lsemihost |
| Newlib-nano | --specs=nano.specs | --config=newlib-nano.cfg (with newlib-nano overlay installed) |
Linker
lld is designed as a drop in replacement for GNU ld,
however there are some known differences to take into account, see:
- Linker Script implementation notes and policy in the LLD documentation.
- The LLD and GNU linker incompatibilities blog post.
- When selecting the printf/scanf picolibc implementation variant with
--defsym from=to, see Printf and Scanf levels in Picolibc, LLD includes not only the printf/scanf implementation variant from picolibc specified through--defsym, but also the default PICOLIBC_DOUBLE_PRINTF_SCANF variant. To avoid linking the default variant into the application, you must include the--gc-sectionslinker flag.
Startup code
Refer to Using Picolibc in Embedded Systems
for the details of how picolibc handles initialization.
By default, picolibc provides an interrupt vector table. To replace it,
the application interrupt vector table should be placed into the init
linker script
section and referenced by the __interrupt_vector symbol.
Standard input and output
See Picolibc and Operating Systems
for the details on redirecting stdin, stdout and stderr.
The baremetal-uart sample
provides a basic code example for redirecting stdout.