函式呼叫背後那點事

2021-08-03 22:30:57 字數 1850 閱讀 1914

當你寫下乙個簡單的c語言程式(比如我們都會寫的hello world),你可曾知道這個簡單的程式背後的那些事情………今天我們從彙編的角度來**一下乙個函式在被呼叫的前前後後。

我們知道棧儲存了乙個函式呼叫所需要的維護資訊,而這些維護資訊通常被稱為堆疊幀或活動記錄。堆疊幀一般包括如下幾個方面:
1>函式的返回位址和引數。

2>臨時變數:包括函式的非靜態區域性變數以及編譯器自動生成的其他臨時變數。

3>儲存的上下文:包括在函式呼叫前後需要保持不變的暫存器。

廢話少說來看**:

`

#include

int sum(int a, int b)

void main()

下面通過反彙編**來分析下這些簡單的**:

int a = 10;

009a13de mov dword ptr [a],0ah

//將10賦值給區域性變數a,以下兩行**一樣的效果

定義三個區域性變數後main函式壓棧過程

res = sum(a, b);
009a13f3 mov eax,dword ptr [b]

009a13f6 push eax

//把區域性變數b賦給暫存器eax,再把eax壓入main函式的棧中

009a13f7 mov ecx,dword ptr [a]

009a13fa push ecx

//把區域性變數a賦給暫存器ecx,再把ecx壓入main函式的棧中

009a1400 add esp,8

// 回退形參變數的記憶體

009a1403 mov dword ptr [res],eax

//把函式的返回值賦給區域性變數res

且看sum函式的反彙編**:

int sum(int a, int b)

009a1471 pop edi

009a1472 pop esi

009a1473 pop ebx

//三個暫存器出棧

009a1474 mov esp,ebp

//回退sum函式的記憶體棧

009a1476 pop ebp

//出棧,回退到main函式中

009a1477 ret

//讓esp出棧,並把下一行指令的位址賦值給cpu的pc暫存器

整個記憶體棧布局如下:

至此,整個sum函式的呼叫過程結束!!

以上sum函式返回值為4位元組(32位機器)大小,我們發現是通過eax暫存器帶回的,對於c語言的的內建型別、結構體、聯合體(union)、列舉型別(enum)函式的返回值如果小於4位元組,其由暫存器eax帶回。

如果是8個位元組則是由eax和edx共同帶回。

如果它大於8個位元組則在呼叫函式的時候會先壓入(先壓引數,後壓臨時量)main函式棧上的一塊臨時記憶體的位址,然後在呼叫函式return時會把要返回的值拷貝到main函式那塊臨時記憶體上,並通過eax暫存器返回臨時記憶體的位址。

再看看最後的函式呼叫約定吧

呼叫約定主要有以下:

函式的呼叫約定會影響:

好累,睡覺。。

派生 虛函式那點事(未完)

includeusing namespace std class b0 基類bo宣告 class b1 public b0 公有派生 class d1 public b1 公有派生 void fun b0 ptr 普通函式 int main 主函式 由於display 為虛函式,且b1公有繼承自b0...

關於虛函式那點破事

如果你是c 程式設計師,我想你可能遇到過這樣的情況 在debug時,對著乙個函式step into,明明呼叫的是a函式,可是結果卻跳進了b函式。為什麼,call stack裡顯示的也是明明白白,就是直接進了b函式。百思不得其解,於是你懷疑是不是系統出了問題,是不是編譯器出了問題,是不是偵錯程式出了問...

學習那點事

這一周快過去了,回顧這一周,學到的,講到的東西,都很多,其實作為一名程式設計師,是不應該怕累的,雖然很累,學無止境,每天都要更新自己的知識,才能成為一名合格的程式設計師。我一直很想成為一名優秀的程式設計師,從剛開始的無知,經過很盲目,到現在明白了自己要學的是什麼,要怎樣學,這是乙個很艱難的過程,自己...