Section program

Semantik .text, .data, .rodata, dan .bss beserta izin baca-tulis-eksekusi yang menyertai masing-masing.

Daftar isi

Topik ini membahas empat section bawaan NASM, yaitu .text, .data, .rodata, dan .bss, beserta izin baca, tulis, dan eksekusi yang menyertai masing-masingnya. Pemeriksaan dilakukan pada satu berkas objek kecil yang memuat keempatnya, lalu pada executable hasil penautan. Perbedaan ukuran berkas dan ukuran memori pada .bss serta akibat melanggar izin memori ditunjukkan dengan keluaran perkakas binutils yang asli.

Empat section bawaan#

Section adalah bagian dari berkas objek yang menampung byte dengan peruntukan serupa, dan pemisahan inilah dasar penetapan izin memori ketika program dijalankan. Direktif section .text menampung kode instruksi, section .data menampung data terinisialisasi yang boleh diubah, section .rodata menampung konstanta yang tidak boleh diubah, sedangkan section .bss memesan ruang kosong yang diisi nol oleh loader, yaitu bagian sistem operasi yang memuat program ke memori. Nama keempat section tersebut bukan kesepakatan semata, melainkan konvensi yang dikenali linker dan skrip penautan bawaannya, sehingga setiap section berakhir pada segmen dengan izin yang tepat.

SectionIsiIzin memori
.textkode instruksibaca dan eksekusi
.datadata terinisialisasi yang boleh diubahbaca dan tulis
.rodatakonstanta yang tetapbaca saja
.bssruang kosong yang diisi nolbaca dan tulis

Izin ditetapkan per halaman memori (page), satuan pelindungan memori yang dikelola prosesor. Setelah program dimuat, instruksi boleh membaca dan mengeksekusi halaman .text tetapi tidak boleh menulisnya, halaman .rodata hanya boleh dibaca, sedangkan halaman .data dan .bss boleh dibaca sekaligus ditulis. Selain keempat section bawaan tersebut, NASM mengizinkan section kustom melalui direktif section yang diberi kualifier, misalnya section kustom write, dan bentuk ini jarang diperlukan pada program biasa.

Pembacaan header section#

Ukuran, offset berkas, dan penanda setiap section dapat diperiksa dengan objdump -h. Berkas berikut memuat keempat section sekaligus, sehingga keluarannya memperlihatkan semuanya dalam satu tabel. Program ini sengaja tidak menggunakan data yang didefinisikannya, karena tugasnya hanya membentuk struktur section.

nasm section-empat.asm
default rel

section .text
global _start

_start:
    mov  eax, 60         ; syscall exit
    xor  edi, edi        ; kode keluar 0
    syscall

section .data
nilai:   dq 42           ; terinisialisasi, boleh diubah

section .rodata
pesan:   db "data tetap", 10

section .bss
buffer:  resb 8192       ; ruang kosong, diisi nol saat dimuat
bash
# rakit berkas objek tanpa menautkannya
nasm -f elf64 section-empat.asm -o section-empat.o

# tampilkan header setiap section beserta penandanya
objdump -h section-empat.o
text Keluaran
section-empat.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000009  0000000000000000  0000000000000000  00000240  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  00000250  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .rodata       0000000b  0000000000000000  0000000000000000  00000260  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .bss          00002000  0000000000000000  0000000000000000  00000270  2**2
                  ALLOC

Kolom Size menyatakan panjang section dalam heksadesimal, sedangkan File off menyatakan posisi awalnya di dalam berkas. Kolom VMA pada berkas objek masih seragam 0000000000000000 karena alamat final baru ditetapkan ketika penautan dilakukan, sehingga yang relevan pada tahap ini hanyalah Size, File off, dan penandanya. Penanda di bawah setiap baris menjelaskan sifat section lebih lanjut. CONTENTS berarti byte section benar-benar tersimpan di dalam berkas, sedangkan ALLOC berarti ruangnya dialokasikan di memori ketika program dimuat. Section .text, .data, dan .rodata memuat kedua penanda tersebut, sedangkan .bss hanya ALLOC karena tidak menyimpan satu byte pun. Nilai 0x2000 pada .bss berarti 8192 byte, sedangkan 0x0b pada .rodata berarti 11 byte untuk teks “data tetap” beserta karakter baris barunya.

Ukuran berkas dan ukuran memori#

Ukuran .bss yang besar tidak membuat berkas objek membengkak karena byte-nya memang tidak pernah disimpan. Perintah stat menampilkan ukuran kedua berkas secara langsung untuk menunjukkan ketimpangan tersebut.

