天天看點

函數調用過程-棧幀 和 程序的關系

程式中,一個函數是一個過程,這個過程可以分為包括傳入參數、過程代碼、傳回三部分構成。由于一個函數過程需要用到内部變量、臨時變量等,是以需要在程序空間的棧空間配置設定一段存儲片段來存儲函數過程中的這些參數,該記憶體片段即為棧幀。

棧幀的由來:

        為一個函數的過程提供一個存儲函數局部變量,參數,傳回位址和其他臨時變量;

棧幀的結構:

函數調用過程-棧幀 和 程式的關系

 圖檔來源(現代編譯原理)

棧幀的周期:

    進入函數~函數傳回,該階段内棧幀作為

    不同的語言具體的實作方式略有不同,但是,總體上,fun(a,b);

局部變量:

    包括函數傳入的形參和函數内部定義的變量;

傳回位址:

    指令指針P指向call fun,那麼fun棧幀存儲的傳回位址為P+1;現今的編譯器的一個約定是将傳回位址存到一個固定的寄存器中,這樣比讀取棧幀(記憶體)效率要高。

臨時變量:

    主要為計算,運算過程中的中間臨時變量;

參數傳遞:

    其一:如果fun中調用另一個函數k(a,b...n);那麼,傳遞的參數是形參,按照現代編譯規定,前k個形參是通過寄存器傳遞,後n-k個形參通過棧幀的實參部分(棧幀的尾部)來傳遞;

    其二:主要為在fun中要調用函數g(&a,&b),那麼為g()函數傳出實參(形參是通過寄存器來傳遞的)是通過“傳出實參”區塊進行的,這麼做主要是為了保證該實參能夠被内層嵌套的函數通路。比如,g函數由調用一個k(a位址)函數,同樣需要用到a的位址,是以fun在傳遞參數時必須為實參(&a)傳遞申請固定的記憶體存儲空間(而非用寄存器)這樣k函數可以通過固定的記憶體位址(fun的形參清單來擷取參數值)。這時的g的棧幀為fun棧幀的下一幀(相鄰的空間位址),即調用者和被調用者的棧幀是相連的;

保護的寄存器:

    棧幀作為函數過程的一個臨時記憶體存儲區塊,同時負責函數調用過程中寄存器值的儲存和還原。即:假設fun函數目前占用了寄存器Ri存儲一個臨時變量t,而此時調用了函數g(),在g()函數中可能需要用到寄存器Ri做運算的臨時存儲,那麼如何確定g()函數調用傳回後,Ri恢複到fun中t的原來值。這就需要在調用者或者被調用者中選擇其一來儲存原有Ri的值,即caller-save或者callee-save。

最後一個問題:程序空間中棧幀的展現是什麼?

程序的棧空間 & 棧幀的增長:

調用函數和被調用函數間的棧幀是相鄰的,即如果程序進入一個遞歸函數f(),遞歸k層。那麼在第k層嵌套時,程序的的棧空間已産生出新的k個連續的f()函數的棧幀,當然每個棧幀的記憶體儲的變量值是因函數過程而定的。

原創:Ordeder  http://blog.csdn.net/ordeder/article/details/20405197

上一篇: ims 用戶端
下一篇: 原根詳解

繼續閱讀