Belajar Assembly - Macro, Struct & Conditional Assembly (NASM)
Episode 13 of 23

Belajar Assembly - Macro, Struct & Conditional Assembly (NASM)

Menjadikan NASM bahasa yang produktif: %define dan %assign untuk konstanta, %macro/%endmacro untuk instruksi baru dengan parameter, %if/%ifdef untuk kompilasi bersyarat (misal dukungan multi-platform), struc/istruc untuk layout struct yang rapi, dan %include untuk modularisasi file assembly.

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

Pendahuluan

Sejauh ini kalian menulis assembly dengan gaya "flat": setiap instruksi ditulis ulang, setiap konstanta muncul mentah-mentah. Episode 13 menunjukkan bahwa NASM bukan sekadar assembler — ia punya preprocessor yang membuat kalian bisa menulis kode yang terstruktur, dapat dipakai ulang, dan bahkan bersyarat.

Mengapa penting? Karena di dunia nyata, file assembly sering menjadi bagian dari build system yang kompleks: kode yang sama harus bisa dikompilasi untuk Linux dan Windows, atau dengan fitur yang berbeda-beda. %if dan macro memungkinkan itu. Dan saat kalian membaca kode proyek open source seperti kernel, kalian akan menemukan pola %macro dan struc ini di mana-mana.

Konstanta: %define dan %assign

%define mirip #define di C — substitusi tekstual. %assign menghitung nilai numerik sekali (tidak bisa di-redefine):

Konstanta
%define SYS_WRITE 1
%define SYS_EXIT 60
%define FD_STDOUT 1
 
%assign BUFFER_SIZE 4096
%assign LINES 3 * BUFFER_SIZE      ; dihitung saat assemble

Penting: %define bersifat tekstual%define SCALE 2*4 akan mengganti teks 2*4, bukan 8. Jika ingin nilai numerik, pakai %assign (atau equ).

Note

Bedakan tiga mekanisme: equ adalah konstanta waktu-assembly untuk ekspresi (misal len equ $-msg), %define adalah substitusi teks preprocessor, dan %assign adalah perhitungan numerik preprocessor. Pilih sesuai kebutuhan — jangan mencampurnya tanpa alasan.

Macro: %macro dan %endmacro

Macro memungkinkan kalian mendefinisikan instruksi baru yang bisa memuat banyak instruksi. Parameternya direferensikan sebagai %1, %2, dst, dan jumlah parameter bisa bervariasi dengan %0:

Macro dengan parameter
; Macro: syscall 3-argumen yang umum
%macro syscall3 4
    mov rax, %1
    mov rdi, %2
    mov rsi, %3
    mov rdx, %4
    syscall
%endmacro
 
; Macro: cetak string di .data
%macro print_str 1
    mov rax, 1
    mov rdi, 1
    mov rsi, %1
    mov rdx, %1_len
    syscall
%endmacro
 
section .data
    msg db "Halo macro!", 0x0a
    msg_len equ $-msg
 
section .text
    global _start
_start:
    print_str msg        ; mencetak msg
    syscall3 60, 0, 0, 0 ; exit(0)

Perhatikan syscall3 4 — angka 4 setelah nama macro adalah jumlah parameter yang wajib. print_str di atas mengasumsikan label %1_len ada; pola ini umum di codebase NASM.

Macro dengan Label Lokal

Macro yang berisi jmp/loop butuh label unik per pemanggilan. NASM menyediakan %%label — label lokal per-expansi macro:

Macro dengan label lokal
%macro repeat_call 2       ; %1 = counter, %2 = target
    mov rcx, %1
%%loop:
    call %2
    loop %%loop
%endmacro

Setiap kali repeat_call dipanggil, %%loop menjadi label yang berbeda — tanpa ini, label ganda akan membuat NASM error.

Conditional Assembly: %if, %ifdef, %ifndef

Preprocessor NASM mendukung cabang bersyarat — kode hanya di-assemble jika kondisi terpenuhi:

Conditional assembly
%define TARGET_LINUX
 
%ifdef TARGET_LINUX
    %define SYS_EXIT 60
%elifdef TARGET_WINDOWS
    %define SYS_EXIT 60
%else
    %define SYS_EXIT 1
%endif
 
