Selain jawaban lain, saya ingin menambahkan bahwa ketika mengukir RAM antara stack dan heap space, Anda juga perlu mempertimbangkan ruang untuk data statis yang tidak konstan (misalnya file global, statika fungsi, dan program-lebar) global dari perspektif C, dan mungkin yang lain untuk C ++).
Cara alokasi tumpukan / tumpukan bekerja
Perlu dicatat bahwa file perakitan startup adalah salah satu cara untuk mendefinisikan wilayah; toolchain (baik lingkungan build Anda dan lingkungan run-time) kebanyakan peduli tentang simbol yang menentukan awal stackspace (digunakan untuk menyimpan pointer stack awal di Tabel Vektor) dan awal dan akhir ruang tumpukan (digunakan oleh dinamis pengalokasi memori, biasanya disediakan oleh libc Anda)
Dalam contoh OP, hanya 2 simbol yang didefinisikan, ukuran tumpukan di 1kiB dan ukuran tumpukan di 0B. Nilai-nilai ini digunakan di tempat lain untuk benar-benar menghasilkan ruang tumpukan dan tumpukan
Dalam contoh @Gilles, ukurannya didefinisikan dan digunakan dalam file assembly untuk mengatur ruang stack mulai dari mana pun dan berlangsungnya ukuran, diidentifikasi oleh simbol Stack_Mem dan menetapkan label __initial_sp di akhir. Demikian juga untuk heap, di mana spasi adalah simbol Heap_Mem (ukuran 0,5kiB), tetapi dengan label di awal dan akhir (__heap_base dan __heap_limit).
Ini diproses oleh linker, yang tidak akan mengalokasikan apa pun di dalam ruang stack dan heap space karena memori tersebut ditempati (oleh simbol Stack_Mem dan Heap_Mem), tetapi ini dapat menempatkan memori itu dan semua global di mana pun ia butuhkan. Label akhirnya menjadi simbol tanpa panjang di alamat yang diberikan. __Initial_sp digunakan langsung untuk tabel vektor pada waktu tautan, dan __heap_base dan __heap_limit oleh kode runtime Anda. Alamat simbol yang sebenarnya diberikan oleh penghubung berdasarkan tempat penempatannya.
Seperti yang saya singgung di atas, simbol-simbol ini sebenarnya tidak harus berasal dari file startup.s. Mereka dapat berasal dari konfigurasi linker Anda (Menyebarkan file di Keil, linkerscript di GNU), dan pada mereka Anda dapat memiliki kontrol yang lebih halus atas penempatan. Misalnya, Anda bisa memaksa tumpukan berada di awal atau akhir RAM, atau menjauhkan global Anda dari tumpukan, atau apa pun yang Anda inginkan. Anda bahkan dapat menentukan bahwa HEAP atau STACK hanya menempati RAM apa pun yang tersisa setelah global ditempatkan. Perhatikan bahwa Anda harus berhati-hati dalam menambahkan lebih banyak variabel statis sehingga memori Anda yang lain akan berkurang.
Namun, setiap toolchain berbeda, dan cara menulis file konfigurasi dan simbol apa yang akan digunakan pengalokasi memori dinamis Anda harus berasal dari dokumentasi lingkungan khusus Anda.
Ukuran Stack
Mengenai cara menentukan ukuran tumpukan, banyak toolchains dapat memberi Anda kedalaman tumpukan maksimum dengan menganalisis pohon panggilan fungsi program Anda, JIKA Anda tidak menggunakan rekursi atau pointer fungsi. Jika Anda menggunakannya, perkirakan ukuran tumpukan dan pra-mengisinya dengan nilai-nilai kardinal (mungkin melalui fungsi entri sebelum utama) dan kemudian periksa setelah program Anda berjalan untuk sementara waktu di mana kedalaman maksimumnya (di mana nilai-nilai kardinal akhir). Jika Anda telah sepenuhnya menjalankan program hingga batasnya, Anda akan tahu secara cukup akurat apakah Anda dapat mengecilkan tumpukan atau, jika program Anda macet atau tidak ada nilai kardinal yang tersisa, Anda perlu menambah tumpukan dan coba lagi.
Heap Sizing
Menentukan ukuran tumpukan lebih tergantung aplikasi. Jika Anda hanya melakukan alokasi dinamis selama startup, Anda bisa menambahkan ruang yang diperlukan dalam kode startup Anda (ditambah beberapa overhead untuk manajemen memori). Jika Anda memiliki akses ke sumber manajer memori Anda, Anda bisa tahu persis apa overhead-nya, dan bahkan mungkin menulis kode untuk menggerakkan memori untuk memberi Anda informasi penggunaan. Untuk aplikasi yang membutuhkan memori runtime dinamis (mis. Mengalokasikan buffer untuk frame ethernet masuk) yang terbaik yang bisa saya sarankan adalah dengan hati-hati mengasah stacksize Anda dan memberikan Heap segala yang tersisa setelah stack dan statika.
Catatan akhir (RTOS)
Pertanyaan OP ditandai dengan bare-metal, tapi saya ingin menambahkan catatan untuk RTOS. Seringkali (selalu?) Setiap tugas / proses / utas (saya hanya akan menulis tugas di sini untuk kesederhanaan) akan diberi ukuran tumpukan ketika tugas dibuat, dan selain tumpukan tugas, kemungkinan akan ada OS kecil tumpukan (digunakan untuk interupsi dan semacamnya)
Struktur akuntansi tugas dan tumpukan harus dialokasikan dari suatu tempat, dan ini akan sering berasal dari ruang tumpukan keseluruhan aplikasi Anda. Dalam kasus ini, ukuran tumpukan awal Anda sering tidak masalah, karena OS hanya akan menggunakannya selama inisialisasi. Saya telah melihat, misalnya, menentukan SEMUA ruang yang tersisa selama penautan dialokasikan ke HEAP dan menempatkan penumpukan tumpukan awal di ujung heap untuk tumbuh menjadi heap, mengetahui bahwa OS akan mengalokasikan mulai dari awal heap dan akan mengalokasikan tumpukan OS sebelum meninggalkan tumpukan initial_sp. Kemudian semua ruang digunakan untuk mengalokasikan tumpukan tugas dan memori yang dialokasikan secara dinamis lainnya.