Direktif data

Definisi data dengan db, dw, dd, dan dq, pemesanan ruang dengan times dan resb, serta konstanta equ.

Daftar isi

Data yang digunakan program harus dideklarasikan terlebih dahulu sebelum dapat dibaca lewat mode pengalamatan. Topik ini membahas direktif definisi data NASM untuk setiap ukuran nilai, cara memesan ruang kosong di section .data maupun .bss, dan konstanta equ yang hanya berlaku pada saat perakitan. Seluruh mekanismenya dibuktikan dengan satu program yang mencetak nilai setiap jenis data, ditambah pengukuran ukuran berkas objek yang memperlihatkan perbedaan ruang berkas antara .data dan .bss.

Direktif definisi data#

Empat direktif dasar menyimpan nilai yang sudah ditentukan sejak perakitan. Direktif db menulis satu byte, dw dua byte, dd empat byte, dan dq delapan byte, sesuai singkatan define byte, define word, define doubleword, dan define quadword. Beberapa nilai dapat ditulis berurutan dalam satu baris dengan pemisah koma, sehingga satu direktif dq dapat membuat sebuah array sekaligus.

DirektifUkuranContoh penulisan
db1 bytesuhu db 28
dw2 bytetegangan dw 220
dd4 bytedetak dd 2400000000
dq8 bytewaktu dq 3600000000000

String juga dideklarasikan dengan db, karena string pada dasarnya adalah deretan byte berisi kode ASCII. Tanda kutip ganda atau tunggal sama-sama diterima oleh NASM, dan byte 10 di akhir menambahkan newline agar tulisannya berpindah baris saat dicetak. Berbeda dengan bahasa C, NASM tidak menambahkan byte penutup nol secara otomatis, sehingga panjang string menjadi tanggung jawab penulis program. Kebiasaan yang menyelamatkan banyak program adalah menaruh direktif times untuk ruang bernilai nol, misalnya times 8 db 0 yang menuliskan byte 0 sebanyak delapan kali berurutan.

Konstanta equ dan panjang terhitung#

Direktif equ mendefinisikan konstanta yang hanya digunakan pada saat perakitan dan tidak menempati satu byte memori pun. Konstanta itu dapat digunakan sebagai nilai langsung pada instruksi, sebagai operand mov, atau dalam perhitungan konstanta lain.

nasm
; tidak-dijalankan
; konstanta equ hanya hidup saat perakitan
JUMLAH_ELEMEN  equ 8
UKURAN_ELEMEN  equ 8
TOTAL_BYTE     equ JUMLAH_ELEMEN * UKURAN_ELEMEN   ; 64

mov rdi, TOTAL_BYTE               ; dipakai sebagai nilai langsung

Pola paling sering digunakan bersama equ adalah perhitungan panjang data dengan simbol $, yaitu penanda posisi assembler saat ini. Ekspresi PANJANG equ $ - pesan yang ditulis tepat setelah definisi pesan menghasilkan selisih posisi terhadap awal data tersebut, sehingga panjang string terhitung otomatis setiap kali isinya diubah. Pola ini menghapus satu sumber error yang lazim, yaitu panjang yang diketik secara manual dan tidak ikut berubah ketika string diperbaiki.

Program contoh#

Program berikut mendeklarasikan satu data untuk setiap ukuran, lalu mencetak nilai satu per satu beserta panjang pesan hasil perhitungan $ - label. Setiap pemuatan nilai menggunakan register seukuran datanya, sehingga jumlah byte yang dibaca sesuai dengan direktif yang mendeklarasikannya.

nasm data.asm
; data.asm, definisi data dengan db, dw, dd, dq, times, resb, dan equ
default rel

BATAS_ATAS   equ 100                ; konstanta waktu rakit, tidak menempati memori

section .data
    pesan     db "Sensor suhu terbaca", 10
    PANJANG   equ $ - pesan          ; 20 byte, terhitung otomatis
    suhu      db 28
    tegangan  dw 220
    detak     dd 2400000000
    waktu     dq 3600000000000
    nol       times 8 db 0

    label1  db "panjang pesan = "
    len1    equ $ - label1
    label2  db "suhu (db) = "
    len2    equ $ - label2
    label3  db "tegangan (dw) = "
    len3    equ $ - label3
    label4  db "detak (dd) = "
    len4    equ $ - label4
    label5  db "waktu (dq) = "
    len5    equ $ - label5

