一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

C|從匯編的角度理解函數(shù)調(diào)用與參數(shù)傳遞

 山峰云繞 2022-01-07

https://m.toutiao.com/is/89vUoUv/?=C++ 


主調(diào)函數(shù)(caller)調(diào)用被調(diào)函數(shù)(callee),編譯器要考慮兩者的相互獨(dú)立和相互聯(lián)系。

一方面通過傳遞參數(shù)(值或址)和函數(shù)返回(值或址)來在兩段代碼之間建立聯(lián)系。傳址還可以形成副作用。

(C++的引用參數(shù)也是一種傳址,只是編譯器做了自動(dòng)取址和解引用取值的動(dòng)作。)

另一方面主調(diào)函數(shù)和被調(diào)函數(shù)都有各自的函數(shù)棧幀(function frame),但兩者的地址空間是透明的(主調(diào)函數(shù)可以通過被調(diào)函數(shù)棧幀上的地址來間接訪問被調(diào)函數(shù)棧幀上的空間)。

主調(diào)函數(shù)調(diào)用被調(diào)函數(shù)時(shí),對(duì)于參數(shù),不管是傳值還是傳址,都會(huì)有一個(gè)壓棧操作,但壓值和壓址的操作稍有不同(后續(xù)會(huì)從匯編的角度分析),參數(shù)壓棧后,被調(diào)函數(shù)體對(duì)參數(shù)的操作就是對(duì)壓??臻g的引用,當(dāng)然,對(duì)值的引用和址的引用在解析成匯編后也會(huì)不同,后者會(huì)增加一個(gè)解引用(從地址取值)的動(dòng)作。

demo:

#include <stdio.h>int __cdecl callee(int *a, int &b, int d) // __cdecl是函數(shù)調(diào)用約定,是略寫時(shí)的默認(rèn)調(diào)用約定{ int t = *a; *a = b*d; b = t*d; return *a*b;}void caller(){ int a=3,b=4,d=2; int c = callee(&a,b,d); // 函數(shù)調(diào)用時(shí)會(huì)傳址或傳址,參數(shù)會(huì)通過壓棧而形成副本機(jī)制 printf('%d\n',c);}int main() // main由操作系統(tǒng)調(diào)用而被執(zhí)行,其它函數(shù)要由另外的函數(shù)去調(diào)用才會(huì)被執(zhí)行, // main函數(shù)通常充當(dāng)被調(diào)函數(shù)的作用 // main函數(shù)內(nèi)定義的變量也是局部變量{ caller(); getchar(); return 0;}

demo中的主調(diào)函數(shù)是caller,被調(diào)函數(shù)是callee。

1 調(diào)用約定

調(diào)用約定主要定義主調(diào)函數(shù)和被調(diào)函數(shù)對(duì)于堆棧平衡的分工,參數(shù)壓棧順序規(guī)定等。

2 主調(diào)函數(shù)caller棧幀空間的建立

