Est. 1986 Advanced

GNU Assembler

The GNU Project assembler (GAS, invoked as "as"), the back-end assembler for GCC and a portable, multi-architecture assembler distributed as part of GNU Binutils.

Created by Dean Elsner (original author); maintained by the GNU Project / Free Software Foundation

Paradigm Assembly, Imperative, Low-level
Typing None (untyped)
First Appeared 1986 (approximately)
Latest Version Distributed as part of GNU Binutils; releases continue on a roughly annual cadence

The GNU Assembler, commonly known as GAS and invoked on the command line as as, is the assembler distributed by the GNU Project as part of the GNU Binutils package. It serves as the back-end assembler for the GNU Compiler Collection (GCC): when GCC compiles a source file to assembly, it is GAS that translates that assembly into machine code. GAS is unusual among assemblers in being deliberately multi-architecture – a single codebase, configured at build time for a target triple, supports dozens of instruction set architectures including x86, x86-64, ARM, AArch64, RISC-V, MIPS, PowerPC, SPARC, s390, and many others. By default GAS uses AT&T syntax for x86 targets, though it also accepts Intel syntax via the .intel_syntax directive.

History & Origins

The GNU Toolchain Vision

The GNU Assembler emerged from Richard Stallman’s broader project, announced in 1983, to build a complete free Unix-compatible operating system. A working compiler toolchain – compiler, assembler, linker, and supporting utilities – was a prerequisite for that goal. GCC handled the compiler role, but it required a free assembler that could turn its output into object files without depending on proprietary Unix tools like AT&T’s as.

Dean Elsner is credited as the original author of GAS, with work beginning around 1986 at the Free Software Foundation. The early assembler targeted the architectures most relevant to the GNU project at the time – the VAX and Motorola 68000 families that dominated Unix workstations – before expanding to additional targets as the GNU toolchain spread to new platforms. Many subsequent maintainers, including Jay Fenlason, Ken Raeburn, Steve Chamberlain, Ian Lance Taylor, Alan Modra, and Nick Clifton, shaped GAS into the multi-architecture assembler it is today.

Integration into Binutils

In the early 1990s the GNU assembler, linker, and binary utilities were unified into a single package, GNU Binutils. This consolidation simplified distribution and made it possible to share a common library – the Binary File Descriptor (BFD) library – across the entire toolchain. BFD abstracts the differences between object file formats (a.out, COFF, ELF, Mach-O, PE) and allows GAS, ld, objdump, objcopy, nm, and other tools to operate uniformly across formats and architectures.

The result is a remarkably portable assembler. The same source tree, configured with different --target options, can produce an assembler for x86-64 Linux, ARM bare-metal firmware, a PowerPC AIX target, or a RISC-V embedded system.

Design Philosophy

One Assembler, Many Targets

Where assemblers such as MASM and NASM are designed around a single architecture (x86), GAS is built around a target-independent core. The core handles lexical analysis, the pseudo-op directives, symbol tables, sections, relocations, and macro processing; an architecture-specific back-end (in gas/config/tc-<arch>.c) plugs in the instruction encoding and target-specific syntax.

This design has costs and benefits:

  • Benefit: A single, maintained codebase delivers reliable assemblers for an enormous range of architectures, including obscure or legacy targets that would otherwise be unsupported.
  • Cost: GAS is not the most ergonomic assembler for any single architecture. NASM and FASM, for example, often have cleaner Intel-syntax tooling for x86 work, and Microsoft’s MASM has deeper integration with the Windows ABI.

AT&T Syntax by Default

For x86 and x86-64 targets, GAS defaults to AT&T syntax, which originated at AT&T Bell Labs for Unix assemblers and differs noticeably from Intel’s documented syntax:

  • Operand order is source first, destination last, the reverse of Intel syntax.
  • Registers are prefixed with %, immediates with $, and memory references use parentheses: movl $42, %eax, addl 8(%ebx), %eax.
  • Mnemonics carry size suffixes: b (byte), w (word, 16-bit), l (long, 32-bit), q (quad, 64-bit) – e.g., movq, addl, movb.
  • Memory addressing uses the form disp(base, index, scale) rather than Intel’s [base + index*scale + disp].

GAS also supports Intel syntax via the .intel_syntax noprefix directive, which is commonly used by developers porting code originally written for MASM or NASM.

Pseudo-Ops and Directives

