Dua dialek utama assembly x86: sintaks Intel yang dipakai NASM (mov dest, src, dengan size byte/word/dword/qword) dan sintaks AT&T yang dipakai GAS (mov src, dest, dengan suffix b/w/l/q dan prefix % untuk register, $ untuk immediate), beserta cara menerjemahkan antara keduanya dengan percaya diri.

Setelah di episode 3 kalian menjalankan Hello World, kalian pasti sadar ada dua cara menulis instruksi yang sama: NASM (mov rax, 1) dan GAS (mov $1, %rax). Keduanya menghasilkan machine code yang identik, tetapi sintaksnya terlihat seperti dua bahasa berbeda. Episode 4 membedah keduanya sampai tuntas.
Mengapa ini penting? Karena di dunia nyata kalian akan bertemu keduanya terus-menerus: dokumentasi Intel memakai sintaks Intel, kernel Linux dan toolchain GNU memakai AT&T, sedangkan objdump bisa diatur ke keduanya, dan Ghidra/radare2 sering memakai Intel. Kemampuan membaca dua dialek ini akan menyelamatkan kalian berkali-kali — termasuk saat debugging di episode 16.
Sintaks hanyalah cara menulis instruksi; opcode yang dihasilkan tetap sama. Perbedaan mendasar ada tiga:
| Aspek | Intel (NASM) | AT&T (GAS) |
|---|---|---|
| Urutan operan | mov dest, src | mov src, dest |
| Prefix register | Tidak ada | % → %rax |
| Prefix immediate | Tidak ada | $ → $1 |
| Ukuran operan | Keyword (byte/word/dword/qword) | Suffix (b/w/l/q) |
| Alamat memori | [rax + rcx*4 + 16] | 16(%rax,%rcx,4) |
| Komentar | ; | # atau /* */ |
Ini sumber kebingungan nomor satu. Di sintaks Intel, destinasi di kiri: mov rax, rbx berarti "salin rbx ke rax". Di AT&T, sumber di kiri: mov %rbx, %rax berarti hal yang sama. Ingatlah AT&T sebagai "tempatkan A ke B": mov %a, %b → b = a.
Sufiks huruf besar vs kecil tidak masalah; yang penting konsistensi. Untuk semua episode series ini, kode utama memakai NASM (Intel).
Di AT&T, setiap register diawali % (%rax, %rsp) agar tidak tertukar dengan label, dan setiap immediate diawali $ ($42, $-1). Aturan praktis: di GAS, jika tidak ada $, nilai dianggap alamat memori.
Di NASM, ukuran ditentukan oleh nama register atau keyword eksplisit:
mov al, 0x41 ; 8 bit (byte) → AL
mov ax, 0x4142 ; 16 bit (word) → AX
mov eax, 0x41424344 ; 32 bit (dword) → EAX
mov rax, 0x4142434445464748 ; 64 bit (qword) → RAX
; Untuk operan memori yang ambigu, wajib ada keyword:
mov byte [rbx], 0x41
mov word [rbx], 0x4142
mov dword [rbx], 0x41424344
mov qword [rbx], 0x4142434445464748Di GAS, ukuran disandikan sebagai suffix pada mnemonic: b (byte/8), w (word/16), l (long/32), q (quad/64):
movb $0x41, %al
movw $0x4142, %ax
movl $0x41424344, %eax
movq $0x4142434445464748, %rax
movb $0x41, (%rbx)
movw $0x4142, (%rbx)
movl $0x41424344, (%rbx)
movq $0x4142434445464748, (%rbx)Perhatikan: movl berarti operasi 32-bit, bukan "long mode" 64-bit. Suffix ini adalah salah satu tempat tersering programmer NASM tersesat saat baca kode GAS.
Ingat sintaks Intel [rbx + rcx*4 + 16] dari episode 5 (nanti)? Di AT&T, formatnya dibalik dan dipisah koma: 16(%rbx,%rcx,4). Polanya displacement(base,index,scale).
| Intel | AT&T | Arti |
|---|---|---|
[rax] | (%rax) | Alamat di rax |
[rax + 16] | 16(%rax) | rax + 16 |
[rbx + rcx*4] | (%rbx,%rcx,4) | rbx + rcx*4 |
[rbx + rcx*4 + 16] | 16(%rbx,%rcx,4) | rbx + rcx*4 + 16 |
Jika kalian membaca disassembly objdump, ketahui bahwa objdump -d default memakai AT&T, sedangkan objdump -d -M intel menampilkan Intel:
objdump -d hello # AT&T (default)
objdump -d -M intel hello # IntelMari terjemahkan program kecil dari episode 3 antara kedua dialek:
section .data
msg db "Halo", 0x0a
len equ $-msg
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, len
syscall
mov rax, 60
mov rdi, 0
syscall.section .data
msg: .ascii "Halo\n"
len = . - msg
.section .text
.global _start
_start:
mov $1, %rax
mov $1, %rdi
mov $msg, %rsi
mov $len, %rdx
syscall
mov $60, %rax
mov $0, %rdi
syscallTip
Perbedaan lain yang sering menjebak: di GAS, mov $msg, %rsi memuat alamat label msg sebagai immediate. Di NASM, mov rsi, msg juga memuat alamat label (NASM memperlakukan label sebagai alamat). Konsisten di kedua dialek, tapi ingat: tanpa $ di GAS, mov msg, %rsi justru memuat isi memori — 8 byte pertama dari label tersebut.
Di dunia nyata, kalian akan membaca file yang memakai kedua dialek. Berikut translasi cepat untuk instruksi yang paling umum:
| Instruksi (Intel) | Instruksi (AT&T) | Makna |
|---|---|---|
mov eax, ebx | movl %ebx, %eax | eax = ebx |
add rax, 16 | addq $16, %rax | rax += 16 |
cmp eax, 5 | cmpl $5, %eax | bandingkan eax dengan 5 |
lea rax, [rsi+rdi] | leaq (%rsi,%rdi), %rax | rax = rsi + rdi |
call func | call func | panggil func |
push rbp | pushq %rbp | dorong rbp ke stack |
Ingat juga: di AT&T, cmp dan test membalik arah perbandingan. cmp $5, %eax di AT&T setara cmp eax, 5 di Intel — nilai dibandingkan dalam urutan terbalik, dan flag yang dihasilkan ikut terbalik, yang memengaruhi pilihan jump (jl vs jg). Ini pitfall klasik yang membingungkan banyak programmer.
Warning
Hati-hati saat menerjemahkan cmp/test antara dua dialek: karena urutan operan terbalik, kondisi jump yang "jelas" di satu dialek bisa jadi terbalik di dialek lain. Jika ragu, selalu uji dengan input nyata — atau seragamkan ke satu dialek (disarankan NASM/Intel) untuk kode produksi.
Pada episode 4 ini, kalian telah menguasai dua dialek assembly x86.
Inti yang harus dibawa pulang:
mov dest, src, ukuran via keyword byte/word/dword/qword.mov src, dest, prefix %/$, ukuran via suffix b/w/l/q.[rbx+rcx*4+16] vs 16(%rbx,%rcx,4).objdump -d default AT&T; gunakan -M intel untuk Intel.cmp/test saat menerjemahkan jump.Di episode 5 selanjutnya, kita bedah fondasi yang paling sering dipakai: register, tipe data, dan addressing modes x86-64 — peta lengkap register general-purpose rax–r15, sub-register eax/ax/al/ah, flags rflags, serta lima cara CPU mengakses data: immediate, register, direct memory, indirect, dan indexed. Pastikan kalian hafal kedua dialek di episode ini, karena semua kode berikutnya akan memakainya terus.