Hello World in Assembly
Your first Assembly program - the classic Hello World example with Docker setup using NASM
Assembly language brings you as close to the hardware as possible while still using human-readable mnemonics. This Hello World example uses x86 assembly with NASM (Netwide Assembler) syntax, running on Linux.
The Code
Create a file named hello.asm:
| |
Understanding the Code
Data Section
| |
section .data- Declares the data segment for initialized datamessage db- Defines a byte string;dbmeans “define bytes”"Hello, World!", 10- The string followed by ASCII 10 (newline character)msglen equ $ - message- Calculates string length;$is current position, so$ - messagegives the byte count
Text Section
| |
section .text- Declares the code segment (executable instructions)global _start- Makes_startvisible to the linker; this is where execution begins on Linux
The Write System Call
| |
This is a Linux system call using the 32-bit calling convention:
| Register | Purpose | Value |
|---|---|---|
eax | System call number | 4 (sys_write) |
ebx | File descriptor | 1 (stdout) |
ecx | Buffer pointer | address of message |
edx | Byte count | length of message |
int 0x80 triggers a software interrupt, transferring control to the Linux kernel to perform the write operation.
The Exit System Call
| |
mov eax, 1- System call 1 issys_exitxor ebx, ebx- Setsebxto 0 (exit code); XOR with itself is a common assembly idiom for zeroing a registerint 0x80- Invokes the kernel to terminate the program
Without this exit call, execution would continue past our code into undefined memory, likely causing a segmentation fault.
Running with Docker
The easiest way to run x86 assembly without setting up a local toolchain:
| |
The Docker image handles:
- Assembling the
.asmfile with NASM - Linking the object file with
ld - Executing the resulting binary
Running Locally
If you have NASM and a linker installed:
| |
Expected Output
Hello, World!
Key Concepts
Registers
x86 processors have general-purpose registers. In 32-bit mode:
| Register | Traditional Use |
|---|---|
eax | Accumulator, return values, syscall numbers |
ebx | Base pointer, first syscall argument |
ecx | Counter, second syscall argument |
edx | Data, third syscall argument |
System Calls
System calls are how programs request services from the operating system kernel:
- Write to screen: syscall 4 (sys_write)
- Read from keyboard: syscall 3 (sys_read)
- Exit program: syscall 1 (sys_exit)
- Open file: syscall 5 (sys_open)
The int 0x80 instruction triggers the kernel to handle the request.
Memory Layout
Assembly programs have distinct sections:
| Section | Contents |
|---|---|
.data | Initialized global variables |
.bss | Uninitialized global variables |
.text | Executable code |
Why _start Instead of main?
In C programs, main() is called by startup code that the C runtime provides. In pure assembly without the C library, we use _start as the entry point that the linker expects.
Common Pitfalls
- Forgetting to exit: Without
sys_exit, the program crashes after your code - Wrong register sizes: Using
axwhen you meaneaxon 32-bit systems - Missing
global _start: The linker can’t find the entry point - Incorrect syscall numbers: Different architectures and ABIs use different numbers
Going Further
This example uses 32-bit x86 assembly with Linux syscalls. Modern systems often use:
- 64-bit mode: Different registers (
rax,rdi,rsi) and syscall convention (syscallinstead ofint 0x80) - C library: Call
printfandexitinstead of raw syscalls - Different platforms: Windows uses different calling conventions entirely
Assembly is the foundation that all other languages build upon. Understanding it gives you insight into what your code really does at the hardware level.
Running Today
All examples can be run using Docker:
docker pull esolang/x86asm-nasm:latest