函數和彙編

來源:互聯網
上載者:User
文章目錄
  • 1.  函數參數
  • 3. 參考

本文基於win32下彙編。

1.  函數參數

函數棧增長方向與地址方向相反,從高地址向低地址增長。esp指向函數棧頂,ebp指向函數棧底。

sub esp XXX 將XXX長度的記憶體塊壓入棧

add esp XXX將XXX長度的記憶體塊彈出棧

參數壓棧順序樣本

int param1 = 1;00C939DF  mov         dword ptr [param1],1 int param2 = 3;00C939E6  mov         dword ptr [param2],3 int sum = pushParametersOrderApp(param1, param2); #壓棧順序跟參數申明順序相反!00C939F0  mov         eax,dword ptr [param2] # 將param2值放入eax00C939F6  push        eax  # 壓棧eax00C939F7  mov         ecx,dword ptr [param1] # 將param1值放入ecx00C939FA  push        ecx  # 壓棧ecx00C939FB  call        pushParametersOrderApp (0C911F9h) # 函數調用00C93A00  add         esp,8 # 將之前壓棧的eax和ecx兩個值移除。pop操作是將esp加8,說明棧增長方向是從高地址到低地址。00C93A03  mov         dword ptr [sum],eax # 函數傳回值在eax中,存入sum變數中# 函數調用現場int pushParametersOrderApp(int param1, int param2){00E41F80  push        ebp  # 儲存之前ebp指標,esp += 400E41F81  mov         ebp,esp # 將新的esp賦給ebp指向當前函數棧底00E41F83  sub         esp,0D8h # 當前函數棧幀 預留216(0D8)的位元組,存放自動變數00E41F89  push        ebx  00E41F8A  push        esi  00E41F8B  push        edi  00E41F8C  lea         edi,[ebp-0D8h] # 棧頂指標地址存入edi00E41F92  mov         ecx,36h # 棧上54(36h)個整數,即216(0D8)個位元組00E41F97  mov         eax,0CCCCCCCCh # 初始化的數值00E41F9C  rep stos    dword ptr es:[edi] # 初始化棧空間int temp1 = param1;00E41F9E  mov         eax,dword ptr [param1] # param1的值存入eax00E41FA1  mov         dword ptr [temp1],eax # eax值存入temp1中int temp2 = param2;00E41FA4  mov         eax,dword ptr [param2] # 同理00E41FA7  mov         dword ptr [temp2],eax return temp1 + temp2;00E41FAA  mov         eax,dword ptr [temp1] # temp1值存入eax00E41FAD  add         eax,dword ptr [temp2] # 相加結果存入eax,與函數返回後00C93A03行操作對應,函數結果在eax中}00FE1FB0  pop         edi  00FE1FB1  pop         esi  00FE1FB2  pop         ebx  00FE1FB3  mov         esp,ebp # 還原esp00FE1FB5  pop         ebp  # 還原ebp,同時esp-=400FE1FB6  ret    

pushParametersOrderApp函數調用前後堆棧:

代碼比較簡單,對兩個變數進行求和,結果返回。通過彙編源碼說明幾點:

1)C/C++ 中函數參數壓棧順序:與申明順序相反

2)函數棧幀的定義:esp和ebp之間的記憶體塊

3)棧上自動變數的初始化,使用0CCCCCCCC

4)函數參數在函數棧幀的外面,見00C939F6、00C939FA行;函數局部變數參數定義在棧上。

傳值拷貝

struct TestItem{int a;int b;int arr[10];};int passValueApp(TestItem item){int value = item.a;int value1 = item.b;return value;}int passReferenceApp(TestItem& item){int value = item.a;int valu1 = item.b;return value;}int passPointerApp(TestItem* item){int value = item->a;int value1 = item->b;return value;}TestItem item = {1, 4, {1,2,3}};00FE3948  mov         dword ptr [item],1 # &item.a==item,a置為100FE394F  mov         dword ptr [ebp-30h],4 # ebp-48 通過ebp指標訪問b00FE3956  mov         dword ptr [ebp-2Ch],1 # ebp-4400FE395D  mov         dword ptr [ebp-28h],2 # ebp-4000FE3964  mov         dword ptr [ebp-24h],3 # ebp-3600FE396B  xor         eax,eax # 異或操作將eax置零00FE396D  mov         dword ptr [ebp-20h],eax # ebp-3200FE3970  mov         dword ptr [ebp-1Ch],eax # ebp-2800FE3973  mov         dword ptr [ebp-18h],eax # ebp-2400FE3976  mov         dword ptr [ebp-14h],eax # ebp-2000FE3979  mov         dword ptr [ebp-10h],eax # ebp-1600FE397C  mov         dword ptr [ebp-0Ch],eax # ebp-1200FE397F  mov         dword ptr [ebp-8],eax # ebp-8passValueApp(item);###### 傳結構體函數 ######00FE3982  sub         esp,30h # 參數值拷貝,esp減去48(30h)正好sizeof TestItem大小00FE3985  mov         ecx,0Ch # 指定要拷貝次數,0Ch即12個整數,對用48byte00FE398A  lea         esi,[item] # 擷取item地址00FE398D  mov         edi,esp # 拷貝基地址指定00FE398F  rep movs    dword ptr es:[edi],dword ptr [esi]  # rep迴圈12次拷貝00FE3991  call        passValue (0FE11E5h) # 00FE3996  add         esp,30h # 將參數拷貝彈出棧空間,esp+=48passPointerApp(&item);###### 傳指標函數 ######00FE3999  lea         eax,[item] # 擷取item地址存入eax00FE399C  push        eax  # 參數值拷貝,壓棧eax esp-=400FE399D  call        passPointerApp (0FE11EFh) # 00FE39A2  add         esp,4 # 將參數拷貝彈出棧空間,esp+=4passReferenceApp(item);00FE39A5  lea         eax,[item] # 彙編層面引用版本和指標一樣00FE39A8  push        eax  00FE39A9  call        passReferenceApp (0FE11EAh) 00FE39AE  add         esp,4 

