函式呼叫棧與活動記錄

2021-06-22 20:56:13 字數 2096 閱讀 8632



函式呼叫棧與活動記錄

在除錯的時候經常遇到棧溢位,由此總結了下函式呼叫棧的知識。

為了理解c++是如何執行函式呼叫的,先考慮乙個稱為棧(stack)的資料結構。棧是一種後入先出的資料結構——壓入(插入)棧的最後一項,是從棧中彈出(移走)的第一項。

函式呼叫棧是「在幕後起作用的」,它支援函式呼叫/返回機制。它還支援每個被掉函式的自動變數的建立、維護和銷毀。

當呼叫每個函式時,它可能呼叫其他函式,而後者可能進而呼叫另外的函式,但所有的呼叫都是在返回前進行的。最終,每個函式都必須將控制返回給呼叫它的那個函式。

因此必須以某種方式跟蹤每個函式的返回位址,以便將控制返回到它的呼叫者。函式呼叫棧是處理這個資訊的絕佳資料結構。每次呼叫函式時,就會將乙個項壓入棧中。這個項稱為棧幀(stack frame)或活動記錄,它包含被呼叫函式返回到呼叫函式時所需的返回位址。如果被調函式返回,則會彈出這個函式呼叫的幀棧,且控制會轉移到被彈出的幀棧所包含的返回位址。

呼叫棧的亮點在於每個被調函式都能夠在呼叫棧的頂部找到返回到它的呼叫者時所需要的資訊。而且,如果乙個函式呼叫了另乙個函式,則這個新函式的棧幀也會被簡單地壓入呼叫棧。因此,新的被調函式返回到它的呼叫者所需要的返回位址,就位於棧的頂部。

幀棧還有另外乙個重要責任。大多數函式都有自動變數,包括引數及他說宣告的所有區域性變數。自動變數需要在函式執行時存在。如果函式呼叫了其他函式,則他們仍然需要保持活動狀態。但是當被調函式返回到他的呼叫者後,它的自動變數需要「消失」。被調函式的幀棧是儲存它的自動變數的理想場所。只要被調函式處於活動狀態,它的幀棧就會存在。當函式返回時(此時不在需要它的區域性自動變數),它的幀棧就從棧彈出,而這些區域性變數不再為程式所知。

當然,計算機中的記憶體容量是有限的,因此只要一定數量的記憶體能夠用於在函式呼叫棧上儲存活動記錄。如果發生的函式呼叫超出了函式呼叫棧上能容納的活動記錄,就會發生棧溢位(stack overflow)的錯誤。

實際使用函式呼叫棧

呼叫棧和活動記錄支援函式呼叫/返回機制,也支援自動變數的建立和銷毀。

下面以乙個demo說明呼叫棧如何支援main所呼叫的square函式的操作(見圖1第08-14行)。

首先:作業系統呼叫main,會將這一活動壓入棧中(如下圖1所示)。這個活動記錄會告訴main函式如何返回到作業系統(即轉移到返回位址r1) ,幷包含main的自動變數(即初始化為10的a)所需的空間。

[cpp]view plain

copy

print?

#include "stdafx.h"

#include 

using

namespace std;  

int square(int);  

int _tmain(int argc, _tchar* argv)  

int square(int x)    

#include "stdafx.h"

#include using namespace std;

int square(int);

int _tmain(int argc, _tchar* argv)

int square(int x)

在返回作業系統之前,現在main函式在**第11行呼叫square函式。這會導致square的乙個幀(16~19行)(見圖2)被壓入函式呼叫棧(見圖2)這個棧幀包含返回位址(即r2),使square函式可以返回到main函式,它還包括square的自動變數(即x)所需的記憶體。

在square計算出實參的平方之後,它需要返回到main,並且不再需要它的自動變數x的記憶體。因此,棧被彈出,向square提供main中的返回位置(即r2),並丟失square的自動變數,(圖3)展示了square的活動記錄被彈出之後的函式呼叫棧。

現在,main函式顯示了呼叫square的結果(第11行),然後x執行return語句(13行)。這會使main的活動記錄從棧彈出。它向main提供了返回到作業系統的位址(圖1中的r1),並使的main的自動變數(即a)的記憶體不能再訪問。

函式呼叫棧

當程式進行函式呼叫的時候,系統會用到下面三種暫存器 3.ebp ebp暫存器裡儲存的是棧基址,是在函式呼叫之前,由esp賦值給ebp的。棧底方向,高位位址 call fun arg1,arg2,arg3 修改esp,棧向下增長,引數入棧,返回位址入棧 arg3 arg2 arg1 返回位址 上一層e...

棧 函式呼叫

編譯以下程式,分析此程式以得出棧的精髓 1 主函式被上層呼叫者呼叫後,執行push ebp,esp 4 因為ebp入棧 ebp值沒有改變,值得注意的是剛開始分配站的時候,第乙個入棧的是return,主函式的返回位址,然後是ebp 2 然後是mov ebp,esp,將esp的值賦給ebp,該語句未執行...

函式呼叫 函式棧

函式呼叫大家都不陌生,呼叫者向被呼叫者傳遞一些引數,然後執行被呼叫者的 最後被呼叫者向呼叫者返回結果,還有大家比較熟悉的一句話,就是函式呼叫是在棧上發生的,那麼在計算機內部到底是如何實現的呢?對於程式,編譯器會對其分配一段記憶體,在邏輯上可以分為 段,資料段,堆,棧 段 儲存程式文字,指令指標eip...