轉載於CSDN:http://blog.csdn.net/do2jiang/article/details/5404566
在計算機科學中,Call stack是指存放某個程序的正在運行的函數的信息的棧。Call stack和stack frames組成,每個stack frame對應於一個未完成運行的函數。
在當今流行的計算機體系架構中,大部分計算機的參數傳遞,局部變量的分配和釋放都是通過操縱程序棧來實現的。棧用來傳遞函數參數,存儲返回值信息,保存寄存器以供恢復調用前處理機狀態。每次調用一個函數,都要為該次調用的函數實例分配棧空間。為單個函數分配的那部分棧空間就叫做stack frame,也就是說,stack frame這個說法主要是為了描述函數調用關系的。
Stack frame組織方式的重要性和作用體現在兩個方面:
第一:它使調用者和被調用者達成某種約定。這個約定定義了函數調用時函數參數的傳遞方式,函數返回值的返回方式,寄存器如何在調用者和被調用者之間進行共享。
第二:它定義了被調用者如何使用它自己的stack frame來完成局部變量的存儲和使用。
- 上圖描述的是一種典型的(MIPS 32)嵌入式芯片的stack frame組織方式。
- 這張圖中,計算機的棧空間采用的是向下增長的方式。
- sp(stack pointer)就是當前函數的棧指針,它指向的是棧底的位置。
- Current Frame所示即為當前函數(被調用者)的frame。
- Caller's Frame是當前函數的調用者的frame。
- 每個frame中所存放的內容和存放順序,則由目標體系架構的調用約定(calling convention)定義。
- MIPS O32調用約定規定了所占空間不大於4個比特的參數應該放在從$4到$8的寄存器中,剩下的參數應該依次放到調用者stack frame的參數域中,並且在參數域中需要前四個參數保留棧空間。
- 如果被調用者需要使用$16到$23這些保留寄存器(saved register),就必須先將這些保留寄存器的值保存在被調用者stack frame的保留寄存器域中,當被調用者返回時恢復這些寄存器值。
- 當被調用者不是葉子函數時,即被調用者中存在對其它函數的調用,需要將RA(return address)寄存器($31)值保存到被調用者stack frame的返回值域中。
- 被調用者所需要的局部變量,應保存在被調用者stack frame的本地變量域中。
- 在沒有BP(base pointer)寄存器的目標架構中,進入一個函數時需要將當前棧指針向下移動n比特,這個大小為n比特的存儲空間就是此函數的stack frame的存儲區域。此后棧指針便不再移動,智能在函數返回時再將棧指針上這個偏移量恢復棧現場。由於不能隨便移動棧指針,所以寄存器壓棧和出棧都必須指定偏移量。
- 在RISC計算機中主要參與計算的是寄存器,saved registers就是指在進入一個函數后,如果某個保存原函數信息的寄存器會在當前函數中被使用,就應該將此寄存器保存到堆棧上,當函數返回恢復此寄存器值。而且由於RISC計算機大部分采用定長指令或者定變長指令,一般指令長度不會超過32個位。而現代計算機的內存地址范圍已經擴展到32位,這樣在一條指令里就不足以包含有效的內存地址,所以RISC計算機一般借助於一個返回地址寄存器RA來實現函數的返回。幾乎在每個函數調用中都會使用到這個寄存器,所以在很多情況下RA寄存器會被保存在堆棧上以避免被后面的函數調用修改,當函數需要返回時,從堆棧上取回RA然后跳轉。移動SP和保存寄存器的動作一般處在函數的開頭,叫做function prologue;恢復這些寄存器狀態的動作一般放在函數的最后,叫做fuction epilogue。