#include
intsum
(int a,
int b)
//mov esp,ebp 釋放空間
//pop ebp 彈出ebp給棧底,即回歸主呼叫 棧
//ret 彈出位址給pc指標,根據pc指標跳轉
intmain()
/*
函式的呼叫時之前,需要掃瞄函式的宣告和定義,然後對實參列表進行解參(與形參個數是否匹配,然後型別是否匹配(是否可以型別轉換))
當在乙個函式的執行期間呼叫另乙個函式時,在執行被調函式之前,系統需要完成三件事:
1、將所有的實際引數,返回位址等資訊傳遞給被調函式。
2、為被調函式的區域性變數(也包括形參)分配儲存空間
3、將控制轉移到被調函式的入口
從被調函式返回主調函式之前,系統也要完成三件事:
1、儲存被調函式的返回結果
2、釋放被調函式所佔的儲存空間(esp=ebp)
3、依照被調函式儲存的返回位址將控制轉移到呼叫函式
所以被調函式的形參、返回位址、棧底ebp的空間其實是由主調方開闢的記憶體(在主調方棧裡開闢記憶體),只是在被調方結束時自己釋放記憶體而形參的記憶體卻是由主調方釋放
返回的結果如果大於8位元組時,在主調方會產生臨時量記憶體,被壓入棧中。
在被調函式裡對形參的訪問是通過棧底操作 ebp+8 ebp+0ch
call 兩個動作
1.壓入pc所指向位址
2.call跳轉到對應函式(此時位址是偏移量)
ret 兩個動作
1.出棧,將棧頂元素賦給pc暫存器
2.根據pc跳轉到call後面的指令
臨時量可能產生的階段:
1.函式呼叫之前產生臨時量。(接收返回值)
2.函式呼叫,在return 產生臨時量
3.函式呼叫完成之後產生臨時量 (const int &a)
內建型別返回的是常量,不可修改(右值,不可定址),要想返回變數加可以被&返回的變數
自定義型別產生的臨時量都是變數,可以修改
ps:返回的臨時量都是放在乙個暫存器裡,只不過可能是數值,也可能是位址,需要進行兩次拷貝。
(一次返回時將其拷貝給臨時量,第二次將臨時量的值拷貝給函式表示式)
_cdecl c呼叫約定(預設)
_stdcall windows標準的呼叫約定
_fastcall 快速呼叫約定
_thiscall c++的成員函式的呼叫約定
_pascal (已棄用)
呼叫方式影響函式的三個方面
函式產生的符號名字不同
函式引數入棧順序不同
右->左
誰來清理形參的記憶體(主要看的還是誰來清理引數)
int _cdecl sum
(int a,
int b)
;內宣告 其.obj產生的符號sum在*und*,對sum的引用
int _stdcall sum
(int a,
int b)
內定義 其.obj產生的符號sum在*.text*
ps:
函式宣告時會產生符號, 在und區 —所有的符號引用都要到定位到對符號的定義(在鏈結時需要進行符號解析)
由於不同的呼叫方式產生的符號不同(編譯器認為其就是不同的符號),無法進行符號解析
_cdecl 呼叫方開闢形參記憶體,呼叫方釋放形參記憶體(主調方eps+8)
_stdcall 呼叫方開闢形參記憶體,被呼叫方自己釋放形參記憶體(被調方ret 8 )
//ret 8
1.將位址彈出放入pc
2.系統自動回退8個位元組位址(形參)
_fastcall 把最左邊(最**棧)(也就是最後8位元組的實參通過暫存器帶到被呼叫函式中)
若當引數大於8byte則需要入棧操作(呼叫方開闢形參記憶體),但也是把最左邊(也就是最後8位元組的實參通過暫存器帶到被呼叫函式中),被呼叫方自己釋放形參記憶體
ps其函式實參通過暫存器傳給形參而不需要進行入棧,出棧
函式呼叫堆疊
一 函式呼叫堆疊 認真體會每一行指令位址!include intsum int a,int b mov ebp,esp 讓esp回退到ebp的位置,回退棧幀的過程中,沒有對棧幀中的值進行清0的操作 pop ebp 出棧並把出棧的值賦給ebp int main 下圖為上面示例函式,程式在sum函式中,...
函式呼叫堆疊
一 棧 1 傳統的棧 被定義為乙個特殊的容器,使用者可以將資料壓入棧中,也可以將壓入 棧中的資料彈出,但必須遵守一條規則 先進後出。2 計算機系統中的棧 是乙個有以上屬性的動態記憶體區域,壓棧操作使得棧增大,彈出操作使棧減小。棧通常是向下增長的。3 最重要的是棧儲存了乙個函式呼叫所需的維護資訊,這通...
函式呼叫堆疊
乙個函式的執行在棧上開闢記憶體。在函式呼叫時,第乙個進棧的是主函式呼叫語句的下一條可執行語句的位址,然後是函式的各個引數。在大多編譯器中,引數是由右往左入棧的,然後再是函式中的區域性變數。下面給乙個例項 int sum int a,int b int main 其中,main函式的反彙編指令 其中,...