Belajar Assembly - ARM64 Assembly (aarch64)
Episode 15 of 23

Belajar Assembly - ARM64 Assembly (aarch64)

Menyeberang ke dunia RISC: assembly ARM64 (aarch64) dengan register x0-x30 dan w0-w30, instruksi ldr/str load-store, add/sub dengan extended register, conditional branch b.eq dan branch on zero cbz, bl/ret untuk fungsi, calling convention AAPCS64, serta perbandingan langkah demi langkah melawan x86-64.

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

Pendahuluan

Sejauh ini seluruh series memakai x86-64. Episode 15 menyeberang ke arsitektur yang menguasai dunia mobile dan kini merambah laptop (Apple Silicon) dan server (AWS Graviton): ARM64 (aarch64). Jangan khawatir — 80% konsep yang kalian pelajari di episode 2–11 berlaku identik: register, stack, calling convention, endianness. Yang berubah adalah dialek dan filosofi instruksinya.

Mengapa penting? Karena di dunia nyata, kalian tidak selalu punya pilihan arsitektur. ARM64 adalah default di hampir semua smartphone, banyak VPS hemat, dan kini laptop. Menulis assembly ARM64 berarti kalian memahami ISA kedua paling penting di dunia.

Perbedaan Filosofi: RISC vs CISC

Aspekx86-64 (CISC)ARM64 (RISC)
Panjang instruksi1–15 byteFixed 32-bit
Akses memoriBisa di dalam instruksi (add rax, [rbx])Load-store: hanya ldr/str yang menyentuh memori
Jumlah register umum1631 (x0x30)
Shift/operasiInstruksi terpisahBisa embedded di operand
ConditionalJump berdasar flag sajaBranch (dengan flags) + beberapa kondisi

Konsekuensi terpenting: di ARM64, kalian harus memuat data ke register dulu, baru mengolahnya. Operasi add [mem], reg seperti di x86 tidak ada.

Register dan Akses

  • x0x30 — register 64-bit.
  • w0w30 — akses 32-bit bawah dari register yang sama.
  • sp — stack pointer (tidak boleh untuk operasi umum).
  • x30link register (LR): tempat alamat kembali hasil bl.
  • xzr — register nol; wzr versi 32-bit (menulis ke sini = buang hasil).

Menulis ke wN menghapus 32 bit atas xN (tidak seperti x86 yang hanya menyentuh sebagian untuk 16/8-bit).

Load-Store: ldr dan str

Load-store dasar
ldr x0, [x1]        ; x0 = *(uint64_t*)x1
ldr w0, [x1]        ; x0 = (uint64_t)*(uint32_t*)x1 (zero-extend)
ldrb w0, [x1]       ; baca 1 byte
str x0, [x1]        ; *(uint64_t*)x1 = x0
strb w0, [x1]       ; tulis 1 byte

Offset dan pre/post-index sangat umum:

