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

ComponentGNU toolchain (arm-none-eabi-)LLVM toolchain
C, C++ compiler​gcc, g++clang, clang++
Assembler​asclang integrated assembler​
Linker​ldlld
Binutils​objdump, readelf, ...llvm-objdump, llvm-readelf, ...
Compiler runtime library​libgcc​compiler-rt
Unwinder​libgcclibunwind
C standard library​newlib, newlib-nanopicolibc (or newlib/newlib-nano as overlay)
C++ ABI library​libsupc++.alibc++abi
C++ standard library​libstdc++​libc++

Toolchain identification

Toolchain version macros:

Version numberGNU macroLLVM 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 .N and .W suffixes for Thumb instructions.
  • Use of S suffix 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 caseGNU optionsLLVM 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:

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.