EmbeddedRelated.com

GCC

Category: Tools | Also known as: gnu compiler collection

GCC (GNU Compiler Collection) is a free, open-source compiler suite maintained by the GNU Project that supports multiple programming languages -- primarily C and C++ -- and can target a wide range of processor architectures. In embedded development, GCC is most commonly used in cross-compilation form, where the compiler runs on a host machine (typically x86 Linux, macOS, or Windows) and produces machine code for a different target architecture such as ARM, RISC-V, AVR, or MIPS.

In practice

GCC is the foundation of most open-source embedded toolchains. For ARM Cortex-M and Cortex-A targets, one widely used distribution is the Arm GNU Toolchain (formerly GNU Arm Embedded Toolchain), which packages GCC together with binutils (assembler, linker, objcopy, etc.) and a C library such as Newlib. Other ARM toolchain distributions exist and have their own histories, including those derived from earlier Code Sourcery work. For AVR microcontrollers, avr-gcc is the canonical compiler. For RISC-V, riscv32-unknown-elf-gcc and related variants are widely used. These toolchains are invoked by prefixed binary names -- for example, arm-none-eabi-gcc -- where the prefix is a shorthand derived from the target triple convention (architecture, vendor, OS/ABI).

In practice, few developers invoke GCC directly from the command line for every build. GCC is almost always driven by a build system: Make with hand-written Makefiles is common on bare-metal projects (as covered in "Coding Step 1 - Hello World and Makefiles"), while CMake with a cross-compilation toolchain file is increasingly prevalent, especially for larger codebases. IDEs such as LPCXpresso, STM32CubeIDE, and MPLAB X can wrap GCC internally so the compiler invocation is abstracted from the developer (as seen in "C++ on microcontrollers 2 - LPCXpresso, LPC-link, Code Sourcery, lpc21isp, linkerscript, LPC1114 startup").

Key GCC flags matter a great deal in embedded work. Optimization level (-O0 through -O3, -Os for size, -Og for debug-friendly optimization) directly affects code size and interrupt latency. Architecture-specific flags such as -mcpu=cortex-m4, -mfpu=fpv4-sp-d16, and -mfloat-abi=hard are required to target the correct instruction set and floating-point ABI. Missing or wrong flags here can silently produce code that links but faults at runtime due to ABI mismatches between compiled objects. The -ffunction-sections and -fdata-sections flags, combined with --gc-sections in the linker, allow the linker to eliminate unused code and data -- a common technique for keeping firmware images small.

The toolchain also generates intermediate artifacts beyond the final binary. The .map file produced by the linker (not GCC itself) is essential for understanding how much flash and RAM each module consumes. Tools like arm-none-eabi-objdump and arm-none-eabi-nm (part of binutils) work alongside GCC to disassemble output or inspect symbol sizes. Getting a working environment configured -- installing the toolchain, verifying PATH entries, and confirming the correct target triple -- is often the first friction point for developers starting out, as discussed in "Coding - Step 0: Setting Up a Development Environment".

Frequently asked

What is the difference between gcc and arm-none-eabi-gcc?
gcc (or cc) on most Linux systems invokes the native compiler, which produces binaries for the host machine. arm-none-eabi-gcc is a cross-compiler that produces code for ARM targets with no OS and the EABI calling convention -- suitable for bare-metal embedded firmware. The prefix 'arm-none-eabi' is a shorthand derived from the target triple convention (architecture, vendor, OS/ABI). Other examples include avr-gcc for AVR targets and riscv32-unknown-elf-gcc for 32-bit RISC-V bare-metal targets.
What C library does GCC use for bare-metal embedded targets?
GCC itself does not include a C library; it relies on a separately provided libc. The Arm GNU Toolchain bundles Newlib, a lightweight C library designed for embedded and bare-metal use. Newlib provides standard functions such as printf and malloc but requires platform-specific syscall stubs (commonly called retarget or semihosting stubs) to function. Picolibc is a more recent alternative that is smaller and aims to be more embedded-friendly. Full-featured libraries like glibc are generally not used on bare-metal targets due to size and OS dependency.
How do I choose the right optimization level for embedded firmware?
It depends on your priorities. -O0 disables optimization and is easiest to debug but produces the largest, slowest code. -Os optimizes for code size, which is often the right default for flash-constrained devices. -O2 or -O3 maximize speed at the cost of size and can make debugging harder because variables and functions may be optimized away or reordered. -Og is designed to produce debuggable code with light optimization and is a reasonable choice during active development. Note that the optimizer can interact with volatile, inline assembly, and hardware register accesses in non-obvious ways, so always verify critical timing-sensitive sections after changing optimization levels.
What does the -mfloat-abi flag do, and why does it matter?
The -mfloat-abi flag controls how floating-point arguments are passed between functions: 'soft' uses integer registers and software emulation with no FPU required; 'softfp' uses software calling conventions but can emit hardware FPU instructions if an FPU is present; 'hard' uses FPU registers for argument passing and requires a hardware FPU. Mixing objects compiled with different float ABIs causes a linker error or, in some cases, silent runtime failure. On Cortex-M4F and Cortex-M7 parts that include an FPU, using -mfloat-abi=hard together with the correct -mfpu flag (e.g., -mfpu=fpv4-sp-d16 for M4F) is necessary to make use of the FPU and is generally required for the FPU to be enabled at all.
Is GCC the only compiler used in embedded development?
No. While GCC is extremely common due to its open-source licensing and broad architecture support, other compilers are widely used. Clang/LLVM has gained significant ground and supports ARM, RISC-V, and other embedded targets with comparable quality. Commercial compilers such as IAR Embedded Workbench (EWARM) and Arm Compiler 6 (armclang, included in Keil MDK) are common in safety-critical and industrial embedded development, where their certified diagnostics, more predictable code generation, or vendor support are valued. Some vendor-specific toolchains for 8-bit and 16-bit MCUs (PIC, 8051 variants) use proprietary compilers with no GCC involvement.

Differentiators vs similar concepts

GCC is often conflated with the entire toolchain, but strictly speaking GCC is the compiler suite itself -- comprising multiple language front ends and shared back ends -- not the whole toolchain. A complete embedded toolchain also includes binutils (the assembler 'as', linker 'ld', and utilities like objcopy, objdump, nm, and size), a C library (commonly Newlib for bare-metal), and optionally a debugger (GDB). Distributions such as the Arm GNU Toolchain bundle all of these together, which is why the names are often used interchangeably. GCC should also be distinguished from Clang/LLVM: both are open-source C/C++ compilers targeting many of the same embedded architectures, but they have different front-end behavior, diagnostic quality, link-time optimization implementations, and licensing (GCC uses GPL, LLVM/Clang uses Apache 2.0). In practice the two are largely compatible for most embedded C code, but there are edge cases around language extensions and compiler-specific attributes (many GCC attributes are supported by Clang for compatibility, but not all).