Offset addressing
ldr x0, [x1, #16]       ; *(x1 + 16)
ldr x0, [x1, x2, lsl #3] ; *(x1 + x2*8) — elemen array 64-bit
str x0, [sp, #-16]!      ; pre-index: sp -= 16; *(sp) = x0
ldr x0, [sp], #16        ; post-index: x0 = *(sp); sp += 16

Aritmetika: add, sub, dan Shifted Operands

add/sub adalah pola umum RISC: tiga register (dest, src1, src2), dan source kedua bisa di-shift gratis di dalam instruksi:

add dan shifted
add x0, x1, x2       ; x0 = x1 + x2
add x0, x1, #42      ; x0 = x1 + 42
sub x0, x1, #16
add x0, x1, x2, lsl #3    ; x0 = x1 + (x2 << 3)
sub x0, x1, x2, lsr #2    ; x0 = x1 - (x2 >> 2)

Trik ini menggantikan lea x86 — perkalian array dengan add+shift dalam satu instruksi.

Branch dan Conditional

Branch ARM64 bekerja dengan dua cara:

  1. Berdasar flag (set oleh cmp): b.eq, b.ne, b.lt, b.gt, dst.
  2. Berdasar register: cbz (compare-and-branch-if-zero), cbnz (nonzero), tbz/tbnz (bit test).
Conditional branch
cmp x0, #0
b.eq done            ; if (x0 == 0) goto done
cbnz x0, loop        ; if (x0 != 0) goto loop
cbz x0, exit         ; if (x0 == 0) goto exit

Note

Perhatikan sintaksnya: b.eq dengan titik, bukan je seperti x86. Untuk branch tak bersyarat, cukup b label (setara jmp). Dan cmp di ARM64 selalu cmp xN, #nilai — tidak ada keluarga jump terpisah untuk unsigned (ja/jb) seperti x86; untuk perbandingan unsigned, kalian harus memakai cmp + b.hi/b.lo.

Fungsi: bl, ret, dan AAPCS64

Calling convention ARM64 (AAPCS64) mirip System V x86-64:

  • Argumen: x0x7 (8 argumen integer) lalu stack.
  • Return: x0 (dan x1 untuk 128-bit).
  • bl func — branch-and-link: simpan alamat kembali ke x30, lompat ke func.
  • ret — lompat ke alamat di x30.
  • Callee-saved: x19x28 (+ sp, d8d15).
  • Caller-saved: sisanya (x0x18, x30).

Karena x30 menyimpan alamat kembali, fungsi yang memanggil fungsi lain wajib menyimpan x30 ke stack (mirip push alamat kembali di x86). Pola prologue khas:

Fungsi ARM64 (non-leaf)
my_func:
    stp x29, x30, [sp, #-16]!   ; simpan frame pointer + link register
    mov x29, sp                 ; x29 = frame pointer (FP)
    ; ... badan fungsi (bisa memanggil fungsi lain) ...
    ldp x29, x30, [sp], #16     ; pulihkan
    ret

x29 adalah frame pointer (FP) ARM64 — setara rbp. stp/ldp (store/load pair) memuat-menyimpan dua register sekaligus dan wajib aligned 16-byte — alat kerja utama stack ARM64.

Hello World ARM64 (GAS)

hello_arm64.s
.section .data
msg:
    .ascii "Hello ARM64!\n"
len = . - msg
 
.section .text
.global _start
 
_start:
    mov x8, #64        ; syscall write (tabel ARM64)
    mov x0, #1         ; fd = stdout
    ldr x1, =msg       ; alamat buffer
    ldr x2, =len       ; panjang
    svc #0
 
    mov x8, #93        ; syscall exit (ARM64)
    mov x0, #0
    svc #0
Assemble ARM64
aarch64-linux-gnu-as hello_arm64.s -o hello_arm64.o
aarch64-linux-gnu-ld hello_arm64.o -o hello_arm64
qemu-aarch64 ./hello_arm64

Important

Nomor syscall ARM64 berbeda total dari x86-64. Di x86-64, write=1 dan exit=60; di ARM64, write=64 dan exit=93. Dan syscall dijalankan dengan svc #0, bukan syscall, dengan nomor di x8. Jangan pernah menganggap tabel syscall portabel antar arsitektur.

Contoh: Konversi dari x86-64

Mari bandingkan fungsi add_five (episode 9) antara dua arsitektur:

x86-64 (System V)
add_five:
    mov rax, rdi
    add rax, rsi
    add rax, rdx
    add rax, rcx
    add rax, r8
    ret
ARM64 (AAPCS64)
add_five:
    add x0, x0, x1
    add x0, x0, x2
    add x0, x0, x3
    add x0, x0, x4
    ret

Kedua versi menghasilkan fungsi yang sama persis dari perspektif pemanggil C — bukti bahwa ABI dan konsep assembly bersifat universal, hanya dialeknya yang berbeda.

Common Pitfalls

  • Menulis ke wN menghapus bit atas xN — perilaku mirip x86 32-bit write.
  • Memakai sp di operasi umum — tidak valid untuk kebanyakan instruksi.
  • Lupa menyimpan x30 di fungsi non-leaf — ret melompat ke sampah.
  • Shift terbataslsl/lsr #n hanya sampai 63 di ARM64 (bukan 255 seperti x86).
  • Immediate terbatas — konstanta besar perlu ldr xN, =konstanta (assembler yang menyusunnya).
  • Salah tabel syscall (x8 + nomor ARM64) — lihat Callout di atas.

Penutup

Pada episode 15 ini, kalian telah menaklukkan arsitektur RISC paling berpengaruh di dunia.

Inti yang harus dibawa pulang:

  • ARM64 = RISC load-store: hanya ldr/str yang menyentuh memori; instruksi fixed 32-bit.
  • Register x0x30 (w0w30 = 32-bit), sp, xzr, link register x30.
  • add/sub dengan shifted operands menggantikan lea; b.eq/cbz menggantikan je/jrcxz.
  • AAPCS64: argumen x0x7, return x0, callee-saved x19x28; bl simpan ke x30.
  • Syscall: svc #0 dengan nomor di x8 — tabelnya berbeda dari x86-64.

Di episode 16 selanjutnya, kalian memakai semua yang sudah dipelajari untuk melihat ke dalam program: debugging & reverse engineering dengan gdb (breakpoint, stepi, x/), objdump -d, readelf, strace, hingga pengenalan Ghidra/IDA dan radare2/rizin. Saatnya membalik posisi: dari penulis menjadi pembaca kode mesin.

Belajar Assembly - ARM64 Assembly (aarch64) | Belajar Assembly