Apa arah pertumbuhan tumpukan di sebagian besar sistem modern?


Jawaban:


147

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:

  • x86: turun.
  • SPARC: dapat dipilih. ABI standar menggunakan down.
  • PPC: turun, saya kira.
  • Sistem z: dalam daftar tertaut, saya tidak bercanda (tapi masih down, setidaknya untuk zLinux).
  • ARM: dapat dipilih, tetapi Thumb2 memiliki encoding kompak hanya untuk down (LDMIA = increment setelah, STMDB = decrement before).
  • 6502: down (tapi hanya 256 byte).
  • RCA 1802A: cara apapun yang Anda inginkan, tunduk pada implementasi SCRT.
  • PDP11: turun.
  • 8051: naik.

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 Rninstruksi. 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 R4akan 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 R3dan jalankan di alamat baru.

Untuk mengembalikan, itu akan SEP R5menarik alamat lama dari tumpukan R2, menambahkan dua ke dalamnya (untuk melewati byte alamat panggilan), memuatnya ke R3 dan SEP R3mulai 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.


3
Untuk menambah daftar, ARM dapat berkembang di kedua arah, tetapi dapat diatur ke salah satu arah atau yang lain dengan implementasi silikon tertentu (atau dapat dibiarkan dapat dipilih oleh perangkat lunak). Beberapa yang saya tangani selalu dalam mode tumbuh-turun.
Michael Burr

1
Di sedikit dunia ARM yang saya lihat sejauh ini (ARM7TDMI) tumpukan sepenuhnya ditangani dalam perangkat lunak. Alamat kembali disimpan dalam register yang disimpan oleh perangkat lunak jika diperlukan, dan instruksi pra- / pasca-kenaikan / penurunan memungkinkan untuk meletakkannya dan hal-hal lain di tumpukan di kedua arah.
starblue

1
Satu HPPA, tumpukan tumbuh! Cukup langka di antara arsitektur yang cukup modern.
tml

2
Bagi yang penasaran, berikut adalah sumber yang bagus tentang cara kerja tumpukan di z / OS: www-03.ibm.com/systems/resources/Stack+and+Heap.pdf
Dillon Cower

1
Terima kasih @paxdiablo atas pengertian Anda. Kadang-kadang orang menganggapnya sebagai penghinaan pribadi ketika Anda membuat komentar seperti itu, terutama ketika komentar itu lebih tua. Saya hanya tahu ada perbedaan karena saya sendiri pernah melakukan kesalahan yang sama di masa lalu. Hati hati.
CasaDeRobison

23

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);
    }
}

14
Wow, sudah lama sekali saya tidak melihat kata kunci "otomatis".
paxdiablo

9
(& dummy> addr) tidak ditentukan. Hasil pengumpanan dua pointer ke operator relasional ditentukan hanya jika dua pointer menunjuk dalam larik atau struktur yang sama.
sigjuice

2
Mencoba untuk menyelidiki tata letak tumpukan Anda sendiri - sesuatu yang C / C ++ tidak menentukan sama sekali - "tidak dapat dibawa" untuk memulai, jadi saya tidak akan terlalu peduli tentang itu. Sepertinya fungsi ini hanya akan bekerja dengan benar sekali.
ephemient

9
Tidak perlu menggunakan a staticuntuk ini. Sebagai gantinya, Anda bisa meneruskan alamat sebagai argumen ke panggilan rekursif.
R .. GitHub STOP HELPING ICE

5
ditambah, dengan menggunakan static, jika Anda memanggil ini lebih dari sekali, panggilan berikutnya mungkin gagal ...
Chris Dodd

7

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.


3
Bukan 'keuntungan', sebenarnya tautologi.
Marquis dari Lorne

1
Bukan tautologi. Intinya adalah memiliki dua wilayah memori yang berkembang tidak mengganggu (kecuali memori penuh), seperti yang ditunjukkan @valenok.
YvesgereY

6

Stack tumbuh di x86 (ditentukan oleh arsitektur, pop increments stack pointer, push decrements.)


5

Di MIPS dan banyak arsitektur RISC modern (seperti PowerPC, RISC-V, SPARC ...) tidak ada pushdan popinstruksi. 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


2

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.


2

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.


intinya sepertinya sudah mati sekarang :(
Ven

@Ven - Saya bisa mendapatkannya
Brett Holman

1

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.


0

Makro ini harus mendeteksinya saat runtime tanpa UB:

#define stk_grows_up_eh() stk_grows_up__(&(char){0})
_Bool stk_grows_up__(char *ParentsLocal);

__attribute((__noinline__))
_Bool stk_grows_up__(char *ParentsLocal) { 
    return (uintptr_t)ParentsLocal < (uintptr_t)&ParentsLocal;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.