Assembler Overview
Choosing an Assembler: Your choice depends on target platform, toolchain integration, syntax preference, and project requirements. This guide covers all major assemblers: NASM (cross-platform), MASM (Windows), GAS (compilers/kernel), FASM (bare-metal), YASM (media), UASM (MASM replacement), and LLVM AS (compiler pipelines).
Quick Reference Table
| Assembler |
Syntax |
Platforms |
Typical Use |
License |
| NASM |
Intel |
Linux, Windows, macOS, BSD |
General x86, cross-platform development |
BSD-2 |
| MASM |
Intel |
Windows |
Windows internals, Visual Studio integration |
Proprietary |
| GAS |
AT&T / Intel |
Unix-like, Cross |
Compilers (GCC output), Linux kernel |
GPL |
| FASM |
Intel |
Cross-platform |
Bare-metal, demos, OS development |
BSD-style |
| YASM |
Intel |
Cross-platform |
Media codecs, performance-critical code |
BSD-3 |
| UASM |
Intel |
Windows, Linux |
MASM replacement with modern features |
Watcom/Sybase |
| LLVM AS |
AT&T |
Cross-platform |
Compiler pipelines, Clang integration |
Apache 2.0 |
MASM (Microsoft Macro Assembler)
Windows
MASM Hello World
; hello_masm.asm - 64-bit Windows
extrn ExitProcess: PROC
extrn MessageBoxA: PROC
.data
caption db "Hello", 0
message db "Hello from MASM!", 0
.code
main PROC
sub rsp, 28h ; Shadow space + alignment
xor r9d, r9d ; MB_OK = 0
lea r8, caption
lea rdx, message
xor ecx, ecx ; hWnd = NULL
call MessageBoxA
xor ecx, ecx ; Exit code 0
call ExitProcess
main ENDP
END
Mainstream Assemblers
NASM (Netwide Assembler)
NASM is the most popular cross-platform assembler, known for its clean Intel syntax and excellent documentation. It produces output for multiple object file formats including ELF, PE/COFF, Mach-O, and raw binary.
Why NASM? Clean syntax, extensive macro system, cross-platform support, active development, and excellent for learning assembly.
Linux ELF64
NASM Hello World
; hello_nasm.asm - 64-bit Linux
section .data
msg db "Hello from NASM!", 10
len equ $ - msg
section .text
global _start
_start:
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, msg ; buffer
mov rdx, len ; length
syscall
mov rax, 60 ; sys_exit
xor rdi, rdi ; exit code 0
syscall
Build: nasm -f elf64 hello_nasm.asm && ld -o hello hello_nasm.o
Key NASM Features
- Preprocessor: Powerful macro system with
%macro, %define, %rep
- Local labels:
.done: syntax for procedure-scoped labels
- Data directives:
db, dw, dd, dq for defining data
- Output formats:
-f elf64, -f win64, -f macho64, -f bin
MASM (Microsoft Macro Assembler)
MASM is Microsoft's assembler, tightly integrated with Visual Studio. It offers high-level features like PROC/ENDP, INVOKE, and structured programming constructs that can simplify Windows development.
MASM Strengths: Deep Visual Studio integration, INVOKE for simplified API calls, PROTO for function prototypes, excellent for Windows system programming.
Key MASM Features
- PROC/ENDP: Procedure definition with automatic prologue/epilogue
- INVOKE: High-level function call syntax with type checking
- PROTO: Function prototype declarations for type safety
- Structured directives:
.IF, .WHILE, .REPEAT
- Tools:
ml.exe (32-bit), ml64.exe (64-bit)
MASM High-Level
MASM INVOKE Example
; Using MASM's INVOKE for cleaner API calls
includelib kernel32.lib
includelib user32.lib
MessageBoxA PROTO :DWORD, :DWORD, :DWORD, :DWORD
ExitProcess PROTO :DWORD
.data
szTitle db "MASM Demo", 0
szMsg db "High-level INVOKE syntax!", 0
.code
main PROC
INVOKE MessageBoxA, 0, ADDR szMsg, ADDR szTitle, 0
INVOKE ExitProcess, 0
main ENDP
END main
GAS (GNU Assembler)
GAS (GNU Assembler, invoked as as) is part of GNU Binutils and the default assembler for GCC. It traditionally uses AT&T syntax but supports Intel syntax via directives. GAS is essential for kernel development and compiler output.
GAS Use Cases: Linux kernel development, GCC inline assembly, reading compiler output, low-level system programming on Unix-like systems.
AT&T Syntax
GAS Hello World (AT&T)
# hello_gas.s - 64-bit Linux (AT&T syntax)
.section .data
msg:
.ascii "Hello from GAS!\n"
len = . - msg
.section .text
.globl _start
_start:
movq $1, %rax # sys_write
movq $1, %rdi # stdout
leaq msg(%rip), %rsi # buffer (RIP-relative)
movq $len, %rdx # length
syscall
movq $60, %rax # sys_exit
xorq %rdi, %rdi # exit code 0
syscall
Build: as hello_gas.s -o hello.o && ld hello.o -o hello
Intel Syntax
GAS with Intel Syntax
# hello_gas_intel.s - Using Intel syntax in GAS
.intel_syntax noprefix
.section .data
msg:
.ascii "Hello from GAS (Intel)!\n"
len = . - msg
.section .text
.globl _start
_start:
mov rax, 1 # sys_write
mov rdi, 1 # stdout
lea rsi, [rip + msg] # buffer
mov rdx, len # length
syscall
mov rax, 60 # sys_exit
xor rdi, rdi
syscall
The .intel_syntax noprefix directive enables Intel syntax without register prefixes.
Key GAS Features
- Directives:
.section, .globl, .ascii, .byte, .long, .quad
- Syntax switch:
.intel_syntax noprefix / .att_syntax
- Comments:
# for line comments, /* */ for block comments
- Integration: Direct output from
gcc -S, inline asm compatibility
Specialized Assemblers
FASM (Flat Assembler)
FASM is a self-hosting assembler (written in assembly!) known for its powerful macro system, minimal dependencies, and ability to create pure binary files. Popular in the demo scene and OS development communities.
FASM Strengths: Self-hosting (no external dependencies), powerful preprocessor, excellent for bootloaders, demos, and learning how assemblers work internally.
FASM
FASM Hello World (Linux)
; hello_fasm.asm - FASM syntax
format ELF64 executable
entry _start
segment readable executable
_start:
mov eax, 1 ; sys_write
mov edi, 1 ; stdout
mov rsi, msg
mov edx, msg_len
syscall
mov eax, 60 ; sys_exit
xor edi, edi
syscall
segment readable writeable
msg db 'Hello from FASM!', 10
msg_len = $ - msg
Build: fasm hello_fasm.asm (produces executable directly!)
Key FASM Features
- Self-hosting: The assembler is written in itself—no runtime dependencies
- Multiple output:
format PE64, format ELF64 executable, format binary
- Powerful macros: Can define complex structures and pseudo-instructions
- Direct executable: Can produce executables without a linker
- Variants:
fasm (original), fasmg (next-gen with improved macro system)
Bootloader
FASM MBR Bootloader
; boot.asm - Simple bootloader in FASM
format binary
use16
org 0x7C00
start:
mov ax, 0x07C0
mov ds, ax
mov si, message
print_loop:
lodsb
or al, al
jz hang
mov ah, 0x0E
int 0x10
jmp print_loop
hang:
jmp hang
message db 'Hello from bootloader!', 0
times 510 - ($ - $$) db 0
dw 0xAA55
YASM
YASM is a rewrite of NASM designed for better performance and modularity. It's particularly popular for media codec development (x264, x265, FFmpeg) due to its speed and NASM compatibility.
YASM Strengths: Faster than NASM, modular architecture, NASM-compatible syntax, widely used in multimedia projects.
YASM
YASM Example (NASM-Compatible)
; simd_yasm.asm - SIMD example (YASM/NASM compatible)
section .data
align 16
vec1: dd 1.0, 2.0, 3.0, 4.0
vec2: dd 5.0, 6.0, 7.0, 8.0
section .bss
align 16
result: resd 4
section .text
global vec_add
; void vec_add(void)
vec_add:
movaps xmm0, [rel vec1]
movaps xmm1, [rel vec2]
addps xmm0, xmm1
movaps [rel result], xmm0
ret
Build: yasm -f elf64 simd_yasm.asm -o simd.o
Key YASM Features
- NASM-compatible: Drop-in replacement for most NASM code
- GAS-compatible: Can also parse GAS/AT&T syntax
- Performance: Generally faster assembly times than NASM
- Modular: Supports multiple parsers and output formats
- Note: Development has slowed; NASM has caught up in features
UASM
UASM (JWASM fork) is a MASM-compatible assembler that runs on multiple platforms. It offers MASM syntax compatibility with modern extensions, making it ideal when you need MASM features on non-Windows systems.
UASM Strengths: MASM syntax on Linux/macOS, open-source MASM replacement, supports AVX-512 and modern instruction sets, actively maintained.
UASM
UASM Example (MASM-Compatible on Linux)
; hello_uasm.asm - MASM syntax on Linux via UASM
.686
.model flat, stdcall
option casemap:none
.data
msg db "Hello from UASM!", 10, 0
.code
_start:
; sys_write(1, msg, 17)
mov eax, 4
mov ebx, 1
mov ecx, OFFSET msg
mov edx, 17
int 80h
; sys_exit(0)
mov eax, 1
xor ebx, ebx
int 80h
end _start
Build: uasm -elf hello_uasm.asm && ld -m elf_i386 -o hello hello_uasm.o
Key UASM Features
- MASM-compatible: Supports PROC, INVOKE, PROTO, structured directives
- Cross-platform: Runs on Windows, Linux, macOS
- Modern ISA: Full AVX, AVX2, AVX-512 support
- Output formats: ELF, PE/COFF, OMF, BIN
- HJWasm-64: Variant with enhanced 64-bit support
LLVM AS (LLVM Assembler)
LLVM AS (llvm-mc) is the assembler in the LLVM toolchain. It's primarily used in compiler pipelines and integrates with Clang. While you can use it directly, it's most commonly encountered when examining or generating LLVM/Clang output.
LLVM AS Use Cases: Compiler development, JIT compilation, examining Clang output, assembly-level optimizations in LLVM-based projects.
LLVM
LLVM MC Example
# hello_llvm.s - Using llvm-mc
.text
.globl _start
_start:
movl $1, %eax # sys_write
movl $1, %edi # stdout
leaq msg(%rip), %rsi # buffer
movl $18, %edx # length
syscall
movl $60, %eax # sys_exit
xorl %edi, %edi
syscall
.data
msg:
.ascii "Hello from LLVM!\n"
Build: llvm-mc -filetype=obj hello_llvm.s -o hello.o && ld hello.o -o hello
Key LLVM AS Features
- Multiple targets: x86, ARM, RISC-V, AArch64, and more
- Integration: Part of LLVM toolchain alongside
lld linker
- Directives: Similar to GAS but with LLVM-specific extensions
- Tool:
llvm-mc is the actual assembler binary
- Intel syntax: Use
-x86-asm-syntax=intel flag
Syntax Comparison
Intel vs AT&T Syntax
Comparison
Same Instruction, Different Syntax
| Operation | Intel (NASM/MASM) | AT&T (GAS) |
| Move immediate | mov rax, 42 | movq $42, %rax |
| Memory access | mov [rax], rbx | movq %rbx, (%rax) |
| Indexed | mov [rax+rbx*4], rcx | movq %rcx, (%rax,%rbx,4) |
| Displacement | mov [rax+8], rdx | movq %rdx, 8(%rax) |
| Call instruction | call printf | call printf |
Operand Size Handling
Size Specifiers
Operand Size Across Assemblers
| Size | NASM/FASM/YASM | MASM/UASM | GAS/LLVM (AT&T) |
| 8-bit | byte [rax] | BYTE PTR [rax] | movb suffix |
| 16-bit | word [rax] | WORD PTR [rax] | movw suffix |
| 32-bit | dword [rax] | DWORD PTR [rax] | movl suffix |
| 64-bit | qword [rax] | QWORD PTR [rax] | movq suffix |
Memory Addressing Syntax
Addressing
Complex Memory Operands
; General form: [base + index*scale + displacement]
; Intel syntax (NASM/MASM/FASM/YASM/UASM):
mov rax, [rbx + rcx*4 + 16] ; Full addressing mode
mov rax, [rip + label] ; RIP-relative (64-bit)
; AT&T syntax (GAS/LLVM):
movq 16(%rbx,%rcx,4), %rax ; disp(base,index,scale)
leaq label(%rip), %rax ; RIP-relative
Cross-Platform Strategies
When developing assembly code that needs to work across platforms, you have several approaches:
Key Insight: The choice between Intel and AT&T syntax is largely personal preference. The bigger challenge is handling ABI differences (calling conventions, system calls) between operating systems.
Strategy 1: Use NASM with Conditional Assembly
NASM
Platform-Conditional Code
; cross_platform.asm - Single source, multiple targets
%ifdef LINUX
%define SYS_write 1
%define SYS_exit 60
%elifdef WINDOWS
extern WriteFile
extern ExitProcess
%endif
section .text
global _start
_start:
%ifdef LINUX
mov rax, SYS_write
mov rdi, 1
mov rsi, msg
mov rdx, len
syscall
%elifdef WINDOWS
; Windows API calls would go here
%endif
Build: nasm -f elf64 -DLINUX code.asm or nasm -f win64 -DWINDOWS code.asm
Strategy 2: Separate Platform Files
Maintain separate source files per platform with shared logic in header files:
core.inc - Shared macros and constants
linux_x64.asm - Linux-specific entry points
win_x64.asm - Windows-specific entry points
Strategy 3: Use UASM for MASM Portability
If you prefer MASM syntax but need to compile on Linux, UASM provides MASM compatibility across platforms.
Choosing the Right Assembler
Quick Decision: Learning? Use NASM. Windows with Visual Studio? Use MASM. Reading compiler output? Learn GAS. OS dev or demos? Try FASM.
Decision Matrix
| Use Case |
Recommended |
Alternative |
Reason |
| Learning assembly |
NASM |
FASM |
Clean syntax, great documentation, cross-platform |
| Windows development (Visual Studio) |
MASM |
UASM |
Native integration, INVOKE, PROTO |
| Linux kernel / GCC integration |
GAS |
LLVM AS |
Default for GCC, kernel uses AT&T |
| Bootloader / bare-metal |
FASM |
NASM |
Direct binary output, no linker needed |
| Media codecs / performance |
YASM / NASM |
- |
Industry standard (x264, FFmpeg use YASM/NASM) |
| MASM code on Linux |
UASM |
- |
MASM-compatible, cross-platform |
| Compiler development / LLVM |
LLVM AS |
GAS |
LLVM toolchain integration |
| Demo scene / size coding |
FASM |
NASM |
Powerful macros, self-hosting |
Summary Recommendations
- NASM: Best all-around choice for learning and cross-platform work
- MASM: Best for Windows-only projects with Visual Studio
- GAS: Essential for Linux kernel work and understanding compiler output
- FASM: Best for OS development, bootloaders, and minimalist projects
- YASM: Good for multimedia projects (though NASM has caught up)
- UASM: Best when you need MASM features on non-Windows systems
- LLVM AS: Best for compiler developers and LLVM-based toolchains