section .bss
    buffer    resb 64
    hitungan  resd 1
    digit     resb 25

section .text
global _start

_start:
    lea  rsi, [pesan]
    mov  rdx, PANJANG
    call cetak_teks

    lea  rsi, [label1]
    mov  rdx, len1
    mov  rax, PANJANG
    call cetak_baris

    lea  rsi, [label2]
    mov  rdx, len2
    movzx rax, byte [suhu]        ; muat 1 byte sesuai ukuran db
    call cetak_baris

    lea  rsi, [label3]
    mov  rdx, len3
    movzx rax, word [tegangan]    ; muat 2 byte sesuai ukuran dw
    call cetak_baris

    lea  rsi, [label4]
    mov  rdx, len4
    mov  eax, [detak]             ; muat 4 byte, bagian atas rax otomatis nol
    call cetak_baris

    lea  rsi, [label5]
    mov  rdx, len5
    mov  rax, [waktu]             ; muat 8 byte sesuai ukuran dq
    call cetak_baris

    mov  rdi, BATAS_ATAS          ; konstanta equ dipakai sebagai immediate
    mov  rax, 60
    syscall

cetak_baris:                  ; rsi = alamat label, rdx = panjang label, rax = nilai
    push rax
    call cetak_teks
    pop  rax
    call cetak_angka
    ret

cetak_teks:                   ; tulis rsi sepanjang rdx byte ke stdout
    mov  rax, 1
    mov  rdi, 1
    syscall
    ret

cetak_angka:                  ; tulis rax sebagai desimal tanpa tanda diikuti baris baru
    mov  rbx, 10              ; pembagi
    lea  r12, [digit + 24]
    mov  byte [r12], 10       ; byte newline di ujung buffer
    lea  r12, [digit + 24]
.isi:
    xor  edx, edx
    div  rbx
    add  dl, 48               ; 48 adalah kode ASCII angka 0
    dec  r12
    mov  [r12], dl
    test rax, rax
    jnz  .isi
    lea  rdx, [digit + 25]
    sub  rdx, r12             ; panjang digit ditambah newline
    mov  rsi, r12
    mov  rax, 1
    mov  rdi, 1
    syscall
    ret

section .note.GNU-stack noalloc noexec nowrite progbits
bash
# rakit, tautkan, lalu jalankan program
nasm -f elf64 data.asm -o data.o
ld data.o -o data
./data
echo "exit=$?"
text Keluaran
Sensor suhu terbaca
panjang pesan = 20
suhu (db) = 28
tegangan (dw) = 220
detak (dd) = 2400000000
waktu (dq) = 3600000000000
exit=100

Keluaran memperlihatkan setiap nilai tercetak utuh sesuai ukurannya. Instruksi movzx rax, byte [suhu] memuat satu byte lalu mengisi sisa register dengan nol, sedangkan mov eax, [detak] memuat empat byte dan otomatis mengosongkan 32 bit atas rax. Kode keluar 100 pada baris terakhir berasal dari mov rdi, BATAS_ATAS, yaitu konstanta equ yang digunakan sebagai nilai langsung, sehingga program itu sekaligus membuktikan bahwa konstanta perakitan dapat mengisi instruksi tanpa pernah berada di memori.

Pemesanan ruang dan perbedaan .data dengan .bss#

Section .data menyimpan byte yang benar-benar ditulis ke berkas, sedangkan section .bss hanya menyatakan ukuran tanpa isi. Direktif pemesanan di .bss adalah resb, resw, resd, dan resq untuk 1, 2, 4, dan 8 byte, sesuai singkatan reserve byte sampai reserve quadword. Dua berkas objek berikut memesan 1000 byte pada tempat yang berbeda, dan perbedaannya langsung terlihat pada ukuran berkasnya.

