Assembly Env Setup
## 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 a Windows system, it is recommended to install WSL (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 a Docker container.
All examples in this tutorial are based on the Ubuntu/Debian system. For other distributions, please adjust the package manager commands accordingly.
* * *
## Installing the NASM Assembler
On Ubuntu/Debian systems, use the apt package manager to install NASM:
$ sudo apt update $ sudo apt install nasm
After installation, verify that NASM is installed successfully:
$ nasm -version NASM version 2.16.01
If you see the version number output, NASM has been successfully installed.
* * *
## Installing the Linker
The assembler generates object files (.o files), which cannot be run directly.
You need a linker to convert the object files into executable files. 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 use gcc for linking because it automatically handles some low-level details, making it more suitable for beginners.
* * *
## Installing the GDB Debugger
GDB (GNU Debugger) is the most commonly used debugger on Linux. It can execute programs step by step, 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, tutorial
Create a new file `hello.asm` and enter the following content:
## Example
; File path: hello.asm
; First assembly program: print Hello, tutorial!
; NASM syntax, Linux 32-bit
section.data; Data segment: stores initialized data
msg db'Hello, tutorial!',0xA; Define string msg, 0xA is newline character
len equ$- msg ; Calculate string length: current address - msg starting address
section.text; Code segment: stores executable instructions
global _start ; Declare _start as 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 string to output
mov edx, len ; String length
int 0x80; Trigger interrupt, 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, execute system call
* * *
## Compiling and Running
The entire compile and run process is shown in the figure:

Use the following commands to compile and run this program:
$ nasm -f elf32 hello.asm -o hello.o # Assemble: convert .asm to .o object file $ ld -m elf_i386 hello.o -o hello # Link: convert .o to executable file $ ./hello # Run programHello, tutorial!
The functions of the three commands above:
| Step | Command | Description |
| --- | --- | --- |
| 1. Assemble | `nasm -f elf32 hello.asm -o hello.o` | -f elf32 specifies 32-bit ELF output format, -o specifies output file name |
| 2. Link | `ld -m elf_i386 hello.o -o hello` | -m elf_i386 specifies 32-bit link mode, generates executable file hello |
| 3. Run | `./hello` | Execute program in current directory |
* * *
## Using GCC to Link (Recommended Method)
If your environment's ld configuration is complex, you can use gcc to link, as it automatically handles C runtime and other details:
$ nasm -f elf32 hello.asm -o hello.o $ gcc -m32 hello.o -o hello -nostartfiles $ ./hello Hello, tutorial!
The `-nostartfiles` option tells GCC not to add default startup code, because we have defined our own `_start` entry point.
* * *
## Code Structure Analysis
Let's understand the program section by section:
| Section | Code | Description |
| --- | --- | --- |
| Data segment declaration | `section .data` | Declare data segment, stores variables and constants |
| String definition | `msg db 'Hello, tutorial!', 0xA` | db defines byte sequence, 0xA is newline ASCII code |
| Length calculation | `len equ $ - msg` | $ represents current address, subtract msg address to get string length |
| Code segment declaration | `section .text` | Declare code segment, stores instructions |
| Entry declaration | `global _start` | Export _start as global symbol, the linker needs it |
| Entry label | `_start:` | Location where program begins execution |
> `int 0x80` is the Linux 32-bit system call instruction. It triggers a software interrupt, causing the kernel to execute the system call we specified through eax. This is the bridge between user programs and the operating system kernel.
* * *
## Using GDB for Debugging
Add debugging information during compilation, then use GDB to execute step by step:
$ nasm -f elf32 -g hello.asm -o hello.o # -g adds debugging information $ ld -m elf_i386 hello.o -o hello $ gdb ./hello (gdb) break _start # Set breakpoint at _start(gdb) run # Run program(gdb) stepi # Single step one instruction(gdb) info registers # View all registers(gdb) x/s msg # View msg string content(gdb) quit # Exit GDB
| GDB Command | Function |
| --- | --- |
| `break _start` | Set breakpoint at _start label |
| `run` | Run program, stop at breakpoint |
| `stepi` | Single step one machine instruction |
| `info registers` | Display current values of all registers |
| `x/s address` | View content at specified address in string format |
* * *
## Common Issues
> If you are compiling 32-bit assembly on a 64-bit system, you need to install 32-bit compatibility libraries: `sudo apt install gcc-multilib`
> If ld reports error "cannot find entry symbol _start", check whether your code correctly has `global _start` and whether the label name is exactly the same (note the underscore).
YouTip