9:    void caller()10:   {00401090   push        ebp// ebp壓棧,屆時(shí)局部變量會(huì)壓在ebp之上(低地址方向,棧往低地址方向增長)00401091   mov         ebp,esp00401093   sub         esp,50h// 局部變量使用的空間,編譯器會(huì)計(jì)算局部變量的需求(適當(dāng)增加)而不同00401096   push        ebx// 為保持寄存器狀態(tài)而額外使用的??臻g(50h以外)00401097   push        esi00401098   push        edi00401099   lea         edi,[ebp-50h]0040109C   mov         ecx,14h004010A1   mov         eax,0CCCCCCCCh// debug模式時(shí),會(huì)將50h的空間全部置0ch004010A6   rep stos    dword ptr [edi]

3 主調(diào)函數(shù)caller局部變量壓棧

11: int a=3,b=4,d=2;004010A8 mov dword ptr [ebp-4],3// 局部變量地址以ebp為基準(zhǔn),向低地址方向增長004010AF mov dword ptr [ebp-8],4004010B6 mov dword ptr [ebp-0Ch],2

4 函數(shù)調(diào)用(實(shí)參壓棧)和返回

12:       int c = callee(&a,b,d); // 函數(shù)調(diào)用時(shí)會(huì)傳址或傳址,參數(shù)會(huì)通過壓棧而形成副本機(jī)制004010BD   mov         eax,dword ptr [ebp-0Ch] // d賦值給eax寄存器,注意這里是mov,值賦值(或值傳遞)004010C0   push        eax // d壓棧004010C1   lea         ecx,[ebp-8] // b的地址賦值給ecx,注意這里是lea,址賦值(或址傳遞)004010C4   push        ecx // &b壓棧004010C5   lea         edx,[ebp-4] // a的地址賦值給edx004010C8   push        edx // &a壓棧004010C9   call        @ILT+20(callee) (00401019) // 這里要進(jìn)入函數(shù)調(diào)用004010CE   add         esp,0Ch  // 函數(shù)調(diào)用完成后返回到這里,按__cdecl約定,由主調(diào)函數(shù)平衡參數(shù)所占空間004010D1   mov         dword ptr [ebp-10h],eax // 返回值存放在寄存器eax中,返回給主調(diào)函數(shù)的c

注意上述引用傳址和指針傳址使用了相同的匯編代碼。

對(duì)于一個(gè)寄存器可以存下的返回值,通常通過eax返回,對(duì)于浮點(diǎn)數(shù),一般通過浮點(diǎn)棧的寄存器返回,對(duì)于復(fù)合類型,會(huì)在主調(diào)函數(shù)的局部空間規(guī)劃出一塊空間用來存放返回值,這塊空間的首地址會(huì)在壓完參數(shù)后壓在棧幀上。

call 函數(shù)名

push 返回地址(EIP) + jmp 函數(shù)地址

(EIP指向下一條指令)

(1) 將程序當(dāng)前執(zhí)行的位置IP的下一個(gè)地址壓入堆棧中;

(2) 轉(zhuǎn)移到調(diào)用的子程序。

5 caller call caller

@ILT+5(?callee@@YAHPAHAAHH@Z):0040100A jmp callee (00401030)

編譯器會(huì)將返回地址004010CE壓棧,此時(shí)的棧幀空間是:

6 被調(diào)函數(shù)棧幀空間建立

2:    int __cdecl callee(int *a, int &b, int d) // __cdecl是函數(shù)調(diào)用約定,是略寫時(shí)的默認(rèn)調(diào)用約定3:    {00401030   push        ebp00401031   mov         ebp,esp00401033   sub         esp,44h00401036   push        ebx00401037   push        esi00401038   push        edi00401039   lea         edi,[ebp-44h]0040103C   mov         ecx,11h00401041   mov         eax,0CCCCCCCCh00401046   rep stos    dword ptr [edi]

7 callee函數(shù)體對(duì)實(shí)參的引用

4: int t = *a;00401048 mov eax,dword ptr [ebp+8]0040104B mov ecx,dword ptr [eax] // 對(duì)a的解引用并賦值0040104D mov dword ptr [ebp-4],ecx5: *a = b*d;00401050 mov edx,dword ptr [ebp+0Ch]00401053 mov eax,dword ptr [edx] // 對(duì)b的解引用并賦值00401055 imul eax,dword ptr [ebp+10h] // 對(duì)b的值的直接引用00401059 mov ecx,dword ptr [ebp+8]0040105C mov dword ptr [ecx],eax6: b = t*d;0040105E mov edx,dword ptr [ebp-4]00401061 imul edx,dword ptr [ebp+10h]00401065 mov eax,dword ptr [ebp+0Ch]00401068 mov dword ptr [eax],edx7: return *a*b;0040106A mov ecx,dword ptr [ebp+8]0040106D mov edx,dword ptr [ebp+0Ch]00401070 mov eax,dword ptr [ecx]00401072 imul eax,dword ptr [edx]8: }

注意以上匯編對(duì)值的直接引用,對(duì)引用傳遞和指針傳遞的變量先是引用地址,然后通過地址來解引用。

8 被調(diào)函數(shù)負(fù)責(zé)的自己部分的堆棧平衡

00401075   pop         edi00401076   pop         esi00401077   pop         ebx00401078   mov         esp,ebp0040107A   pop         ebp // 相當(dāng)于C語言中的ebp = *esp; esp += 40040107B   ret  // 相當(dāng)于 pop EIP

-End-

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    国产爆操白丝美女在线观看| 日本精品最新字幕视频播放| 福利一区二区视频在线| 亚洲中文在线观看小视频| 91精品国产品国语在线不卡 | 超碰在线播放国产精品| 色偷偷偷拍视频在线观看| 亚洲最大福利在线观看| 一区二区三区精品人妻| 久久精品国产亚洲av久按摩| 亚洲乱码av中文一区二区三区| 国产丝袜女优一区二区三区| 国产内射一级一片内射高清| 国产麻豆一线二线三线| 亚洲天堂精品在线视频| 亚洲中文字幕高清乱码毛片 | 国产色第一区不卡高清| 国产精品成人免费精品自在线观看| 大屁股肥臀熟女一区二区视频| 国产不卡最新在线视频| 国产专区亚洲专区久久| 黄片在线免费看日韩欧美| 男人操女人下面国产剧情| 少妇淫真视频一区二区| 日韩美成人免费在线视频| 久久精品久久精品中文字幕| 成人国产激情福利久久| 扒开腿狂躁女人爽出白浆av| 欧美日韩久久精品一区二区| 欧美日韩在线视频一区| 中文字幕人妻一区二区免费 | 国产精品日韩欧美一区二区 | 在线日韩中文字幕一区| 国产精品久久精品毛片| 久久夜色精品国产高清不卡| 青青操成人免费在线视频| 国产精品久久精品毛片| 欧美野外在线刺激在线观看| 国产欧美精品对白性色| 中文字幕一区久久综合| 亚洲国产精品一区二区|