Saya sedang mempersiapkan beberapa materi pelatihan dalam C dan saya ingin contoh saya sesuai dengan model tumpukan yang khas.
Ke arah mana tumpukan C tumbuh di Linux, Windows, Mac OSX (PPC dan x86), Solaris, dan Unix terbaru?
Saya sedang mempersiapkan beberapa materi pelatihan dalam C dan saya ingin contoh saya sesuai dengan model tumpukan yang khas.
Ke arah mana tumpukan C tumbuh di Linux, Windows, Mac OSX (PPC dan x86), Solaris, dan Unix terbaru?
Jawaban:
Pertumbuhan tumpukan biasanya tidak bergantung pada sistem operasi itu sendiri, tetapi pada prosesor yang menjalankannya. Solaris, misalnya, berjalan di x86 dan SPARC. Mac OSX (seperti yang Anda sebutkan) berjalan di PPC dan x86. Linux berjalan pada segala hal mulai dari Sistem z honkin besar saya di tempat kerja hingga jam tangan kecil yang lemah .
Jika CPU menyediakan jenis pilihan apa pun, ABI / konvensi pemanggilan yang digunakan oleh OS menentukan pilihan mana yang perlu Anda buat jika Anda ingin kode Anda memanggil kode orang lain.
Prosesor dan arahannya adalah:
Menunjukkan usia saya pada beberapa yang terakhir, 1802 adalah chip yang digunakan untuk mengontrol angkutan awal (merasakan jika pintunya terbuka, saya curiga, berdasarkan kekuatan pemrosesan yang dimilikinya :-) dan komputer kedua saya, COMX-35 ( mengikuti ZX80 saya ).
Rincian PDP11 dikumpulkan dari sini , rincian 8051 dari sini .
Arsitektur SPARC menggunakan model register jendela geser. Detail arsitektural yang terlihat juga mencakup buffer melingkar dari jendela register yang valid dan di-cache secara internal, dengan perangkap saat over / underflow tersebut. Lihat di sini untuk detailnya. Seperti yang dijelaskan oleh manual SPARCv8 , instruksi SIMPAN dan KEMBALIKAN seperti instruksi TAMBAHKAN ditambah rotasi jendela register. Menggunakan konstanta positif daripada negatif biasa akan menghasilkan tumpukan yang tumbuh ke atas.
Teknik SCRT yang disebutkan di atas adalah teknik lain - 1802 menggunakan beberapa atau enam belas register 16-bit untuk SCRT (teknik panggilan dan pengembalian standar). Salah satunya adalah penghitung program, Anda dapat menggunakan register apa pun sebagai PC dengan SEP Rn
instruksi. Satu adalah penunjuk tumpukan dan dua ditetapkan selalu untuk menunjuk ke alamat kode SCRT, satu untuk panggilan, satu untuk kembali. Tidak ada register yang diperlakukan dengan cara khusus. Ingatlah bahwa detail ini berasal dari memori, mungkin tidak sepenuhnya benar.
Misalnya, jika R3 adalah PC, R4 adalah alamat panggilan SCRT, R5 adalah alamat pengirim SCRT dan R2 adalah "tumpukan" (tanda kutip seperti yang diterapkan dalam perangkat lunak), SEP R4
akan menetapkan R4 menjadi PC dan mulai menjalankan SCRT kode panggilan.
Ini kemudian akan menyimpan R3 pada R2 "stack" (saya pikir R6 digunakan untuk penyimpanan sementara), menyesuaikannya ke atas atau ke bawah, ambil dua byte setelah R3, muat ke R3, lalu lakukan SEP R3
dan jalankan di alamat baru.
Untuk mengembalikan, itu akan SEP R5
menarik alamat lama dari tumpukan R2, menambahkan dua ke dalamnya (untuk melewati byte alamat panggilan), memuatnya ke R3 dan SEP R3
mulai menjalankan kode sebelumnya.
Sangat sulit untuk membungkus kepala Anda pada awalnya setelah semua kode berbasis tumpukan 6502/6809 / z80 tetapi masih elegan dengan cara yang benar-benar membenturkan kepala Anda ke dinding. Juga salah satu fitur penjualan besar dari chip ini adalah rangkaian lengkap 16 register 16-bit, meskipun faktanya Anda langsung kehilangan 7 register (5 untuk SCRT, dua untuk DMA dan interupsi dari memori). Ahh, kemenangan pemasaran atas realitas :-)
Sistem z sebenarnya sangat mirip, menggunakan register R14 dan R15 untuk panggilan / pengembalian.
Di C ++ (dapat beradaptasi dengan C) stack.cc :
static int
find_stack_direction ()
{
static char *addr = 0;
auto char dummy;
if (addr == 0)
{
addr = &dummy;
return find_stack_direction ();
}
else
{
return ((&dummy > addr) ? 1 : -1);
}
}
static
untuk ini. Sebagai gantinya, Anda bisa meneruskan alamat sebagai argumen ke panggilan rekursif.
static
, jika Anda memanggil ini lebih dari sekali, panggilan berikutnya mungkin gagal ...
Keuntungan tumbuh ke bawah adalah dalam sistem yang lebih lama tumpukan biasanya berada di bagian atas memori. Program biasanya mengisi memori mulai dari bawah sehingga manajemen memori semacam ini meminimalkan kebutuhan untuk mengukur dan menempatkan bagian bawah tumpukan di suatu tempat yang masuk akal.
Di MIPS dan banyak arsitektur RISC modern (seperti PowerPC, RISC-V, SPARC ...) tidak ada push
dan pop
instruksi. Operasi tersebut secara eksplisit dilakukan dengan menyesuaikan penunjuk tumpukan secara manual kemudian memuat / menyimpan nilai secara relatif ke penunjuk yang disesuaikan. Semua register (kecuali register nol) adalah tujuan umum sehingga dalam teori register apa pun dapat menjadi penunjuk tumpukan, dan tumpukan dapat tumbuh ke segala arah yang diinginkan programmer
Meskipun demikian, tumpukan biasanya tumbuh di sebagian besar arsitektur, mungkin untuk menghindari kasus saat tumpukan dan data program atau data tumpukan tumbuh dan bentrok satu sama lain. Ada juga alasan pengalamatan yang bagus menyebutkan jawaban sh- . Beberapa contoh: MIPS ABI tumbuh ke bawah dan menggunakan $29
(AKA $sp
) sebagai penunjuk tumpukan, RISC-V ABI juga tumbuh ke bawah dan menggunakan x2 sebagai penunjuk tumpukan
Di Intel 8051, tumpukan bertambah, mungkin karena ruang memori sangat kecil (128 byte dalam versi asli) sehingga tidak ada heap dan Anda tidak perlu meletakkan tumpukan di atas sehingga akan terpisah dari tumpukan yang berkembang dari bawah
Anda dapat menemukan informasi lebih lanjut tentang penggunaan tumpukan dalam berbagai arsitektur di https://en.wikipedia.org/wiki/Calling_convention
Lihat juga
Hanya sedikit tambahan untuk jawaban lainnya, yang sejauh yang saya lihat belum menyentuh poin ini:
Memiliki tumpukan tumbuh ke bawah membuat semua alamat di dalam tumpukan memiliki offset positif relatif terhadap penunjuk tumpukan. Tidak perlu ada offset negatif, karena offset hanya akan menunjuk ke ruang tumpukan yang tidak digunakan. Ini menyederhanakan mengakses lokasi tumpukan saat prosesor mendukung pengalamatan relatif-stackpointer.
Banyak prosesor memiliki instruksi yang memungkinkan akses dengan offset hanya-positif relatif terhadap beberapa register. Itu termasuk banyak arsitektur modern, serta beberapa yang lama. Misalnya, ARM Thumb ABI menyediakan akses relatif stackpointer dengan offset positif yang dienkode dalam satu kata instruksi 16-bit.
Jika tumpukan tumbuh ke atas, semua offset yang berguna relatif terhadap stackpointer akan menjadi negatif, yang kurang intuitif dan kurang nyaman. Ini juga bertentangan dengan aplikasi lain dari pengalamatan register-relatif, misalnya untuk mengakses bidang struct.
Pada kebanyakan sistem, tumpukan tumbuh turun, dan artikel saya di https://gist.github.com/cpq/8598782 menjelaskan MENGAPA tumpukan itu tumbuh turun. Ini sederhana: bagaimana mengatur tata letak dua blok memori yang berkembang (heap dan stack) dalam satu potongan memori tetap? Solusi terbaik adalah meletakkannya di ujung yang berlawanan dan membiarkannya tumbuh satu sama lain.
Itu tumbuh ke bawah karena memori yang dialokasikan ke program memiliki "data permanen" yaitu kode untuk program itu sendiri di bagian bawah, lalu heap di tengah. Anda membutuhkan titik tetap lain untuk mereferensikan tumpukan, sehingga Anda berada di puncak. Ini berarti tumpukan tumbuh ke bawah, hingga berpotensi berdekatan dengan objek di heap.