該樣本說明了函數傳值拷貝問題:

1)passValueApp函數調用需要在棧幀上預留48位元組的空間,00FE398D、00FE398F拷貝item結構體,函數執行完成以後將esp加上48位元組將參數拷貝出棧。

2)passPointerApp函數傳指標,00FE399C行將指標變數拷貝入棧,函數調用完成將esp+4完成參數拷貝出棧操作。

3)passReferenceApp 傳引用於傳指標原理一樣。

由此可見,大資料結構一定要傳指標或者引用。

2. 函數傳回值

# 函數內部堆棧現場TestItem returnStructApp(){00EC3850  push        ebp  00EC3851  mov         ebp,esp 00EC3853  sub         esp,0F8h 00EC3859  push        ebx  00EC385A  push        esi  00EC385B  push        edi  00EC385C  lea         edi,[ebp-0F8h] 00EC3862  mov         ecx,3Eh 00EC3867  mov         eax,0CCCCCCCCh 00EC386C  rep stos    dword ptr es:[edi] TestItem item = { 1,2, {3,4,5} };00EC386E  mov         dword ptr [item],1 00EC3875  mov         dword ptr [ebp-30h],2 00EC387C  mov         dword ptr [ebp-2Ch],3 00EC3883  mov         dword ptr [ebp-28h],4 00EC388A  mov         dword ptr [ebp-24h],5 00EC3891  xor         eax,eax 00EC3893  mov         dword ptr [ebp-20h],eax 00EC3896  mov         dword ptr [ebp-1Ch],eax 00EC3899  mov         dword ptr [ebp-18h],eax 00EC389C  mov         dword ptr [ebp-14h],eax 00EC389F  mov         dword ptr [ebp-10h],eax 00EC38A2  mov         dword ptr [ebp-0Ch],eax 00EC38A5  mov         dword ptr [ebp-8],eax return item;00EC38A8  mov         ecx,0Ch # 拷貝長度12個整數00EC38AD  lea         esi,[item] # 擷取item地址00EC38B0  mov         edi,dword ptr [ebp+8] # 臨時對象1地址00EC38B3  rep movs    dword ptr es:[edi],dword ptr [esi] # 將item內容拷貝到edi指向記憶體區,edi被改變00EC38B5  mov         eax,dword ptr [ebp+8] # 將臨時對象1地址存入eax寄存器,傳出函數!}00EC38B8  push        edx  00EC38B9  mov         ecx,ebp 00EC38BB  push        eax  00EC38BC  lea         edx,[ (0EC38D0h)] 00EC38C2  call        @ILT+135(@_RTC_CheckStackVars@8) (0EC108Ch) 00EC38C7  pop         eax  00EC38C8  pop         edx  00EC38C9  pop         edi  00EC38CA  pop         esi  00EC38CB  pop         ebx  00EC38CC  mov         esp,ebp 00EC38CE  pop         ebp  00EC38CF  ret   # 函數呼叫堆疊現場TestItem item1 = returnStructApp();00EC39B1  lea         eax,[ebp-188h] 00EC39B7  push        eax  # returnStructApp是個無參函數,但是也會壓eax入棧00EC39B8  call        returnStructApp (0EC11F4h) 00EC39BD  add         esp,4 # 彈出eax00EC39C0  mov         ecx,0Ch # 拷貝長度12整數00EC39C5  mov         esi,eax # eax指向函數返回的臨時對象資料區,在returnStructApp函數內部被修改00EC39C7  lea         edi,[ebp-1C0h] # 臨時對象2記憶體塊地址00EC39CD  rep movs    dword ptr es:[edi],dword ptr [esi] # 迴圈執行資料拷貝,從函數內部臨時對象1到臨時對象200EC39CF  mov         ecx,0Ch # 拷貝長度12整數00EC39D4  lea         esi,[ebp-1C0h] # 臨時對象2記憶體塊地址00EC39DA  lea         edi,[item1] # 目標item1資料區00EC39DD  rep movs    dword ptr es:[edi],dword ptr [esi] # 迴圈執行資料拷貝,從臨時對象2到item1

上面代碼中,函數中返回一個結構體對象,然後函數傳回值賦給item1,函數返回過程中構造了兩個臨時對象,一共執行了3次資料拷貝。所以效率比較低。盡量避免直接返回結構對象。

3. 參考

1. http://blog.csdn.net/ENO_REZ/article/details/2158682

2. http://blog.csdn.net/vagrxie/article/details/2501238

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.