Oleh: Reza Ervani bin Asmanu
Dalam kode bootloader (boot.S) yang kita tulis untuk Raspberry Pi, terdapat satu baris instruksi yang tampak sederhana namun memegang peran paling krusial dalam transisi dari Assembly ke C:
mov sp, #0x8000
Mengapa kita harus mengatur register sp (Stack Pointer)? Mengapa angka 0x8000 yang dipilih? Artikel ini akan membedah mekanisme memori “Tumpukan” (Stack) pada arsitektur ARM dan strategi tata letak memori yang kita gunakan.
1. Definisi dan Fungsi Stack
Dalam ilmu komputer, Stack adalah area memori khusus yang beroperasi dengan prinsip LIFO (Last In, First Out).
Berbeda dengan memori statis (tempat kita menyimpan variabel global) atau Heap (tempat malloc), Stack bersifat dinamis dan sementara. Bahasa tingkat tinggi seperti C mutlak membutuhkan Stack untuk tiga hal utama:
- Menyimpan Variabel Lokal: Variabel yang dideklarasikan di dalam fungsi (misal:
int i = 0;) hidup di dalam Stack. - Menyimpan Return Address: Saat fungsi A memanggil fungsi B, CPU harus mencatat alamat “jalan pulang” ke fungsi A. Catatan ini disimpan di Stack.
- Preservasi Register: Jika fungsi membutuhkan banyak register untuk berhitung, ia harus menyimpan nilai register lama ke Stack agar tidak menimpa data fungsi sebelumnya.
Tanpa Stack yang terinisialisasi, fungsi main() pada bahasa C tidak akan bisa beroperasi. CPU akan mengalami crash saat mencoba menyimpan variabel lokal pertama.
2. Mekanisme “Full Descending Stack” pada ARM
Salah satu keunikan arsitektur ARM (dan banyak arsitektur modern lainnya) adalah arah pertumbuhan Stack.
- Kode Program & Data: Tumbuh ke atas (dari alamat rendah ke tinggi).
- Contoh: Baris 1 di alamat
0x100, Baris 2 di0x104, dst.
- Contoh: Baris 1 di alamat
- Stack: Tumbuh ke bawah (dari alamat tinggi ke rendah).
- Contoh: Data pertama di
0x8000, data kedua di0x7FFC, dst.
- Contoh: Data pertama di
Ini disebut Descending Stack. Bayangkan seperti membangun gedung pencakar langit (Kode Program) yang tumbuh ke atas, dan menggali sumur (Stack) yang semakin dalam ke bawah.
3. Strategi Alamat 0x8000: Titik Pisah Memori
Mengapa kita memilih angka 0x8000? Keputusan ini didasarkan pada tata letak memori standar Raspberry Pi dan efisiensi pemisahan ruang.
Mari kita visualisasikan peta memori di sekitar alamat 0x8000:
ALAMAT TINGGI (High Address)
^
|
+-----+------------------+
| ... | (Memori Bebas) |
| | |
| | KERNEL (Kode OS) | <-- Kernel tumbuh ke ATAS
| | (main.c, dll) | (0x8000, 0x8004, 0x8008...)
+-----+------------------+ <-- TITIK MULAI (0x8000)
| | STACK | (sp diset di sini)
| | (Variabel Lokal) | <-- Stack tumbuh ke BAWAH
| | | (0x7FFC, 0x7FF8, 0x7FF4...)
+-----+------------------+
| ... | |
| | (Exception Table)|
+-----+------------------+
|
ALAMAT RENDAH (Low Address)
Logika “Punggung-punggungan”
Dengan mengatur sp tepat di 0x8000:
- Kernel (Kernel Image): Dimuat oleh GPU mulai dari
0x8000dan menempati alamat0x8000ke atas (misal:0x8000s.d0x8100). - Stack: Kita inisialisasi pointer di
0x8000. Ketika ada data yang dimasukkan (push) ke stack, pointer akan bergeser turun (dikurangi) terlebih dahulu.- Data pertama akan masuk di
0x7FFC(4 byte di bawah 0x8000). - Data kedua di
0x7FF8.
- Data pertama akan masuk di
Keuntungan:
Dengan strategi ini, Kernel dan Stack bergerak menjauh satu sama lain. Kita tidak perlu menghitung secara manual berapa ukuran Kernel kita agar tidak tertabrak oleh Stack. Selama Stack tidak tumbuh terlalu besar hingga mencapai alamat 0x0000 (Stack Overflow), sistem kita aman.
4. Bedah Instruksi
mov sp, #0x8000
Mari kita terjemahkan instruksi ini ke dalam bahasa manusia yang formal:
mov(Move): Instruksi transfer data. Salin nilai di sebelah kanan (source) ke lokasi di sebelah kiri (destination).#0x8000(Immediate Value): Nilai konstan heksadesimal 8000.sp(Stack Pointer / R13): Register R13 pada ARM yang didedikasikan untuk menyimpan alamat puncak tumpukan.
Interpretasi Sistem:
“Wahai CPU, sebelum engkau menjalankan kode C yang rumit, tetapkanlah titik awal tumpukanmu di alamat memori 0x8000. Jika nanti kode C meminta ruang penyimpanan sementara, mulailah mengalokasikannya dari alamat di bawah 0x8000.”
Kesimpulan
Baris mov sp, #0x8000 adalah batas demarkasi. Sebelum baris ini, kita berada di dunia yang tidak stabil tanpa memori sementara. Setelah baris ini, lingkungan runtime C tercipta, memungkinkan kita memanggil fungsi, membuat variabel, dan menjalankan logika sistem operasi yang kompleks dengan aman.
