Peta lengkap register x86-64: general-purpose rax-r15 beserta sub-register eax/ax/al/ah, RFLAGS dan flag ZF CF SF OF, serta instruction pointer RIP. Di episode ini juga dibedah lima addressing mode (immediate, register, direct, indirect, indexed) dan penyimpanan little-endian yang menentukan cara data diletakkan di memori.

Setelah menguasai dua dialek sintaks di episode 4, sekarang kita bedah bahan bakunya: register, tipe data, dan cara CPU mengakses memori. Ketiganya adalah "kosakata" yang membentuk hampir semua instruksi. Tanpa pemahaman ini, kalian hanya akan menghafal contoh — dengan pemahaman ini, kalian mulai berpikir seperti CPU.
Bayangkan register sebagai kotak penyimpanan di meja kerja: ada yang 64-bit besar (qword), ada yang 32-bit, ada yang cuma 1 byte. Memahami register mana yang menyentuh bagian mana dari register lain adalah kunci membaca kode assembly apa pun dengan cepat.
x86-64 punya 16 register general-purpose 64-bit: rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, dan r8–r15. Masing-masing bisa diakses utuh (64-bit) atau sebagian (32/16/8 bit):
| Register 64-bit | 32-bit (bawah) | 16-bit (bawah) | 8-bit (bawah) | 8-bit (atas) |
|---|---|---|---|---|
rax | eax | ax | al | ah |
rbx | ebx | bx | bl | bh |
rcx | ecx | cx | cl | ch |
rdx | edx | dx | dl | dh |
rsi | esi | si | sil | — |
rdi | edi | di | dil | — |
rbp | ebp | bp | bpl | — |
rsp | esp | sp | spl | — |
r8 | r8d | r8w | r8b | — |
| ... | ... | ... | ... | — |
r15 | r15d | r15w | r15b | — |
Important
Pitfall klasik: menulis ke register 32-bit (mov eax, 0x1) secara otomatis menghapus 32 bit atas dari register 64-bit (rax), sedangkan menulis ke register 16/8-bit (mov ax, 1) tidak menyentuh bit atas. Ini adalah salah satu perilaku x86-64 yang paling sering menyebabkan bug halus.
Beberapa register punya peran konvensional yang dipakai sistem operasi dan compiler — kita bedah lengkap saat membahas ABI di episode 9:
rax — hasil return fungsi, dan nomor syscall.rdi, rsi, rdx, rcx, r8, r9 — argumen fungsi (System V).rsp — stack pointer.rbp — base pointer (frame pointer).rcx — counter untuk loop/shift.RIP (Instruction Pointer) menunjuk instruksi berikutnya yang akan dieksekusi — diperkenalkan di episode 2. Kalian tidak bisa menulis ke RIP secara langsung, hanya lewat jmp/call/ret.
RFLAGS adalah register 64-bit berisi flag status. Lima flag yang paling penting bagi kita:
| Flag | Nama | Set ketika |
|---|---|---|
ZF | Zero Flag | hasil operasi nol |
CF | Carry Flag | terjadi carry/borrow (unsigned overflow) |
SF | Sign Flag | hasil negatif (bit tertinggi = 1) |
OF | Overflow Flag | overflow signed |
DF | Direction Flag | arah operasi string (STD/CLD) |
Flag inilah "otak" dari conditional jump (je, jg, dst) di episode 6:
mov rax, 5
sub rax, 5 ; hasil 0 → ZF = 1
sub rax, 1 ; hasil -1 → SF = 1, ZF = 0NASM mendeklarasikan data dengan direktif berikut:
| Direktif | Ukuran | Contoh |
|---|---|---|
db | 1 byte | db 0x41 |
dw | 2 byte | dw 0x4142 |
dd | 4 byte | dd 0x41424344 |
dq | 8 byte | dq 0x4142434445464748 |
resb/resw/resd/resq | reserve (untuk .bss) | resb 64 |
Contoh penggunaan nyata:
section .data
byte_val db 0x41, 0x42, 0x43 ; 3 byte: 'A' 'B' 'C'
word_val dw 0x1234 ; 2 byte
dword_val dd 1000000 ; 4 byte
qword_val dq 0x1122334455667788 ; 8 byte
float32 dd 3.14 ; single precision
float64 dq 2.718281828 ; double precision
str_null db "hello", 0 ; string null-terminated
repeat10 times 10 db 0 ; 10 byte noltimes adalah perkalian deklarasi — berguna sekali untuk array dan buffer, dan kita pakai lagi di episode 11 dan 13.
Ini adalah inti episode ini. "Addressing mode" menjawab pertanyaan: di mana operan berada? CPU x86-64 mendukung lima mode utama:
Nilai ditanam langsung di instruksi:
mov rax, 42
add rbx, 0xffOperan adalah isi register:
mov rax, rbx ; salin isi rbx ke rax
add rcx, rdxAlamat ditulis langsung:
mov rax, [msg] ; muat 8 byte yang dimulai di alamat msg
mov rbx, [0x4000a0] ; alamat absolut (jarang dalam asm modern)Register berisi alamat; [] membongkar isinya. Ini adalah cara kerja pointer C:
mov rax, [rbx] ; rax = *(uint64_t*)rbx
mov [rsi], rdx ; *(uint64_t*)rsi = rdx
mov rax, [rbp-8] ; rax = *(uint64_t*)(rbp-8)Kombinasi lengkap: [base + index*scale + displacement], dengan scale hanya boleh 1, 2, 4, atau 8:
mov rax, [arr + rcx*8] ; elemen ke-rcx dari array 64-bit
mov rax, [rbx + rcx*4 + 16] ; base + index*4 + offset
lea rax, [rsi + rdi] ; lea = hitung alamat, simpan di registerTip
lea (Load Effective Address) tidak membaca memori — ia hanya menghitung alamat dan menyimpannya ke register. Inilah trik favorit compiler untuk menambahkan tiga angka sekaligus: lea rax, [rbx + rcx*4 + 16] sama dengan rax = rbx + rcx*4 + 16, tanpa menyentuh RAM sama sekali.
Dari episode 2 kita tahu x86-64 menyimpan byte terendah di alamat terendah. Mari lihat nyata:
section .data
val dq 0x1122334455667788Di memori, byte tersimpan sebagai:
alamat: +0 +1 +2 +3 +4 +5 +6 +7
byte: 0x88 0x77 0x66 0x55 0x44 0x33 0x22 0x11Membaca dengan mov al, [val] akan memberi 0x88 — byte paling rendah. Inilah alasan mengapa kalian harus konsisten dengan lebar operan saat menulis dan membaca (lihat Callout di episode 2). Untuk membalik urutan byte, x86-64 menyediakan bswap:
mov rax, 0x1122334455667788
bswap rax ; rax = 0x8877665544332211Pada episode 5 ini, kalian telah menguasai kosakata dasar assembly x86-64.
Inti yang harus dibawa pulang:
RIP menunjuk instruksi berikutnya; RFLAGS (ZF, CF, SF, OF) menyimpan status operasi.db (1B), dw (2B), dd (4B), dq (8B); times untuk pengulangan.[base+idx*scale+disp]).bswap untuk membalik.Di episode 6 selanjutnya, kalian mulai membuat program "cerdas": control flow dengan jump dan conditional — jmp tanpa syarat, cmp + je/jne/jg/jl, perbandingan unsigned ja/jb, loop/jrcxz, serta cara fungsi dipanggil lewat call/ret. Saatnya mesin mulai mengambil keputusan!