nasm ruang-data.asm
; ruang-data.asm, seribu byte di section .data
section .data
nol: times 1000 db 0
nasm ruang-bss.asm
; ruang-bss.asm, seribu byte di section .bss
section .bss
nol: resb 1000
bash
nasm -f elf64 ruang-data.asm -o ruang-data.o
nasm -f elf64 ruang-bss.asm -o ruang-bss.o

# bandingkan ukuran kedua berkas objek
wc -c ruang-data.o ruang-bss.o
text Keluaran
1568 ruang-data.o
 544 ruang-bss.o
2112 total

Kedua berkas memesan 1000 byte yang sama, tetapi ruang-data.o berukuran 1568 byte karena byte nol itu benar-benar tertulis di dalamnya, sedangkan ruang-bss.o hanya berukuran 544 byte karena .bss tidak menyimpan isi sama sekali. Ukuran .bss hanya berupa catatan yang dibaca loader saat program dijalankan, sehingga 1000 byte itu baru benar-benar dialokasikan di memori tanpa pernah membebani berkas. Pada program utama data, perintah size merangkum ketiga section tersebut.

bash
# periksa ukuran section pada program utama
size data
text Keluaran
   text	   data	    bss	    dec	    hex	filename
    244	    113	    100	    457	    1c9	data

Kolom text berisi kode instruksi berukuran 244 byte, kolom data berisi 113 byte dari 43 byte data utama ditambah 70 byte string label, dan kolom bss berisi 100 byte dari 93 byte yang dipesan ditambah pembulatan penyelarasan yang dilakukan linker. Kolom dec dan hex hanyalah jumlah ketiganya dalam desimal dan heksadesimal. Perbandingan ini sekaligus menunjukkan bahwa memindahkan data besar dari .data ke .bss memangkas ukuran berkas tanpa mengubah perilaku program.

Kesalahan umum#

Menaruh resb di section .data. Direktif pemesanan memang dirakit, tetapi NASM memberi warning dan mengisinya dengan nol di dalam berkas, sehingga tujuan hemat ruang .bss tidak tercapai. Perbaikannya adalah memindahkan deklarasi itu ke section .bss, sebagaimana dibuktikan perintah berikut.

bash
# resb di .data memunculkan warning, bukan error
cat > salah-tempat.asm <<'EOF'
section .data
isi: resb 8
EOF

nasm -f elf64 salah-tempat.asm -o salah-tempat.o
echo "exit=$?"
text Keluaran
salah-tempat.asm:2: warning: uninitialized space declared in non-BSS section `.data': zeroing [-w+zeroing]
exit=0

Mengira string otomatis diberi penutup. NASM menyimpan byte persis seperti yang ditulis, sehingga db "AB" hanya menghasilkan dua byte tanpa nol penutup. Penulisan ke terminal yang menggunakan panjang lebih besar dari isi sebenarnya akan menyertakan byte acak yang bersebelahan. Selalu hitung panjangnya dengan pola NAMA equ $ - label yang diletakkan tepat setelah data yang diukur.

Memperlakukan equ seperti variabel. Konstanta equ tidak menempati memori dan tidak dapat diubah saat program berjalan, karena nilainya disubstitusi oleh assembler. Data yang nilainya berubah selama eksekusi harus dideklarasikan di .data dengan nilai awal atau di .bss sebagai ruang kosong.

Ringkasan#

  • Direktif db, dw, dd, dan dq menyimpan data 1, 2, 4, dan 8 byte sekaligus menjadi sarana penulisan string, sedangkan times N db 0 mengulang satu nilai berkali-kali.
  • Section .bss memesan ruang dengan resb, resw, resd, dan resq tanpa menambah ukuran berkas, karena isinya hanya catatan ukuran, sedangkan ruang yang dipesan diisi nol oleh kernel saat program dimuat.
  • Konstanta equ hanya berlaku pada saat perakitan, digunakan sebagai nilai langsung, dan bersama $ - label menghitung panjang data secara otomatis.
  • Perintah size mengelompokkan isi program ke dalam kolom text, data, dan bss sehingga dampak penempatan data terhadap ukuran berkas terlihat langsung.

Referensi#