A large part of GAS is its set of pseudo-operations (directives that begin with a period) that control sections, alignment, symbol visibility, debug info, and macro expansion. Examples include:

  • .text, .data, .bss, .section – section selection
  • .globl, .local, .weak, .hidden – symbol attributes
  • .byte, .word, .long, .quad, .ascii, .asciz – data emission
  • .align, .balign, .p2align – alignment
  • .macro/.endm, .if/.else/.endif, .include – macro and conditional assembly
  • .cfi_startproc/.cfi_endproc and related CFI directives – DWARF unwinding information

These directives are largely consistent across architectures, which makes basic GAS source files quite portable – only the actual instruction mnemonics tend to differ between targets.

Key Features

Macro System

GAS supports a relatively powerful macro facility through .macro/.endm, with parameter substitution, default values, and conditional assembly. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    .macro push_all
        pushq %rax
        pushq %rbx
        pushq %rcx
        pushq %rdx
    .endm

    .text
    .globl _start
_start:
    push_all

While not as elaborate as MASM’s high-level macro system or NASM’s %macro constructs, the GAS macro system is sufficient for the kinds of repetitive patterns that arise in operating-system and library code.

Architecture Coverage

GAS supports an exceptionally broad set of targets. A non-exhaustive list of architectures with first-class support in recent Binutils releases includes:

FamilyExamples
x86i386, x86-64, x32
ARMARMv4-ARMv8 (32-bit), AArch64 (ARMv8-A and later)
RISC-VRV32, RV64, with standard extensions (I, M, A, F, D, C, V)
PowerPC32-bit PowerPC, PowerPC64 (BE and LE), POWER ISA
MIPSMIPS I-V, MIPS32, MIPS64, microMIPS
s390IBM z/Architecture (s390, s390x)
SPARCSPARC V8, V9
Otherm68k, SH, ARC, AVR, MSP430, Xtensa, LoongArch, and many others

For some legacy or specialty targets (e.g., older Motorola, Hitachi, or NEC chips), GAS is one of the few maintained free assemblers still in active use.

Integration with GCC

A typical gcc hello.c -o hello invocation runs three programs in sequence: the compiler proper (cc1), the assembler (as = GAS), and the linker (ld). The assembly that cc1 produces is hand-tailored to GAS’s syntax and directives; this tight coupling is one of the reasons GAS and GCC versions are usually upgraded together as a matched toolchain. The gcc -S option stops the compilation pipeline after producing assembly, exposing the input GAS would normally consume.

Evolution

From a.out to ELF

Early GAS releases targeted the a.out object file format used by BSD Unix and early System V variants. Through the 1990s, most Unix and Unix-like systems migrated to ELF (Executable and Linkable Format), and GAS followed – ELF is today the default object format for the great majority of GAS targets, with BFD providing transparent support for COFF (Windows PE-COFF via the MinGW toolchain), Mach-O (older macOS toolchains), and other formats where required.

New Architectures

The introduction of new architectures has been a recurring milestone in GAS’s history. Notable additions include x86-64 around 2003 (tracking AMD’s AMD64 launch), AArch64 around the Binutils 2.23 release in October 2012, RISC-V upstreamed in 2017 with Binutils 2.28, and LoongArch in the early 2020s. Because GAS is the canonical assembler for the GNU toolchain, “upstreamed into Binutils” is often the moment a new architecture is considered to have arrived in the mainstream open-source ecosystem.

Pace of Releases

GNU Binutils – and therefore GAS – has followed a roughly annual release cadence in recent years, with point releases for bug fixes. Releases are coordinated on the binutils mailing list; Nick Clifton has been a long-running release manager. Each release typically brings new instruction support for recent CPU extensions (for example, x86 AVX-512, ARM SVE, RISC-V vector extensions) and incremental improvements to existing back-ends.

Current Relevance

GAS occupies a load-bearing position in the open-source software ecosystem:

  • It is the default assembler for GCC, which in turn builds most of the user-space and kernel code shipped in Linux distributions. Every glibc release, every Linux kernel build, and every distribution’s package archive flows through GAS at build time on the relevant architectures.
  • It underpins cross-compilation. Embedded developers building firmware for ARM Cortex-M, RISC-V microcontrollers, or PowerPC SoCs typically use a cross-compiled GCC + Binutils toolchain, where GAS is the assembler component.
  • It is the de facto reference for AT&T-syntax x86 assembly taught in many Unix-oriented systems courses and used by developers who hand-write inline assembly in GCC’s asm() blocks.

