Assembly Language - Environment Setup

This chapter will guide you through setting up the NASM assembly development environment on a Linux system and completing your first assembly program.


Linux Environment Preparation

If you are using Windows, it is recommended to installWSL(Windows Subsystem for Linux)or use a virtual machine to obtain a Linux environment.

macOS users can install Linux in a virtual machine or use Docker containers.

All examples in this tutorial are based onUbuntu/Debiansystem. For other distributions, please adjust the package manager commands accordingly.


Install NASM Assembler

On Ubuntu/Debian systems, install NASM using the apt package manager:

$ sudo apt update
$ sudo apt install nasm

After installation, verify that NASM was installed successfully:

$ nasm -version
NASM version 2.16.01

If you see the version number output, it means NASM has been installed successfully.


Install Linker

The assembler generatesobject files (.o files), which cannot be run directly.

You need a linker to convert the object file into an executable. We use the linker that comes with GCC:

$ sudo apt install gcc

Alternatively, you can directly use the GNU linker ld:

$ ld --version

In this tutorial, we mainly usegccfor linking, because it automatically handles some low-level details and is more suitable for beginners.


Install Debugging Tool GDB

GDB(GNU Debugger)is the most commonly used debugger on Linux, allowing you to step through programs, view register states, and inspect memory contents.

$ sudo apt install gdb

Verify GDB installation:

$ gdb --version
GNU gdb (Ubuntu 12.1-0ubuntu1) 12.1

First Assembly Program: Hello, example

Create a new filehello.asm, and enter the following content:

Example

; File path: hello.asm
; First assembly program: print Hello, example!
; NASM syntax, Linux 32-bit

section .data                       ; Data section: stores initialized data
    msg db 'Hello, example!', 0xA    ; Define string msg, 0xA is newline character
    len equ $ - msg                 ; Compute string length: current address - msg start address

section .text                       ; Code section: stores executable instructions
    global _start                   ; Declare _start as the program entry point

_start:                             ; Program entry
    ; System call sys_write (4): output string to stdout
    mov eax, 4                      ; System call number 4 = sys_write
    mov ebx, 1                      ; File descriptor 1 = stdout (standard output)
    mov ecx, msg                    ; Address of the string to output
    mov edx, len                    ; String length
    int 0x80                        ; Trigger interrupt to execute system call

    ; System call sys_exit (1): exit program normally
    mov eax, 1                      ; System call number 1 = sys_exit
    mov ebx, 0                      ; Return value 0 = normal exit
    int 0x80                        ; Trigger interrupt to execute system call

Compile and Run

The entire compilation and execution flow is shown in the diagram:

汇编程序编译运行流程

Use the following commands to compile and run this program:

$ nasm -f elf32 hello.asm -o hello.o    # 汇编:将 .asm 转为 .o 目标文件
$ ld -m elf_i386 hello.o -o hello       # 链接:将 .o 转为可执行文件
$ ./hello                               # 运行程序
Hello, example!

The purpose of each of the three commands above:

StepCommandDescription
1. Assemblenasm -f elf32 hello.asm -o hello.o-f elf32 specifies the output format as 32-bit ELF, -o specifies the output file name
2. Linkld -m elf_i386 hello.o -o hello-m elf_i386 specifies 32-bit linking mode, generating the executable file hello
3. Run./helloExecute the program in the current directory

Linking with GCC (Recommended)

If the ld configuration in your environment is complex, you can use gcc to link, which will automatically handle details such as the C runtime:

$ nasm -f elf32 hello.asm -o hello.o
$ gcc -m32 hello.o -o hello -nostartfiles
$ ./hello
Hello, example!

-nostartfilesThe option tells GCC not to add default startup code, because we define our own_startentry point.


Code Structure Analysis

Let's understand the above program segment by segment:

PartCodeDescription
Data segment declarationsection .dataDeclares the data segment, storing variables and constants
String definitionmsg db 'Hello, example!', 0xAdb defines a byte sequence; 0xA is the ASCII code for newline
Length calculationlen equ $ - msg$ represents the current address; subtracting the msg address gives the string length
Code segment declarationsection .textDeclares the code segment, storing instructions
Entry declarationglobal _startExport _start as a global symbol; the linker needs it
Entry label_start:Where the program starts execution

int 0x80It is the Linux 32-bit system call instruction. It triggers a software interrupt, allowing the kernel to execute the system call we specify through eax. This is the bridge between user programs and the operating system kernel.


Debugging with GDB

Add debug information during compilation, then step through with GDB:

$ nasm -f elf32 -g hello.asm -o hello.o       # -g 添加调试信息
$ ld -m elf_i386 hello.o -o hello
$ gdb ./hello
(gdb) break _start                             # 在 _start 处设置断点
(gdb) run                                      # 运行程序
(gdb) stepi                                    # 单步执行一条指令
(gdb) info registers                           # 查看所有寄存器
(gdb) x/s msg                                  # 查看 msg 字符串内容
(gdb) quit                                     # 退出 GDB
GDB commandFunction
break _startSet a breakpoint at the _start label
runRun the program, stop at breakpoint
stepiExecute one machine instruction at a time
info registersDisplay current values of all registers
x/s 地址View content at specified address in string format

Frequently Asked Questions

If you compile 32-bit assembly on a 64-bit system, you need to install 32-bit compatibility libraries:sudo apt install gcc-multilib

If ld reports "cannot find entry symbol _start" during linking, check whether you wrote it correctly in your codeglobal _startand whether the label name exactly matches (note the underscore).

Other Extensions