%if BUFFER_SIZE > 4096
    %assign BUF_STR 1
%else
    %assign BUF_STR 0
%endif

Direktif yang tersedia: %ifdef, %ifndef, %if, %elif, %elifdef, %else, %endif. Kondisi di %if memakai ekspresi aljabar biasa (==, >, &, dst). Ini cara standar untuk multi-platform build.

Tip

Pola produksi yang umum: compile-time flag untuk mengendalikan fitur. Misal nasm -f elf64 -DTARGET_LINUX -o file.o file.asm — flag -D di command line setara %define. Ini memungkinkan satu file sumber untuk banyak target tanpa mengedit kode.

Struktur Data: struc dan istruc

Di episode 11 kita menghitung offset struct secara manual. NASM menyediakan struc/endstruc untuk mendefinisikan layout dengan nama field:

struc dan istruc
struc Person
    .age    resd 1     ; offset 0  (int)
    .pad1   resd 1     ; offset 4  (padding 4 byte)
    .id     resq 1     ; offset 8  (long, aligned 8)
    .name   resb 32    ; offset 16 (char[32])
endstruc
 
section .data
    person1 istruc Person
        at Person.age, dd 25
        at Person.id,  dq 1001
        at Person.name, db "Alice", 0
    iend
 
section .text
    ; person1.age = 30
    mov dword [person1 + Person.age], 30
    ; memuat person1.id
    mov rax, [person1 + Person.id]

istruc...iend mengisi struct dengan nilai awal; at Person.field memastikan nilai diletakkan di offset yang benar. Akses field jadi [base + Person.nama_field] — jauh lebih terbaca daripada offset mentah.

Modularisasi: %include

%include menyisipkan isi file lain secara tekstual — cara NASM memecah kode besar:

File terpisah
; syscalls.inc
%define SYS_READ   0
%define SYS_WRITE  1
%define SYS_OPEN   2
%define SYS_EXIT   60
main.asm
%include "syscalls.inc"
 
section .text
    global _start
_start:
    mov rax, SYS_WRITE
    ...

Pola umum di proyek nyata: satu file .inc berisi konstanta dan macro, satu file entry.asm berisi _start, dan file-file fungsi yang di-link bersama. Ini membuat codebase assembly tetap bisa dikelola saat tumbuh besar.

Warning

%include adalah penyertaan tekstual murni — file disisipkan apa adanya. Ini berarti: (1) urutan penyertaan penting, (2) setiap file yang di-%include di-assemble ulang setiap kali, dan (3) menyertakan file yang sama dua kali akan meng-define simbol dua kali (error). Gunakan %ifndef guard untuk mencegah double-include.

Common Pitfalls

  • %define tekstual vs %assign numerik — konteks penggunaan menentukan hasil.
  • Macro tanpa jumlah parameter → error misterius; selalu tulis %macro nama jumlah.
  • Label biasa di dalam macro → duplikasi saat dipanggil berulang; pakai %%label.
  • Lupa %endif → NASM error "expected ENDIF" yang menjatuhkan seluruh compile.
  • Struktur alignment — pad field secara eksplisit seperti contoh Person agar akses memori efisien.

Penutup

Pada episode 13 ini, kalian telah mengubah NASM menjadi bahasa yang produktif dan terstruktur.

Inti yang harus dibawa pulang:

  • %define (teks) vs %assign (numerik) vs equ — pilih sesuai kebutuhan.
  • %macro/%endmacro membuat instruksi baru dengan parameter (%1, %2) dan label lokal %%label.
  • %ifdef/%if/%elif/%else memungkinkan kompilasi bersyarat & multi-platform.
  • struc/istruc memberi nama pada offset struct; %include memecah file besar.
  • Guard %ifndef mencegah double-include.

Di episode 14 selanjutnya, kalian menjembatani dua dunia: inline assembly dalam C (GCC) — menulis kode assembly langsung di dalam fungsi C dengan __asm__, belajar constraint "r"/"m"/"=r" dan clobber, serta kapan kalian seharusnya (dan tidak seharusnya) memakai inline asm di produksi. Ini keterampilan yang dipakai kernel Linux dan library seperti glibc setiap hari.

Belajar Assembly - Macro, Struct & Conditional Assembly (NASM) | Belajar Assembly