分析簡單的c語言函式編譯得到的X86彙編程式碼(VS2013)
檢視原始碼生成的彙編程式碼:單步除錯->除錯->視窗->反彙編
總結:
①、函式被呼叫時,實參值賦值給函式棧中的形參,使用以下步驟:
I、call函式前實參值壓棧
II、函式中分配區域性變數的程式碼執行完
III、使用原始棧頂值 ebp 的正偏移量(實參),和負偏移量(形參),配合mov指令來實現值傳遞,如:
mov [ebp,ebp-3] [ebp+16,ebp+13] //計算時不可遺漏了棧中 push pc 和 push ebp帶來的esp變化
②、vc編譯c原始碼時,給函式中的臨時變數在棧中分配的儲存區域,不是根據臨時變數的多少制定的,而是一個固定值 204B
③、vc在棧中給函式中臨時變數分配儲存單元后,會執行一系列彙編程式碼,給這些儲存單元賦上初始值,本例中每個位元組都是十六進位制 0xcc ; 執行完賦初始值操作後,才開始進行實參形參值傳遞
④、vc函式中的臨時變數包括以下種類: ①、函式形參 ②、函式體內定義的臨時變數 ③、函式返回值
⑤、本例子中 sum 函式的返回值使用 暫存器eax來傳遞; 一般化的適用於所有情況的函式返回值要使用棧來傳遞給呼叫本函式的程式碼吧。
c原始碼:
int sum(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int a = 2, b = 3;
int c = 0;
c=sum(a, b);
return 1;
}
彙編程式碼:
int sum(int a, int b)
{
00E813C0 push ebp
00E813C1 mov ebp,esp ;將當前棧頂值esp賦值給ebp
00E813C3 sub esp,0CCh ;esp=esp-204,空出204B的棧空間用於本函式的臨時變數(這裡為何是204B不理解,本函式不優化的情況下臨時變數只需要4*4=16B)
;繼續解釋上行程式碼,本組合語言採用遞減棧,即push dword值語句等價於下面①②
①、mov dword ptr [esp],dword值 ②、mov esp esp-4
00E813C9 push ebx ;ebx值入棧儲存
00E813CA push esi ;esi值入棧儲存
00E813CB push edi ;edi值入棧儲存
00E813CC lea edi,[ebp-0CCh] ;給edi=當前段中ebp的地址-204(即00E813C3行執行完後的esp值)
00E813D2 mov ecx,33h ;給ecx賦值33h (十進位制數51,由204/4計算得出,204是棧中儲存臨時變數的位元組數)
00E813D7 mov eax,0CCCCCCCCh ;給eax賦值 0CCCCCCCCh ,本值作為棧中臨時變數區每個dword元素的初始值
00E813DC rep stos dword ptr es:[edi] ;給棧中204B的臨時變數區位元組賦初始值。本語句由以下①②指令複合而來
①、rep 指令 :重複執行指令ecx次(每執行完一次ecx=ecx-1,然後判斷是否繼續執行)
②、stos dword ptr es:[edi] : I、move dword ptr es:[edi] eax II、mov edi edi+4
int c = 0;
00E813DE mov dword ptr [c],0 ; 這裡應該是 mov dword ptr [ebp-8,ebp-11],0
插入以下本編譯器UI中未生成的但實際執行了的語句(此時記憶體中資料排布見下面分析):
mov [ebp,ebp-3] [ebp+16,ebp+13] ; sum函式形參b=sum函式實參b
mov [ebp-4,ebp-7] [ebp+12,ebp+9] ; sum函式形參a=sum函式實參a
c = a + b;
00E813E5 mov eax,dword ptr [a]
00E813E8 add eax,dword ptr [b]
00E813EB mov dword ptr [c],eax
return c;
00E813EE mov eax,dword ptr [c]
上面幾行程式碼中a、b、c所佔的儲存器空間應該是:(佔據棧中臨時變數區起始單元)
b(實參):[ebp+16,ebp+13] (這裡的ebp是esp給棧中臨時變數分配空間前的值)
a(實參):[ebp+12,ebp+9]
push pc (call sum產生,佔4位元組)
push ebp(sum函式開始部分的操作,佔4位元組)
b(形參):[ebp,ebp-3]
a(形參):[ebp-4,ebp-7]
c:[ebp-8,ebp-11]
從main函式 call sum 開始(包括本行),共執行了以下彙編程式碼
main函式中呼叫sum函式的操作包括:
mov eax,dword ptr [b] ; 這裡的 a b 是main函式棧內的臨時變數a b
push eax ;實參入棧
mov ecx,dword ptr [a]
push ecx ;實參入棧
call sum (0E8105Fh) ; 本行等價於①、 push pc ②、move pc sum地址
}
00E813F1 pop edi
00E813F2 pop esi
00E813F3 pop ebx
00E813F4 mov esp,ebp
00E813F6 pop ebp
00E813F7 ret ; pop pc
--- 無原始檔 -----------------------------------------------------------------------
00E813F8 int 3
00E813F9 int 3
00E813FA int 3
00E813FB int 3
00E813FC int 3
00E813FD int 3
00E813FE int 3
00E813FF int 3
--- c:\user_data\11project\practise_project\cpp\testasm\testasm\main.cpp -------
int main()
{
00E81400 push ebp
00E81401 mov ebp,esp
00E81403 sub esp,0E4h
00E81409 push ebx
00E8140A push esi
00E8140B push edi
00E8140C lea edi,[ebp-0E4h]
00E81412 mov ecx,39h
00E81417 mov eax,0CCCCCCCCh
00E8141C rep stos dword ptr es:[edi]
int a = 2, b = 3;
00E8141E mov dword ptr [a],2
00E81425 mov dword ptr [b],3
int c = 0;
00E8142C mov dword ptr [c],0
c=sum(a, b);
00E81433 mov eax,dword ptr [b]
00E81436 push eax
00E81437 mov ecx,dword ptr [a]
00E8143A push ecx
00E8143B call sum (0E8105Fh)
00E81440 add esp,8
00E81443 mov dword ptr [c],eax
return 1;
00E81446 mov eax,1
}
00E8144B pop edi
00E8144C pop esi
00E8144D pop ebx
00E8144E add esp,0E4h
00E81454 cmp ebp,esp
00E81456 call __RTC_CheckEsp (0E8113Bh)
00E8145B mov esp,ebp
00E8145D pop ebp
00E8145E ret