bash
# ukuran berkas sumber dan berkas objek yang dihasilkannya
stat -c '%s byte %n' section-empat.asm section-empat.o
text Keluaran
338 byte section-empat.asm
976 byte section-empat.o

Seluruh berkas objek hanya 976 byte, padahal .bss di dalamnya memesan 8192 byte ruang memori. Loader memetakan halaman untuk .bss lalu mengisi halaman tersebut dengan nol, tanpa membaca apa pun dari berkas. Pola ini cocok untuk buffer besar yang isinya memang dimulai dari nol, misalnya buffer pembacaan berkas. Buffer semacam ini lazim ditempatkan pada .bss justru karena keadaan awalnya memang nol, sehingga tidak ada byte yang perlu disalin dari berkas pada saat program dimuat. Dengan begitu, waktu muat program tetap singkat sekalipun ruang yang dipesannya besar. Konsekuensinya, variabel pada .bss tidak boleh diberi nilai awal selain nol, sehingga nilai awal lain harus ditempatkan pada .data.

Izin segmen dan pelanggarannya#

Setelah penautan, section yang serupa digabungkan menjadi segment, yaitu rentang memori yang dipetakan dengan satu set izin. Perintah readelf -lW menampilkan program header yang memuat daftar segmen tersebut, dan kolom Flg pada tabelnya menyatakan izin yang digunakan kernel untuk memetakan setiap segmen.

bash
# tautkan menjadi executable, lalu lihat izin tiap segmen
ld section-empat.o -o section-empat
readelf -lW section-empat | grep -E 'LOAD|Type'
text Keluaran
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x000120 0x000120 R   0x1000
  LOAD           0x001000 0x0000000000401000 0x0000000000401000 0x000009 0x000009 R E 0x1000
  LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x00000b 0x00000b R   0x1000
  LOAD           0x00200c 0x000000000040300c 0x000000000040300c 0x000008 0x00200c RW  0x1000

Terdapat empat baris LOAD. Baris pertama berisi header ELF itu sendiri dengan izin baca saja. Baris kedua bertanda R E memuat .text yang boleh dibaca dan dieksekusi. Baris ketiga bertanda R memuat .rodata yang hanya boleh dibaca. Baris keempat bertanda RW menggabungkan .data dan .bss, dengan FileSiz 0x8 dan MemSiz 0x200c karena sebagian besar isinya adalah .bss yang tidak tersimpan di berkas.

Pelanggaran izin dapat dibuktikan dengan program yang menulis ke .rodata.

bash
# program yang menulis byte ke section .rodata
cat > tulis-rodata.asm <<'EOF'
default rel

section .rodata
pesan: db "teks tetap", 10

section .text
global _start

_start:
    mov  byte [pesan], 88
    mov  eax, 60
    xor  edi, edi
    syscall
EOF
nasm -f elf64 tulis-rodata.asm -o tulis-rodata.o
ld tulis-rodata.o -o tulis-rodata

# jalankan lewat sh agar pesan kernelnya terlihat
sh -c ./tulis-rodata
echo "exit=$?"
text Keluaran
Segmentation fault
exit=139

Instruksi mov byte [pesan], 88 berusaha menulis ke halaman .rodata yang hanya boleh dibaca. Prosesor menolak akses tersebut dan mengirim sinyal SIGSEGV kepada proses, sehingga program dihentikan sebelum baris exit sempat dijalankan. Shell melaporkan “Segmentation fault” beserta kode keluar 139, yaitu 128 ditambah nomor sinyal 11. Kode keluar semacam ini bersifat tetap dan dapat digunakan sebagai penanda kuat bahwa sebuah alamat berada pada halaman yang tidak boleh ditulis.

Ringkasan#

  • Section .text, .data, .rodata, dan .bss memisahkan kode, data terinisialisasi, konstanta, dan ruang kosong berisi nol, masing-masing dengan izin baca, tulis, dan eksekusi yang berbeda.
  • Penanda CONTENTS dan ALLOC pada objdump -h membedakan byte yang tersimpan di berkas dari ruang yang hanya dialokasikan di memori.
  • .bss tidak menambah ukuran berkas karena loader mengisinya dengan nol saat program dimuat.
  • Izin ditetapkan per segmen pada program final, dan penulisan ke .rodata berakhir dengan SIGSEGV serta kode keluar 139.

Referensi#