Memahami Assembler Directives pada GNU Assembler (GAS): Bedah Kode boot.S

Oleh: Reza Ervani bin Asmanu

Dalam pemrograman bahasa rakitan (assembly), kode yang kita tulis tidak sepenuhnya terdiri dari instruksi yang dieksekusi oleh prosesor (CPU). Terdapat kategori perintah khusus yang ditujukan bukan untuk perangkat keras, melainkan untuk perangkat lunak penerjemah itu sendiri (Assembler). Perintah-perintah ini dikenal sebagai Assembler Directives atau Pseudo-operations.

Pada berkas boot.S yang kita gunakan untuk inisialisasi Raspberry Pi, terdapat dua directive krusial yang diawali dengan tanda titik (.), yaitu .section dan .global. Artikel ini akan membahas fungsi teknis dan implikasi arsitektural dari kedua directive tersebut dalam lingkungan GNU Assembler (GAS).

1. Definisi Assembler Directives

Assembler Directives adalah perintah administratif yang mengontrol proses perakitan kode. Jika instruksi mesin (seperti MOV, ADD, BL) diterjemahkan secara langsung menjadi kode biner untuk dieksekusi CPU, maka directives berfungsi untuk mengatur tata letak memori, visibilitas simbol, dan struktur berkas objek (.o) yang dihasilkan.

CPU tidak pernah “melihat” directives ini. Mereka dieksekusi dan diselesaikan pada saat kompilasi (compile-time), bukan saat eksekusi (run-time).

2. Analisis Directive .section

Salah satu tugas utama seorang pengembang OS adalah manajemen memori (Memory Layout). Di sinilah directive .section memegang peranan vital.

Sintaks

.section ".text.boot"

Penjelasan Teknis

Dalam format berkas ELF (Executable and Linkable Format), program dibagi menjadi beberapa segmen logis yang disebut Section. Beberapa section standar meliputi:

  • .text: Berisi kode program (instruksi mesin) yang bersifat read-only.
  • .data: Berisi variabel global yang telah diinisialisasi.
  • .bss: Berisi variabel yang belum diinisialisasi (dialokasikan saat runtime).

Implementasi pada Raspberry Pi

Pada baris kode di atas, kita mendefinisikan sebuah section kustom bernama .text.boot. Kita tidak menggunakan section standar .text secara langsung karena kita memiliki kebutuhan spesifik terkait urutan booting.

  1. Grouping (Pengelompokan): Directive ini memerintahkan assembler untuk menempatkan seluruh kode di bawahnya ke dalam wadah bernama .text.boot.
  2. Linking Control (Kendali Tautan): Nama .text.boot ini menjadi referensi bagi Linker (melalui skrip linker.ld).

Dalam skrip linker.ld, kita menginstruksikan Linker untuk mengambil section .text.boot ini dan meletakkannya tepat di alamat memori 0x8000.

Mengapa ini krusial? Karena bootloader bawaan Raspberry Pi (GPU Firmware) diprogram secara keras (hardcoded) untuk melompat ke alamat fisik 0x8000 saat menyalakan CPU ARM. Dengan memisahkan kode ini ke dalam section khusus .text.boot, kita menjamin bahwa instruksi pertama yang ditemui CPU adalah kode inisialisasi kita, bukan kode fungsi lain yang mungkin teracak posisinya.

3. Analisis Directive .global

Dalam proyek perangkat lunak yang kompleks, kode seringkali dipecah menjadi beberapa berkas (modular). Directive .global mengatur visibilitas simbol antar-modul tersebut.

Sintaks

.global _start

Penjelasan Teknis

Secara default, label atau simbol (seperti _start:, loop:, atau halt:) yang didefinisikan dalam assembly bersifat Lokal. Artinya, simbol tersebut hanya dikenali di dalam berkas tempat ia ditulis dan tidak terlihat oleh berkas lain atau oleh Linker.

Directive .global mengubah atribut simbol tersebut menjadi Global (External Linkage).

Peran dalam Entry Point

Pada kasus _start:

  1. Simbol Eksternal: Dengan mendeklarasikan .global _start, kita memberitahu Assembler untuk mencatat _start dalam tabel simbol (symbol table) berkas objek sebagai simbol yang bisa diakses dari luar.
  2. Referensi Linker: Linker (ld) membutuhkan titik masuk (entry point) untuk mengetahui di mana eksekusi program dimulai. Secara konvensi standar GNU, titik masuk ini diberi nama _start.
  3. Resolusi Alamat: Jika kita memiliki berkas C yang ingin memanggil fungsi assembly, atau sebaliknya, simbol-simbol tersebut wajib dideklarasikan sebagai .global. Tanpa directive ini, Linker akan mengeluarkan pesan kesalahan “undefined reference” karena ia tidak dapat menemukan alamat dari label tersebut.

Kesimpulan

Kedua directive di atas bekerja secara sinergis untuk membentuk fondasi eksekusi program:

  1. .section ".text.boot" memastikan lokasi fisik kode berada di tempat yang benar (0x8000) agar bisa ditemukan oleh hardware/bootloader.
  2. .global _start memastikan alamat logika kode dapat ditemukan dan dikelola oleh software (Linker) sebagai pintu masuk program.

Tanpa pemahaman yang tepat mengenai directives ini, kode assembly yang valid sekalipun tidak akan dapat berjalan karena gagal ditempatkan pada struktur memori yang dipersyaratkan oleh sistem.