【摘自Linux/Unix系統編程手冊】
函數的調用和返回使棧的增長和收縮呈線性。X86-32體系架構上的Linux(和大多數其它Linux和Unix的實現),棧駐留在內存的高端並向下增長(朝堆的方向)。專用寄存器--棧指針(stack pointer),用於跟蹤當前棧頂。每次調用函數時,會在棧上新分配一幀,每當函數返回時,再從棧上將此幀移去。
雖然棧向下增長,但仍將棧的增長端稱為棧頂,因為抽象地來說,情況本就如此。棧的實際增長方向是個屬於硬件范疇的實現細節。在HP PA-RISC的Linux實現中,棧的增長方向就是向上的。
就虛擬內存而言,分配棧幀后,棧段的大小將會增長,但在大多數Linux實現中,釋放這些棧幀后,棧的大小並未減少(在分配新的棧幀時,會對這些內存重新加以利用)。當談論棧段的增長和收縮時,只是從邏輯視角來看待棧幀在棧中的增減情況。
有時,會用用戶棧(user stack)來表示此處所討論的棧,以便與內核棧區分開來。內核棧是每個進程保留在內核內存中的內存區域,在執行系統調用的過程中供(內核)內部函數調用使用。(由於用戶棧駐留在不受保護的用戶內存中,所以內核無法利用用戶棧來達成這一目的)
每個(用戶)棧幀包括如下內容:
- 函數實參和局部變量:由於這些變量都是在調用函數時自動創建的,因此在C語言中稱其為自動變量。函數返回時將自動銷毀這些變量(因為棧幀會被釋放),這也是自動變量和靜態(以及全局)變量主要的語義區別:后者與函數執行無關,且長期存在。
- 函數調用的鏈接信息:每個函數都會用到一些CPU寄存器,比如程序計數器,其指向下一條將要執行的機器語言指令。每當一函數調用另一函數時,會在被調用函數的棧幀中保存這些寄存器的副本,以便函數返回時能為函數調用者將寄存器恢復原狀。
因為函數能夠嵌套調用,所以棧中可能有多個棧幀(若一函數遞歸調用自身,則函數在棧中將有多個棧幀)。