Momen pertama menulis kode assembly: memastikan NASM terinstall, menyusun program Hello World Linux x86-64 paling sederhana memakai syscall write(1, msg, len) dan exit(0), lalu assemble dengan nasm -f elf64 dan link dengan ld, hingga memverifikasi eksekusi dan belajar membaca error assembler.

Semua fondasi sudah berdiri: toolchain di episode 0, sejarah di episode 1, dan arsitektur CPU di episode 2. Sekarang saatnya momen yang ditunggu — menulis program assembly pertama dan melihat hasilnya tercetak di terminal. Program ini bukan sekadar "Hello World": ia memperkenalkan tiga konsep inti yang akan menemani kita sepanjang series: syscall, section, dan label.
Episode 3 juga menandai transisi dari teori ke praktik. Kalian akan merasakan siklus yang akan kalian ulangi ratusan kali: tulis → assemble → link → jalankan → debug. Mari kita mulai.
Jika sudah menyelesaikan episode 0, NASM seharusnya sudah siap. Verifikasi cepat:
nasm -vOutputnya berbentuk NASM version 3.02 ... atau setidaknya 2.16.x. Jika belum ada, install sesuai distro:
sudo apt install nasm # Debian/Ubuntu
sudo dnf install nasm # RHEL/Fedora
brew install nasm # macOSBuat file hello.asm di ~/asm-lab/src:
section .data
msg db "Hello, World!", 0x0a
len equ $-msg
section .text
global _start
_start:
mov rax, 1 ; syscall number untuk write = 1
mov rdi, 1 ; fd pertama = stdout
mov rsi, msg ; alamat buffer yang berisi pesan
mov rdx, len ; panjang buffer
syscall
mov rax, 60 ; syscall number untuk exit = 60
mov rdi, 0 ; exit code = 0 (sukses)
syscallBaris 2–3 mendefinisikan section .data — area memori yang diisi di awal dan bisa dibaca/ditulis. msg db "Hello, World!", 0x0a mendeklarasikan array of bytes (db = define byte) berisi string pesan plus 0x0a (newline). Label msg menunjuk ke alamat awal array ini.
Baris 4 adalah trik yang wajib diingat: len equ $-msg menghitung panjang pesan secara otomatis. Simbol $ berarti "alamat di sini", jadi $-msg adalah selisih antara posisi saat ini dan alamat msg — jumlah byte persis dari string tersebut.
Section .text berisi instruksi yang akan dieksekusi. global _start memberi tahu linker bahwa simbol _start adalah titik masuk program. Tanpa ini, ld tidak akan menemukan entry point.
Di Linux x86-64, cara berkomunikasi dengan kernel adalah instruksi syscall. Konvensinya: masukkan nomor syscall ke rax, argumen ke rdi, rsi, rdx (dst), lalu jalankan syscall.
write (nomor 1): rdi = file descriptor, rsi = buffer, rdx = panjang.exit (nomor 60): rdi = exit code.Inilah cara kerja paling fundamental: kalian tidak memanggil fungsi libc, kalian berbicara langsung ke kernel. Kita bedah tabel syscall Linux secara lengkap di episode 10.
Sekarang terjemahkan assembly menjadi biner:
cd ~/asm-lab/src
nasm -f elf64 hello.asm -o hello.o
ld hello.o -o hellonasm -f elf64 menghasilkan object file ELF 64-bit (hello.o).ld menghubungkannya menjadi executable hello tanpa libc sama sekali — ukurannya hanya sekitar 4 KB.Tip
Wajib diingat: nasm hanya menerjemahkan syntax → machine code (assembling), ld yang menggabungkan object file dan menetapkan entry point (linking). Kedua langkah ini terpisah — di episode 19 kita akan menambahkan gcc sebagai linker untuk bisa memanggil libc.
Jalankan:
./helloOutput yang benar:
Hello, World!Cek juga exit code dan ukuran biner:
echo $? # 0
file hello # ELF 64-bit LSB executable...
ls -l helloUntuk perbandingan, program yang sama dalam GAS dengan sintaks AT&T (kita bedah lengkap di episode 4):
.section .data
msg: .ascii "Hello, World!\n"
len = . - msg
.section .text
.global _start
_start:
mov $1, %rax
mov $1, %rdi
lea msg(%rip), %rsi
mov $len, %rdx
syscall
mov $60, %rax
mov $0, %rdi
syscallAssemble dengan as lalu link:
as hello-att.s -o hello-att.o
ld hello-att.o -o hello-att
./hello-attPerhatikan perbedaan syntax yang mencolok: % sebelum register, $ sebelum immediate, dan urutan operan terbalik (mov $1, %rax vs mov rax, 1). Episode 4 akan membedah keduanya secara tuntas.
Berikut kesalahan yang paling sering muncul pada Hello World pertama:
Warning
Lupa global _start → ld error entry point not found. Selalu deklarasikan global _start di section .text.
0x0a.rax: 1 untuk write, 60 untuk exit.eax (32-bit) vs rax (64-bit). Untuk syscall di kernel 64-bit, gunakan register 64-bit.$ di GAS → mov 1, %rax akan ditafsirkan sebagai alamat memori, bukan nilai. Immediate harus diawali $.Bahkan Hello World bisa di-debug. Coba:
gdb -q ./hello
(gdb) break _start
(gdb) run
(gdb) info registers rax
(gdb) stepi
(gdb) info registers rax
(gdb) quitinfo registers rax akan menunjukkan bagaimana rax berubah setelah stepi — kalian melihat langsung satu instruksi mengubah mesin. Ini adalah kekuatan yang tidak dimiliki programmer Python. Detail gdb kita bedah di episode 16.
Important
Selalu verifikasi program assembly dengan echo $? setelah eksekusi. Exit code 0 berarti exit(0) dipanggil dengan benar. Jika program "hang" tanpa output, hampir pasti kalian lupa syscall exit — CPU terus mengeksekusi memori setelah program selesai hingga crash.
Pada episode 3 ini, kalian telah menulis, meng-assemble, me-link, dan menjalankan program assembly pertama.
Inti yang harus dibawa pulang:
nasm -f elf64 hello.asm -o hello.o lalu ld hello.o -o hello.rax, argumen di rdi/rsi/rdx, jalankan syscall.section .data untuk data, section .text untuk kode, global _start untuk entry point.db untuk byte, equ untuk konstanta, $ untuk alamat saat ini — kombinasi $-msg untuk menghitung panjang.% dan $; perbandingan lengkap menyusul.Di episode 4 selanjutnya, kita bedah sintaks Intel vs AT&T secara menyeluruh: mengapa urutan operan berbeda, apa arti suffix b/w/l/q di GAS, dan bagaimana menerjemahkan dua dialek assembly ini dengan percaya diri — keterampilan yang menyelamatkan kalian saat membaca dokumentasi, disassembler, dan kode sumber kernel yang campur aduk.