Alternatives exist – LLVM’s integrated assembler is now used by Clang for many targets, often replacing GAS in the LLVM toolchain – but GAS remains the canonical assembler for GCC-centric workflows and continues to be the first-class assembler for many architectures that LLVM either supports less completely or not at all.

Why It Matters

The GNU Assembler is not famous in the way that GCC, the Linux kernel, or Git are famous, but its quiet ubiquity is part of what makes it important. Almost every program compiled by GCC – which is to say almost every program in a typical Linux distribution – has at some point in its build passed through GAS. The assembler is, in effect, the layer where the GNU toolchain’s promise of free software meets the silicon: it is the piece of software that turns human- or compiler-written assembly text into the bytes that the processor actually executes.

GAS also embodies a particular bet about how assemblers should be built. Rather than building dozens of separate, architecture-specific tools, the GNU Project built one assembler with pluggable back-ends, and that bet has paid off across decades of new architectures. When RISC-V appeared, when AArch64 appeared, when LoongArch appeared, the path to mainstream toolchain support ran through GAS and the rest of Binutils. For programmers working close to the hardware on free software systems, GAS is the assembler – often the only assembler – they ever need to learn.

Timeline

1986
Dean Elsner begins work on the GNU Assembler at the Free Software Foundation as part of the GNU toolchain effort; earliest source releases of 'gas' circulate around this period
1987
GCC 1.0 released by Richard Stallman (March 22); GAS is developed in parallel as the assembler back-end for the GNU toolchain
1991
GAS is folded into the GNU Binutils package (Binutils 1.x line), unifying it with the GNU linker (ld), archiver (ar), and related tools
1994
GNU Binutils 2.0 released, establishing the modern 2.x version line that has continued through the present day
1995
BFD (Binary File Descriptor) library integration matures, allowing GAS and the rest of Binutils to support multiple object file formats (a.out, COFF, ELF, Mach-O) and many target architectures through a common abstraction
2000
Binutils maintainership transitions to a community model under the GNU Project, with Nick Clifton becoming a long-running release manager for the 2.x series
2003
Support for AMD64 / x86-64 added to GAS, tracking the AMD Opteron launch and the broader 64-bit transition of the x86 ecosystem
2012
ARM AArch64 (64-bit ARM) support added to GAS around the Binutils 2.23 release (October 2012), enabling assembly for ARMv8-A processors
2017
RISC-V support upstreamed into GAS (Binutils 2.28, released March 2017), bringing the open RISC-V instruction set into the standard GNU toolchain
2024
GNU Binutils 2.42 released (January 29, 2024), continuing the project's roughly annual release cadence with updated architecture support and bug fixes

Notable Uses & Legacy

GCC (GNU Compiler Collection)

GCC emits assembly source that is consumed by GAS to produce object files. On nearly every GNU/Linux system, every C, C++, Fortran, Ada, or Go program built with GCC passes through GAS as part of the standard compilation pipeline.

Linux Kernel

The Linux kernel build system uses GAS to assemble architecture-specific assembly sources -- boot code, context switching, interrupt handlers, and CPU feature probing -- across x86, x86-64, ARM, AArch64, PowerPC, RISC-V, MIPS, s390, and other supported architectures.

GNU C Library (glibc)

glibc contains hand-written assembly implementations of performance-critical functions (memcpy, memset, strlen, and math routines) for multiple architectures, all assembled with GAS.

Cygwin and MinGW Toolchains

The Cygwin and MinGW/MinGW-w64 projects ship GAS as part of their GCC-based toolchains, providing GNU-style assembly support on Windows for both 32-bit and 64-bit targets.

Cross-compilation Toolchains

Embedded and operating-system development relies on cross-compiled Binutils packages (e.g., arm-none-eabi-as, aarch64-linux-gnu-as, riscv64-unknown-elf-as) where GAS is the assembler component for building firmware, bootloaders, and bare-metal software.

Language Influence

Influenced By

Unix as (AT&T assembler) ASM-x86 AT&T Syntax Assembly

Influenced

LLVM Integrated Assembler

Running Today

Run examples using the official Docker image:

docker pull gcc:latest

Example usage:

docker run --rm -v $(pwd):/src -w /src gcc:latest sh -c 'as -o hello.o hello.s && ld -o hello hello.o && ./hello'
Last updated: