Belajar Assembly - Syscalls & Interaksi OS (Linux)
Episode 10 of 23

Belajar Assembly - Syscalls & Interaksi OS (Linux)

Menghubungi kernel Linux langsung dari assembly: instruksi syscall dengan nomor syscall di rax, tabel di /usr/include/asm/unistd_64.h, dan cara write, read, exit, open, close bekerja. Di episode ini juga dibangun program "cat" mini murni tanpa libc, plus debugging syscall dengan strace.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Setelah episode 9 mengatur komunikasi antar-fungsi, episode 10 mengatur komunikasi antara program dan sistem operasi. Syscall adalah satu-satunya jembatan resmi menuju kernel: membaca file, menulis ke terminal, mengalokasikan memori, membuat proses. Memahami syscall di level assembly membuat kalian melihat apa yang sebenarnya dilakukan libc saat kalian memanggil printf atau read di C.

Mengapa ini penting? Karena di sinilah letak perbedaan paling kentara antara "program assembly" dan "program C": assembly murni bisa berjalan tanpa libc sama sekali (seperti Hello World kita di episode 3) — cukup syscall. Dan saat kalian memakai strace (episode 16), kalian akan melihat jejak syscall inilah yang terbaca.

Instruksi syscall dan Mekanismenya

Di Linux x86-64, instruksi syscall mentransfer kontrol dari user space ke kernel. Konvensi panggilannya bukan System V biasa, melainkan khusus:

RegisterIsi
raxnomor syscall
rdiargumen 1
rsiargumen 2
rdxargumen 3
r10argumen 4 (bukan rcx!)
r8argumen 5
r9argumen 6
returnrax (nilai negatif = errno negatif)

Important

Perhatikan: argumen ke-4 syscall memakai r10, bukan rcx. Ini karena instruksi syscall sendiri secara internal menimpa rcx dan r11 (untuk menyimpan state). Saat memanggil mmap atau ptrace (yang butuh 4 argumen lebih), kesalahan memakai rcx adalah bug klasik yang hasilnya error ENOSYS atau EFAULT.

Tabel Nomor Syscall

Nomor syscall Linux dapat dilihat di:

Tabel syscall x86-64
grep -E "write|exit|read|open" /usr/include/asm/unistd_64.h

Hasilnya (untuk kernel 64-bit):

/usr/include/asm/unistd_64.h (ringkas)
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_exit 60

Setiap arsitektur punya tabel sendiri: unistd_64.h untuk x86-64, unistd_32.h untuk i386, dan ARM64 memakai tabel yang berbeda lagi. Nomor ini stabil lintas versi kernel — salah satu janji stabilitas ABI Linux.

Fungsi-fungsi yang akan kalian pakai

SyscallNomorArgumenFungsi
read0rdi=fd, rsi=buf, rdx=countbaca dari fd
write1rdi=fd, rsi=buf, rdx=counttulis ke fd
open2rdi=path, rsi=flags, rdx=modebuka file
close3rdi=fdtutup fd
exit60rdi=statushentikan proses
brk12rdi=addralokasi memori heap

Program "Cat" Mini: Baca File dan Cetak

Mari gabungkan semuanya menjadi program yang membaca sebuah file dan mencetak isinya — versi mini cat, murni syscall tanpa libc:

catmini.asm (NASM)
section .data
    path db "hello.txt", 0        ; nama file (null-terminated)
    errmsg db "open failed", 0x0a
    errlen equ $-errmsg
 
section .bss
    buffer resb 4096
 
section .text
    global _start
 
_start:
    ; open("hello.txt", O_RDONLY)
    mov rax, 2
    mov rdi, path
    mov rsi, 0            ; O_RDONLY = 0
    mov rdx, 0
    syscall
    test rax, rax
    js open_failed        ; rax negatif = error
    mov r8, rax           ; simpan fd di r8
 
read_loop:
    ; read(fd, buffer, 4096)
    mov rax, 0
    mov rdi, r8
    mov rsi, buffer
    mov rdx, 4096
    syscall
    test rax, rax
    jz close_file         ; 0 byte = EOF
    js close_file
    mov r9, rax           ; simpan jumlah byte terbaca
 
    ; write(1, buffer, n)
    mov rax, 1
    mov rdi, 1
    mov rsi, buffer
    mov rdx, r9
    syscall
    jmp read_loop
 
close_file:
    mov rax, 3            ; close(fd)
    mov rdi, r8
    syscall
    jmp exit_ok
 
open_failed:
    mov rax, 1
    mov rdi, 1
    mov rsi, errmsg
    mov rdx, errlen
    syscall
    mov rax, 60
    mov rdi, 1
    syscall
 
exit_ok:
    mov rax, 60
    mov rdi, 0
    syscall
Assemble, link, jalankan
cd ~/asm-lab/src
echo "Halo dari file" > hello.txt
nasm -f elf64 catmini.asm -o catmini.o
ld catmini.o -o catmini
./catmini

Output: Halo dari file. Perhatikan detail penting:

  • open mengembalikan fd (deskriptor file) atau errno negatif — pola test rax, rax; js memeriksa tanda untuk mendeteksi error.
  • Kita membaca file berulang (loop) sampai read mengembalikan 0 (EOF). read bisa mengembalikan kurang dari buffer yang diminta — loop adalah praktik yang benar.
  • r8 dan r9 kita pakai sebagai variabel persist selama loop karena bebas dipakai (caller-saved, dan kita memang "caller"-nya).

Tip

Nilai negatif dari syscall adalah errno negatif. Contoh: open file yang tidak ada mengembalikan -2 (ENOENT). Coba jalankan ./catmini di direktori tanpa hello.txt — program kalian menampilkan pesan error buatan sendiri, persis yang dilakukan strace dan tools Unix.

Exit Codes dan Pipe

Karena exit menerima status, program assembly bisa menjadi bagian pipeline Unix:

Exit code sederhana
; exit(42)
mov rax, 60
mov rdi, 42
syscall
Membaca exit code
./prog
echo $?        # 42

Di shell, exit code 0 = sukses, selain itu = error. Ini bahasa yang dipakai script, CI, dan cron untuk tahu program kalian bekerja — jadi biasakan men-set status yang bermakna.

Debugging Syscall dengan strace

strace adalah jendela ke syscall. Jalankan program Hello World episode 3:

Trace syscall program assembly
strace -f ./hello

Output (dipotong) menunjukkan jejak sebenarnya:

Output strace
execve("./hello", ["./hello"], ...) = 0
write(1, "Hello, World!\n", 14) = 14
exit(0) = ?

Perhatikan: hanya dua syscall yang dilakukan — write dan exit. Tidak ada brk, tidak ada pemetaan library, tidak ada pembukaan file, karena program ini tanpa libc dan tanpa runtime. Bandingkan dengan strace ./ls | head -5 — kalian akan melihat puluhan syscall karena libc dan loader ikut bekerja. Perbedaan inilah "kebersihan" assembly murni.

Common Pitfalls

  • Argumen ke-4 harus di r10 (bukan rcx) — lihat Callout di atas.
  • Lupa null-terminate pathopen("hello.txt") tanpa 0 di akhir akan membaca melampaui string.
  • File tidak adaopen mengembalikan negatif; selalu cek sebelum memakai fd.
  • Read loop tidak menangani EOF — loop tak berujung atau meng-cat sampah.
  • Salah nomor syscall antar arsitekturwrite di x86-64 adalah 1, tapi di i386 adalah 4. Selalu cek unistd_64.h.

Penutup

Pada episode 10 ini, kalian telah menghubungkan assembly ke kernel Linux.

Inti yang harus dibawa pulang:

  • syscall dengan nomor di rax, argumen rdi/rsi/rdx/r10/r8/r9; return rax (negatif = errno).
  • Tabel syscall di /usr/include/asm/unistd_64.h; write=1, read=0, exit=60.
  • Program "cat mini" menunjukkan open/read/write/close dan loop baca-print.
  • strace membuka tabir: assembly murni hanya menghasilkan sedikit syscall.
  • Selalu cek nilai return negatif dan handle EOF dengan benar.

Di episode 11 selanjutnya, kita bedah data structures di assembly: section .data dan .bss, direktif db/dw/dd/dq, array dengan times, string null-terminated, dan implementasi manual strlen/strcpy — membangun kembali apa yang kalian tahu dari C, tapi sekarang dengan kendali penuh atas memori. Pastikan flag dan syscall kalian sudah hangat, karena kita mulai menulis program yang mengolah data sungguhan.

Belajar Assembly - Syscalls & Interaksi OS (Linux) | Belajar Assembly